summaryrefslogtreecommitdiff
path: root/lib_i386
diff options
context:
space:
mode:
authorKevin2014-11-15 11:48:36 +0800
committerKevin2014-11-15 11:48:36 +0800
commitd04075478d378d9e15f3e1abfd14b0bd124077d4 (patch)
tree733dd964582f388b9e3e367c249946cd32a2851f /lib_i386
downloadFOSSEE-netbook-uboot-source-d04075478d378d9e15f3e1abfd14b0bd124077d4.tar.gz
FOSSEE-netbook-uboot-source-d04075478d378d9e15f3e1abfd14b0bd124077d4.tar.bz2
FOSSEE-netbook-uboot-source-d04075478d378d9e15f3e1abfd14b0bd124077d4.zip
init commit via android 4.4 uboot
Diffstat (limited to 'lib_i386')
-rwxr-xr-xlib_i386/Makefile45
-rwxr-xr-xlib_i386/bios.S462
-rwxr-xr-xlib_i386/bios.h94
-rwxr-xr-xlib_i386/bios_pci.S411
-rwxr-xr-xlib_i386/bios_setup.c233
-rwxr-xr-xlib_i386/board.c427
-rwxr-xr-xlib_i386/i386_linux.c173
-rwxr-xr-xlib_i386/pci.c155
-rwxr-xr-xlib_i386/pci_type1.c56
-rwxr-xr-xlib_i386/realmode.c95
-rwxr-xr-xlib_i386/realmode_switch.S222
-rwxr-xr-xlib_i386/video.c237
-rwxr-xr-xlib_i386/video_bios.c219
-rwxr-xr-xlib_i386/zimage.c275
14 files changed, 3104 insertions, 0 deletions
diff --git a/lib_i386/Makefile b/lib_i386/Makefile
new file mode 100755
index 0000000..e5925e5
--- /dev/null
+++ b/lib_i386/Makefile
@@ -0,0 +1,45 @@
+#
+# (C) Copyright 2002
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = lib$(ARCH).a
+
+AOBJS = bios.o bios_pci.o realmode_switch.o
+
+COBJS = board.o bios_setup.o i386_linux.o zimage.o realmode.o \
+ pci_type1.o pci.o video_bios.o video.o
+
+OBJS = $(AOBJS) $(COBJS)
+
+$(LIB): .depend $(OBJS)
+ $(AR) crv $@ $(OBJS)
+
+#########################################################################
+
+.depend: Makefile $(AOBJS:.o=.S) $(COBJS:.o=.c)
+ $(CC) -M $(CFLAGS) $(AOBJS:.o=.S) $(COBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/lib_i386/bios.S b/lib_i386/bios.S
new file mode 100755
index 0000000..4606419
--- /dev/null
+++ b/lib_i386/bios.S
@@ -0,0 +1,462 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Based on msbios.c from rolo 1.6:
+ *----------------------------------------------------------------------
+ * (C) Copyright 2000
+ * Sysgo Real-Time Solutions GmbH
+ * Klein-Winternheim, Germany
+ *----------------------------------------------------------------------
+ */
+
+#include "bios.h"
+
+/*
+ * During it's initialization phase, before switching to protected
+ * mode, the Linux Kernel makes a few BIOS calls. This won't work
+ * if the board does not have a BIOS.
+ *
+ * This is a very minimalisic BIOS that supplies just enough
+ * functionality to keep the Linux Kernel happy. It is NOT
+ * a general purpose replacement for a real BIOS !!
+ */
+
+
+.section .bios, "ax"
+.code16
+.org 0
+ /* a call to f000:0 should warmboot */
+ jmp realmode_reset
+
+.globl rm_int00
+rm_int00:
+ pushw $0
+ jmp any_interrupt16
+.globl rm_int01
+rm_int01:
+ pushw $1
+ jmp any_interrupt16
+.globl rm_int02
+rm_int02:
+ pushw $2
+ jmp any_interrupt16
+.globl rm_int03
+rm_int03:
+ pushw $3
+ jmp any_interrupt16
+.globl rm_int04
+rm_int04:
+ pushw $4
+ jmp any_interrupt16
+.globl rm_int05
+rm_int05:
+ pushw $5
+ jmp any_interrupt16
+.globl rm_int06
+rm_int06:
+ pushw $6
+ jmp any_interrupt16
+.globl rm_int07
+rm_int07:
+ pushw $7
+ jmp any_interrupt16
+.globl rm_int08
+rm_int08:
+ pushw $8
+ jmp any_interrupt16
+.globl rm_int09
+rm_int09:
+ pushw $9
+ jmp any_interrupt16
+.globl rm_int0a
+rm_int0a:
+ pushw $10
+ jmp any_interrupt16
+.globl rm_int0b
+rm_int0b:
+ pushw $11
+ jmp any_interrupt16
+.globl rm_int0c
+rm_int0c:
+ pushw $12
+ jmp any_interrupt16
+.globl rm_int0d
+rm_int0d:
+ pushw $13
+ jmp any_interrupt16
+.globl rm_int0e
+rm_int0e:
+ pushw $14
+ jmp any_interrupt16
+.globl rm_int0f
+rm_int0f:
+ pushw $15
+ jmp any_interrupt16
+.globl rm_int10
+rm_int10:
+ pushw $16
+ jmp any_interrupt16
+.globl rm_int11
+rm_int11:
+ pushw $17
+ jmp any_interrupt16
+.globl rm_int12
+rm_int12:
+ pushw $18
+ jmp any_interrupt16
+.globl rm_int13
+rm_int13:
+ pushw $19
+ jmp any_interrupt16
+.globl rm_int14
+rm_int14:
+ pushw $20
+ jmp any_interrupt16
+.globl rm_int15
+rm_int15:
+ pushw $21
+ jmp any_interrupt16
+.globl rm_int16
+rm_int16:
+ pushw $22
+ jmp any_interrupt16
+.globl rm_int17
+rm_int17:
+ pushw $23
+ jmp any_interrupt16
+.globl rm_int18
+rm_int18:
+ pushw $24
+ jmp any_interrupt16
+.globl rm_int19
+rm_int19:
+ pushw $25
+ jmp any_interrupt16
+.globl rm_int1a
+rm_int1a:
+ pushw $26
+ jmp any_interrupt16
+.globl rm_int1b
+rm_int1b:
+ pushw $27
+ jmp any_interrupt16
+.globl rm_int1c
+rm_int1c:
+ pushw $28
+ jmp any_interrupt16
+.globl rm_int1d
+rm_int1d:
+ pushw $29
+ jmp any_interrupt16
+.globl rm_int1e
+rm_int1e:
+ pushw $30
+ jmp any_interrupt16
+.globl rm_int1f
+rm_int1f:
+ pushw $31
+ jmp any_interrupt16
+.globl rm_def_int
+rm_def_int:
+ iret
+
+
+ /*
+ * All interrupt jumptable entries jump to here
+ * after pushing the interrupt vector number onto the
+ * stack.
+ */
+any_interrupt16:
+ MAKE_BIOS_STACK
+
+gs movw OFFS_VECTOR(%bp), %ax
+ cmpw $0x10, %ax
+ je Lint_10h
+ cmpw $0x11, %ax
+ je Lint_11h
+ cmpw $0x12, %ax
+ je Lint_12h
+ cmpw $0x13, %ax
+ je Lint_13h
+ cmpw $0x15, %ax
+ je Lint_15h
+ cmpw $0x16, %ax
+ je Lint_16h
+ cmpw $0x1a, %ax
+ je Lint_1ah
+ movw $0xffff, %ax
+ jmp Lout
+Lint_10h: /* VGA BIOS services */
+ call bios_10h
+ jmp Lout
+Lint_11h:
+ call bios_11h
+ jmp Lout
+Lint_12h:
+ call bios_12h
+ jmp Lout
+Lint_13h: /* BIOS disk services */
+ call bios_13h
+ jmp Lout
+Lint_15h: /* Misc. BIOS services */
+ call bios_15h
+ jmp Lout
+Lint_16h: /* keyboard services */
+ call bios_16h
+ jmp Lout
+Lint_1ah: /* PCI bios */
+ call bios_1ah
+ jmp Lout
+Lout:
+ cmpw $0, %ax
+ je Lhandeled
+
+ /* Insert code for unhandeled INTs here.
+ *
+ * ROLO prints a message to the console
+ * (we could do that but then we're in 16bit mode
+ * so we'll have to get back into 32bit mode
+ * to use the console I/O routines (if we do this
+ * we shuls make int 0x10 and int 0x16 work as well))
+ */
+Lhandeled:
+ RESTORE_CALLERS_STACK
+ addw $2,%sp /* dump vector number */
+ iret /* return from interrupt */
+
+
+/*
+ ************************************************************
+ * BIOS interrupt 10h -- VGA services
+ ************************************************************
+ */
+bios_10h:
+gs movw OFFS_AX(%bp), %ax
+ shrw $8, %ax
+ cmpw $0x3, %ax
+ je Lcur_pos
+ cmpw $0xf, %ax
+ je Lvid_state
+ cmpw $0x12, %ax
+ je Lvid_cfg
+ movw $0xffff, %ax
+ ret
+Lcur_pos: /* Read Cursor Position and Size */
+gs movw $0, OFFS_CX(%bp)
+gs movw $0, OFFS_DX(%bp)
+ xorw %ax, %ax
+ ret
+Lvid_state: /* Get Video State */
+gs movw $(80 << 8|0x03), OFFS_AX(%bp) /* 80 columns, 80x25, 16 colors */
+gs movw $0, OFFS_BX(%bp)
+ xorw %ax, %ax
+ ret
+Lvid_cfg: /* Video Subsystem Configuration (EGA/VGA) */
+gs movw $0x10, OFFS_BX(%bp) /* indicate CGA/MDA/HGA */
+ xorw %ax, %ax
+ ret
+
+
+/*
+ ************************************************************
+ * BIOS interrupt 11h -- Equipment determination
+ ************************************************************
+ */
+
+bios_11h:
+cs movw bios_equipment, %ax
+gs movw %ax, OFFS_AX(%bp)
+ xorw %ax, %ax
+ ret
+
+
+/*
+ ************************************************************
+ * BIOS interrupt 12h -- Get Memory Size
+ ************************************************************
+ */
+bios_12h:
+cs movw ram_in_64kb_chunks, %ax
+ cmpw $0xa, %ax
+ ja b12_more_than_640k
+ shlw $6, %ax
+ jmp b12_return
+b12_more_than_640k:
+ movw $0x280, %ax
+b12_return:
+gs movw %ax, OFFS_AX(%bp) /* return number of kilobytes in ax */
+
+gs movw OFFS_FLAGS(%bp), %ax
+ andw $0xfffe, %ax /* clear carry -- function succeeded */
+gs movw %ax, OFFS_FLAGS(%bp)
+
+ xorw %ax, %ax
+ ret
+
+
+/*
+ ************************************************************
+ * BIOS interrupt 13h -- Disk services
+ ************************************************************
+ */
+bios_13h:
+gs movw OFFS_AX(%bp), %ax
+ shrw $8, %ax
+ cmpw $0x15, %ax
+ je Lfunc_15h
+ movw $0xffff, %ax
+ ret
+Lfunc_15h:
+gs movw OFFS_AX(%bp), %ax
+ andw $0xff, %ax /* return AH=0->drive not present */
+gs movw %ax, OFFS_AX(%bp)
+ xorw %ax, %ax
+ ret
+
+
+/*
+ ***********************************************************
+ * BIOS interrupt 15h -- Miscellaneous services
+ ***********************************************************
+ */
+bios_15h:
+gs movw OFFS_AX(%bp), %ax
+ shrw $8, %ax
+ cmpw $0xc0, %ax
+ je Lfunc_c0h
+ cmpw $0xe8, %ax
+ je Lfunc_e8h
+ cmpw $0x88, %ax
+ je Lfunc_88h
+ movw $0xffff, %ax
+ ret
+
+Lfunc_c0h: /* Return System Configuration Parameters (PS2 only) */
+gs movw OFFS_FLAGS(%bp), %ax
+ orw $1, %ax /* return carry -- function not supported */
+gs movw %ax, OFFS_FLAGS(%bp)
+ xorw %ax, %ax
+ ret
+
+Lfunc_e8h:
+gs movw OFFS_AX(%bp), %ax
+ andw $0xff, %ax
+ cmpw $1, %ax
+ je Lfunc_e801h
+gs movw OFFS_FLAGS(%bp), %ax
+ orw $1, %ax /* return carry -- function not supported */
+gs movw %ax, OFFS_FLAGS(%bp)
+ xorw %ax, %ax
+ ret
+
+Lfunc_e801h: /* Get memory size for >64M Configurations */
+cs movw ram_in_64kb_chunks, %ax
+ cmpw $0x100, %ax
+ ja e801_more_than_16mb
+ shlw $6, %ax /* multiply by 64 */
+ subw $0x400, %ax /* 1st meg does not count */
+
+gs movw %ax, OFFS_AX(%bp) /* return memory size between 1M and 16M in 1kb chunks in AX and CX */
+gs movw %ax, OFFS_CX(%bp)
+gs movw $0, OFFS_BX(%bp) /* set BX and DX to 0*/
+gs movw $0, OFFS_DX(%bp)
+gs movw OFFS_FLAGS(%bp), %ax
+ andw $0xfffe, %ax /* clear carry -- function succeeded */
+gs movw %ax, OFFS_FLAGS(%bp)
+ xorw %ax, %ax
+ ret
+
+e801_more_than_16mb:
+ subw $0x100, %ax /* subtract 16MB */
+
+gs movw $0x3c00, OFFS_AX(%bp) /* return 0x3c00 (16MB-1MB) in AX and CX */
+gs movw $0x3c00, OFFS_CX(%bp)
+gs movw %ax, OFFS_BX(%bp) /* set BX and DX to number of 64kb chunks above 16MB */
+gs movw %ax, OFFS_DX(%bp)
+
+gs movw OFFS_FLAGS(%bp), %ax
+ andw $0xfffe, %ax /* clear carry -- function succeeded */
+gs movw %ax, OFFS_FLAGS(%bp)
+ xorw %ax, %ax
+ ret
+
+Lfunc_88h:
+cs movw ram_in_64kb_chunks, %ax
+ cmpw $0x100, %ax
+ jna b88_not_more_than16
+ movw $0x100, %ax
+b88_not_more_than16:
+ shlw $6, %ax
+ subw $0x400, %ax /* 1st meg does not count */
+
+gs movw %ax, OFFS_AX(%bp) /* return number of kilobytes between 16MB and 16MB in ax */
+
+gs movw OFFS_FLAGS(%bp), %ax
+ andw $0xfffe, %ax /* clear carry -- function succeeded */
+gs movw %ax, OFFS_FLAGS(%bp)
+
+ xorw %ax, %ax
+ ret
+
+
+/*
+ ************************************************************
+ * BIOS interrupt 16h -- keyboard services
+ ************************************************************
+ */
+bios_16h:
+gs movw OFFS_AX(%bp), %ax
+ shrw $8, %ax
+ cmpw $0x03, %ax
+ je Lfunc_03h
+ movw $0xffff, %ax
+ ret
+Lfunc_03h:
+ xorw %ax, %ax /* do nothing -- function not supported */
+ ret
+
+/*
+ ************************************************************
+ * BIOS interrupt 1ah -- PCI bios
+ ************************************************************
+ */
+bios_1ah:
+gs movw OFFS_AX(%bp), %ax
+ cmpb $0xb1, %ah
+ je Lfunc_b1h
+ movw $0xffff, %ax
+ ret
+Lfunc_b1h:
+ call realmode_pci_bios
+ xorw %ax, %ax /* do nothing -- function not supported */
+ ret
+
+
+.globl ram_in_64kb_chunks
+ram_in_64kb_chunks:
+ .word 0
+
+.globl bios_equipment
+bios_equipment:
+ .word 0
diff --git a/lib_i386/bios.h b/lib_i386/bios.h
new file mode 100755
index 0000000..59143dd
--- /dev/null
+++ b/lib_i386/bios.h
@@ -0,0 +1,94 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _BIOS_H_
+#define _BIOS_H_
+
+#define OFFS_ES 0 /* 16bit */
+#define OFFS_GS 2 /* 16bit */
+#define OFFS_DS 4 /* 16bit */
+#define OFFS_EDI 6 /* 32bit */
+#define OFFS_DI 6 /* low 16 bits of EDI */
+#define OFFS_ESI 10 /* 32bit */
+#define OFFS_SI 10 /* low 16 bits of ESI */
+#define OFFS_EBP 14 /* 32bit */
+#define OFFS_BP 14 /* low 16 bits of EBP */
+#define OFFS_ESP 18 /* 32bit */
+#define OFFS_SP 18 /* low 16 bits of ESP */
+#define OFFS_EBX 22 /* 32bit */
+#define OFFS_BX 22 /* low 16 bits of EBX */
+#define OFFS_BL 22 /* low 8 bits of BX */
+#define OFFS_BH 23 /* high 8 bits of BX */
+#define OFFS_EDX 26 /* 32bit */
+#define OFFS_DX 26 /* low 16 bits of EBX */
+#define OFFS_DL 26 /* low 8 bits of BX */
+#define OFFS_DH 27 /* high 8 bits of BX */
+#define OFFS_ECX 30 /* 32bit */
+#define OFFS_CX 30 /* low 16 bits of EBX */
+#define OFFS_CL 30 /* low 8 bits of BX */
+#define OFFS_CH 31 /* high 8 bits of BX */
+#define OFFS_EAX 34 /* 32bit */
+#define OFFS_AX 34 /* low 16 bits of EBX */
+#define OFFS_AL 34 /* low 8 bits of BX */
+#define OFFS_AH 35 /* high 8 bits of BX */
+#define OFFS_VECTOR 38 /* 16bit */
+#define OFFS_IP 40 /* 16bit */
+#define OFFS_CS 42 /* 16bit */
+#define OFFS_FLAGS 44 /* 16bit */
+
+#define SEGMENT 0x40
+#define STACK 0x800 /* stack at 0x40:0x800 -> 0x800 */
+
+/* save general registers */
+/* save some segments */
+/* save callers stack segment .. */
+/* ... in gs */
+ /* setup my segments */
+ /* setup BIOS stackpointer */
+
+#define MAKE_BIOS_STACK \
+ pushal ; \
+ pushw %ds ; \
+ pushw %gs ; \
+ pushw %es ; \
+ pushw %ss ; \
+ popw %gs ; \
+ movw $SEGMENT,%ax ; \
+ movw %ax,%ds ; \
+ movw %ax,%es ; \
+ movw %ax,%ss ; \
+ movw %sp,%bp ; \
+ movw $STACK,%sp
+
+#define RESTORE_CALLERS_STACK \
+ pushw %gs ; /* restore callers stack segment */ \
+ popw %ss ; \
+ movw %bp,%sp ; /* restore stackpointer */ \
+ \
+ popw %es ; /* restore segment selectors */ \
+ popw %gs ; \
+ popw %ds ; \
+ \
+ popal /* restore GP registers */
+
+#endif
diff --git a/lib_i386/bios_pci.S b/lib_i386/bios_pci.S
new file mode 100755
index 0000000..b57b726
--- /dev/null
+++ b/lib_i386/bios_pci.S
@@ -0,0 +1,411 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * x86 realmode assembly implementation of a PCI BIOS
+ * for platforms that use one PCI hose and configuration
+ * access type 1. (The common case for low-end PC's)
+ */
+
+#include "bios.h"
+
+#define PCI_BIOS_DEBUG
+
+.section .bios, "ax"
+.code16
+.globl realmode_pci_bios_call_entry
+realmode_pci_bios_call_entry:
+ MAKE_BIOS_STACK
+ call realmode_pci_bios
+ RESTORE_CALLERS_STACK
+ ret
+
+
+.globl realmode_pci_bios
+realmode_pci_bios:
+gs movw OFFS_AX(%bp), %ax
+ cmpb $1, %al
+ je pci_bios_present
+ cmpb $2, %al
+ je pci_bios_find_device
+ cmpb $3, %al
+ je pci_bios_find_class
+ cmpb $6, %al
+ je pci_bios_generate_special_cycle
+ cmpb $8, %al
+ je pci_bios_read_cfg_byte
+ cmpb $9, %al
+ je pci_bios_read_cfg_word
+ cmpb $10, %al
+ je pci_bios_read_cfg_dword
+ cmpb $11, %al
+ je pci_bios_write_cfg_byte
+ cmpb $12, %al
+ je pci_bios_write_cfg_word
+ cmpb $13, %al
+ je pci_bios_write_cfg_dword
+ cmpb $14, %al
+ je pci_bios_get_irq_routing
+ cmpb $15, %al
+ je pci_bios_set_irq
+ jmp unknown_function
+
+/*****************************************************************************/
+
+pci_bios_present:
+#ifdef PCI_BIOS_DEBUG
+cs incl num_pci_bios_present
+#endif
+ movl $0x20494350, %eax
+gs movl %eax, OFFS_EDX(%bp)
+ movb $0x01, %al
+gs movb %al, OFFS_AL(%bp) /* We support cfg type 1 */
+ movw $0x0210, %ax /* version 2.10 */
+gs movw %ax, OFFS_BX(%bp)
+cs movb pci_last_bus, %al /* last bus number */
+gs movb %al, OFFS_CL(%bp)
+ jmp clear_carry
+
+/*****************************************************************************/
+
+/* device 0-31, function 0-7 */
+pci_bios_find_device:
+#ifdef PCI_BIOS_DEBUG
+cs incl num_pci_bios_find_device
+#endif
+gs movw OFFS_CX(%bp), %di
+ shll $16, %edi
+gs movw OFFS_DX(%bp), %di /* edi now holds device in upper 16
+ * bits and vendor in lower 16 bits */
+gs movw OFFS_SI(%bp), %si
+ xorw %bx, %bx /* start at bus 0 dev 0 function 0 */
+pfd_loop:
+ xorw %ax, %ax /* dword 0 is vendor/device */
+ call __pci_bios_select_register
+ movw $0xcfc, %dx
+ inl %dx, %eax
+ cmpl %edi, %eax /* our device ? */
+ je pfd_found_one
+pfd_next_dev:
+ /* check for multi function devices */
+ movw %bx, %ax
+ andw $3, %ax
+ jnz pfd_function_not_zero
+ movw $0x000c, %ax
+ call __pci_bios_select_register
+ movw $0xcfe, %dx
+ inb %dx, %al
+ andb $0x80, %al
+ jz pfd_not_multi_function
+pfd_function_not_zero:
+ incw %bx /* next function, overflows in to
+ * device number, then bus number */
+ jmp pfd_check_bus
+
+pfd_not_multi_function:
+ andw $0xfff8, %bx /* remove function bits */
+ addw $0x0008, %bx /* next device, overflows in to bus number */
+pfd_check_bus:
+cs movb pci_last_bus, %ah
+ cmpb %ah, %bh
+ ja pfd_not_found
+ jmp pfd_loop
+pfd_found_one:
+ decw %si
+ js pfd_done
+ jmp pfd_next_dev
+
+pfd_done:
+gs movw %bx, OFFS_BX(%bp)
+ jmp clear_carry
+
+pfd_not_found:
+ movb $0x86, %ah /* device not found */
+ jmp set_carry
+
+/*****************************************************************************/
+
+pci_bios_find_class:
+#ifdef PCI_BIOS_DEBUG
+cs incl num_pci_bios_find_class
+#endif
+gs movl OFFS_ECX(%bp), %edi
+ andl $0x00ffffff, %edi /* edi now holds class-code in lower 24 bits */
+gs movw OFFS_SI(%bp), %si
+ xorw %bx, %bx /* start at bus 0 dev 0 function 0 */
+pfc_loop:
+ movw $8, %ax /* dword 8 is class-code high 24bits */
+ call __pci_bios_select_register
+ movw $0xcfc, %dx
+ inl %dx, %eax
+ shrl $8, %eax
+ andl $0x00ffffff, %eax
+ cmpl %edi, %eax /* our device ? */
+ je pfc_found_one
+pfc_next_dev:
+ /* check for multi function devices */
+ andw $3, %bx
+ jnz pfc_function_not_zero
+ movw $0x000c, %ax
+ call __pci_bios_select_register
+ movw $0xcfe, %dx
+ inb %dx, %al
+ andb $0x80, %al
+ jz pfc_not_multi_function
+pfc_function_not_zero:
+ incw %bx /* next function, overflows in to
+ * device number, then bus number */
+ jmp pfc_check_bus
+
+pfc_not_multi_function:
+ andw $0xfff8, %bx /* remove function bits */
+ addw $0x0008, %bx /* next device, overflows in to bus number */
+pfc_check_bus:
+cs movb pci_last_bus, %ah
+ cmpb %ah, %bh
+ ja pfc_not_found
+ jmp pfc_loop
+pfc_found_one:
+ decw %si
+ js pfc_done
+ jmp pfc_next_dev
+
+pfc_done:
+gs movw %bx, OFFS_BX(%bp)
+ jmp clear_carry
+
+pfc_not_found:
+ movb $0x86, %ah /* device not found */
+ jmp set_carry
+
+/*****************************************************************************/
+
+pci_bios_generate_special_cycle:
+#ifdef PCI_BIOS_DEBUG
+cs incl num_pci_bios_generate_special_cycle
+#endif
+ movb $0x81, %ah /* function not supported */
+ jmp set_carry
+
+/*****************************************************************************/
+
+pci_bios_read_cfg_byte:
+#ifdef PCI_BIOS_DEBUG
+cs incl num_pci_bios_read_cfg_byte
+#endif
+ call pci_bios_select_register
+gs movw OFFS_DI(%bp), %dx
+ andw $3, %dx
+ addw $0xcfc, %dx
+ inb %dx, %al
+gs movb %al, OFFS_CL(%bp)
+ jmp clear_carry
+
+/*****************************************************************************/
+
+pci_bios_read_cfg_word:
+#ifdef PCI_BIOS_DEBUG
+cs incl num_pci_bios_read_cfg_word
+#endif
+ call pci_bios_select_register
+gs movw OFFS_DI(%bp), %dx
+ andw $2, %dx
+ addw $0xcfc, %dx
+ inw %dx, %ax
+gs movw %ax, OFFS_CX(%bp)
+ jmp clear_carry
+
+
+/*****************************************************************************/
+
+pci_bios_read_cfg_dword:
+#ifdef PCI_BIOS_DEBUG
+cs incl num_pci_bios_read_cfg_dword
+#endif
+ call pci_bios_select_register
+ movw $0xcfc, %dx
+ inl %dx, %eax
+gs movl %eax, OFFS_ECX(%bp)
+ jmp clear_carry
+
+/*****************************************************************************/
+
+pci_bios_write_cfg_byte:
+#ifdef PCI_BIOS_DEBUG
+cs incl num_pci_bios_write_cfg_byte
+#endif
+ call pci_bios_select_register
+gs movw OFFS_DI(%bp), %dx
+gs movb OFFS_CL(%bp), %al
+ andw $3, %dx
+ addw $0xcfc, %dx
+ outb %al, %dx
+ jmp clear_carry
+
+/*****************************************************************************/
+
+pci_bios_write_cfg_word:
+#ifdef PCI_BIOS_DEBUG
+cs incl num_pci_bios_write_cfg_word
+#endif
+ call pci_bios_select_register
+gs movw OFFS_DI(%bp), %dx
+gs movw OFFS_CX(%bp), %ax
+ andw $2, %dx
+ addw $0xcfc, %dx
+ outw %ax, %dx
+ jmp clear_carry
+
+/*****************************************************************************/
+
+pci_bios_write_cfg_dword:
+#ifdef PCI_BIOS_DEBUG
+cs incl num_pci_bios_write_cfg_dword
+#endif
+ call pci_bios_select_register
+gs movl OFFS_ECX(%bp), %eax
+ movw $0xcfc, %dx
+ outl %eax, %dx
+ jmp clear_carry
+
+/*****************************************************************************/
+
+pci_bios_get_irq_routing:
+#ifdef PCI_BIOS_DEBUG
+cs incl num_pci_bios_get_irq_routing
+#endif
+ movb $0x81, %ah /* function not supported */
+ jmp set_carry
+
+/*****************************************************************************/
+
+pci_bios_set_irq:
+#ifdef PCI_BIOS_DEBUG
+cs incl num_pci_bios_set_irq
+#endif
+ movb $0x81, %ah /* function not supported */
+ jmp set_carry
+
+/*****************************************************************************/
+
+unknown_function:
+#ifdef PCI_BIOS_DEBUG
+cs incl num_pci_bios_unknown_function
+#endif
+ movb $0x81, %ah /* function not supported */
+ jmp set_carry
+
+/*****************************************************************************/
+
+pci_bios_select_register:
+gs movw OFFS_BX(%bp), %bx
+gs movw OFFS_DI(%bp), %ax
+/* destroys eax, dx */
+__pci_bios_select_register: /* BX holds device id, AX holds register index */
+ pushl %ebx
+ andl $0xfc, %eax
+ andl $0xffff, %ebx
+ shll $8, %ebx
+ orl %ebx, %eax
+ orl $0x80000000, %eax
+ movw $0xcf8, %dx
+ outl %eax, %dx
+ popl %ebx
+ ret
+
+
+clear_carry:
+gs movw OFFS_FLAGS(%bp), %ax
+ andw $0xfffe, %ax /* clear carry -- function succeeded */
+gs movw %ax, OFFS_FLAGS(%bp)
+ xorw %ax, %ax
+gs movb %ah, OFFS_AH(%bp)
+ ret
+
+set_carry:
+gs movb %ah, OFFS_AH(%bp)
+gs movw OFFS_FLAGS(%bp), %ax
+ orw $1, %ax /* return carry -- function not supported */
+gs movw %ax, OFFS_FLAGS(%bp)
+ movw $-1, %ax
+ ret
+
+/*****************************************************************************/
+
+.globl pci_last_bus
+pci_last_bus:
+ .byte 0
+
+#ifdef PCI_BIOS_DEBUG
+.globl num_pci_bios_present
+num_pci_bios_present:
+ .long 0
+
+.globl num_pci_bios_find_device
+num_pci_bios_find_device:
+ .long 0
+
+.globl num_pci_bios_find_class
+num_pci_bios_find_class:
+ .long 0
+
+.globl num_pci_bios_generate_special_cycle
+num_pci_bios_generate_special_cycle:
+ .long 0
+
+.globl num_pci_bios_read_cfg_byte
+num_pci_bios_read_cfg_byte:
+ .long 0
+
+.globl num_pci_bios_read_cfg_word
+num_pci_bios_read_cfg_word:
+ .long 0
+
+.globl num_pci_bios_read_cfg_dword
+num_pci_bios_read_cfg_dword:
+ .long 0
+
+.globl num_pci_bios_write_cfg_byte
+num_pci_bios_write_cfg_byte:
+ .long 0
+
+.globl num_pci_bios_write_cfg_word
+num_pci_bios_write_cfg_word:
+ .long 0
+
+.globl num_pci_bios_write_cfg_dword
+num_pci_bios_write_cfg_dword:
+ .long 0
+
+.globl num_pci_bios_get_irq_routing
+num_pci_bios_get_irq_routing:
+ .long 0
+
+.globl num_pci_bios_set_irq
+num_pci_bios_set_irq:
+ .long 0
+
+.globl num_pci_bios_unknown_function
+num_pci_bios_unknown_function:
+ .long 0
+#endif
diff --git a/lib_i386/bios_setup.c b/lib_i386/bios_setup.c
new file mode 100755
index 0000000..bc97815
--- /dev/null
+++ b/lib_i386/bios_setup.c
@@ -0,0 +1,233 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+/*
+ * Partly based on msbios.c from rolo 1.6:
+ *----------------------------------------------------------------------
+ * (C) Copyright 2000
+ * Sysgo Real-Time Solutions GmbH
+ * Klein-Winternheim, Germany
+ *----------------------------------------------------------------------
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <asm/realmode.h>
+#include <asm/io.h>
+
+#define NUMVECTS 256
+
+#define BIOS_DATA ((char*)0x400)
+#define BIOS_DATA_SIZE 256
+#define BIOS_BASE ((char*)0xf0000)
+#define BIOS_CS 0xf000
+
+/* these are defined in a 16bit segment and needs
+ * to be accessed with the RELOC_16_xxxx() macros below
+ */
+extern u16 ram_in_64kb_chunks;
+extern u16 bios_equipment;
+extern u8 pci_last_bus;
+
+extern void *rm_int00;
+extern void *rm_int01;
+extern void *rm_int02;
+extern void *rm_int03;
+extern void *rm_int04;
+extern void *rm_int05;
+extern void *rm_int06;
+extern void *rm_int07;
+extern void *rm_int08;
+extern void *rm_int09;
+extern void *rm_int0a;
+extern void *rm_int0b;
+extern void *rm_int0c;
+extern void *rm_int0d;
+extern void *rm_int0e;
+extern void *rm_int0f;
+extern void *rm_int10;
+extern void *rm_int11;
+extern void *rm_int12;
+extern void *rm_int13;
+extern void *rm_int14;
+extern void *rm_int15;
+extern void *rm_int16;
+extern void *rm_int17;
+extern void *rm_int18;
+extern void *rm_int19;
+extern void *rm_int1a;
+extern void *rm_int1b;
+extern void *rm_int1c;
+extern void *rm_int1d;
+extern void *rm_int1e;
+extern void *rm_int1f;
+extern void *rm_def_int;
+
+extern void *realmode_reset;
+extern void *realmode_pci_bios_call_entry;
+
+static int set_jmp_vector(int entry_point, void *target)
+{
+ if (entry_point & ~0xffff) {
+ return -1;
+ }
+
+ if (((u32)target-0xf0000) & ~0xffff) {
+ return -1;
+ }
+ printf("set_jmp_vector: 0xf000:%04x -> %p\n",
+ entry_point, target);
+
+ /* jmp opcode */
+ writeb(0xea, 0xf0000 + entry_point);
+
+ /* offset */
+ writew(((u32)target-0xf0000), 0xf0000 + entry_point + 1);
+
+ /* segment */
+ writew(0xf000, 0xf0000 + entry_point + 3);
+
+ return 0;
+}
+
+
+/*
+ ************************************************************
+ * Install an interrupt vector
+ ************************************************************
+ */
+
+static void setvector(int vector, u16 segment, void *handler)
+{
+ u16 *ptr = (u16*)(vector*4);
+ ptr[0] = ((u32)handler - (segment << 4))&0xffff;
+ ptr[1] = segment;
+
+#if 0
+ printf("setvector: int%02x -> %04x:%04x\n",
+ vector, ptr[1], ptr[0]);
+#endif
+}
+
+#define RELOC_16_LONG(seg, off) *(u32*)(seg << 4 | (u32)&off)
+#define RELOC_16_WORD(seg, off) *(u16*)(seg << 4 | (u32)&off)
+#define RELOC_16_BYTE(seg, off) *(u8*)(seg << 4 | (u32)&off)
+
+int bios_setup(void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+ static int done=0;
+ int vector;
+ struct pci_controller *pri_hose;
+
+ if (done) {
+ return 0;
+ }
+ done = 1;
+
+ if (i386boot_bios_size > 65536) {
+ printf("BIOS too large (%ld bytes, max is 65536)\n",
+ i386boot_bios_size);
+ return -1;
+ }
+
+ memcpy(BIOS_BASE, (void*)i386boot_bios, i386boot_bios_size);
+
+ /* clear bda */
+ memset(BIOS_DATA, 0, BIOS_DATA_SIZE);
+
+ /* enter some values to the bda */
+ writew(0x3f8, BIOS_DATA); /* com1 addr */
+ writew(0x2f8, BIOS_DATA+2); /* com2 addr */
+ writew(0x3e8, BIOS_DATA+4); /* com3 addr */
+ writew(0x2e8, BIOS_DATA+6); /* com4 addr */
+ writew(0x278, BIOS_DATA+8); /* lpt1 addr */
+ /*
+ * The kernel wants to read the base memory size
+ * from 40:13. Put a zero there to avoid an error message
+ */
+ writew(0, BIOS_DATA+0x13); /* base memory size */
+
+
+ /* setup realmode interrupt vectors */
+ for (vector = 0; vector < NUMVECTS; vector++) {
+ setvector(vector, BIOS_CS, &rm_def_int);
+ }
+
+ setvector(0x00, BIOS_CS, &rm_int00);
+ setvector(0x01, BIOS_CS, &rm_int01);
+ setvector(0x02, BIOS_CS, &rm_int02);
+ setvector(0x03, BIOS_CS, &rm_int03);
+ setvector(0x04, BIOS_CS, &rm_int04);
+ setvector(0x05, BIOS_CS, &rm_int05);
+ setvector(0x06, BIOS_CS, &rm_int06);
+ setvector(0x07, BIOS_CS, &rm_int07);
+ setvector(0x08, BIOS_CS, &rm_int08);
+ setvector(0x09, BIOS_CS, &rm_int09);
+ setvector(0x0a, BIOS_CS, &rm_int0a);
+ setvector(0x0b, BIOS_CS, &rm_int0b);
+ setvector(0x0c, BIOS_CS, &rm_int0c);
+ setvector(0x0d, BIOS_CS, &rm_int0d);
+ setvector(0x0e, BIOS_CS, &rm_int0e);
+ setvector(0x0f, BIOS_CS, &rm_int0f);
+ setvector(0x10, BIOS_CS, &rm_int10);
+ setvector(0x11, BIOS_CS, &rm_int11);
+ setvector(0x12, BIOS_CS, &rm_int12);
+ setvector(0x13, BIOS_CS, &rm_int13);
+ setvector(0x14, BIOS_CS, &rm_int14);
+ setvector(0x15, BIOS_CS, &rm_int15);
+ setvector(0x16, BIOS_CS, &rm_int16);
+ setvector(0x17, BIOS_CS, &rm_int17);
+ setvector(0x18, BIOS_CS, &rm_int18);
+ setvector(0x19, BIOS_CS, &rm_int19);
+ setvector(0x1a, BIOS_CS, &rm_int1a);
+ setvector(0x1b, BIOS_CS, &rm_int1b);
+ setvector(0x1c, BIOS_CS, &rm_int1c);
+ setvector(0x1d, BIOS_CS, &rm_int1d);
+ setvector(0x1e, BIOS_CS, &rm_int1e);
+ setvector(0x1f, BIOS_CS, &rm_int1f);
+
+ set_jmp_vector(0xfff0, &realmode_reset);
+ set_jmp_vector(0xfe6e, &realmode_pci_bios_call_entry);
+
+ /* fill in data area */
+ RELOC_16_WORD(0xf000, ram_in_64kb_chunks) = gd->ram_size >> 16;
+ RELOC_16_WORD(0xf000, bios_equipment) = 0; /* FixMe */
+
+ /* If we assume only one PCI hose, this PCI hose
+ * will own PCI bus #0, and the last PCI bus of
+ * that PCI hose will be the last PCI bus in the
+ * system.
+ * (This, ofcause break on multi hose systems,
+ * but our PCI BIOS only support one hose anyway)
+ */
+ pri_hose = pci_bus_to_hose(0);
+ if (NULL != pri_hose) {
+ /* fill in last pci bus number for use by the realmode
+ * PCI BIOS */
+ RELOC_16_BYTE(0xf000, pci_last_bus) = pri_hose->last_busno;
+ }
+
+ return 0;
+}
diff --git a/lib_i386/board.c b/lib_i386/board.c
new file mode 100755
index 0000000..e90eb6e
--- /dev/null
+++ b/lib_i386/board.c
@@ -0,0 +1,427 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
+ *
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <watchdog.h>
+#include <command.h>
+#include <devices.h>
+#include <version.h>
+#include <malloc.h>
+#include <net.h>
+#include <ide.h>
+#include <asm/u-boot-i386.h>
+
+extern long _i386boot_start;
+extern long _i386boot_end;
+extern long _i386boot_romdata_start;
+extern long _i386boot_romdata_dest;
+extern long _i386boot_romdata_size;
+extern long _i386boot_bss_start;
+extern long _i386boot_bss_size;
+
+extern long _i386boot_realmode;
+extern long _i386boot_realmode_size;
+extern long _i386boot_bios;
+extern long _i386boot_bios_size;
+
+/* The symbols defined by the linker script becomes pointers
+ * which is somewhat inconveient ... */
+ulong i386boot_start = (ulong)&_i386boot_start; /* code start (in flash) defined in start.S */
+ulong i386boot_end = (ulong)&_i386boot_end; /* code end (in flash) */
+ulong i386boot_romdata_start = (ulong)&_i386boot_romdata_start; /* datasegment in flash (also code+rodata end) */
+ulong i386boot_romdata_dest = (ulong)&_i386boot_romdata_dest; /* data location segment in ram */
+ulong i386boot_romdata_size = (ulong)&_i386boot_romdata_size; /* size of data segment */
+ulong i386boot_bss_start = (ulong)&_i386boot_bss_start; /* bss start */
+ulong i386boot_bss_size = (ulong)&_i386boot_bss_size; /* bss size */
+
+ulong i386boot_realmode = (ulong)&_i386boot_realmode; /* start of realmode entry code */
+ulong i386boot_realmode_size = (ulong)&_i386boot_realmode_size; /* size of realmode entry code */
+ulong i386boot_bios = (ulong)&_i386boot_bios; /* start of BIOS emulation code */
+ulong i386boot_bios_size = (ulong)&_i386boot_bios_size; /* size of BIOS emulation code */
+
+
+const char version_string[] =
+ U_BOOT_VERSION" (" __DATE__ " - " __TIME__ ")";
+
+
+/*
+ * Begin and End of memory area for malloc(), and current "brk"
+ */
+static ulong mem_malloc_start = 0;
+static ulong mem_malloc_end = 0;
+static ulong mem_malloc_brk = 0;
+
+static int mem_malloc_init(void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ /* start malloc area right after the stack */
+ mem_malloc_start = i386boot_bss_start +
+ i386boot_bss_size + CFG_STACK_SIZE;
+ mem_malloc_start = (mem_malloc_start+3)&~3;
+
+ /* Use all available RAM for malloc() */
+ mem_malloc_end = gd->ram_size;
+
+ mem_malloc_brk = mem_malloc_start;
+
+ return 0;
+}
+
+void *sbrk (ptrdiff_t increment)
+{
+ ulong old = mem_malloc_brk;
+ ulong new = old + increment;
+
+ if ((new < mem_malloc_start) || (new > mem_malloc_end)) {
+ return (NULL);
+ }
+ mem_malloc_brk = new;
+
+ return ((void *) old);
+}
+
+char *strmhz (char *buf, long hz)
+{
+ long l, n;
+ long m;
+
+ n = hz / 1000000L;
+ l = sprintf (buf, "%ld", n);
+ m = (hz % 1000000L) / 1000L;
+ if (m != 0)
+ sprintf (buf + l, ".%03ld", m);
+ return (buf);
+}
+
+/************************************************************************
+ * Init Utilities *
+ ************************************************************************
+ * Some of this code should be moved into the core functions,
+ * or dropped completely,
+ * but let's get it working (again) first...
+ */
+static int init_baudrate (void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+
+ char tmp[64]; /* long enough for environment variables */
+ int i = getenv_r("baudrate", tmp, 64);
+
+ gd->baudrate = (i != 0)
+ ? (int) simple_strtoul (tmp, NULL, 10)
+ : CONFIG_BAUDRATE;
+
+ return (0);
+}
+
+static int display_banner (void)
+{
+
+ printf ("\n\n%s\n\n", version_string);
+ printf ("U-Boot code: %08lX -> %08lX data: %08lX -> %08lX\n"
+ " BSS: %08lX -> %08lX stack: %08lX -> %08lX\n",
+ i386boot_start, i386boot_romdata_start-1,
+ i386boot_romdata_dest, i386boot_romdata_dest+i386boot_romdata_size-1,
+ i386boot_bss_start, i386boot_bss_start+i386boot_bss_size-1,
+ i386boot_bss_start+i386boot_bss_size,
+ i386boot_bss_start+i386boot_bss_size+CFG_STACK_SIZE-1);
+
+
+ return (0);
+}
+
+/*
+ * WARNING: this code looks "cleaner" than the PowerPC version, but
+ * has the disadvantage that you either get nothing, or everything.
+ * On PowerPC, you might see "DRAM: " before the system hangs - which
+ * gives a simple yet clear indication which part of the
+ * initialization if failing.
+ */
+static int display_dram_config (void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+ int i;
+
+ puts ("DRAM Configuration:\n");
+
+ for (i=0; i<CONFIG_NR_DRAM_BANKS; i++) {
+ printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start);
+ print_size (gd->bd->bi_dram[i].size, "\n");
+ }
+
+ return (0);
+}
+
+static void display_flash_config (ulong size)
+{
+ puts ("Flash: ");
+ print_size (size, "\n");
+}
+
+
+/*
+ * Breath some life into the board...
+ *
+ * Initialize an SMC for serial comms, and carry out some hardware
+ * tests.
+ *
+ * The first part of initialization is running from Flash memory;
+ * its main purpose is to initialize the RAM so that we
+ * can relocate the monitor code to RAM.
+ */
+
+/*
+ * All attempts to come up with a "common" initialization sequence
+ * that works for all boards and architectures failed: some of the
+ * requirements are just _too_ different. To get rid of the resulting
+ * mess of board dependend #ifdef'ed code we now make the whole
+ * initialization sequence configurable to the user.
+ *
+ * The requirements for any new initalization function is simple: it
+ * receives a pointer to the "global data" structure as it's only
+ * argument, and returns an integer return code, where 0 means
+ * "continue" and != 0 means "fatal error, hang the system".
+ */
+typedef int (init_fnc_t) (void);
+
+init_fnc_t *init_sequence[] = {
+ cpu_init, /* basic cpu dependent setup */
+ board_init, /* basic board dependent setup */
+ dram_init, /* configure available RAM banks */
+ mem_malloc_init, /* dependant on dram_init */
+ interrupt_init, /* set up exceptions */
+ timer_init,
+ serial_init,
+ env_init, /* initialize environment */
+ init_baudrate, /* initialze baudrate settings */
+ serial_init, /* serial communications setup */
+ display_banner,
+ display_dram_config,
+
+ NULL,
+};
+
+gd_t *global_data;
+
+void start_i386boot (void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+ char *s;
+ int i;
+ ulong size;
+ static gd_t gd_data;
+ static bd_t bd_data;
+ init_fnc_t **init_fnc_ptr;
+
+ show_boot_progress(0x21);
+
+ gd = global_data = &gd_data;
+ /* compiler optimization barrier needed for GCC >= 3.4 */
+ __asm__ __volatile__("": : :"memory");
+
+ memset (gd, 0, sizeof (gd_t));
+ gd->bd = &bd_data;
+ memset (gd->bd, 0, sizeof (bd_t));
+ show_boot_progress(0x22);
+
+ gd->baudrate = CONFIG_BAUDRATE;
+
+ for (init_fnc_ptr = init_sequence, i=0; *init_fnc_ptr; ++init_fnc_ptr, i++) {
+ show_boot_progress(0xa130|i);
+
+ if ((*init_fnc_ptr)() != 0) {
+ hang ();
+ }
+ }
+ show_boot_progress(0x23);
+
+ /* configure available FLASH banks */
+ size = flash_init();
+ display_flash_config(size);
+ show_boot_progress(0x24);
+
+ show_boot_progress(0x25);
+
+ /* initialize environment */
+ env_relocate ();
+ show_boot_progress(0x26);
+
+
+ /* IP Address */
+ bd_data.bi_ip_addr = getenv_IPaddr ("ipaddr");
+
+ /* MAC Address */
+ {
+ int i;
+ ulong reg;
+ char *s, *e;
+ uchar tmp[64];
+
+ i = getenv_r ("ethaddr", tmp, sizeof (tmp));
+ s = (i > 0) ? tmp : NULL;
+
+ for (reg = 0; reg < 6; ++reg) {
+ bd_data.bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
+ if (s)
+ s = (*e) ? e + 1 : e;
+ }
+ }
+
+#if defined(CONFIG_PCI)
+ /*
+ * Do pci configuration
+ */
+ pci_init();
+#endif
+
+ show_boot_progress(0x27);
+
+
+ devices_init ();
+
+ jumptable_init ();
+
+ /* Initialize the console (after the relocation and devices init) */
+ console_init_r();
+
+#ifdef CONFIG_MISC_INIT_R
+ /* miscellaneous platform dependent initialisations */
+ misc_init_r();
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_PCMCIA) && !(CONFIG_COMMANDS & CFG_CMD_IDE)
+ WATCHDOG_RESET();
+ puts ("PCMCIA:");
+ pcmcia_init();
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_KGDB)
+ WATCHDOG_RESET();
+ puts("KGDB: ");
+ kgdb_init();
+#endif
+
+ /* enable exceptions */
+ enable_interrupts();
+ show_boot_progress(0x28);
+
+ /* Must happen after interrupts are initialized since
+ * an irq handler gets installed
+ */
+#ifdef CONFIG_SERIAL_SOFTWARE_FIFO
+ serial_buffered_init();
+#endif
+
+#ifdef CONFIG_STATUS_LED
+ status_led_set (STATUS_LED_BOOT, STATUS_LED_BLINKING);
+#endif
+
+ udelay(20);
+
+ set_timer (0);
+
+ /* Initialize from environment */
+ if ((s = getenv ("loadaddr")) != NULL) {
+ load_addr = simple_strtoul (s, NULL, 16);
+ }
+#if (CONFIG_COMMANDS & CFG_CMD_NET)
+ if ((s = getenv ("bootfile")) != NULL) {
+ copy_filename (BootFile, s, sizeof (BootFile));
+ }
+#endif /* CFG_CMD_NET */
+
+ WATCHDOG_RESET();
+
+#if (CONFIG_COMMANDS & CFG_CMD_IDE)
+ WATCHDOG_RESET();
+ puts("IDE: ");
+ ide_init();
+#endif /* CFG_CMD_IDE */
+
+#if (CONFIG_COMMANDS & CFG_CMD_SCSI)
+ WATCHDOG_RESET();
+ puts("SCSI: ");
+ scsi_init();
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_DOC)
+ WATCHDOG_RESET();
+ puts("DOC: ");
+ doc_init();
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_NET)
+#if defined(CONFIG_NET_MULTI)
+ WATCHDOG_RESET();
+ puts("Net: ");
+#endif
+ eth_initialize(gd->bd);
+#endif
+
+#if (CONFIG_COMMANDS & CFG_CMD_NET) && (0)
+ WATCHDOG_RESET();
+# ifdef DEBUG
+ puts ("Reset Ethernet PHY\n");
+# endif
+ reset_phy();
+#endif
+
+#ifdef CONFIG_LAST_STAGE_INIT
+ WATCHDOG_RESET();
+ /*
+ * Some parts can be only initialized if all others (like
+ * Interrupts) are up and running (i.e. the PC-style ISA
+ * keyboard).
+ */
+ last_stage_init();
+#endif
+
+
+#ifdef CONFIG_POST
+ post_run (NULL, POST_RAM | post_bootmode_get(0));
+#endif
+
+
+ show_boot_progress(0x29);
+
+ /* main_loop() can return to retry autoboot, if so just run it again. */
+ for (;;) {
+ main_loop();
+ }
+
+ /* NOTREACHED - no way out of command loop except booting */
+}
+
+void hang (void)
+{
+ puts ("### ERROR ### Please RESET the board ###\n");
+ for (;;);
+}
diff --git a/lib_i386/i386_linux.c b/lib_i386/i386_linux.c
new file mode 100755
index 0000000..e5d8eea
--- /dev/null
+++ b/lib_i386/i386_linux.c
@@ -0,0 +1,173 @@
+/*
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * Copyright (C) 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <command.h>
+#include <image.h>
+#include <zlib.h>
+#include <asm/byteorder.h>
+#include <asm/zimage.h>
+
+/*cmd_boot.c*/
+extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+
+extern image_header_t header; /* from cmd_bootm.c */
+
+
+image_header_t *fake_header(image_header_t *hdr, void *ptr, int size)
+{
+ /* try each supported image type in order */
+ if (NULL != fake_zimage_header(hdr, ptr, size)) {
+ return hdr;
+ }
+
+ return NULL;
+}
+
+
+void do_bootm_linux(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
+ ulong addr, ulong *len_ptr, int verify)
+{
+ void *base_ptr;
+
+ ulong len = 0, checksum;
+ ulong initrd_start, initrd_end;
+ ulong data;
+ image_header_t *hdr = &header;
+
+ /*
+ * Check if there is an initrd image
+ */
+ if (argc >= 3) {
+ addr = simple_strtoul(argv[2], NULL, 16);
+
+ printf ("## Loading Ramdisk Image at %08lx ...\n", addr);
+
+ /* Copy header so we can blank CRC field for re-calculation */
+ memcpy (&header, (char *)addr, sizeof(image_header_t));
+
+ if (ntohl(hdr->ih_magic) != IH_MAGIC) {
+ printf ("Bad Magic Number\n");
+ do_reset (cmdtp, flag, argc, argv);
+ }
+
+ data = (ulong)&header;
+ len = sizeof(image_header_t);
+
+ checksum = ntohl(hdr->ih_hcrc);
+ hdr->ih_hcrc = 0;
+
+ if (crc32 (0, (char *)data, len) != checksum) {
+ printf ("Bad Header Checksum\n");
+ do_reset (cmdtp, flag, argc, argv);
+ }
+
+ print_image_hdr (hdr);
+
+ data = addr + sizeof(image_header_t);
+ len = ntohl(hdr->ih_size);
+
+ if (verify) {
+ ulong csum = 0;
+
+ printf (" Verifying Checksum ... ");
+ csum = crc32 (0, (char *)data, len);
+ if (csum != ntohl(hdr->ih_dcrc)) {
+ printf ("Bad Data CRC\n");
+ do_reset (cmdtp, flag, argc, argv);
+ }
+ printf ("OK\n");
+ }
+
+ if ((hdr->ih_os != IH_OS_LINUX) ||
+ (hdr->ih_arch != IH_CPU_I386) ||
+ (hdr->ih_type != IH_TYPE_RAMDISK) ) {
+ printf ("No Linux i386 Ramdisk Image\n");
+ do_reset (cmdtp, flag, argc, argv);
+ }
+
+ /*
+ * Now check if we have a multifile image
+ */
+ } else if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1])) {
+ ulong tail = ntohl(len_ptr[0]) % 4;
+ int i;
+
+ /* skip kernel length and terminator */
+ data = (ulong)(&len_ptr[2]);
+ /* skip any additional image length fields */
+ for (i=1; len_ptr[i]; ++i)
+ data += 4;
+ /* add kernel length, and align */
+ data += ntohl(len_ptr[0]);
+ if (tail) {
+ data += 4 - tail;
+ }
+
+ len = ntohl(len_ptr[1]);
+
+ } else {
+ /*
+ * no initrd image
+ */
+ data = 0;
+ }
+
+#ifdef DEBUG
+ if (!data) {
+ printf ("No initrd\n");
+ }
+#endif
+
+ if (data) {
+ initrd_start = data;
+ initrd_end = initrd_start + len;
+ printf (" Loading Ramdisk to %08lx, end %08lx ... ",
+ initrd_start, initrd_end);
+ memmove ((void *)initrd_start, (void *)data, len);
+ printf ("OK\n");
+ } else {
+ initrd_start = 0;
+ initrd_end = 0;
+ }
+
+ base_ptr = load_zimage((void*)addr + sizeof(image_header_t), ntohl(hdr->ih_size),
+ initrd_start, initrd_end-initrd_start, 0);
+
+ if (NULL == base_ptr) {
+ printf ("## Kernel loading failed ...\n");
+ do_reset(cmdtp, flag, argc, argv);
+
+ }
+
+#ifdef DEBUG
+ printf ("## Transferring control to Linux (at address %08x) ...\n",
+ (u32)base_ptr);
+#endif
+
+ /* we assume that the kernel is in place */
+ printf("\nStarting kernel ...\n\n");
+
+ boot_zimage(base_ptr);
+
+}
diff --git a/lib_i386/pci.c b/lib_i386/pci.c
new file mode 100755
index 0000000..a7f16aa
--- /dev/null
+++ b/lib_i386/pci.c
@@ -0,0 +1,155 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+
+#ifdef CONFIG_PCI
+#undef PCI_ROM_SCAN_VERBOSE
+
+int pci_shadow_rom(pci_dev_t dev, unsigned char *dest)
+{
+ struct pci_controller *hose;
+ int res = -1;
+ int i;
+
+ u32 rom_addr;
+ u32 addr_reg;
+ u32 size;
+
+ u16 vendor;
+ u16 device;
+ u32 class_code;
+
+ hose = pci_bus_to_hose(PCI_BUS(dev));
+#if 0
+ printf("pci_shadow_rom() asked to shadow device %x to %x\n",
+ dev, (u32)dest);
+#endif
+ pci_read_config_word(dev, PCI_VENDOR_ID, &vendor);
+ pci_read_config_word(dev, PCI_DEVICE_ID, &device);
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_code);
+
+ class_code &= 0xffffff00;
+ class_code >>= 8;
+
+#if 0
+ printf("PCI Header Vendor %04x device %04x class %06x\n",
+ vendor, device, class_code);
+#endif
+ /* Enable the rom addess decoder */
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS, PCI_ROM_ADDRESS_MASK);
+ pci_read_config_dword(dev, PCI_ROM_ADDRESS, &addr_reg);
+
+ if (!addr_reg) {
+ /* register unimplemented */
+ printf("pci_chadow_rom: device do not seem to have a rom\n");
+ return -1;
+ }
+
+ size = (~(addr_reg&PCI_ROM_ADDRESS_MASK))+1;
+
+#if 0
+ printf("ROM is %d bytes\n", size);
+#endif
+ rom_addr = pci_get_rom_window(hose, size);
+#if 0
+ printf("ROM mapped at %x \n", rom_addr);
+#endif
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+ pci_phys_to_mem(dev, rom_addr)
+ |PCI_ROM_ADDRESS_ENABLE);
+
+
+ for (i=rom_addr;i<rom_addr+size; i+=512) {
+
+
+ if (readw(i) == 0xaa55) {
+ u32 pci_data;
+#ifdef PCI_ROM_SCAN_VERBOSE
+ printf("ROM signature found\n");
+#endif
+ pci_data = readw(0x18+i);
+ pci_data += i;
+
+ if (0==memcmp((void*)pci_data, "PCIR", 4)) {
+#ifdef PCI_ROM_SCAN_VERBOSE
+ printf("Fount PCI rom image at offset %d\n", i-rom_addr);
+ printf("Vendor %04x device %04x class %06x\n",
+ readw(pci_data+4), readw(pci_data+6),
+ readl(pci_data+0x0d)&0xffffff);
+ printf("%s\n",
+ (readw(pci_data+0x15) &0x80)?
+ "Last image":"More images follow");
+ switch (readb(pci_data+0x14)) {
+ case 0:
+ printf("X86 code\n");
+ break;
+ case 1:
+ printf("Openfirmware code\n");
+ break;
+ case 2:
+ printf("PARISC code\n");
+ break;
+ }
+ printf("Image size %d\n", readw(pci_data+0x10) * 512);
+#endif
+ /* FixMe: I think we should compare the class code
+ * bytes as well but I have no reference on the
+ * exact order of these bytes in the PCI ROM header */
+ if (readw(pci_data+4) == vendor &&
+ readw(pci_data+6) == device &&
+ /* (readl(pci_data+0x0d)&0xffffff) == class_code && */
+ readb(pci_data+0x14) == 0 /* x86 code image */ ) {
+#ifdef PCI_ROM_SCAN_VERBOSE
+ printf("Suitable ROM image found, copying\n");
+#endif
+ memmove(dest, (void*)rom_addr, readw(pci_data+0x10) * 512);
+ res = 0;
+ break;
+
+ }
+ if (readw(pci_data+0x15) &0x80) {
+ break;
+ }
+ }
+ }
+
+ }
+
+#ifdef PCI_ROM_SCAN_VERBOSE
+ if (res) {
+ printf("No suitable image found\n");
+ }
+#endif
+ /* disable PAR register and PCI device ROM address devocer */
+ pci_remove_rom_window(hose, rom_addr);
+
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS, 0);
+
+ return res;
+}
+
+#endif
diff --git a/lib_i386/pci_type1.c b/lib_i386/pci_type1.c
new file mode 100755
index 0000000..5dfa8ab
--- /dev/null
+++ b/lib_i386/pci_type1.c
@@ -0,0 +1,56 @@
+/*
+ * Support for type PCI configuration cycles.
+ * based on pci_indirect.c
+ *
+ * Copyright (C) 2002 Daniel Engström, Omicron Ceti AB, daniel@omicron.se.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_PCI
+
+#include <asm/io.h>
+#include <pci.h>
+
+#define cfg_read(val, addr, op) *val = op((int)(addr))
+#define cfg_write(val, addr, op) op((val), (int)(addr))
+
+#define TYPE1_PCI_OP(rw, size, type, op, mask) \
+static int \
+type1_##rw##_config_##size(struct pci_controller *hose, \
+ pci_dev_t dev, int offset, type val) \
+{ \
+ outl(dev | (offset & 0xfc) | 0x80000000, (int)hose->cfg_addr); \
+ cfg_##rw(val, hose->cfg_data + (offset & mask), op); \
+ return 0; \
+}
+
+
+TYPE1_PCI_OP(read, byte, u8 *, inb, 3)
+TYPE1_PCI_OP(read, word, u16 *, inw, 2)
+TYPE1_PCI_OP(read, dword, u32 *, inl, 0)
+
+TYPE1_PCI_OP(write, byte, u8, outb, 3)
+TYPE1_PCI_OP(write, word, u16, outw, 2)
+TYPE1_PCI_OP(write, dword, u32, outl, 0)
+
+void pci_setup_type1(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
+{
+ pci_set_ops(hose,
+ type1_read_config_byte,
+ type1_read_config_word,
+ type1_read_config_dword,
+ type1_write_config_byte,
+ type1_write_config_word,
+ type1_write_config_dword);
+
+ hose->cfg_addr = (unsigned int *) cfg_addr;
+ hose->cfg_data = (unsigned char *) cfg_data;
+}
+
+#endif
diff --git a/lib_i386/realmode.c b/lib_i386/realmode.c
new file mode 100755
index 0000000..6cf2738
--- /dev/null
+++ b/lib_i386/realmode.c
@@ -0,0 +1,95 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/ptrace.h>
+#include <asm/realmode.h>
+
+
+#define REALMODE_BASE ((char*)0x7c0)
+#define REALMODE_MAILBOX ((char*)0xe00)
+
+
+extern char realmode_enter;
+
+int realmode_setup(void)
+{
+ /* copy the realmode switch code */
+ if (i386boot_realmode_size > (REALMODE_MAILBOX-REALMODE_BASE)) {
+ printf("realmode switch too large (%ld bytes, max is %d)\n",
+ i386boot_realmode_size, (REALMODE_MAILBOX-REALMODE_BASE));
+ return -1;
+ }
+
+ memcpy(REALMODE_BASE, (void*)i386boot_realmode, i386boot_realmode_size);
+ asm("wbinvd\n");
+
+ return 0;
+}
+
+int enter_realmode(u16 seg, u16 off, struct pt_regs *in, struct pt_regs *out)
+{
+
+ /* setup out thin bios emulation */
+ if (bios_setup()) {
+ return -1;
+ }
+
+ if (realmode_setup()) {
+ return -1;
+ }
+
+ in->eip = off;
+ in->xcs = seg;
+ if (3>(in->esp & 0xffff)) {
+ printf("Warning: entering realmode with sp < 4 will fail\n");
+ }
+
+ memcpy(REALMODE_MAILBOX, in, sizeof(struct pt_regs));
+ asm("wbinvd\n");
+
+ __asm__ volatile (
+ "lcall $0x20,%0\n" : : "i" (&realmode_enter) );
+
+ asm("wbinvd\n");
+ memcpy(out, REALMODE_MAILBOX, sizeof(struct pt_regs));
+
+ return out->eax;
+}
+
+
+/* This code is supposed to access a realmode interrupt
+ * it does currently not work for me */
+int enter_realmode_int(u8 lvl, struct pt_regs *in, struct pt_regs *out)
+{
+ /* place two instructions at 0x700 */
+ writeb(0xcd, 0x700); /* int $lvl */
+ writeb(lvl, 0x701);
+ writeb(0xcb, 0x702); /* lret */
+ asm("wbinvd\n");
+
+ enter_realmode(0x00, 0x700, in, out);
+
+ return out->eflags&1;
+}
diff --git a/lib_i386/realmode_switch.S b/lib_i386/realmode_switch.S
new file mode 100755
index 0000000..0433cd4
--- /dev/null
+++ b/lib_i386/realmode_switch.S
@@ -0,0 +1,222 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+/* 32bit -> 16bit -> 32bit mode switch code */
+
+/*
+ * Stack frame at 0xe00
+ * e00 ebx;
+ * e04 ecx;
+ * e08 edx;
+ * e0c esi;
+ * e10 edi;
+ * e14 ebp;
+ * e18 eax;
+ * e1c ds;
+ * e20 es;
+ * e24 fs;
+ * e28 gs;
+ * e2c orig_eax;
+ * e30 eip;
+ * e34 cs;
+ * e38 eflags;
+ * e3c esp;
+ * e40 ss;
+ */
+
+#define a32 .byte 0x67; /* address size prefix 32 */
+#define o32 .byte 0x66; /* operand size prefix 32 */
+
+.section .realmode, "ax"
+.code16
+ /* 16bit protected mode code here */
+.globl realmode_enter
+realmode_enter:
+o32 pusha
+o32 pushf
+ cli
+ sidt saved_idt
+ sgdt saved_gdt
+ movl %esp, %eax
+ movl %eax, saved_protected_mode_esp
+
+ movl $0x10, %eax
+ movl %eax, %esp
+ movw $0x28, %ax
+ movw %ax, %ds
+ movw %ax, %es
+ movw %ax, %fs
+ movw %ax, %gs
+
+ lidt realmode_idt_ptr
+ movl %cr0, %eax /* Go back into real mode by */
+ andl $0x7ffffffe, %eax /* clearing PE to 0 */
+ movl %eax, %cr0
+ ljmp $0x0,$do_realmode /* switch to real mode */
+
+do_realmode: /* realmode code from here */
+ movw %cs,%ax
+ movw %ax,%ds
+ movw %ax,%es
+ movw %ax,%fs
+ movw %ax,%gs
+
+ /* create a temporary stack */
+
+ movw $0xc0, %ax
+ movw %ax, %ss
+ movw $0x200, %ax
+ movw %ax, %sp
+
+ popl %ebx
+ popl %ecx
+ popl %edx
+ popl %esi
+ popl %edi
+ popl %ebp
+ popl %eax
+ movl %eax, temp_eax
+ popl %eax
+ movw %ax, %ds
+ popl %eax
+ movw %ax, %es
+ popl %eax
+ movw %ax, %fs
+ popl %eax
+ movw %ax, %gs
+ popl %eax /* orig_eax */
+ popl %eax
+cs movw %ax, temp_ip
+ popl %eax
+cs movw %ax, temp_cs
+o32 popf
+ popl %eax
+ popw %ss
+ movl %eax, %esp
+cs movl temp_eax, %eax
+ wbinvd /* self-modifying code,
+ * better flush the cache */
+
+ .byte 0x9a /* lcall */
+temp_ip:
+ .word 0 /* new ip */
+temp_cs:
+ .word 0 /* new cs */
+realmode_ret:
+ /* save eax, esp and ss */
+cs movl %eax, saved_eax
+ movl %esp, %eax
+cs movl %eax, saved_esp
+ movw %ss, %ax
+cs movw %ax, saved_ss
+
+ /* restore the stack, note that we set sp to 0x244;
+ * pt_regs is 0x44 bytes long and we push the structure
+ * backwards on to the stack, bottom first */
+
+ movw $0xc0, %ax
+ movw %ax, %ss
+ movw $0x244, %ax
+ movw %ax, %sp
+
+ xorl %eax,%eax
+cs movw saved_ss, %ax
+ pushl %eax
+cs movl saved_esp, %eax
+ pushl %eax
+o32 pushf
+ xorl %eax,%eax
+cs movw temp_cs, %ax
+ pushl %eax
+cs movw temp_ip, %ax
+ pushl %eax
+ pushl $0
+ movw %gs, %ax
+ pushl %eax
+ movw %fs, %ax
+ pushl %eax
+ movw %es, %ax
+ pushl %eax
+ movw %ds, %ax
+ pushl %eax
+ movl saved_eax, %eax
+ pushl %eax
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %edx
+ pushl %ecx
+ pushl %ebx
+
+o32 cs lidt saved_idt
+o32 cs lgdt saved_gdt /* Set GDTR */
+
+ movl %cr0, %eax /* Go back into protected mode */
+ orl $1,%eax /* reset PE to 1 */
+ movl %eax, %cr0
+ jmp next_line /* flush prefetch queue */
+next_line:
+ movw $return_ptr, %ax
+ movw %ax,%bp
+o32 cs ljmp *(%bp)
+
+.code32
+protected_mode:
+ movl $0x18,%eax /* reload GDT[3] */
+ movw %ax,%fs /* reset FS */
+ movw %ax,%ds /* reset DS */
+ movw %ax,%gs /* reset GS */
+ movw %ax,%es /* reset ES */
+ movw %ax,%ss /* reset SS */
+ movl saved_protected_mode_esp, %eax
+ movl %eax, %esp
+ popf
+ popa
+ ret
+
+temp_eax:
+ .long 0
+
+saved_ss:
+ .word 0
+saved_esp:
+ .long 0
+saved_eax:
+ .long 0
+
+realmode_idt_ptr:
+ .word 0x400
+ .word 0x0, 0x0
+
+saved_gdt:
+ .word 0, 0, 0, 0
+saved_idt:
+ .word 0, 0, 0, 0
+
+saved_protected_mode_esp:
+ .long 0
+
+return_ptr:
+ .long protected_mode
+ .word 0x10
diff --git a/lib_i386/video.c b/lib_i386/video.c
new file mode 100755
index 0000000..cd89457
--- /dev/null
+++ b/lib_i386/video.c
@@ -0,0 +1,237 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <devices.h>
+#include <i8042.h>
+#include <asm/ptrace.h>
+#include <asm/realmode.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+
+
+/* basic textmode I/O from linux kernel */
+static char *vidmem = (char *)0xb8000;
+static int vidport;
+static int lines, cols;
+static int orig_x, orig_y;
+
+static void beep(int dur)
+{
+ int i;
+
+ outb_p(3, 0x61);
+ for (i=0;i<10*dur;i++) {
+ udelay(1000);
+ }
+ outb_p(0, 0x61);
+}
+
+static void scroll(void)
+{
+ int i;
+
+ memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 );
+ for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 )
+ vidmem[i] = ' ';
+}
+
+static void __video_putc(const char c, int *x, int *y)
+{
+ if (c == '\n') {
+ (*x) = 0;
+ if ( ++(*y) >= lines ) {
+ scroll();
+ (*y)--;
+ }
+ } else if (c == '\b') {
+ if ((*x) != 0) {
+ --(*x);
+ vidmem [ ( (*x) + cols * (*y) ) * 2 ] = ' ';
+ }
+ } else if (c == '\r') {
+ (*x) = 0;
+
+ } else if (c == '\a') {
+ beep(3);
+
+ } else if (c == '\t') {
+ __video_putc(' ', x, y);
+ __video_putc(' ', x, y);
+ __video_putc(' ', x, y);
+ __video_putc(' ', x, y);
+ __video_putc(' ', x, y);
+ __video_putc(' ', x, y);
+ __video_putc(' ', x, y);
+ __video_putc(' ', x, y);
+ } else if (c == '\v') {
+ switch ((*x) % 8) {
+ case 0:
+ __video_putc(' ', x, y);
+ case 7:
+ __video_putc(' ', x, y);
+ case 6:
+ __video_putc(' ', x, y);
+ case 5:
+ __video_putc(' ', x, y);
+ case 4:
+ __video_putc(' ', x, y);
+ case 3:
+ __video_putc(' ', x, y);
+ case 2:
+ __video_putc(' ', x, y);
+ case 1:
+ __video_putc(' ', x, y);
+ }
+ } else if (c == '\f') {
+ int i;
+ for (i=0;i<lines*cols*2;i+=2) {
+ vidmem[i] = 0;
+ }
+ (*x) = 0;
+ (*y) = 0;
+ } else {
+ vidmem [ ( (*x) + cols * (*y) ) * 2 ] = c;
+ if ( ++(*x) >= cols ) {
+ (*x) = 0;
+ if ( ++(*y) >= lines ) {
+ scroll();
+ (*y)--;
+ }
+ }
+ }
+}
+
+static void video_putc(const char c)
+{
+ int x,y,pos;
+
+ x = orig_x;
+ y = orig_y;
+
+ __video_putc(c, &x, &y);
+
+ orig_x = x;
+ orig_y = y;
+
+ pos = (x + cols * y) * 2; /* Update cursor position */
+ outb_p(14, vidport);
+ outb_p(0xff & (pos >> 9), vidport+1);
+ outb_p(15, vidport);
+ outb_p(0xff & (pos >> 1), vidport+1);
+}
+
+static void video_puts(const char *s)
+{
+ int x,y,pos;
+ char c;
+
+ x = orig_x;
+ y = orig_y;
+
+ while ( ( c = *s++ ) != '\0' ) {
+ __video_putc(c, &x, &y);
+ }
+
+ orig_x = x;
+ orig_y = y;
+
+ pos = (x + cols * y) * 2; /* Update cursor position */
+ outb_p(14, vidport);
+ outb_p(0xff & (pos >> 9), vidport+1);
+ outb_p(15, vidport);
+ outb_p(0xff & (pos >> 1), vidport+1);
+}
+
+int video_init(void)
+{
+ u16 pos;
+
+ static device_t vga_dev;
+ static device_t kbd_dev;
+
+ vidmem = (char *) 0xb8000;
+ vidport = 0x3d4;
+
+ lines = 25;
+ cols = 80;
+
+ outb_p(14, vidport);
+ pos = inb_p(vidport+1);
+ pos <<= 8;
+ outb_p(15, vidport);
+ pos |= inb_p(vidport+1);
+
+ orig_x = pos%cols;
+ orig_y = pos/cols;
+
+#if 0
+ printf("pos %x %d %d\n", pos, orig_x, orig_y);
+#endif
+ if (orig_y > lines) {
+ orig_x = orig_y =0;
+ }
+
+
+ memset(&vga_dev, 0, sizeof(vga_dev));
+ strcpy(vga_dev.name, "vga");
+ vga_dev.ext = 0;
+ vga_dev.flags = DEV_FLAGS_OUTPUT | DEV_FLAGS_SYSTEM;
+ vga_dev.putc = video_putc; /* 'putc' function */
+ vga_dev.puts = video_puts; /* 'puts' function */
+ vga_dev.tstc = NULL; /* 'tstc' function */
+ vga_dev.getc = NULL; /* 'getc' function */
+
+ if (device_register(&vga_dev) == 0) {
+ return 1;
+ }
+
+ if (i8042_kbd_init()) {
+ return 1;
+ }
+
+ memset(&kbd_dev, 0, sizeof(kbd_dev));
+ strcpy(kbd_dev.name, "kbd");
+ kbd_dev.ext = 0;
+ kbd_dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM;
+ kbd_dev.putc = NULL; /* 'putc' function */
+ kbd_dev.puts = NULL; /* 'puts' function */
+ kbd_dev.tstc = i8042_tstc; /* 'tstc' function */
+ kbd_dev.getc = i8042_getc; /* 'getc' function */
+
+ if (device_register(&kbd_dev) == 0) {
+ return 1;
+ }
+ return 0;
+}
+
+
+int drv_video_init(void)
+{
+ if (video_bios_init()) {
+ return 1;
+ }
+
+ return video_init();
+}
diff --git a/lib_i386/video_bios.c b/lib_i386/video_bios.c
new file mode 100755
index 0000000..45f78e2
--- /dev/null
+++ b/lib_i386/video_bios.c
@@ -0,0 +1,219 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <malloc.h>
+#include <asm/ptrace.h>
+#include <asm/realmode.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+
+#undef PCI_BIOS_DEBUG
+#undef VGA_BIOS_DEBUG
+
+#ifdef VGA_BIOS_DEBUG
+#define PRINTF(fmt,args...) printf (fmt ,##args)
+#else
+#define PRINTF(fmt,args...)
+#endif
+
+#ifdef CONFIG_PCI
+
+#ifdef PCI_BIOS_DEBUG
+#define RELOC_16(seg, off) *(u32*)(seg << 4 | (u32)&off)
+extern u32 num_pci_bios_present;
+extern u32 num_pci_bios_find_device;
+extern u32 num_pci_bios_find_class;
+extern u32 num_pci_bios_generate_special_cycle;
+extern u32 num_pci_bios_read_cfg_byte;
+extern u32 num_pci_bios_read_cfg_word;
+extern u32 num_pci_bios_read_cfg_dword;
+extern u32 num_pci_bios_write_cfg_byte;
+extern u32 num_pci_bios_write_cfg_word;
+extern u32 num_pci_bios_write_cfg_dword;
+extern u32 num_pci_bios_get_irq_routing;
+extern u32 num_pci_bios_set_irq;
+extern u32 num_pci_bios_unknown_function;
+
+void print_bios_bios_stat(void)
+{
+ printf("16 bit functions:\n");
+ printf("pci_bios_present: %d\n", RELOC_16(0xf000, num_pci_bios_present));
+ printf("pci_bios_find_device: %d\n", RELOC_16(0xf000, num_pci_bios_find_device));
+ printf("pci_bios_find_class: %d\n", RELOC_16(0xf000, num_pci_bios_find_class));
+ printf("pci_bios_generate_special_cycle: %d\n", RELOC_16(0xf000, num_pci_bios_generate_special_cycle));
+ printf("pci_bios_read_cfg_byte: %d\n", RELOC_16(0xf000, num_pci_bios_read_cfg_byte));
+ printf("pci_bios_read_cfg_word: %d\n", RELOC_16(0xf000, num_pci_bios_read_cfg_word));
+ printf("pci_bios_read_cfg_dword: %d\n", RELOC_16(0xf000, num_pci_bios_read_cfg_dword));
+ printf("pci_bios_write_cfg_byte: %d\n", RELOC_16(0xf000, num_pci_bios_write_cfg_byte));
+ printf("pci_bios_write_cfg_word: %d\n", RELOC_16(0xf000, num_pci_bios_write_cfg_word));
+ printf("pci_bios_write_cfg_dword: %d\n", RELOC_16(0xf000, num_pci_bios_write_cfg_dword));
+ printf("pci_bios_get_irq_routing: %d\n", RELOC_16(0xf000, num_pci_bios_get_irq_routing));
+ printf("pci_bios_set_irq: %d\n", RELOC_16(0xf000, num_pci_bios_set_irq));
+ printf("pci_bios_unknown_function: %d\n", RELOC_16(0xf000, num_pci_bios_unknown_function));
+
+}
+#endif
+
+#define PCI_CLASS_VIDEO 3
+#define PCI_CLASS_VIDEO_STD 0
+#define PCI_CLASS_VIDEO_PROG_IF_VGA 0
+
+
+static u32 probe_pci_video(void)
+{
+ pci_dev_t devbusfn;
+
+ if ((devbusfn = pci_find_class(PCI_CLASS_VIDEO,
+ PCI_CLASS_VIDEO_STD,
+ PCI_CLASS_VIDEO_PROG_IF_VGA, 0)) != -1) {
+ u32 old;
+ u32 addr;
+
+ /* PCI video device detected */
+ printf("Found PCI VGA device at %02x.%02x.%x\n",
+ PCI_BUS(devbusfn), PCI_DEV(devbusfn), PCI_FUNC(devbusfn));
+
+ /* Enable I/O decoding as well, PCI viudeo boards
+ * support I/O accesses, but they provide no
+ * bar register for this since the ports are fixed.
+ */
+ pci_write_config_word(devbusfn, PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_IO | PCI_COMMAND_MASTER);
+
+ /* Test the ROM decoder, do the device support a rom? */
+ pci_read_config_dword(devbusfn, PCI_ROM_ADDRESS, &old);
+ pci_write_config_dword(devbusfn, PCI_ROM_ADDRESS, PCI_ROM_ADDRESS_MASK);
+ pci_read_config_dword(devbusfn, PCI_ROM_ADDRESS, &addr);
+ pci_write_config_dword(devbusfn, PCI_ROM_ADDRESS, old);
+
+ if (!addr) {
+ printf("PCI VGA have no ROM?\n");
+ return 0;
+ }
+
+ /* device have a rom */
+ if (pci_shadow_rom(devbusfn, (void*)0xc0000)) {
+ printf("Shadowing of PCI VGA BIOS failed\n");
+ return 0;
+ }
+
+ /* Now enable lagacy VGA port access */
+ if (pci_enable_legacy_video_ports(pci_bus_to_hose(PCI_BUS(devbusfn)))) {
+ printf("PCI VGA enable failed\n");
+ return 0;
+ }
+
+
+ /* return the pci device info, that we'll need later */
+ return PCI_BUS(devbusfn) << 8 |
+ PCI_DEV(devbusfn) << 3 | (PCI_FUNC(devbusfn)&7);
+ }
+
+ return 0;
+}
+
+
+#endif
+
+static int probe_isa_video(void)
+{
+ u32 ptr;
+ char *buf;
+
+ if (0 == (ptr = isa_map_rom(0xc0000, 0x8000))) {
+ return -1;
+ }
+ if (NULL == (buf=malloc(0x8000))) {
+ isa_unmap_rom(ptr);
+ return -1;
+ }
+ if (readw(ptr) != 0xaa55) {
+ free(buf);
+ isa_unmap_rom(ptr);
+ return -1;
+ }
+
+ /* shadow the rom */
+ memcpy(buf, (void*)ptr, 0x8000);
+ isa_unmap_rom(ptr);
+ memcpy((void*)0xc0000, buf, 0x8000);
+
+ free(buf);
+
+ return 0;
+}
+
+int video_bios_init(void)
+{
+ struct pt_regs regs;
+
+ /* clear the video bios area in case we warmbooted */
+ memset((void*)0xc0000, 0, 0x8000);
+ memset(&regs, 0, sizeof(struct pt_regs));
+
+ if (probe_isa_video()) {
+ /* No ISA board found, try the PCI bus */
+ regs.eax = probe_pci_video();
+ }
+
+ /* Did we succeed in mapping any video bios */
+ if (readw(0xc0000) == 0xaa55) {
+ int size;
+ int i;
+ u8 sum;
+
+ PRINTF("Found video bios signature\n");
+ size = 512*readb(0xc0002);
+ PRINTF("size %d\n", size);
+ sum=0;
+ for (i=0;i<size;i++) {
+ sum += readb(0xc0000 + i);
+ }
+ PRINTF("Checksum is %sOK\n",sum?"NOT ":"");
+ if (sum) {
+ return 1;
+ }
+
+ /* some video bioses (ATI Mach64) seem to think that
+ * the original int 10 handler is always at
+ * 0xf000:0xf065 , place an iret instruction there
+ */
+ writeb(0xcf, 0xff065);
+
+ regs.esp = 0x8000;
+ regs.xss = 0x2000;
+ enter_realmode(0xc000, 3, &regs, &regs);
+ PRINTF("INT 0x10 vector after: %04x:%04x\n",
+ readw(0x42), readw(0x40));
+ PRINTF("BIOS returned %scarry\n", regs.eflags & 1?"":"NOT ");
+#ifdef PCI_BIOS_DEBUG
+ print_bios_bios_stat();
+#endif
+ return (regs.eflags & 1);
+
+ }
+
+ return 1;
+
+}
diff --git a/lib_i386/zimage.c b/lib_i386/zimage.c
new file mode 100755
index 0000000..3510f2f
--- /dev/null
+++ b/lib_i386/zimage.c
@@ -0,0 +1,275 @@
+/*
+ * (C) Copyright 2002
+ * Daniel Engström, Omicron Ceti AB, daniel@omicron.se
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Linux i386 zImage and bzImage loading
+ *
+ * based on the procdure described in
+ * linux/Documentation/i386/boot.txt
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/ptrace.h>
+#include <asm/zimage.h>
+#include <asm/realmode.h>
+#include <asm/byteorder.h>
+
+/*
+ * Memory lay-out:
+ *
+ * relative to setup_base (which is 0x90000 currently)
+ *
+ * 0x0000-0x7FFF Real mode kernel
+ * 0x8000-0x8FFF Stack and heap
+ * 0x9000-0x90FF Kernel command line
+ */
+#define DEFAULT_SETUP_BASE 0x90000
+#define COMMAND_LINE_OFFSET 0x9000
+#define HEAP_END_OFFSET 0x8e00
+
+#define COMMAND_LINE_SIZE 2048
+
+static void build_command_line(char *command_line, int auto_boot)
+{
+ char *env_command_line;
+
+ command_line[0] = '\0';
+
+ env_command_line = getenv("bootargs");
+
+ /* set console= argument if we use a serial console */
+ if (NULL == strstr(env_command_line, "console=")) {
+ if (0==strcmp(getenv("stdout"), "serial")) {
+
+ /* We seem to use serial console */
+ sprintf(command_line, "console=ttyS0,%s ",
+ getenv("baudrate"));
+ }
+ }
+
+ if (auto_boot) {
+ strcat(command_line, "auto ");
+ }
+
+ if (NULL != env_command_line) {
+ strcat(command_line, env_command_line);
+ }
+
+
+ printf("Kernel command line: \"%s\"\n", command_line);
+}
+
+void *load_zimage(char *image, unsigned long kernel_size,
+ unsigned long initrd_addr, unsigned long initrd_size,
+ int auto_boot)
+{
+ void *setup_base;
+ int setup_size;
+ int bootproto;
+ int big_image;
+ void *load_address;
+
+
+ setup_base = (void*)DEFAULT_SETUP_BASE; /* base address for real-mode segment */
+
+ if (KERNEL_MAGIC != *(u16*)(image + BOOT_FLAG_OFF)) {
+ printf("Error: Invalid kernel magic (found 0x%04x, expected 0xaa55)\n",
+ *(u16*)(image + BOOT_FLAG_OFF));
+ return 0;
+ }
+
+
+ /* determine boot protocol version */
+ if (KERNEL_V2_MAGIC == *(u32*)(image+HEADER_OFF)) {
+ bootproto = *(u16*)(image+VERSION_OFF);
+ } else {
+ /* Very old kernel */
+ bootproto = 0x0100;
+ }
+
+ /* determine size of setup */
+ if (0 == *(u8*)(image + SETUP_SECTS_OFF)) {
+ setup_size = 5 * 512;
+ } else {
+ setup_size = (*(u8*)(image + SETUP_SECTS_OFF) + 1) * 512;
+ }
+
+ if (setup_size > SETUP_MAX_SIZE) {
+ printf("Error: Setup is too large (%d bytes)\n", setup_size);
+ }
+
+ /* Determine image type */
+ big_image = (bootproto >= 0x0200) && (*(u8*)(image + LOADFLAGS_OFF) & BIG_KERNEL_FLAG);
+
+ /* Derermine load address */
+ load_address = (void*)(big_image ? BZIMAGE_LOAD_ADDR:ZIMAGE_LOAD_ADDR);
+
+ /* load setup */
+ memmove(setup_base, image, setup_size);
+
+ printf("Using boot protocol version %x.%02x\n",
+ (bootproto & 0xff00) >> 8, bootproto & 0xff);
+
+
+ if (bootproto == 0x0100) {
+
+ *(u16*)(setup_base + CMD_LINE_MAGIC_OFF) = COMMAND_LINE_MAGIC;
+ *(u16*)(setup_base + CMD_LINE_OFFSET_OFF) = COMMAND_LINE_OFFSET;
+
+ /* A very old kernel MUST have its real-mode code
+ * loaded at 0x90000 */
+
+ if ((u32)setup_base != 0x90000) {
+ /* Copy the real-mode kernel */
+ memmove((void*)0x90000, setup_base, setup_size);
+ /* Copy the command line */
+ memmove((void*)0x99000, setup_base+COMMAND_LINE_OFFSET,
+ COMMAND_LINE_SIZE);
+
+ setup_base = (void*)0x90000; /* Relocated */
+ }
+
+ /* It is recommended to clear memory up to the 32K mark */
+ memset((void*)0x90000 + setup_size, 0, SETUP_MAX_SIZE-setup_size);
+ }
+
+ if (bootproto >= 0x0200) {
+ *(u8*)(setup_base + TYPE_OF_LOADER_OFF) = 0xff;
+ printf("Linux kernel version %s\n",
+ (char*)(setup_base + SETUP_START_OFFSET +
+ *(u16*)(setup_base + START_SYS_OFF + 2)));
+
+ if (initrd_addr) {
+ printf("Initial RAM disk at linear address 0x%08lx, size %ld bytes\n",
+ initrd_addr, initrd_size);
+
+ *(u32*)(setup_base + RAMDISK_IMAGE_OFF) = initrd_addr;
+ *(u32*)(setup_base + RAMDISK_SIZE_OFF)=initrd_size;
+ }
+ }
+
+ if (bootproto >= 0x0201) {
+ *(u16*)(setup_base + HEAP_END_PTR_OFF) = HEAP_END_OFFSET;
+
+ /* CAN_USE_HEAP */
+ *(u8*)(setup_base + LOADFLAGS_OFF) =
+ *(u8*)(setup_base + LOADFLAGS_OFF) | HEAP_FLAG;
+ }
+
+ if (bootproto >= 0x0202) {
+ *(u32*)(setup_base + CMD_LINE_PTR_OFF) = (u32)setup_base + COMMAND_LINE_OFFSET;
+ } else if (bootproto >= 0x0200) {
+ *(u16*)(setup_base + CMD_LINE_MAGIC_OFF) = COMMAND_LINE_MAGIC;
+ *(u16*)(setup_base + CMD_LINE_OFFSET_OFF) = COMMAND_LINE_OFFSET;
+ *(u16*)(setup_base + SETUP_MOVE_SIZE_OFF) = 0x9100;
+ }
+
+
+ if (big_image) {
+ if ((kernel_size - setup_size) > BZIMAGE_MAX_SIZE) {
+ printf("Error: bzImage kernel too big! (size: %ld, max: %d)\n",
+ kernel_size - setup_size, BZIMAGE_MAX_SIZE);
+ return 0;
+ }
+
+ } else if ((kernel_size - setup_size) > ZIMAGE_MAX_SIZE) {
+ printf("Error: zImage kernel too big! (size: %ld, max: %d)\n",
+ kernel_size - setup_size, ZIMAGE_MAX_SIZE);
+ return 0;
+ }
+
+ /* build command line at COMMAND_LINE_OFFSET */
+ build_command_line(setup_base + COMMAND_LINE_OFFSET, auto_boot);
+
+ printf("Loading %czImage at address 0x%08x (%ld bytes)\n", big_image ? 'b' : ' ',
+ (u32)load_address, kernel_size - setup_size);
+
+
+ memmove(load_address, image + setup_size, kernel_size - setup_size);
+
+ /* ready for booting */
+ return setup_base;
+}
+
+
+void boot_zimage(void *setup_base)
+{
+ struct pt_regs regs;
+
+ memset(&regs, 0, sizeof(struct pt_regs));
+ regs.xds = (u32)setup_base >> 4;
+ regs.xss = 0x9000;
+ regs.esp = 0x9000;
+ regs.eflags = 0;
+ enter_realmode(((u32)setup_base+SETUP_START_OFFSET)>>4, 0, &regs, &regs);
+}
+
+
+image_header_t *fake_zimage_header(image_header_t *hdr, void *ptr, int size)
+{
+ /* There is no way to know the size of a zImage ... *
+ * so we assume that 2MB will be enough for now */
+#define ZIMAGE_SIZE 0x200000
+
+ /* load a 1MB, the loaded will have to be moved to its final
+ * position again later... */
+#define ZIMAGE_LOAD 0x100000
+
+ ulong checksum;
+
+ if (KERNEL_MAGIC != *(u16*)(ptr + BOOT_FLAG_OFF)) {
+ /* not a zImage or bzImage */
+ return NULL;
+ }
+
+ if (-1 == size) {
+ size = ZIMAGE_SIZE;
+ }
+#if 0
+ checksum = crc32 (0, ptr, size);
+#else
+ checksum = 0;
+#endif
+ memset(hdr, 0, sizeof(image_header_t));
+
+ /* Build new header */
+ hdr->ih_magic = htonl(IH_MAGIC);
+ hdr->ih_time = 0;
+ hdr->ih_size = htonl(size);
+ hdr->ih_load = htonl(ZIMAGE_LOAD);
+ hdr->ih_ep = 0;
+ hdr->ih_dcrc = htonl(checksum);
+ hdr->ih_os = IH_OS_LINUX;
+ hdr->ih_arch = IH_CPU_I386;
+ hdr->ih_type = IH_TYPE_KERNEL;
+ hdr->ih_comp = IH_COMP_NONE;
+
+ strncpy((char *)hdr->ih_name, "(none)", IH_NMLEN);
+
+ checksum = crc32(0,(const char *)hdr,sizeof(image_header_t));
+
+ hdr->ih_hcrc = htonl(checksum);
+
+ return hdr;
+}