From 2262cfeef91458b01a1bfe3812ccbbfdf8b82807 Mon Sep 17 00:00:00 2001 From: wdenk Date: Mon, 18 Nov 2002 00:14:45 +0000 Subject: * Patch by Daniel Engström, 13 Nov 2002: Add support for i386 architecture and AMD SC520 board MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Patch by Pierre Aubert, 12 Nov 2002: Add support for DOS filesystem and booting from DOS floppy disk --- lib_i386/Makefile | 45 ++++ lib_i386/bios.S | 443 +++++++++++++++++++++++++++++++++++++ lib_i386/bios_setup.c | 178 +++++++++++++++ lib_i386/board.c | 448 ++++++++++++++++++++++++++++++++++++++ lib_i386/i386_linux.c | 174 +++++++++++++++ lib_i386/ic/ali512x.c | 442 +++++++++++++++++++++++++++++++++++++ lib_i386/ic/sc520.c | 348 +++++++++++++++++++++++++++++ lib_i386/ic/sc520_asm.S | 530 +++++++++++++++++++++++++++++++++++++++++++++ lib_i386/pci_type1.c | 57 +++++ lib_i386/realmode.c | 69 ++++++ lib_i386/realmode_switch.S | 223 +++++++++++++++++++ lib_i386/zimage.c | 276 +++++++++++++++++++++++ 12 files changed, 3233 insertions(+) create mode 100644 lib_i386/Makefile create mode 100644 lib_i386/bios.S create mode 100644 lib_i386/bios_setup.c create mode 100644 lib_i386/board.c create mode 100644 lib_i386/i386_linux.c create mode 100644 lib_i386/ic/ali512x.c create mode 100644 lib_i386/ic/sc520.c create mode 100644 lib_i386/ic/sc520_asm.S create mode 100644 lib_i386/pci_type1.c create mode 100644 lib_i386/realmode.c create mode 100644 lib_i386/realmode_switch.S create mode 100644 lib_i386/zimage.c (limited to 'lib_i386') diff --git a/lib_i386/Makefile b/lib_i386/Makefile new file mode 100644 index 000000000..34994e544 --- /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 realmode_switch.o ic/sc520_asm.o + +COBJS = board.o bios_setup.o i386_linux.o zimage.o realmode.o \ + pci_type1.o ic/sc520.o ic/ali512x.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 100644 index 000000000..2f5ea8cda --- /dev/null +++ b/lib_i386/bios.S @@ -0,0 +1,443 @@ +/* + * (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 + *---------------------------------------------------------------------- + */ + +/* + * 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 !! + */ + +#define OFFS_ES 0 +#define OFFS_GS 2 +#define OFFS_DS 4 +#define OFFS_DI 6 +#define OFFS_SI 8 +#define OFFS_BP 10 +#define OFFS_SP 12 +#define OFFS_BX 14 +#define OFFS_DX 16 +#define OFFS_CX 18 +#define OFFS_AX 20 +#define OFFS_VECTOR 22 +#define OFFS_IP 24 +#define OFFS_CS 26 +#define OFFS_FLAGS 28 + +#define SEGMENT 0x40 +#define STACK 0x800 /* stack at 0x40:0x800 -> 0x800 */ + +.section .bios, "ax" +.code16 +.org 0 + +.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: + pusha /* save general registers */ + pushw %ds /* save some segments */ + pushw %gs + pushw %es + pushw %ss /* save callers stack segment .. */ + popw %gs /* ... in gs */ + movw $SEGMENT,%ax /* setup my segments */ + movw %ax,%ds + movw %ax,%es + movw %ax,%ss + movw %sp,%bp + movw $STACK,%sp /* setup BIOS stackpointer */ + +gs movw OFFS_VECTOR(%bp), %ax + cmpw $0x10, %ax + je Lint_10h + cmpw $0x11, %ax + je Lint_11h + cmpw $0x13, %ax + je Lint_13h + cmpw $0x15, %ax + je Lint_15h + cmpw $0x16, %ax + je Lint_16h + movw $0xffff, %ax + jmp Lout +Lint_10h: /* VGA BIOS services */ + call bios_10h + jmp Lout +Lint_11h: + call bios_11h + 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 +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: + + pushw %gs /* restore callers stack segment */ + popw %ss + movw %bp,%sp /* restore stackpointer */ + + popw %es /* restore segment selectors */ + popw %gs + popw %ds + + popa /* restore GP registers */ + 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: + movw bios_equipment, %ax +gs movw %ax, OFFS_AX(%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 */ + movw $ram_in_64kb_chunks, %ax + cmpw $256, %ax + ja Lmore_than_16mb + shlw $6, %ax /* multiply by 64 */ +gs movw %ax, OFFS_AX(%bp) /* return memory size in 1kb chunks in AX and CX */ +gs movw %ax, OFFS_CX(%bp) + xorw %ax, %ax +gs movw %ax, OFFS_BX(%bp) /* set BX and DX to 0*/ +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 + +Lmore_than_16mb: + subw $0x100, %ax /* subtract 16MB */ + +gs movw $0x3c00, OFFS_AX(%bp) /* return 0x3c00 (16MB-384k) 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 - 256 */ +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: + movw ram_in_64kb_chunks, %ax + subw $16, %ax + shlw $6, %ax + +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 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 + + +.globl ram_in_64kb_chunks +ram_in_64kb_chunks: + .word 0 + +.globl bios_equipment +bios_equipment: + .word 0 + diff --git a/lib_i386/bios_setup.c b/lib_i386/bios_setup.c new file mode 100644 index 000000000..94319afc5 --- /dev/null +++ b/lib_i386/bios_setup.c @@ -0,0 +1,178 @@ +/* + * (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 +#include +#include + +#define NUMVECTS 256 + +#define BIOS_DATA ((char*)0x400) +#define BIOS_DATA_SIZE 256 +#define BIOS_BASE ((char*)0xf0000) +#define BIOS_CS 0xf000 + +extern u16 ram_in_64kb_chunks; +extern u16 bios_equipment; +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; + +/* + ************************************************************ + * 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 +} + +int bios_setup(void) +{ + DECLARE_GLOBAL_DATA_PTR; + static int done=0; + int vector; + + 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); + + /* fill in data area */ + ram_in_64kb_chunks = gd->ram_size >> 16; + bios_equipment = 0; /* FixMe */ + + return 0; +} + diff --git a/lib_i386/board.c b/lib_i386/board.c new file mode 100644 index 000000000..193860a87 --- /dev/null +++ b/lib_i386/board.c @@ -0,0 +1,448 @@ +/* + * (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 + * Marius Groeger + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +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; + +#if 1 + /* 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; +#else + mem_malloc_start = 0x400000; +#endif +#if 1 + /* Use all available RAM for malloc() */ + mem_malloc_end = gd->ram_size; +#else + /* Use only CONFIG_MALLOC_SIZE bytes of RAM for malloc() */ + mem_malloc_end = mem_malloc_start + CONFIG_MALLOC_SIZE; +#endif + 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 void syscalls_init (void) +{ + syscall_tbl[SYSCALL_MALLOC] = (void *) malloc; + syscall_tbl[SYSCALL_FREE] = (void *) free; + + syscall_tbl[SYSCALL_INSTALL_HDLR] = (void *) irq_install_handler; + syscall_tbl[SYSCALL_FREE_HDLR] = (void *) irq_free_handler; + +} + +static int init_baudrate (void) +{ + DECLARE_GLOBAL_DATA_PTR; + + uchar tmp[64]; /* long enough for environment variables */ + int i = getenv_r ("baudrate", tmp, sizeof (tmp)); + + 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; ibd->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, + 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; + + memset (gd, 0, sizeof (gd_t)); + gd->bd = &bd_data; + memset (gd->bd, 0, sizeof (bd_t)); + show_boot_progress(0x22); + + + 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 (); + + /* allocate syscalls table (console_init_r will fill it in */ + syscall_tbl = (void **) malloc (NR_SYSCALLS * sizeof (void *)); + + /* Initialize the console (after the relocation and devices init) */ + console_init_r(); + syscalls_init(); + +#ifdef CONFIG_MISC_INIT_R + /* miscellaneous platform dependent initialisations */ + misc_init_r(); +#endif + + +#if (CONFIG_COMMANDS & CFG_CMD_NET) && (0) + WATCHDOG_RESET(); +# ifdef DEBUG + puts ("Reset Ethernet PHY\n"); +# endif + reset_phy(); +#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) && defined(CONFIG_NET_MULTI) + WATCHDOG_RESET(); + puts("Net: "); + eth_initialize(gd->bd); +#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)); + if (post_bootmode_get(0) & POST_POWERFAIL) { + post_bootmode_clear(); + board_poweroff(); + } +#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 100644 index 000000000..c37a0d8ee --- /dev/null +++ b/lib_i386/i386_linux.c @@ -0,0 +1,174 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH + * Marius Groeger + * + * 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 +#include +#include +#include +#include +#include +#include + + +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) +{ + ulong 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(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/ic/ali512x.c b/lib_i386/ic/ali512x.c new file mode 100644 index 000000000..4537095db --- /dev/null +++ b/lib_i386/ic/ali512x.c @@ -0,0 +1,442 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB . + * + * 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 sc520cdp.c from rolo 1.6: + *---------------------------------------------------------------------- + * (C) Copyright 2000 + * Sysgo Real-Time Solutions GmbH + * Klein-Winternheim, Germany + *---------------------------------------------------------------------- + */ + +#include +#include +#include + + +/* ALI M5123 Logical device numbers: + * 0 FDC + * 1 unused? + * 2 unused? + * 3 lpt + * 4 UART1 + * 5 UART2 + * 6 RTC + * 7 mouse/kbd + * 8 CIO + */ + +/* + ************************************************************ + * Some access primitives for the ALi chip: * + ************************************************************ + */ + +static void ali_write(u8 index, u8 value) +{ + /* write an arbirary register */ + outb(index, ALI_INDEX); + outb(value, ALI_DATA); +} + +static int ali_read(u8 index) +{ + outb(index, ALI_INDEX); + return inb(ALI_DATA); +} + +#define ALI_OPEN() \ + outb(0x51, ALI_DATA); \ + outb(0x23, ALI_DATA) + + +#define ALI_CLOSE() \ + outb(0xbb, ALI_DATA) + +/* Select a logical device */ +#define ALI_SELDEV(dev) \ + ali_write(0x07, dev) + + +void ali512x_init(void) +{ + ALI_OPEN(); + + ali_write(0x02, 0x01); /* soft reset */ + ali_write(0x03, 0x03); /* disable access to CIOs */ + ali_write(0x22, 0x00); /* disable direct powerdown */ + ali_write(0x23, 0x00); /* disable auto powerdown */ + ali_write(0x24, 0x00); /* IR 8 is active hi, pin26 is PDIR */ + + ALI_CLOSE(); +} + +void ali512x_set_fdc(int enabled, u16 io, u8 irq, u8 dma_channel) +{ + ALI_OPEN(); + ALI_SELDEV(0); + + ali_write(0x30, enabled?1:0); + if (enabled) { + ali_write(0x60, io >> 8); + ali_write(0x61, io & 0xff); + ali_write(0x70, irq); + ali_write(0x74, dma_channel); + + /* AT mode, no drive swap */ + ali_write(0xf0, 0x08); + ali_write(0xf1, 0x00); + ali_write(0xf2, 0xff); + ali_write(0xf4, 0x00); + } + ALI_CLOSE(); +} + + +void ali512x_set_pp(int enabled, u16 io, u8 irq, u8 dma_channel) +{ + ALI_OPEN(); + ALI_SELDEV(3); + + ali_write(0x30, enabled?1:0); + if (enabled) { + ali_write(0x60, io >> 8); + ali_write(0x61, io & 0xff); + ali_write(0x70, irq); + ali_write(0x74, dma_channel); + + /* mode: EPP 1.9, ECP FIFO threshold = 7, IRQ active low */ + ali_write(0xf0, 0xbc); + /* 12 MHz, Burst DMA in ECP */ + ali_write(0xf1, 0x05); + } + ALI_CLOSE(); + +} + +void ali512x_set_uart(int enabled, int index, u16 io, u8 irq) +{ + ALI_OPEN(); + ALI_SELDEV(index?5:4); + + ali_write(0x30, enabled?1:0); + if (enabled) { + ali_write(0x60, io >> 8); + ali_write(0x61, io & 0xff); + ali_write(0x70, irq); + + ali_write(0xf0, 0x00); + ali_write(0xf1, 0x00); + + /* huh? write 0xf2 twice - a typo in rolo + * or some secret ali errata? Who knows? + */ + if (index) { + ali_write(0xf2, 0x00); + } + ali_write(0xf2, 0x0c); + } + ALI_CLOSE(); + +} + +void ali512x_set_uart2_irda(int enabled) +{ + ALI_OPEN(); + ALI_SELDEV(5); + + ali_write(0xf1, enabled?0x48:0x00); /* fullduplex IrDa */ + ALI_CLOSE(); + +} + +void ali512x_set_rtc(int enabled, u16 io, u8 irq) +{ + ALI_OPEN(); + ALI_SELDEV(6); + + ali_write(0x30, enabled?1:0); + if (enabled) { + ali_write(0x60, io >> 8); + ali_write(0x61, io & 0xff); + ali_write(0x70, irq); + + ali_write(0xf0, 0x00); + } + ALI_CLOSE(); +} + +void ali512x_set_kbc(int enabled, u8 kbc_irq, u8 mouse_irq) +{ + ALI_OPEN(); + ALI_SELDEV(7); + + ali_write(0x30, enabled?1:0); + if (enabled) { + ali_write(0x70, kbc_irq); + ali_write(0x72, mouse_irq); + + ali_write(0xf0, 0x00); + } + ALI_CLOSE(); +} + + +/* Common I/O + * + * (This descripotsion is base on several incompete sources + * since I have not been able to obtain any datasheet for the device + * there may be some mis-understandings burried in here. + * -- Daniel daniel@omicron.se) + * + * There are 22 CIO pins numbered + * 10-17 + * 20-25 + * 30-37 + * + * 20-24 are dedicated CIO pins, the other 17 are muliplexed with + * other functions. + * + * Secondary + * CIO Pin Function Decription + * ======================================================= + * CIO10 IRQIN1 Interrupt input 1? + * CIO11 IRQIN2 Interrupt input 2? + * CIO12 IRRX IrDa Receive + * CIO13 IRTX IrDa Transmit + * CIO14 P21 KBC P21 fucntion + * CIO15 P20 KBC P21 fucntion + * CIO16 I2C_CLK I2C Clock + * CIO17 I2C_DAT I2C Data + * + * CIO20 - + * CIO21 - + * CIO22 - + * CIO23 - + * CIO24 - + * CIO25 LOCK Keylock + * + * CIO30 KBC_CLK Keybaord Clock + * CIO31 CS0J General Chip Select decoder CS0J + * CIO32 CS1J General Chip Select decoder CS1J + * CIO33 ALT_KCLK Alternative Keyboard Clock + * CIO34 ALT_KDAT Alternative Keyboard Data + * CIO35 ALT_MCLK Alternative Mouse Clock + * CIO36 ALT_MDAT Alternative Mouse Data + * CIO37 ALT_KBC Alternative KBC select + * + * The CIO use a double indirect address scheme. + * + * Reigster 3 in the SIO is used to selectg where the CIO + * I/O registers show up under function 8. Note that these + * registers clash with the CIO function select regsters, + * below. + * + * SIO reigster 3 (CIO Address Selection) bit definitions: + * bit 7 CIO data register enabled + * bit 1-0 CIO indirect registers select + * 0 index = 0xE0 data = 0xE1 + * 1 index = 0xE2 data = 0xE3 + * 2 index = 0xE4 data = 0xE5 + * 3 index = 0xEA data = 0xEB + * + * There are three CIO I/O register accessed via CIO index and CIO data + * 0x01 CIO 10-17 data + * 0x02 CIO 20-25 data (bits 7-6 unused) + * 0x03 CIO 30-37 data + * + * + * The pin function is accessed through normal + * SIO registers, each register have the same format: + * + * Bit Function Value + * 0 Input/output 1=input + * 1 Polarity of signal 1=inverted + * 2 Unused ?? + * 3 Function (normal or special) 1=special + * 7-4 Unused + * + * SIO REG + * 0xe0 CIO 10 Config + * 0xe1 CIO 11 Config + * 0xe2 CIO 12 Config + * 0xe3 CIO 13 Config + * 0xe4 CIO 14 Config + * 0xe5 CIO 15 Config + * 0xe6 CIO 16 Config + * 0xe7 CIO 16 Config + * + * 0xe8 CIO 20 Config + * 0xe9 CIO 21 Config + * 0xea CIO 22 Config + * 0xeb CIO 23 Config + * 0xec CIO 24 Config + * 0xed CIO 25 Config + * + * 0xf5 CIO 30 Config + * 0xf6 CIO 31 Config + * 0xf7 CIO 32 Config + * 0xf8 CIO 33 Config + * 0xf9 CIO 34 Config + * 0xfa CIO 35 Config + * 0xfb CIO 36 Config + * 0xfc CIO 37 Config + * + */ + +void ali512x_set_cio(int enabled) +{ + int i; + + ALI_OPEN(); + ali_write(0x3, 3); /* Disable CIO data register */ + + ALI_SELDEV(8); + ali_write(0x30, enabled?1:0); + + /* set all pins to input to start with */ + for (i=0xe0;i<0xee;i++) { + ali_write(i, 1); + } + for (i=0xf5;i<0xfe;i++) { + ali_write(i, 1); + } + + ALI_CLOSE(); +} + +void ali512x_cio_function(int pin, int special, int inv, int input) +{ + u8 data; + u8 addr; + + + /* valid pins are 10-17, 20-25 and 30-37 */ + if (pin >= 10 && pin <= 17) { + addr = 0xe0+(pin-10); + } else if (pin >= 20 && pin <= 25) { + addr = 0xe8+(pin-20); + } else if (pin >= 30 && pin <= 37) { + addr = 0xf5+(pin-30); + } else { + return; + } + + ALI_OPEN(); + ALI_SELDEV(8); + + ali_write(0x03, 0x03); /* Disable CIO data register */ + + data=0; + if (special) { + data |= 0x08; + } else { + if (inv) { + data |= 0x02; + } + if (input) { + data |= 0x01; + } + } + + ali_write(addr, data); + + ALI_CLOSE(); +} + +void ali512x_cio_out(int pin, int value) +{ + u8 reg; + u8 data; + u8 bit; + + /* valid pins are 10-17, 20-25 and 30-37 */ + if (pin >= 10 && pin <= 17) { + reg = 1; + pin -= 10; + } else if (pin >= 20 && pin <= 25) { + reg = 2; + pin -= 20; + } else if (pin >= 30 && pin <= 37) { + reg = 3; + pin -= 30; + } else { + return; + } + bit = 1 << pin; + + ALI_OPEN(); + ALI_SELDEV(8); + + ali_write(0x03, 0x83); /* Enable CIO data register, use data port at 0xea */ + + ali_write(0xea, reg); /* select I/O register */ + data = ali_read(0xeb); + if (value) { + data |= bit; + } else { + data &= ~bit; + } + ali_write(0xeb, data); + ali_write(0xea, 0); /* select register 0 */ + ali_write(0x03, 0x03); /* Disable CIO data register */ + ALI_CLOSE(); +} + +int ali512x_cio_in(int pin) +{ + u8 reg; + u8 data; + u8 bit; + + /* valid pins are 10-17, 20-25 and 30-37 */ + if (pin >= 10 && pin <= 17) { + reg = 1; + pin -= 10; + } else if (pin >= 20 && pin <= 25) { + reg = 2; + pin -= 20; + } else if (pin >= 30 && pin <= 37) { + reg = 3; + pin -= 30; + } else { + return -1; + } + bit = 1 << pin; + + ALI_OPEN(); + ALI_SELDEV(8); + + ali_write(0x03, 0x83); /* Enable CIO data register, use data port at 0xea */ + + ali_write(0xea, reg); /* select I/O register */ + data = ali_read(0xeb); + ali_write(0xea, 0); /* select register 0 */ + ali_write(0x03, 0x03); /* Disable CIO data register */ + ALI_CLOSE(); + + return data & bit; +} + + diff --git a/lib_i386/ic/sc520.c b/lib_i386/ic/sc520.c new file mode 100644 index 000000000..d202625bb --- /dev/null +++ b/lib_i386/ic/sc520.c @@ -0,0 +1,348 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB . + * + * 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 + */ + +/* stuff specific for the sc520, + * but idependent of implementation */ + + +#include +#include +#include +#include +#include +#include + +/* + * utility functions for boards based on the AMD sc520 + * + * void write_mmcr_byte(u16 mmcr, u8 data) + * void write_mmcr_word(u16 mmcr, u16 data) + * void write_mmcr_long(u16 mmcr, u32 data) + * + * u8 read_mmcr_byte(u16 mmcr) + * u16 read_mmcr_word(u16 mmcr) + * u32 read_mmcr_long(u16 mmcr) + * + * void init_sc520(void) + * unsigned long init_sc520_dram(void) + * void pci_sc520_init(struct pci_controller *hose) + * + * void reset_timer(void) + * ulong get_timer(ulong base) + * void set_timer(ulong t) + * void udelay(unsigned long usec) + * + */ + +static u32 mmcr_base= 0xfffef000; + +void write_mmcr_byte(u16 mmcr, u8 data) +{ + writeb(data, mmcr+mmcr_base); +} + +void write_mmcr_word(u16 mmcr, u16 data) +{ + writew(data, mmcr+mmcr_base); +} + +void write_mmcr_long(u16 mmcr, u32 data) +{ + writel(data, mmcr+mmcr_base); +} + +u8 read_mmcr_byte(u16 mmcr) +{ + return readb(mmcr+mmcr_base); +} + +u16 read_mmcr_word(u16 mmcr) +{ + return readw(mmcr+mmcr_base); +} + +u32 read_mmcr_long(u16 mmcr) +{ + return readl(mmcr+mmcr_base); +} + + +void init_sc520(void) +{ + DECLARE_GLOBAL_DATA_PTR; + + /* Set the UARTxCTL register at it's slower, + * baud clock giving us a 1.8432 MHz reference + */ + write_mmcr_byte(SC520_UART1CTL, 7); + write_mmcr_byte(SC520_UART2CTL, 7); + + /* first set the timer pin mapping */ + write_mmcr_byte(SC520_CLKSEL, 0x72); /* no clock frequency selected, use 1.1892MHz */ + + /* enable PCI bus arbitrer */ + write_mmcr_byte(SC520_SYSARBCTL,0x02); /* enable concurrent mode */ + + write_mmcr_word(SC520_SYSARBMENB,0x1f); /* enable external grants */ + write_mmcr_word(SC520_HBCTL,0x04); /* enable posted-writes */ + + + if (CFG_SC520_HIGH_SPEED) { + write_mmcr_byte(SC520_CPUCTL, 0x2); /* set it to 133 MHz and write back */ + gd->cpu_clk = 133000000; + printf("## CPU Speed set to 133MHz\n"); + } else { + write_mmcr_byte(SC520_CPUCTL, 1); /* set CPU to 100 MHz and write back cache */ + printf("## CPU Speed set to 100MHz\n"); + gd->cpu_clk = 100000000; + } + + + /* wait at least one millisecond */ + asm("movl $0x2000,%%ecx\n" + "wait_loop: pushl %%ecx\n" + "popl %%ecx\n" + "loop wait_loop\n": : : "ecx"); + + /* turn on the SDRAM write buffer */ + write_mmcr_byte(SC520_DBCTL, 0x11); + + /* turn on the cache and disable write through */ + asm("movl %%cr0, %%eax\n" + "andl $0x9fffffff, %%eax\n" + "movl %%eax, %%cr0\n" : : : "eax"); +} + +unsigned long init_sc520_dram(void) +{ + DECLARE_GLOBAL_DATA_PTR; + bd_t *bd = gd->bd; + + u32 dram_present=0; + u32 dram_ctrl; + + int val; + + int cas_precharge_delay = CFG_SDRAM_PRECHARGE_DELAY; + int refresh_rate = CFG_SDRAM_REFRESH_RATE; + int ras_cas_delay = CFG_SDRAM_RAS_CAS_DELAY; + + /* set SDRAM speed here */ + + refresh_rate/=78; + if (refresh_rate<=1) { + val = 0; /* 7.8us */ + } else if (refresh_rate==2) { + val = 1; /* 15.6us */ + } else if (refresh_rate==3 || refresh_rate==4) { + val = 2; /* 31.2us */ + } else { + val = 3; /* 62.4us */ + } + write_mmcr_byte(SC520_DRCCTL, (read_mmcr_byte(SC520_DRCCTL) & 0xcf) | (val<<4)); + + val = read_mmcr_byte(SC520_DRCTMCTL); + val &= 0xf0; + + if (cas_precharge_delay==3) { + val |= 0x04; /* 3T */ + } else if (cas_precharge_delay==4) { + val |= 0x08; /* 4T */ + } else if (cas_precharge_delay>4) { + val |= 0x0c; + } + + if (ras_cas_delay > 3) { + val |= 2; + } else { + val |= 1; + } + write_mmcr_byte(SC520_DRCTMCTL, val); + + + /* We read-back the configuration of the dram + * controller that the assembly code wrote */ + dram_ctrl = read_mmcr_long(SC520_DRCBENDADR); + + + bd->bi_dram[0].start = 0; + if (dram_ctrl & 0x80) { + /* bank 0 enabled */ + dram_present = bd->bi_dram[1].start = (dram_ctrl & 0x7f) << 22; + bd->bi_dram[0].size = bd->bi_dram[1].start; + + } else { + bd->bi_dram[0].size = 0; + bd->bi_dram[1].start = bd->bi_dram[0].start; + } + + if (dram_ctrl & 0x8000) { + /* bank 1 enabled */ + dram_present = bd->bi_dram[2].start = (dram_ctrl & 0x7f00) << 14; + bd->bi_dram[1].size = bd->bi_dram[2].start - bd->bi_dram[1].start; + } else { + bd->bi_dram[1].size = 0; + bd->bi_dram[2].start = bd->bi_dram[1].start; + } + + if (dram_ctrl & 0x800000) { + /* bank 2 enabled */ + dram_present = bd->bi_dram[3].start = (dram_ctrl & 0x7f0000) << 6; + bd->bi_dram[2].size = bd->bi_dram[3].start - bd->bi_dram[2].start; + } else { + bd->bi_dram[2].size = 0; + bd->bi_dram[3].start = bd->bi_dram[2].start; + } + + if (dram_ctrl & 0x80000000) { + /* bank 3 enabled */ + dram_present = (dram_ctrl & 0x7f000000) >> 2; + bd->bi_dram[3].size = dram_present - bd->bi_dram[3].start; + } else { + bd->bi_dram[3].size = 0; + } + + +#if 0 + printf("Configured %d bytes of dram\n", dram_present); +#endif + gd->ram_size = dram_present; + + return dram_present; +} + + +#ifdef CONFIG_PCI + + + +void pci_sc520_init(struct pci_controller *hose) +{ + hose->first_busno = 0; + hose->last_busno = 0xff; + + /* System memory space */ + pci_set_region(hose->regions + 0, + SC520_PCI_MEMORY_BUS, + SC520_PCI_MEMORY_PHYS, + SC520_PCI_MEMORY_SIZE, + PCI_REGION_MEM | PCI_REGION_MEMORY); + + /* PCI memory space */ + pci_set_region(hose->regions + 1, + SC520_PCI_MEM_BUS, + SC520_PCI_MEM_PHYS, + SC520_PCI_MEM_SIZE, + PCI_REGION_MEM); + + /* ISA/PCI memory space */ + pci_set_region(hose->regions + 2, + SC520_ISA_MEM_BUS, + SC520_ISA_MEM_PHYS, + SC520_ISA_MEM_SIZE, + PCI_REGION_MEM); + + /* PCI I/O space */ + pci_set_region(hose->regions + 3, + SC520_PCI_IO_BUS, + SC520_PCI_IO_PHYS, + SC520_PCI_IO_SIZE, + PCI_REGION_IO); + + /* ISA/PCI I/O space */ + pci_set_region(hose->regions + 4, + SC520_ISA_IO_BUS, + SC520_ISA_IO_PHYS, + SC520_ISA_IO_SIZE, + PCI_REGION_IO); + + hose->region_count = 5; + + pci_setup_type1(hose, + SC520_REG_ADDR, + SC520_REG_DATA); + + pci_register_hose(hose); + + hose->last_busno = pci_hose_scan(hose); + + /* enable target memory acceses on host brige */ + pci_write_config_word(0, PCI_COMMAND, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + +} + + +#endif + +#ifdef CFG_TIMER_SC520 + + +void reset_timer(void) +{ + write_mmcr_word(SC520_GPTMR0CNT, 0); + write_mmcr_word(SC520_GPTMR0CTL, 0x6001); + +} + +ulong get_timer(ulong base) +{ + /* fixme: 30 or 33 */ + return read_mmcr_word(SC520_GPTMR0CNT) / 33; +} + +void set_timer(ulong t) +{ + /* FixMe: use two cascade coupled timers */ + write_mmcr_word(SC520_GPTMR0CTL, 0x4001); + write_mmcr_word(SC520_GPTMR0CNT, t*33); + write_mmcr_word(SC520_GPTMR0CTL, 0x6001); +} + + +void udelay(unsigned long usec) +{ + int m=0; + long u; + + read_mmcr_word(SC520_SWTMRMILLI); + read_mmcr_word(SC520_SWTMRMICRO); + +#if 0 + /* do not enable this line, udelay is used in the serial driver -> recursion */ + printf("udelay: %ld m.u %d.%d tm.tu %d.%d\n", usec, m, u, tm, tu); +#endif + while (1) { + + m += read_mmcr_word(SC520_SWTMRMILLI); + u = read_mmcr_word(SC520_SWTMRMICRO) + (m * 1000); + + if (usec <= u) { + break; + } + } +} + +#endif + + diff --git a/lib_i386/ic/sc520_asm.S b/lib_i386/ic/sc520_asm.S new file mode 100644 index 000000000..72110c4a0 --- /dev/null +++ b/lib_i386/ic/sc520_asm.S @@ -0,0 +1,530 @@ +/* + * (C) Copyright 2002 + * Daniel Engström, Omicron Ceti AB . + * + * 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 + */ + +/* This file is largely based on code obtned from AMD. AMD's original + * copyright is included below + */ + +/* + * ============================================================================= + * + * Copyright 1999 Advanced Micro Devices, Inc. + * + * This software is the property of Advanced Micro Devices, Inc (AMD) which + * specifically grants the user the right to modify, use and distribute this + * software provided this COPYRIGHT NOTICE is not removed or altered. All + * other rights are reserved by AMD. + * + * THE MATERIALS ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY + * OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT OF + * THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY PARTICULAR PURPOSE. + * IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER + * (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS + * INTERRUPTION, LOSS OF INFORMAITON) ARISING OUT OF THE USE OF OR INABILITY + * TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. BECAUSE SOME JURSIDICTIONS PROHIBIT THE EXCLUSION OR + * LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE + * LIMITATION MAY NOT APPLY TO YOU. + * + * AMD does not assume any responsibility for any errors that may appear in + * the Materials nor any responsibility to support or update the Materials. + * AMD retains the right to make changes to its test specifications at any + * time, without notice. + * + * So that all may benefit from your experience, please report any problems + * or suggestions about this software back to AMD. Please include your name, + * company, telephone number, AMD product requiring support and question or + * problem encountered. + * + * Advanced Micro Devices, Inc. Worldwide support and contact + * Embedded Processor Division information available at: + * Systems Engineering epd.support@amd.com + * 5204 E. Ben White Blvd. -or- + * Austin, TX 78741 http://www.amd.com/html/support/techsup.html + * ============================================================================ + */ + + +/******************************************************************************* + * AUTHOR : Buddy Fey - Original. + ******************************************************************************* + */ + + +/******************************************************************************* + * FUNCTIONAL DESCRIPTION: + * This routine is called to autodetect the geometry of the DRAM. + * + * This routine is called to determine the number of column bits for the DRAM + * devices in this external bank. This routine assumes that the external bank + * has been configured for an 11-bit column and for 4 internal banks. This gives + * us the maximum address reach in memory. By writing a test value to the max + * address and locating where it aliases to, we can determine the number of valid + * column bits. + * + * This routine is called to determine the number of internal banks each DRAM + * device has. The external bank (under test) is configured for maximum reach + * with 11-bit columns and 4 internal banks. This routine will write to a max + * address (BA1 and BA0 = 1) and then read from an address with BA1=0 to see if + * that column is a "don't care". If BA1 does not affect write/read of data, + * then this device has only 2 internal banks. + * + * This routine is called to determine the ending address for this external + * bank of SDRAM. We write to a max address with a data value and then disable + * row address bits looking for "don't care" locations. Each "don't care" bit + * represents a dividing of the maximum density (128M) by 2. By dividing the + * maximum of 32 4M chunks in an external bank down by all the "don't care" bits + * determined during sizing, we set the proper density. + * + * WARNINGS. + * bp must be preserved because it is used for return linkage. + * + * EXIT + * nothing returned - but the memory subsystem is enabled + ******************************************************************************* + */ + +.section .text +.equ DRCCTL, 0x0fffef010 /* DRAM control register */ +.equ DRCTMCTL, 0x0fffef012 /* DRAM timing control register */ +.equ DRCCFG, 0x0fffef014 /* DRAM bank configuration register */ +.equ DRCBENDADR, 0x0fffef018 /* DRAM bank ending address register */ +.equ ECCCTL, 0x0fffef020 /* DRAM ECC control register */ +.equ DBCTL, 0x0fffef040 /* DRAM buffer control register */ + +.equ CACHELINESZ, 0x00000010 /* size of our cache line (read buffer) */ +.equ COL11_ADR, 0x0e001e00 /* 11 col addrs */ +.equ COL10_ADR, 0x0e000e00 /* 10 col addrs */ +.equ COL09_ADR, 0x0e000600 /* 9 col addrs */ +.equ COL08_ADR, 0x0e000200 /* 8 col addrs */ +.equ ROW14_ADR, 0x0f000000 /* 14 row addrs */ +.equ ROW13_ADR, 0x07000000 /* 13 row addrs */ +.equ ROW12_ADR, 0x03000000 /* 12 row addrs */ +.equ ROW11_ADR, 0x01000000 /* 11 row addrs/also bank switch */ +.equ ROW10_ADR, 0x00000000 /* 10 row addrs/also bank switch */ +.equ COL11_DATA, 0x0b0b0b0b /* 11 col addrs */ +.equ COL10_DATA, 0x0a0a0a0a /* 10 col data */ +.equ COL09_DATA, 0x09090909 /* 9 col data */ +.equ COL08_DATA, 0x08080808 /* 8 col data */ +.equ ROW14_DATA, 0x3f3f3f3f /* 14 row data (MASK) */ +.equ ROW13_DATA, 0x1f1f1f1f /* 13 row data (MASK) */ +.equ ROW12_DATA, 0x0f0f0f0f /* 12 row data (MASK) */ +.equ ROW11_DATA, 0x07070707 /* 11 row data/also bank switch (MASK) */ +.equ ROW10_DATA, 0xaaaaaaaa /* 10 row data/also bank switch (MASK) */ + + + /* + * initialize dram controller registers + */ +.globl mem_init +mem_init: + xorw %ax,%ax + movl $DBCTL, %edi +fs movb %al, (%edi) /* disable write buffer */ + + movl $ECCCTL, %edi +fs movb %al, (%edi) /* disable ECC */ + + movl $DRCTMCTL, %edi + movb $0x1E,%al /* Set SDRAM timing for slowest */ +fs movb %al, (%edi) + + /* + * setup loop to do 4 external banks starting with bank 3 + */ + movl $0xff000000,%eax /* enable last bank and setup */ + movl $DRCBENDADR, %edi /* ending address register */ +fs movl %eax, (%edi) + + movl $DRCCFG, %edi /* setup */ + movw $0xbbbb,%ax /* dram config register for */ +fs movw %ax, (%edi) + + /* + * issue a NOP to all DRAMs + */ + movl $DRCCTL, %edi /* setup DRAM control register with */ + movb $0x1,%al /* Disable refresh,disable write buffer */ +fs movb %al, (%edi) + movl $CACHELINESZ, %esi /* just a dummy address to write for */ +fs movw %ax, (%esi) + /* + * delay for 100 usec? 200? + * ******this is a cludge for now ************* + */ + movw $100,%cx +sizdelay: + loop sizdelay /* we need 100 usec here */ + /***********************************************/ + + /* + * issue all banks precharge + */ + movb $0x2,%al /* All banks precharge */ +fs movb %al, (%edi) +fs movw %ax, (%esi) + + /* + * issue 2 auto refreshes to all banks + */ + movb $0x4,%al /* Auto refresh cmd */ +fs movb %al, (%edi) + movw $2,%cx +refresh1: +fs movw %ax, (%esi) + loop refresh1 + + /* + * issue LOAD MODE REGISTER command + */ + movb $0x3,%al /* Load mode register cmd */ +fs movb %al, (%edi) +fs movw %ax, (%esi) + + /* + * issue 8 more auto refreshes to all banks + */ + movb $0x4,%al /* Auto refresh cmd */ +fs movb %al, (%edi) + movw $8,%cx +refresh2: +fs movw %ax, (%esi) + loop refresh2 + + /* + * set control register to NORMAL mode + */ + movb $0x0,%al /* Normal mode value */ +fs movb %al, (%edi) + + /* + * size dram starting with external bank 3 moving to external bank 0 + */ + movl $0x3,%ecx /* start with external bank 3 */ + +nextbank: + + /* + * write col 11 wrap adr + */ + movl $COL11_ADR, %esi /* set address to max col (11) wrap addr */ + movl $COL11_DATA, %eax /* pattern for max supported columns(11) */ +fs movl %eax, (%esi) /* write max col pattern at max col adr */ +fs movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write col 10 wrap adr + */ + + movl $COL10_ADR, %esi /* set address to 10 col wrap address */ + movl $COL10_DATA, %eax /* pattern for 10 col wrap */ +fs movl %eax, (%esi) /* write 10 col pattern @ 10 col wrap adr */ +fs movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write col 9 wrap adr + */ + movl $COL09_ADR, %esi /* set address to 9 col wrap address */ + movl $COL09_DATA, %eax /* pattern for 9 col wrap */ +fs movl %eax, (%esi) /* write 9 col pattern @ 9 col wrap adr */ +fs movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write col 8 wrap adr + */ + movl $COL08_ADR, %esi /* set address to min(8) col wrap address */ + movl $COL08_DATA, %eax /* pattern for min (8) col wrap */ +fs movl %eax, (%esi) /* write min col pattern @ min col adr */ +fs movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write row 14 wrap adr + */ + movl $ROW14_ADR, %esi /* set address to max row (14) wrap addr */ + movl $ROW14_DATA, %eax /* pattern for max supported rows(14) */ +fs movl %eax, (%esi) /* write max row pattern at max row adr */ +fs movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write row 13 wrap adr + */ + movl $ROW13_ADR, %esi /* set address to 13 row wrap address */ + movl $ROW13_DATA, %eax /* pattern for 13 row wrap */ +fs movl %eax, (%esi) /* write 13 row pattern @ 13 row wrap adr */ +fs movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write row 12 wrap adr + */ + movl $ROW12_ADR, %esi /* set address to 12 row wrap address */ + movl $ROW12_DATA, %eax /* pattern for 12 row wrap */ +fs movl %eax, (%esi) /* write 12 row pattern @ 12 row wrap adr */ +fs movl (%esi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write row 11 wrap adr + */ + movl $ROW11_ADR, %edi /* set address to 11 row wrap address */ + movl $ROW11_DATA, %eax /* pattern for 11 row wrap */ +fs movl %eax, (%edi) /* write 11 row pattern @ 11 row wrap adr */ +fs movl (%edi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * write row 10 wrap adr --- this write is really to determine number of banks + */ + movl $ROW10_ADR, %edi /* set address to 10 row wrap address */ + movl $ROW10_DATA, %eax /* pattern for 10 row wrap (AA) */ +fs movl %eax, (%edi) /* write 10 row pattern @ 10 row wrap adr */ +fs movl (%edi), %ebx /* optional read */ + cmpl %ebx,%eax /* to verify write */ + jnz bad_ram /* this ram is bad */ + /* + * read data @ row 12 wrap adr to determine * banks, + * and read data @ row 14 wrap adr to determine * rows. + * if data @ row 12 wrap adr is not AA, 11 or 12 we have bad RAM. + * if data @ row 12 wrap == AA, we only have 2 banks, NOT 4 + * if data @ row 12 wrap == 11 or 12, we have 4 banks, + */ + xorw %di,%di /* value for 2 banks in DI */ +fs movl (%esi), %ebx /* read from 12 row wrap to check banks + * (esi is setup from the write to row 12 wrap) */ + cmpl %ebx,%eax /* check for AA pattern (eax holds the aa pattern) */ + jz only2 /* if pattern == AA, we only have 2 banks */ + + /* 4 banks */ + + movw $8,%di /* value for 4 banks in DI (BNK_CNT bit) */ + cmpl $ROW11_DATA, %ebx /* only other legitimate values are 11 */ + jz only2 + cmpl $ROW12_DATA, %ebx /* and 12 */ + jnz bad_ram /* its bad if not 11 or 12! */ + + /* fall through */ +only2: + /* + * validate row mask + */ + movl $ROW14_ADR, %esi /* set address back to max row wrap addr */ +fs movl (%esi), %eax /* read actual number of rows @ row14 adr */ + + cmpl $ROW11_DATA, %eax /* row must be greater than 11 pattern */ + jb bad_ram + + cmpl $ROW14_DATA, %eax /* and row must be less than 14 pattern */ + ja bad_ram + + cmpb %ah,%al /* verify all 4 bytes of dword same */ + jnz bad_ram + movl %eax,%ebx + shrl $16,%ebx + cmpw %bx,%ax + jnz bad_ram + /* + * read col 11 wrap adr for real column data value + */ + movl $COL11_ADR, %esi /* set address to max col (11) wrap addr */ +fs movl (%esi), %eax /* read real col number at max col adr */ + /* + * validate column data + */ + cmpl $COL08_DATA, %eax /* col must be greater than 8 pattern */ + jb bad_ram + + cmpl $COL11_DATA, %eax /* and row must be less than 11 pattern */ + ja bad_ram + + subl $COL08_DATA, %eax /* normalize column data to zero */ + jc bad_ram + cmpb %ah,%al /* verify all 4 bytes of dword equal */ + jnz bad_ram + movl %eax,%edx + shrl $16,%edx + cmpw %dx,%ax + jnz bad_ram + /* + * merge bank and col data together + */ + addw %di,%dx /* merge of bank and col info in dl */ + /* + * fix ending addr mask based upon col info + */ + movb $3,%al + subb %dh,%al /* dh contains the overflow from the bank/col merge */ + movb %bl,%dh /* bl contains the row mask (aa, 07, 0f, 1f or 3f) */ + xchgw %cx,%ax /* cx = ax = 3 or 2 depending on 2 or 4 bank device */ + shrb %cl,%dh /* */ + incb %dh /* ending addr is 1 greater than real end */ + xchgw %cx,%ax /* cx is bank number again */ + /* + * issue all banks precharge + */ +bad_reint: + movl $DRCCTL, %esi /* setup DRAM control register with */ + movb $0x2,%al /* All banks precharge */ +fs movb %al, (%esi) + movl $CACHELINESZ, %esi /* address to init read buffer */ +fs movw %ax, (%esi) + + /* + * update ENDING ADDRESS REGISTER + */ + movl $DRCBENDADR, %edi /* DRAM ending address register */ + movl %ecx,%ebx + addl %ebx, %edi +fs movb %dh, (%edi) + /* + * update CONFIG REGISTER + */ + xorb %dh,%dh + movw $0x00f,%bx + movw %cx,%ax + shlw $2,%ax + xchgw %cx,%ax + shlw %cl,%dx + shlw %cl,%bx + notw %bx + xchgw %cx,%ax + movl $DRCCFG, %edi +fs mov (%edi), %ax + andw %bx,%ax + orw %dx,%ax +fs movw %ax, (%edi) + jcxz cleanup + + decw %cx + movl %ecx,%ebx + movl $DRCBENDADR, %edi /* DRAM ending address register */ + movb $0xff,%al + addl %ebx, %edi +fs movb %al, (%edi) + /* + * set control register to NORMAL mode + */ + movl $DRCCTL, %esi /* setup DRAM control register with */ + movb $0x0,%al /* Normal mode value */ +fs movb %al, (%esi) + movl $CACHELINESZ, %esi /* address to init read buffer */ +fs movw %ax, (%esi) + jmp nextbank + +cleanup: + movl $DRCBENDADR, %edi /* DRAM ending address register */ + movw $4,%cx + xorw %ax,%ax +cleanuplp: +fs movb (%edi), %al + orb %al,%al + jz emptybank + + addb %ah,%al + jns nottoomuch + + movb $0x7f,%al +nottoomuch: + movb %al,%ah + orb $0x80,%al +fs movb %al, (%edi) +emptybank: + incl %edi + loop cleanuplp + +#if defined(CFG_SDRAM_CAS_LATENCY_2T) || defined(CFG_SDRAM_CAS_LATENCY_3T) + /* set the CAS latency now since it is hard to do + * when we run from the RAM */ + movl $DRCTMCTL, %edi /* DRAM timing register */ + movb (%edi), %al +#ifdef CFG_SDRAM_CAS_LATENCY_2T + andb $0xef, %al +#endif +#ifdef CFG_SDRAM_CAS_LATENCY_3T + orb $0x10, %al +#endif + movb %al, (%edi) +#endif + movl $DRCCTL, %edi /* DRAM Control register */ + movb $0x3,%al /* Load mode register cmd */ +fs movb %al, (%edi) +fs movw %ax, (%esi) + + + movl $DRCCTL, %edi /* DRAM Control register */ + movb $0x18,%al /* Enable refresh and NORMAL mode */ +fs movb %al, (%edi) + + jmp dram_done + +bad_ram: + xorl %edx,%edx + xorl %edi,%edi + jmp bad_reint + +dram_done: + + /* readback DRCBENDADR and return the number + * of available ram bytes in %eax */ + + movl $DRCBENDADR, %edi /* DRAM ending address register */ + + movl (%edi), %eax + movl %eax, %ecx + andl $0x80000000, %ecx + jz bank2 + andl $0x7f000000, %eax + shrl $2, %eax + movl %eax, %ebx + +bank2: movl (%edi), %eax + movl %eax, %ecx + andl $0x00800000, %ecx + jz bank1 + andl $0x007f0000, %eax + shll $6, %eax + movl %eax, %ebx + +bank1: movl (%edi), %eax + movl %eax, %ecx + andl $0x00008000, %ecx + jz bank0 + andl $0x00007f00, %eax + shll $14, %eax + movl %eax, %ebx + +bank0: movl (%edi), %eax + movl %eax, %ecx + andl $0x00000080, %ecx + jz done + andl $0x0000007f, %eax + shll $22, %eax + movl %eax, %ebx + +done: movl %ebx, %eax + + jmp *%ebp diff --git a/lib_i386/pci_type1.c b/lib_i386/pci_type1.c new file mode 100644 index 000000000..e5577e820 --- /dev/null +++ b/lib_i386/pci_type1.c @@ -0,0 +1,57 @@ +/* + * 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 + +#ifdef CONFIG_PCI + +#include +#include +#include + +#define cfg_read(val, addr, type, op) *val = op((type)(addr)) +#define cfg_write(val, addr, type, op) op((val), (type *)(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, hose->cfg_addr); \ + cfg_##rw(val, hose->cfg_data + (offset & mask), type, 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 100644 index 000000000..372147cf2 --- /dev/null +++ b/lib_i386/realmode.c @@ -0,0 +1,69 @@ +/* + * (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 +#include +#include + + +#define REALMODE_BASE ((char*)0x7c0) +#define REALMODE_MAILBOX ((char*)0xe00) + + +extern char realmode_enter; + + +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; + } + + /* 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, i386boot_realmode, i386boot_realmode_size); + + + 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__ volatile ( + "lcall $0x20,%0\n" : : "i" (&realmode_enter) ); + + memcpy(out, REALMODE_MAILBOX, sizeof(struct pt_regs)); + + return out->eax; +} + diff --git a/lib_i386/realmode_switch.S b/lib_i386/realmode_switch.S new file mode 100644 index 000000000..9f212c2e8 --- /dev/null +++ b/lib_i386/realmode_switch.S @@ -0,0 +1,223 @@ +/* + * (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/zimage.c b/lib_i386/zimage.c new file mode 100644 index 000000000..190d46ef7 --- /dev/null +++ b/lib_i386/zimage.c @@ -0,0 +1,276 @@ +/* + * (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 +#include +#include +#include +#include +#include + +/* + * 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(®s, 0, sizeof(struct pt_regs)); + regs.xds = (u32)setup_base >> 4; + regs.xss = 0x8e00; + regs.esp = 0x200; + regs.eflags = 0; + enter_realmode(((u32)setup_base+SETUP_START_OFFSET)>>4, 0, ®s, ®s); +} + + +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; +} -- cgit v1.2.3