From 458379d674f256d32132e29c20a223a3c39b9e34 Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:17 +1100 Subject: [PATCH 01/20] x86: Remove bi_env from do_bdinfo Commit 55e97429d1e6cf0976711e4e0f29ea924b7e5917 removed the definition from /arch/i386/include/asm/u-boot.h but not its usage in do_bdinfo() --- common/cmd_bdinfo.c | 1 - 1 file changed, 1 deletion(-) diff --git a/common/cmd_bdinfo.c b/common/cmd_bdinfo.c index 6b611b1482..1326c8fac1 100644 --- a/common/cmd_bdinfo.c +++ b/common/cmd_bdinfo.c @@ -385,7 +385,6 @@ int do_bdinfo ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) bd_t *bd = gd->bd; char buf[32]; - print_num ("env_t", (ulong)bd->bi_env); print_num ("boot_params", (ulong)bd->bi_boot_params); print_num ("bi_memstart", bd->bi_memstart); print_num ("bi_memsize", bd->bi_memsize); From 76d5763a4982b3d38a3b149c5ac987229262536a Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:18 +1100 Subject: [PATCH 02/20] x86: Make CONFIG_RELOC_FIXUP_WORKS generic for all x86 boards Relocation is not board-specific for the x86 architectrure, so CONFIG_RELOC_FIXUP_WORKS can be defined globally in the config.h --- arch/i386/include/asm/config.h | 2 ++ include/configs/eNET.h | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/i386/include/asm/config.h b/arch/i386/include/asm/config.h index 049c44eaf8..1952de79f8 100644 --- a/arch/i386/include/asm/config.h +++ b/arch/i386/include/asm/config.h @@ -21,4 +21,6 @@ #ifndef _ASM_CONFIG_H_ #define _ASM_CONFIG_H_ +#define CONFIG_RELOC_FIXUP_WORKS + #endif diff --git a/include/configs/eNET.h b/include/configs/eNET.h index da2a97d26d..fc7c1c6ce9 100644 --- a/include/configs/eNET.h +++ b/include/configs/eNET.h @@ -29,8 +29,6 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define CONFIG_RELOC_FIXUP_WORKS - /* * Stuff still to be dealt with - */ From de25059404b630012eef050532a3f73f47c567c5 Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:18 +1100 Subject: [PATCH 03/20] x86: Use TEXT_BASE in linker scripts Use TEXT_BASE rather than a hard-coded base address on x86 linker scripts. This will allow any board to define its base link address without having to modify the linker script --- board/eNET/u-boot.lds | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/board/eNET/u-boot.lds b/board/eNET/u-boot.lds index 7b0ffaa6cc..d78d75f2c5 100644 --- a/board/eNET/u-boot.lds +++ b/board/eNET/u-boot.lds @@ -27,7 +27,7 @@ ENTRY(_start) SECTIONS { - . = 0x06000000; /* Location of bootcode in flash */ + . = TEXT_BASE; /* Location of bootcode in flash */ _i386boot_text_start = .; .text : { *(.text); } @@ -98,12 +98,12 @@ SECTIONS * The fff0 offset of resetvec is important, however. */ . = 0xfffffe00; - .start32 : AT (0x0603fe00) { *(.start32); } + .start32 : AT (TEXT_BASE + 0x3fe00) { *(.start32); } . = 0xf800; - .start16 : AT (0x0603f800) { *(.start16); } + .start16 : AT (TEXT_BASE + 0x3f800) { *(.start16); } . = 0xfff0; - .resetvec : AT (0x0603fff0) { *(.resetvec); } + .resetvec : AT (TEXT_BASE + 0x3fff0) { *(.resetvec); } _i386boot_end = (LOADADDR(.resetvec) + SIZEOF(.resetvec) ); } From abe98f49e191ce0183132bed548643db7e2b80c5 Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:19 +1100 Subject: [PATCH 04/20] x86: zboot update The header of recent Linux Kernels includes the size of the image, and therefore is not needed to be passed to zboot. Still process the third parameter (size of image) in the event that an older kernel is being loaded --- arch/i386/lib/zimage.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/arch/i386/lib/zimage.c b/arch/i386/lib/zimage.c index 89fe015e6e..0c42072691 100644 --- a/arch/i386/lib/zimage.c +++ b/arch/i386/lib/zimage.c @@ -248,7 +248,8 @@ void boot_zimage(void *setup_base) int do_zboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { void *base_ptr; - void *bzImage_addr; + void *bzImage_addr = NULL; + char *s; ulong bzImage_size = 0; disable_interrupts(); @@ -256,10 +257,17 @@ int do_zboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) /* Setup board for maximum PC/AT Compatibility */ setup_pcat_compatibility(); - /* argv[1] holds the address of the bzImage */ - bzImage_addr = (void *)simple_strtoul(argv[1], NULL, 16); + if (argc >= 2) + /* argv[1] holds the address of the bzImage */ + s = argv[1]; + else + s = getenv("fileaddr"); - if (argc == 3) + if (s) + bzImage_addr = (void *)simple_strtoul(s, NULL, 16); + + if (argc >= 3) + /* argv[2] holds the size of the bzImage */ bzImage_size = simple_strtoul(argv[2], NULL, 16); /* Lets look for*/ @@ -282,7 +290,7 @@ int do_zboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) } U_BOOT_CMD( - zboot, 3, 0, do_zboot, + zboot, 2, 0, do_zboot, "Boot bzImage", "" ); From d664adb6bb7243fc9be1cb242a18a76901bc5c3a Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:20 +1100 Subject: [PATCH 05/20] x86: use gc sections to reduce image size Follow the discussion of Charles Manning and Mike Frysinger. Using gc_sections helps reduce image size. --- arch/i386/config.mk | 3 +++ board/eNET/u-boot.lds | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/i386/config.mk b/arch/i386/config.mk index 4b990e04ef..0e80a1ae58 100644 --- a/arch/i386/config.mk +++ b/arch/i386/config.mk @@ -26,3 +26,6 @@ CROSS_COMPILE ?= i386-linux- STANDALONE_LOAD_ADDR = 0x40000 PLATFORM_CPPFLAGS += -DCONFIG_I386 -D__I386__ + +LDFLAGS += --cref --gc-sections +PLATFORM_RELFLAGS += -ffunction-sections diff --git a/board/eNET/u-boot.lds b/board/eNET/u-boot.lds index d78d75f2c5..7b211a8d9a 100644 --- a/board/eNET/u-boot.lds +++ b/board/eNET/u-boot.lds @@ -77,13 +77,13 @@ SECTIONS _i386boot_bss_size = SIZEOF(.bss); /* 16bit realmode trampoline code */ - .realmode 0x7c0 : AT ( LOADADDR(.rel.dyn) + SIZEOF(.rel.dyn) ) { *(.realmode) } + .realmode 0x7c0 : AT ( LOADADDR(.rel.dyn) + SIZEOF(.rel.dyn) ) { KEEP(*(.realmode)) } _i386boot_realmode = LOADADDR(.realmode); _i386boot_realmode_size = SIZEOF(.realmode); /* 16bit BIOS emulation code (just enough to boot Linux) */ - .bios 0 : AT ( LOADADDR(.realmode) + SIZEOF(.realmode) ) { *(.bios) } + .bios 0 : AT ( LOADADDR(.realmode) + SIZEOF(.realmode) ) { KEEP(*(.bios)) } _i386boot_bios = LOADADDR(.bios); _i386boot_bios_size = SIZEOF(.bios); @@ -98,12 +98,12 @@ SECTIONS * The fff0 offset of resetvec is important, however. */ . = 0xfffffe00; - .start32 : AT (TEXT_BASE + 0x3fe00) { *(.start32); } + .start32 : AT (TEXT_BASE + 0x3fe00) { KEEP(*(.start32)); } . = 0xf800; - .start16 : AT (TEXT_BASE + 0x3f800) { *(.start16); } + .start16 : AT (TEXT_BASE + 0x3f800) { KEEP(*(.start16)); } . = 0xfff0; - .resetvec : AT (TEXT_BASE + 0x3fff0) { *(.resetvec); } + .resetvec : AT (TEXT_BASE + 0x3fff0) { KEEP(*(.resetvec)); } _i386boot_end = (LOADADDR(.resetvec) + SIZEOF(.resetvec) ); } From 59c6d0ef9af5fe0daf1b95992d061a10b33e23d4 Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:21 +1100 Subject: [PATCH 06/20] x86: Move loading of GTD to C code Linux has C macros and code to load the GTD after switching to Protected Mode. Using these greatly simplifies the assembler code --- arch/i386/cpu/cpu.c | 57 +++++++++++++++++++++++++ arch/i386/cpu/start.S | 96 ------------------------------------------- 2 files changed, 57 insertions(+), 96 deletions(-) diff --git a/arch/i386/cpu/cpu.c b/arch/i386/cpu/cpu.c index bd6aced873..ae40384f09 100644 --- a/arch/i386/cpu/cpu.c +++ b/arch/i386/cpu/cpu.c @@ -37,6 +37,61 @@ #include #include +/* Constructor for a conventional segment GDT (or LDT) entry */ +/* This is a macro so it can be used in initializers */ +#define GDT_ENTRY(flags, base, limit) \ + ((((base) & 0xff000000ULL) << (56-24)) | \ + (((flags) & 0x0000f0ffULL) << 40) | \ + (((limit) & 0x000f0000ULL) << (48-16)) | \ + (((base) & 0x00ffffffULL) << 16) | \ + (((limit) & 0x0000ffffULL))) + +/* Simple and small GDT entries for booting only */ + +#define GDT_ENTRY_32BIT_CS 2 +#define GDT_ENTRY_32BIT_DS (GDT_ENTRY_32BIT_CS + 1) +#define GDT_ENTRY_16BIT_CS (GDT_ENTRY_32BIT_DS + 1) +#define GDT_ENTRY_16BIT_DS (GDT_ENTRY_16BIT_CS + 1) + +/* + * Set up the GDT + */ + +struct gdt_ptr { + u16 len; + u32 ptr; +} __attribute__((packed)); + +static void reload_gdt(void) +{ + /* There are machines which are known to not boot with the GDT + being 8-byte unaligned. Intel recommends 16 byte alignment. */ + static const u64 boot_gdt[] __attribute__((aligned(16))) = { + /* CS: code, read/execute, 4 GB, base 0 */ + [GDT_ENTRY_32BIT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff), + /* DS: data, read/write, 4 GB, base 0 */ + [GDT_ENTRY_32BIT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff), + /* 16-bit CS: code, read/execute, 64 kB, base 0 */ + [GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x109b, 0, 0x0ffff), + /* 16-bit DS: data, read/write, 64 kB, base 0 */ + [GDT_ENTRY_16BIT_DS] = GDT_ENTRY(0x1093, 0, 0x0ffff), + }; + static struct gdt_ptr gdt; + + gdt.len = sizeof(boot_gdt)-1; + gdt.ptr = (u32)&boot_gdt; + + asm volatile("lgdtl %0\n" \ + "movl $((2+1)*8), %%ecx\n" \ + "movl %%ecx, %%ds\n" \ + "movl %%ecx, %%es\n" \ + "movl %%ecx, %%fs\n" \ + "movl %%ecx, %%gs\n" \ + "movl %%ecx, %%ss" \ + : : "m" (gdt) : "ecx"); +} + + int cpu_init_f(void) { /* initialize FPU, reset EM, set MP and NE */ @@ -51,6 +106,8 @@ int cpu_init_f(void) int cpu_init_r(void) { + reload_gdt(); + /* Initialize core interrupt and exception functionality of CPU */ cpu_init_interrupts (); return 0; diff --git a/arch/i386/cpu/start.S b/arch/i386/cpu/start.S index 7def8def8b..3cea04b4ce 100644 --- a/arch/i386/cpu/start.S +++ b/arch/i386/cpu/start.S @@ -100,53 +100,6 @@ mem_init_ret: jmp get_mem_size get_mem_size_ret: - /* - * We are now in 'Flat Protected Mode' and we know how much memory - * the board has. The (temporary) Global Descriptor Table is not - * in a 'Safe' place (it is either in Flash which can be erased or - * reprogrammed or in a fail-safe boot-strap image which could be - * over-written). - * - * Move the final gdt to a safe place (top of RAM) and load it. - * This is not a trivial excercise - the lgdt instruction does not - * have a register operand (memory only) and we may well be - * running from Flash, so self modifying code will not work here. - * To overcome this, we copy a stub into upper memory along with - * the GDT. - */ - - /* Reduce upper memory limit by (Stub + GDT Pointer + GDT) */ - subl $(end_gdt_setup - start_gdt_setup), %eax - - /* Copy the GDT and Stub */ - movl $start_gdt_setup, %esi - movl %eax, %edi - movl $(end_gdt_setup - start_gdt_setup), %ecx - shrl $2, %ecx - cld - rep movsl - - /* write the lgdt 'parameter' */ - subl $(jmp_instr - start_gdt_setup - 4), %ebp - addl %eax, %ebp - movl $(gdt_ptr - start_gdt_setup), %ebx - addl %eax, %ebx - movl %ebx, (%ebp) - - /* write the gdt address into the pointer */ - movl $(gdt_addr - start_gdt_setup), %ebp - addl %eax, %ebp - movl $(gdt - start_gdt_setup), %ebx - addl %eax, %ebx - movl %ebx, (%ebp) - - /* Save the return address */ - movl $load_gdt_ret, %ebp - - /* Load the new (safe) Global Descriptor Table */ - jmp *%eax - -load_gdt_ret: /* Check we have enough memory for stack */ movl $CONFIG_SYS_STACK_SIZE, %ecx cmpl %ecx, %eax @@ -221,52 +174,3 @@ die: hlt blank_idt_ptr: .word 0 /* limit */ .long 0 /* base */ - -.align 4 -start_gdt_setup: - lgdt gdt_ptr -jmp_instr: - jmp *%ebp - -.align 4 -gdt_ptr: - .word 0x30 /* limit (48 bytes = 6 GDT entries) */ -gdt_addr: - .long gdt /* base */ - - /* The GDT table ... - * - * Selector Type - * 0x00 NULL - * 0x08 Unused - * 0x10 32bit code - * 0x18 32bit data/stack - * 0x20 16bit code - * 0x28 16bit data/stack - */ - -.align 4 -gdt: - .word 0, 0, 0, 0 /* NULL */ - .word 0, 0, 0, 0 /* unused */ - - .word 0xFFFF /* 4Gb - (0x100000*0x1000 = 4Gb) */ - .word 0 /* base address = 0 */ - .word 0x9B00 /* code read/exec */ - .word 0x00CF /* granularity = 4096, 386 (+5th nibble of limit) */ - - .word 0xFFFF /* 4Gb - (0x100000*0x1000 = 4Gb) */ - .word 0x0 /* base address = 0 */ - .word 0x9300 /* data read/write */ - .word 0x00CF /* granularity = 4096, 386 (+5th nibble of limit) */ - - .word 0xFFFF /* 64kb */ - .word 0 /* base address = 0 */ - .word 0x9b00 /* data read/write */ - .word 0x0010 /* granularity = 1 (+5th nibble of limit) */ - - .word 0xFFFF /* 64kb */ - .word 0 /* base address = 0 */ - .word 0x9300 /* data read/write */ - .word 0x0010 /* granularity = 1 (+5th nibble of limit) */ -end_gdt_setup: From 8ffb2e8f3365d9b80e8f7e5b7c0130b875e3b899 Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:21 +1100 Subject: [PATCH 07/20] x86: Coding Style Cleanup Perform some basic code cleanups of the x86 files --- arch/i386/cpu/sc520/sc520.c | 54 +-- arch/i386/cpu/sc520/sc520_asm.S | 622 ++++++++++++++++---------------- arch/i386/cpu/start.S | 30 +- arch/i386/cpu/start16.S | 9 +- 4 files changed, 352 insertions(+), 363 deletions(-) diff --git a/arch/i386/cpu/sc520/sc520.c b/arch/i386/cpu/sc520/sc520.c index 519bfd8b0c..7acd471d96 100644 --- a/arch/i386/cpu/sc520/sc520.c +++ b/arch/i386/cpu/sc520/sc520.c @@ -41,7 +41,8 @@ volatile sc520_mmcr_t *sc520_mmcr = (sc520_mmcr_t *)0xfffef000; void init_sc520(void) { - /* Set the UARTxCTL register at it's slower, + /* + * Set the UARTxCTL register at it's slower, * baud clock giving us a 1.8432 MHz reference */ writeb(0x07, &sc520_mmcr->uart1ctl); @@ -50,25 +51,30 @@ void init_sc520(void) /* first set the timer pin mapping */ writeb(0x72, &sc520_mmcr->clksel); /* no clock frequency selected, use 1.1892MHz */ - /* enable PCI bus arbitrer */ - writeb(0x02, &sc520_mmcr->sysarbctl); /* enable concurrent mode */ + /* enable PCI bus arbiter (concurrent mode) */ + writeb(0x02, &sc520_mmcr->sysarbctl); - writeb(0x1f, &sc520_mmcr->sysarbmenb); /* enable external grants */ - writeb(0x04, &sc520_mmcr->hbctl); /* enable posted-writes */ + /* enable external grants */ + writeb(0x1f, &sc520_mmcr->sysarbmenb); + + /* enable posted-writes */ + writeb(0x04, &sc520_mmcr->hbctl); if (CONFIG_SYS_SC520_HIGH_SPEED) { - writeb(0x02, &sc520_mmcr->cpuctl); /* set it to 133 MHz and write back */ + /* set it to 133 MHz and write back */ + writeb(0x02, &sc520_mmcr->cpuctl); gd->cpu_clk = 133000000; printf("## CPU Speed set to 133MHz\n"); } else { - writeb(0x01, &sc520_mmcr->cpuctl); /* set it to 100 MHz and write back */ + /* set it to 100 MHz and write back */ + writeb(0x01, &sc520_mmcr->cpuctl); printf("## CPU Speed set to 100MHz\n"); gd->cpu_clk = 100000000; } /* wait at least one millisecond */ - asm("movl $0x2000,%%ecx\n" + asm("movl $0x2000, %%ecx\n" "0: pushl %%ecx\n" "popl %%ecx\n" "loop 0b\n": : : "ecx"); @@ -107,15 +113,15 @@ unsigned long init_sc520_dram(void) /* 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 */ + 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 */ + val = 3; /* 62.4us */ } tmp = (readb(&sc520_mmcr->drcctl) & 0xcf) | (val<<4); @@ -124,9 +130,9 @@ unsigned long init_sc520_dram(void) val = readb(&sc520_mmcr->drctmctl) & 0xf0; if (cas_precharge_delay==3) { - val |= 0x04; /* 3T */ + val |= 0x04; /* 3T */ } else if (cas_precharge_delay==4) { - val |= 0x08; /* 4T */ + val |= 0x08; /* 4T */ } else if (cas_precharge_delay>4) { val |= 0x0c; } @@ -139,8 +145,10 @@ unsigned long init_sc520_dram(void) writeb(val, &c520_mmcr->drctmctl); #endif - /* We read-back the configuration of the dram - * controller that the assembly code wrote */ + /* + * We read-back the configuration of the dram + * controller that the assembly code wrote + */ dram_ctrl = readl(&sc520_mmcr->drcbendadr); bd->bi_dram[0].start = 0; @@ -148,7 +156,6 @@ unsigned long init_sc520_dram(void) /* 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; @@ -179,11 +186,6 @@ unsigned long init_sc520_dram(void) } 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; diff --git a/arch/i386/cpu/sc520/sc520_asm.S b/arch/i386/cpu/sc520/sc520_asm.S index fff56c00b4..7c2de31134 100644 --- a/arch/i386/cpu/sc520/sc520_asm.S +++ b/arch/i386/cpu/sc520/sc520_asm.S @@ -172,366 +172,349 @@ .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 - movb %al, (%edi) /* disable write buffer */ + /* initialize dram controller registers */ + xorw %ax, %ax + movl $DBCTL, %edi + movb %al, (%edi) /* disable write buffer */ - movl $ECCCTL, %edi - movb %al, (%edi) /* disable ECC */ + movl $ECCCTL, %edi + movb %al, (%edi) /* disable ECC */ - movl $DRCTMCTL, %edi - movb $0x1E,%al /* Set SDRAM timing for slowest */ - movb %al, (%edi) + movl $DRCTMCTL, %edi + movb $0x1e, %al /* Set SDRAM timing for slowest */ + 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 */ - movl %eax, (%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 */ + movl %eax, (%edi) - movl $DRCCFG, %edi /* setup */ - movw $0xbbbb,%ax /* dram config register for */ - movw %ax, (%edi) + movl $DRCCFG, %edi /* setup */ + movw $0xbbbb, %ax /* dram config register for */ + 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 */ - movb %al, (%edi) - movl $CACHELINESZ, %esi /* just a dummy address to write for */ - movw %ax, (%esi) - /* - * delay for 100 usec? 200? - * ******this is a cludge for now ************* - */ - movw $100,%cx + /* issue a NOP to all DRAMs */ + movl $DRCCTL, %edi /* setup DRAM control register with */ + movb $0x01, %al /* Disable refresh,disable write buffer */ + movb %al, (%edi) + movl $CACHELINESZ, %esi /* just a dummy address to write for */ + movw %ax, (%esi) + + /* delay for 100 usec? */ + movw $100, %cx sizdelay: - loop sizdelay /* we need 100 usec here */ - /***********************************************/ + loop sizdelay - /* - * issue all banks precharge - */ - movb $0x2,%al /* All banks precharge */ - movb %al, (%edi) - movw %ax, (%esi) + /* issue all banks precharge */ + movb $0x02, %al + movb %al, (%edi) + movw %ax, (%esi) - /* - * issue 2 auto refreshes to all banks - */ - movb $0x4,%al /* Auto refresh cmd */ - movb %al, (%edi) - movw $2,%cx + /* issue 2 auto refreshes to all banks */ + movb $0x04, %al /* Auto refresh cmd */ + movb %al, (%edi) + movw $0x02, %cx refresh1: - movw %ax, (%esi) - loop refresh1 + movw %ax, (%esi) + loop refresh1 - /* - * issue LOAD MODE REGISTER command - */ - movb $0x3,%al /* Load mode register cmd */ - movb %al, (%edi) - movw %ax, (%esi) + /* issue LOAD MODE REGISTER command */ + movb $0x03, %al /* Load mode register cmd */ + movb %al, (%edi) + movw %ax, (%esi) - /* - * issue 8 more auto refreshes to all banks - */ - movb $0x4,%al /* Auto refresh cmd */ - movb %al, (%edi) - movw $8,%cx + /* issue 8 more auto refreshes to all banks */ + movb $0x04, %al /* Auto refresh cmd */ + movb %al, (%edi) + movw $0x0008, %cx refresh2: - movw %ax, (%esi) - loop refresh2 + movw %ax, (%esi) + loop refresh2 - /* - * set control register to NORMAL mode - */ - movb $0x0,%al /* Normal mode value */ - movb %al, (%edi) + /* set control register to NORMAL mode */ + movb $0x00, %al /* Normal mode value */ + movb %al, (%edi) - /* - * size dram starting with external bank 3 moving to external bank 0 - */ - movl $0x3,%ecx /* start with external bank 3 */ + /* + * 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) */ - movl %eax, (%esi) /* write max col pattern at max col adr */ - movl (%esi), %ebx /* optional read */ - cmpl %ebx,%eax /* to verify write */ - jnz bad_ram /* this ram is bad */ - /* - * write col 10 wrap adr - */ + /* 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) */ + movl %eax, (%esi) /* write max col pattern at max col adr */ + movl (%esi), %ebx /* optional read */ + cmpl %ebx, %eax /* to verify write */ + jnz bad_ram /* this ram is bad */ - movl $COL10_ADR, %esi /* set address to 10 col wrap address */ - movl $COL10_DATA, %eax /* pattern for 10 col wrap */ - movl %eax, (%esi) /* write 10 col pattern @ 10 col wrap adr */ - 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 */ - movl %eax, (%esi) /* write 9 col pattern @ 9 col wrap adr */ - 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 */ - movl %eax, (%esi) /* write min col pattern @ min col adr */ - 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) */ - movl %eax, (%esi) /* write max row pattern at max row adr */ - 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 */ - movl %eax, (%esi) /* write 13 row pattern @ 13 row wrap adr */ - 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 */ - movl %eax, (%esi) /* write 12 row pattern @ 12 row wrap adr */ - 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 */ - movl %eax, (%edi) /* write 11 row pattern @ 11 row wrap adr */ - 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) */ - movl %eax, (%edi) /* write 10 row pattern @ 10 row wrap adr */ - 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 */ - 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 */ + /* 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 */ + movl %eax, (%esi) /* write 10 col pattern @ 10 col wrap adr */ + 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 */ + movl %eax, (%esi) /* write 9 col pattern @ 9 col wrap adr */ + 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 */ + movl %eax, (%esi) /* write min col pattern @ min col adr */ + 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) */ + movl %eax, (%esi) /* write max row pattern at max row adr */ + 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 */ + movl %eax, (%esi) /* write 13 row pattern @ 13 row wrap adr */ + 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 */ + movl %eax, (%esi) /* write 12 row pattern @ 12 row wrap adr */ + 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 */ + movl %eax, (%edi) /* write 11 row pattern @ 11 row wrap adr */ + 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) */ + movl %eax, (%edi) /* write 10 row pattern @ 10 row wrap adr */ + 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 */ + 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! */ + movw $0x008, %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 */ - movl (%esi), %eax /* read actual number of rows @ row14 adr */ + movl $ROW14_ADR, %esi /* set address back to max row wrap addr */ + 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 $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 + 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 */ - 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 + 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 - cmpl $COL11_DATA, %eax /* and row must be less than 11 pattern */ - ja bad_ram + /* + * read col 11 wrap adr for real column data value + */ + movl $COL11_ADR, %esi /* set address to max col (11) wrap addr */ + 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 $0x03, %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 */ - 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 */ - movb %al, (%esi) - movl $CACHELINESZ, %esi /* address to init read buffer */ - movw %ax, (%esi) + /* + * issue all banks precharge + */ + movl $DRCCTL, %esi /* setup DRAM control register with */ + movb $0x02, %al /* All banks precharge */ + movb %al, (%esi) + movl $CACHELINESZ, %esi /* address to init read buffer */ + movw %ax, (%esi) - /* - * update ENDING ADDRESS REGISTER - */ - movl $DRCBENDADR, %edi /* DRAM ending address register */ - movl %ecx,%ebx + /* + * update ENDING ADDRESS REGISTER + */ + movl $DRCBENDADR, %edi /* DRAM ending address register */ + movl %ecx, %ebx addl %ebx, %edi - 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 - mov (%edi), %ax - andw %bx,%ax - orw %dx,%ax - movw %ax, (%edi) - jcxz cleanup + movb %dh, (%edi) - decw %cx - movl %ecx,%ebx - movl $DRCBENDADR, %edi /* DRAM ending address register */ - movb $0xff,%al + /* + * update CONFIG REGISTER + */ + xorb %dh, %dh + movw $0x000f, %bx + movw %cx, %ax + shlw $2, %ax + xchgw %cx, %ax + shlw %cl, %dx + shlw %cl, %bx + notw %bx + xchgw %cx, %ax + movl $DRCCFG, %edi + movw (%edi), %ax + andw %bx, %ax + orw %dx, %ax + movw %ax, (%edi) + jcxz cleanup + + decw %cx + movl %ecx, %ebx + movl $DRCBENDADR, %edi /* DRAM ending address register */ + movb $0xff, %al addl %ebx, %edi - movb %al, (%edi) - /* - * set control register to NORMAL mode - */ - movl $DRCCTL, %esi /* setup DRAM control register with */ - movb $0x0,%al /* Normal mode value */ - movb %al, (%esi) - movl $CACHELINESZ, %esi /* address to init read buffer */ - movw %ax, (%esi) - jmp nextbank + movb %al, (%edi) + + /* + * set control register to NORMAL mode + */ + movl $DRCCTL, %esi /* setup DRAM control register with */ + movb $0x00, %al /* Normal mode value */ + movb %al, (%esi) + movl $CACHELINESZ, %esi /* address to init read buffer */ + movw %ax, (%esi) + jmp nextbank cleanup: - movl $DRCBENDADR, %edi /* DRAM ending address register */ - movw $4,%cx - xorw %ax,%ax + movl $DRCBENDADR, %edi /* DRAM ending address register */ + movw $0x04, %cx + xorw %ax, %ax cleanuplp: - movb (%edi), %al - orb %al,%al - jz emptybank + movb (%edi), %al + orb %al, %al + jz emptybank - addb %ah,%al - jns nottoomuch + addb %ah, %al + jns nottoomuch - movb $0x7f,%al + movb $0x7f, %al nottoomuch: - movb %al,%ah - orb $0x80,%al - movb %al, (%edi) + movb %al, %ah + orb $0x80, %al + movb %al, (%edi) emptybank: - incl %edi - loop cleanuplp + incl %edi + loop cleanuplp #if defined CONFIG_SYS_SDRAM_DRCTMCTL /* just have your hardware desinger _GIVE_ you what you need here! */ - movl $DRCTMCTL, %edi - movb $CONFIG_SYS_SDRAM_DRCTMCTL,%al - movb %al, (%edi) + movl $DRCTMCTL, %edi + movb $CONFIG_SYS_SDRAM_DRCTMCTL, %al + movb %al, (%edi) #else #if defined(CONFIG_SYS_SDRAM_CAS_LATENCY_2T) || defined(CONFIG_SYS_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 + /* + * 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 CONFIG_SYS_SDRAM_CAS_LATENCY_2T - andb $0xef, %al + andb $0xef, %al #endif #ifdef CONFIG_SYS_SDRAM_CAS_LATENCY_3T - orb $0x10, %al + orb $0x10, %al #endif - movb %al, (%edi) + movb %al, (%edi) #endif #endif - movl $DRCCTL, %edi /* DRAM Control register */ - movb $0x3,%al /* Load mode register cmd */ - movb %al, (%edi) - movw %ax, (%esi) + movl $DRCCTL, %edi /* DRAM Control register */ + movb $0x03, %al /* Load mode register cmd */ + movb %al, (%edi) + movw %ax, (%esi) - movl $DRCCTL, %edi /* DRAM Control register */ - movb $0x18,%al /* Enable refresh and NORMAL mode */ - movb %al, (%edi) + movl $DRCCTL, %edi /* DRAM Control register */ + movb $0x18, %al /* Enable refresh and NORMAL mode */ + movb %al, (%edi) - jmp dram_done + jmp dram_done bad_ram: - xorl %edx,%edx - xorl %edi,%edi - jmp bad_reint + xorl %edx, %edx + xorl %edi, %edi + jmp bad_reint dram_done: @@ -551,17 +534,17 @@ init_ecc: movl %ebx, %ebp /* A nominal memory test: just a byte at each address line */ - movl %eax, %ecx - shrl $0x1, %ecx + movl %eax, %ecx + shrl $0x1, %ecx movl $0x1, %edi memtest0: movb $0xa5, (%edi) - cmpb $0xa5, (%edi) + cmpb $0xa5, (%edi) jne out - shrl $1, %ecx - andl %ecx,%ecx + shrl $0x1, %ecx + andl %ecx, %ecx jz set_ecc - shll $1, %edi + shll $0x1, %edi jmp memtest0 set_ecc: @@ -570,21 +553,24 @@ set_ecc: xorl %esi, %esi xorl %edi, %edi xorl %eax, %eax - shrl $2, %ecx + shrl $0x2, %ecx cld rep stosl - /* enable read, write buffers */ - movb $0x11, %al - movl $DBCTL, %edi - movb %al, (%edi) - /* enable NMI mapping for ECC */ - movl $ECCINT, %edi - mov $0x10, %al - movb %al, (%edi) - /* Turn on ECC */ - movl $ECCCTL, %edi - mov $0x05, %al - movb %al, (%edi) + + /* enable read, write buffers */ + movb $0x11, %al + movl $DBCTL, %edi + movb %al, (%edi) + + /* enable NMI mapping for ECC */ + movl $ECCINT, %edi + movb $0x10, %al + movb %al, (%edi) + + /* Turn on ECC */ + movl $ECCCTL, %edi + movb $0x05, %al + movb %al,(%edi) #endif out: @@ -596,7 +582,7 @@ out: */ .globl get_mem_size get_mem_size: - movl $DRCBENDADR, %edi /* DRAM ending address register */ + movl $DRCBENDADR, %edi /* DRAM ending address register */ bank0: movl (%edi), %eax movl %eax, %ecx diff --git a/arch/i386/cpu/start.S b/arch/i386/cpu/start.S index 3cea04b4ce..f67a1b7a6e 100644 --- a/arch/i386/cpu/start.S +++ b/arch/i386/cpu/start.S @@ -45,7 +45,7 @@ _i386boot_start: /* Turn of cache (this might require a 486-class CPU) */ movl %cr0, %eax - orl $0x60000000,%eax + orl $0x60000000, %eax movl %eax, %cr0 wbinvd @@ -54,13 +54,13 @@ _i386boot_start: _start: /* This is the 32-bit cold-reset entry point */ - movl $0x18,%eax /* Load our segement registes, the + movl $0x18, %eax /* Load our segement registes, the * gdt have already been loaded by start16.S */ - movw %ax,%fs - movw %ax,%ds - movw %ax,%gs - movw %ax,%es - movw %ax,%ss + movw %ax, %fs + movw %ax, %ds + movw %ax, %gs + movw %ax, %es + movw %ax, %ss /* Clear the interupt vectors */ lidt blank_idt_ptr @@ -79,7 +79,7 @@ _start: * to store the return address */ /* Early platform init (setup gpio, etc ) */ - mov $early_board_init_ret, %ebp + mov $early_board_init_ret, %ebp jmp early_board_init early_board_init_ret: @@ -92,12 +92,12 @@ early_board_init_ret: /* size memory */ mov $mem_init_ret, %ebp - jmp mem_init + jmp mem_init mem_init_ret: /* fetch memory size (into %eax) */ mov $get_mem_size_ret, %ebp - jmp get_mem_size + jmp get_mem_size get_mem_size_ret: /* Check we have enough memory for stack */ @@ -113,7 +113,7 @@ get_mem_size_ret: jmp die mem_ok: /* Set stack pointer to upper memory limit*/ - movl %eax, %esp + movl %eax, %esp /* indicate progress */ movw $0x02, %ax @@ -150,12 +150,12 @@ stack_ok: wbinvd /* Get upper memory limit */ - movl %esp, %ecx - subl $CONFIG_SYS_STACK_SIZE, %ecx + movl %esp, %ecx + subl $CONFIG_SYS_STACK_SIZE, %ecx /* Create a Stack Frame */ - pushl %ebp - movl %esp, %ebp + pushl %ebp + movl %esp, %ebp /* stack_limit parameter */ pushl %ecx diff --git a/arch/i386/cpu/start16.S b/arch/i386/cpu/start16.S index ebe5835841..2a5cca9d69 100644 --- a/arch/i386/cpu/start16.S +++ b/arch/i386/cpu/start16.S @@ -31,7 +31,8 @@ .code16 .globl start16 start16: - /* First we let the BSP do some early initialization + /* + * First we let the BSP do some early initialization * this code have to map the flash to its final position */ mov $board_init16_ret, %bp @@ -40,7 +41,7 @@ board_init16_ret: /* Turn of cache (this might require a 486-class CPU) */ movl %cr0, %eax - orl $0x60000000,%eax + orl $0x60000000, %eax movl %eax, %cr0 wbinvd @@ -50,7 +51,7 @@ o32 cs lgdt gdt_ptr /* Now, we enter protected mode */ movl %cr0, %eax - orl $1,%eax + orl $1, %eax movl %eax, %cr0 /* Flush the prefetch queue */ @@ -61,7 +62,7 @@ ff: /* Finally jump to the 32bit initialization code */ movw $code32start, %ax - movw %ax,%bp + movw %ax, %bp o32 cs ljmp *(%bp) /* 48-bit far pointer */ From 5c161653db3aa585f3e47a650ae177ba9ffb7232 Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:23 +1100 Subject: [PATCH 08/20] x86: Change compiler options Change to: - reparam=3 - no-from-pointer - no-stack-protector - preferred-stack-boundary=2 - no-top-level-reorder These options make the code a little smaller and faster --- arch/i386/config.mk | 8 ++++++++ arch/i386/cpu/interrupts.c | 7 +------ arch/i386/cpu/start.S | 12 +++--------- arch/i386/include/asm/interrupt.h | 2 -- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/arch/i386/config.mk b/arch/i386/config.mk index 0e80a1ae58..8743f1a663 100644 --- a/arch/i386/config.mk +++ b/arch/i386/config.mk @@ -25,6 +25,14 @@ CROSS_COMPILE ?= i386-linux- STANDALONE_LOAD_ADDR = 0x40000 +PLATFORM_CPPFLAGS += -fno-strict-aliasing +PLATFORM_CPPFLAGS += -Wstrict-prototypes +PLATFORM_CPPFLAGS += -mregparm=3 +PLATFORM_CPPFLAGS += -fomit-frame-pointer +PLATFORM_CPPFLAGS += $(call cc-option, -ffreestanding) +PLATFORM_CPPFLAGS += $(call cc-option, -fno-toplevel-reorder, $(call cc-option, -fno-unit-at-a-time)) +PLATFORM_CPPFLAGS += $(call cc-option, -fno-stack-protector) +PLATFORM_CPPFLAGS += $(call cc-option, -mpreferred-stack-boundary=2) PLATFORM_CPPFLAGS += -DCONFIG_I386 -D__I386__ LDFLAGS += --cref --gc-sections diff --git a/arch/i386/cpu/interrupts.c b/arch/i386/cpu/interrupts.c index 51023f3a86..47a7a29013 100644 --- a/arch/i386/cpu/interrupts.c +++ b/arch/i386/cpu/interrupts.c @@ -225,7 +225,7 @@ int disable_interrupts(void) } /* IRQ Low-Level Service Routine */ -__isr__ irq_llsr(struct pt_regs *regs) +void irq_llsr(struct pt_regs *regs) { /* * For detailed description of each exception, refer to: @@ -370,12 +370,7 @@ asm(".globl irq_common_entry\n" \ "pushl %ecx\n" \ "pushl %ebx\n" \ "mov %esp, %eax\n" \ - "pushl %ebp\n" \ - "movl %esp,%ebp\n" \ - "pushl %eax\n" \ "call irq_llsr\n" \ - "popl %eax\n" \ - "leave\n"\ "popl %ebx\n" \ "popl %ecx\n" \ "popl %edx\n" \ diff --git a/arch/i386/cpu/start.S b/arch/i386/cpu/start.S index f67a1b7a6e..90dfd5d210 100644 --- a/arch/i386/cpu/start.S +++ b/arch/i386/cpu/start.S @@ -149,16 +149,10 @@ stack_ok: wbinvd - /* Get upper memory limit */ - movl %esp, %ecx - subl $CONFIG_SYS_STACK_SIZE, %ecx + /* Set the upper memory limit parameter */ + movl %esp, %eax + subl $CONFIG_SYS_STACK_SIZE, %eax - /* Create a Stack Frame */ - pushl %ebp - movl %esp, %ebp - - /* stack_limit parameter */ - pushl %ecx call board_init_f /* Enter, U-boot! */ /* indicate (lack of) progress */ diff --git a/arch/i386/include/asm/interrupt.h b/arch/i386/include/asm/interrupt.h index 07426fe6a7..99ae8437b8 100644 --- a/arch/i386/include/asm/interrupt.h +++ b/arch/i386/include/asm/interrupt.h @@ -41,6 +41,4 @@ void specific_eoi(int irq); extern char exception_stack[]; -#define __isr__ void __attribute__ ((regparm(0))) - #endif From 7228efa3cb6e05b9a120f26456fd3ffed9afe2ba Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:23 +1100 Subject: [PATCH 09/20] x86: Fix %ss and %esp in register structure for interrupts --- arch/i386/cpu/interrupts.c | 23 +++++++++++++++++++---- arch/i386/include/asm/interrupt.h | 2 ++ arch/i386/include/asm/ptrace.h | 24 ++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/arch/i386/cpu/interrupts.c b/arch/i386/cpu/interrupts.c index 47a7a29013..e4d0868cde 100644 --- a/arch/i386/cpu/interrupts.c +++ b/arch/i386/cpu/interrupts.c @@ -104,7 +104,7 @@ static inline unsigned long get_debugreg(int regno) return val; } -void dump_regs(struct pt_regs *regs) +void dump_regs(struct irq_regs *regs) { unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; unsigned long d0, d1, d2, d3, d6, d7; @@ -225,7 +225,7 @@ int disable_interrupts(void) } /* IRQ Low-Level Service Routine */ -void irq_llsr(struct pt_regs *regs) +void irq_llsr(struct irq_regs *regs) { /* * For detailed description of each exception, refer to: @@ -234,7 +234,7 @@ void irq_llsr(struct pt_regs *regs) * Order Number: 253665-029US, November 2008 * Table 6-1. Exceptions and Interrupts */ - switch (regs->orig_eax) { + switch (regs->irq_id) { case 0x00: printf("Divide Error (Division by zero)\n"); dump_regs(regs); @@ -340,7 +340,7 @@ void irq_llsr(struct pt_regs *regs) default: /* Hardware or User IRQ */ - do_irq(regs->orig_eax); + do_irq(regs->irq_id); } } @@ -352,17 +352,30 @@ void irq_llsr(struct pt_regs *regs) * Interrupt entries are now very small (a push and a jump) but they are * now slower (all registers pushed on stack which provides complete * crash dumps in the low level handlers + * + * Interrupt Entry Point: + * - Interrupt has caused eflags, CS and EIP to be pushed + * - Interrupt Vector Handler has pushed orig_eax + * - pt_regs.esp needs to be adjusted by 40 bytes: + * 12 bytes pushed by CPU (EFLAGSF, CS, EIP) + * 4 bytes pushed by vector handler (irq_id) + * 24 bytes pushed before SP (SS, GS, FS, ES, DS, EAX) + * NOTE: Only longs are pushed on/popped off the stack! */ asm(".globl irq_common_entry\n" \ ".hidden irq_common_entry\n" \ ".type irq_common_entry, @function\n" \ "irq_common_entry:\n" \ "cld\n" \ + "pushl %ss\n" \ "pushl %gs\n" \ "pushl %fs\n" \ "pushl %es\n" \ "pushl %ds\n" \ "pushl %eax\n" \ + "movl %esp, %eax\n" \ + "addl $40, %eax\n" \ + "pushl %eax\n" \ "pushl %ebp\n" \ "pushl %edi\n" \ "pushl %esi\n" \ @@ -378,10 +391,12 @@ asm(".globl irq_common_entry\n" \ "popl %edi\n" \ "popl %ebp\n" \ "popl %eax\n" \ + "popl %eax\n" \ "popl %ds\n" \ "popl %es\n" \ "popl %fs\n" \ "popl %gs\n" \ + "popl %ss\n" \ "add $4, %esp\n" \ "iret\n" \ DECLARE_INTERRUPT(0) \ diff --git a/arch/i386/include/asm/interrupt.h b/arch/i386/include/asm/interrupt.h index 99ae8437b8..d32ef8b190 100644 --- a/arch/i386/include/asm/interrupt.h +++ b/arch/i386/include/asm/interrupt.h @@ -27,6 +27,8 @@ #ifndef __ASM_INTERRUPT_H_ #define __ASM_INTERRUPT_H_ 1 +#include + /* arch/i386/cpu/interrupts.c */ void set_vector(u8 intnum, void *routine); diff --git a/arch/i386/include/asm/ptrace.h b/arch/i386/include/asm/ptrace.h index 750e40d030..a727dbfb05 100644 --- a/arch/i386/include/asm/ptrace.h +++ b/arch/i386/include/asm/ptrace.h @@ -1,6 +1,8 @@ #ifndef _I386_PTRACE_H #define _I386_PTRACE_H +#include + #define EBX 0 #define ECX 1 #define EDX 2 @@ -43,6 +45,28 @@ struct pt_regs { int xss; } __attribute__ ((packed)); +struct irq_regs { + /* Pushed by irq_common_entry */ + long ebx; + long ecx; + long edx; + long esi; + long edi; + long ebp; + long esp; + long eax; + long xds; + long xes; + long xfs; + long xgs; + long xss; + /* Pushed by vector handler (irq_) */ + long irq_id; + /* Pushed by cpu in response to interrupt */ + long eip; + long xcs; + long eflags; +} __attribute__ ((packed)); /* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */ #define PTRACE_GETREGS 12 From 6ae032a86aa21def97aada054bd24589fdb8e947 Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:24 +1100 Subject: [PATCH 10/20] x86: Remove progress indication in low-level init Progress indication is not relocation friendly so remove it in preperation for full relocatability support --- arch/i386/cpu/start.S | 44 ++--------------------------------------- board/eNET/eNET_start.S | 12 ----------- 2 files changed, 2 insertions(+), 54 deletions(-) diff --git a/arch/i386/cpu/start.S b/arch/i386/cpu/start.S index 90dfd5d210..cb47ce7faa 100644 --- a/arch/i386/cpu/start.S +++ b/arch/i386/cpu/start.S @@ -83,13 +83,6 @@ _start: jmp early_board_init early_board_init_ret: - /* The __port80 entry-point should be usabe by now */ - /* so we try to indicate progress */ - movw $0x01, %ax - movl $.progress0, %ebp - jmp show_boot_progress_asm -.progress0: - /* size memory */ mov $mem_init_ret, %ebp jmp mem_init @@ -103,24 +96,11 @@ get_mem_size_ret: /* Check we have enough memory for stack */ movl $CONFIG_SYS_STACK_SIZE, %ecx cmpl %ecx, %eax - jae mem_ok - - /* indicate (lack of) progress */ - movw $0x81, %ax - movl $.progress0a, %ebp - jmp show_boot_progress_asm -.progress0a: - jmp die + jb die mem_ok: /* Set stack pointer to upper memory limit*/ movl %eax, %esp - /* indicate progress */ - movw $0x02, %ax - movl $.progress1, %ebp - jmp show_boot_progress_asm -.progress1: - /* Test the stack */ pushl $0 popl %eax @@ -129,23 +109,7 @@ mem_ok: push $0x55aa55aa popl %ebx cmpl $0x55aa55aa, %ebx - je stack_ok - -no_stack: - /* indicate (lack of) progress */ - movw $0x82, %ax - movl $.progress1a, %ebp - jmp show_boot_progress_asm -.progress1a: - jmp die - - -stack_ok: - /* indicate progress */ - movw $0x03, %ax - movl $.progress2, %ebp - jmp show_boot_progress_asm -.progress2: + jne die wbinvd @@ -157,10 +121,6 @@ stack_ok: /* indicate (lack of) progress */ movw $0x85, %ax - movl $.progress4a, %ebp - jmp show_boot_progress_asm -.progress4a: - die: hlt jmp die hlt diff --git a/board/eNET/eNET_start.S b/board/eNET/eNET_start.S index 1b07d622f7..6659549a37 100644 --- a/board/eNET/eNET_start.S +++ b/board/eNET/eNET_start.S @@ -29,18 +29,6 @@ early_board_init: /* No 32-bit board specific initialisation */ jmp *%ebp /* return to caller */ -.globl show_boot_progress_asm -show_boot_progress_asm: - - movb %al, %dl /* Create Working Copy */ - andb $0x80, %dl /* Mask in only Error bit */ - shrb $0x02, %dl /* Shift Error bit to Error LED */ - andb $0x0f, %al /* Mask out 'Error' bit */ - orb %dl, %al /* Mask in ERR LED */ - movw $LED_LATCH_ADDRESS, %dx - outb %al, %dx - jmp *%ebp /* return to caller */ - .globl cpu_halt_asm cpu_halt_asm: movb $0x0f, %al From 00940a229d564044d52a5449bce14090c7298f92 Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:26 +1100 Subject: [PATCH 11/20] x86: Move ECC initialisation outside RAM initialisation To allow for 'load anywhere' images, the %ebp return pointer 'hack' must be removed, so we cannot have two 'calls' to get_mem_size --- arch/i386/cpu/sc520/sc520_asm.S | 17 +++-------------- arch/i386/cpu/start.S | 11 +++++++++++ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/arch/i386/cpu/sc520/sc520_asm.S b/arch/i386/cpu/sc520/sc520_asm.S index 7c2de31134..e0d3102ce2 100644 --- a/arch/i386/cpu/sc520/sc520_asm.S +++ b/arch/i386/cpu/sc520/sc520_asm.S @@ -517,22 +517,11 @@ bad_ram: jmp bad_reint dram_done: + jmp *%ebp #if CONFIG_SYS_SDRAM_ECC_ENABLE - /* - * We are in the middle of an existing 'call' - Need to store the - * existing return address before making another 'call' - */ - movl %ebp, %ebx - - /* Get the memory size */ - movl $init_ecc, %ebp - jmpl get_mem_size - +.globl init_ecc init_ecc: - /* Restore the orignal return address */ - movl %ebx, %ebp - /* A nominal memory test: just a byte at each address line */ movl %eax, %ecx shrl $0x1, %ecx @@ -571,10 +560,10 @@ set_ecc: movl $ECCCTL, %edi movb $0x05, %al movb %al,(%edi) -#endif out: jmp *%ebp +#endif /* * Read and decode the sc520 DRCBENDADR MMCR and return the number of diff --git a/arch/i386/cpu/start.S b/arch/i386/cpu/start.S index cb47ce7faa..819274f050 100644 --- a/arch/i386/cpu/start.S +++ b/arch/i386/cpu/start.S @@ -93,6 +93,17 @@ mem_init_ret: jmp get_mem_size get_mem_size_ret: +#if CONFIG_SYS_SDRAM_ECC_ENABLE + /* Skip ECC initialization if not starting from cold-reset */ + movl %ebx, %ecx + andl $GD_FLG_COLD_BOOT, %ecx + jz init_ecc_ret + mov $init_ecc_ret, %ebp + jmp init_ecc + +init_ecc_ret: +#endif + /* Check we have enough memory for stack */ movl $CONFIG_SYS_STACK_SIZE, %ecx cmpl %ecx, %eax From 88fa0a6eb906b532cd073b6e3d8f688c47404709 Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:27 +1100 Subject: [PATCH 12/20] x86: Remove usage of %ebp as a return pointer Using %ebp as a return pointer prevents creating 'load anywhere' images --- arch/i386/cpu/sc520/sc520_asm.S | 6 +++--- arch/i386/cpu/start.S | 12 ++++++------ arch/i386/cpu/start16.S | 2 +- board/eNET/eNET_start.S | 2 +- board/eNET/eNET_start16.S | 3 +-- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/arch/i386/cpu/sc520/sc520_asm.S b/arch/i386/cpu/sc520/sc520_asm.S index e0d3102ce2..a18e2c3d0c 100644 --- a/arch/i386/cpu/sc520/sc520_asm.S +++ b/arch/i386/cpu/sc520/sc520_asm.S @@ -517,7 +517,7 @@ bad_ram: jmp bad_reint dram_done: - jmp *%ebp + jmp mem_init_ret #if CONFIG_SYS_SDRAM_ECC_ENABLE .globl init_ecc @@ -562,7 +562,7 @@ set_ecc: movb %al,(%edi) out: - jmp *%ebp + jmp init_ecc_ret #endif /* @@ -607,4 +607,4 @@ bank3: movl (%edi), %eax done: movl %ebx, %eax - jmp *%ebp + jmp get_mem_size_ret diff --git a/arch/i386/cpu/start.S b/arch/i386/cpu/start.S index 819274f050..551965f42e 100644 --- a/arch/i386/cpu/start.S +++ b/arch/i386/cpu/start.S @@ -1,7 +1,7 @@ /* * U-boot - i386 Startup Code * - * Copyright (c) 2002 Omicron Ceti AB, Daniel Engström + * Copyright (c) 2002 Omicron Ceti AB, Daniel Engstr�m * * See file CREDITS for list of people who contributed to this * project. @@ -79,18 +79,18 @@ _start: * to store the return address */ /* Early platform init (setup gpio, etc ) */ - mov $early_board_init_ret, %ebp jmp early_board_init +.globl early_board_init_ret early_board_init_ret: /* size memory */ - mov $mem_init_ret, %ebp jmp mem_init +.globl mem_init_ret mem_init_ret: /* fetch memory size (into %eax) */ - mov $get_mem_size_ret, %ebp jmp get_mem_size +.globl get_mem_size_ret get_mem_size_ret: #if CONFIG_SYS_SDRAM_ECC_ENABLE @@ -98,9 +98,9 @@ get_mem_size_ret: movl %ebx, %ecx andl $GD_FLG_COLD_BOOT, %ecx jz init_ecc_ret - mov $init_ecc_ret, %ebp jmp init_ecc +.globl init_ecc_ret init_ecc_ret: #endif @@ -116,7 +116,7 @@ mem_ok: pushl $0 popl %eax cmpl $0, %eax - jne no_stack + jne die push $0x55aa55aa popl %ebx cmpl $0x55aa55aa, %ebx diff --git a/arch/i386/cpu/start16.S b/arch/i386/cpu/start16.S index 2a5cca9d69..0de4d09398 100644 --- a/arch/i386/cpu/start16.S +++ b/arch/i386/cpu/start16.S @@ -35,8 +35,8 @@ start16: * First we let the BSP do some early initialization * this code have to map the flash to its final position */ - mov $board_init16_ret, %bp jmp board_init16 +.globl board_init16_ret board_init16_ret: /* Turn of cache (this might require a 486-class CPU) */ diff --git a/board/eNET/eNET_start.S b/board/eNET/eNET_start.S index 6659549a37..137fe41b4b 100644 --- a/board/eNET/eNET_start.S +++ b/board/eNET/eNET_start.S @@ -27,7 +27,7 @@ .globl early_board_init early_board_init: /* No 32-bit board specific initialisation */ - jmp *%ebp /* return to caller */ + jmp early_board_init_ret .globl cpu_halt_asm cpu_halt_asm: diff --git a/board/eNET/eNET_start16.S b/board/eNET/eNET_start16.S index af2c132156..06cfd558d1 100644 --- a/board/eNET/eNET_start16.S +++ b/board/eNET/eNET_start16.S @@ -65,8 +65,7 @@ board_init16: movl $0x000000cb, %eax outl %eax, %dx - /* the return address is stored in bp */ - jmp *%bp + jmp board_init16_ret .section .bios, "ax" .code16 From 5f2679055d5f58db9548efe5545fac256d1c7d4d Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:28 +1100 Subject: [PATCH 13/20] x86: Don't clobber %ebx %ebx will hold low-level boot flags and must be preserved --- arch/i386/cpu/sc520/sc520_asm.S | 15 ++++++++++----- arch/i386/cpu/start.S | 4 ++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/arch/i386/cpu/sc520/sc520_asm.S b/arch/i386/cpu/sc520/sc520_asm.S index a18e2c3d0c..63c14b7eb0 100644 --- a/arch/i386/cpu/sc520/sc520_asm.S +++ b/arch/i386/cpu/sc520/sc520_asm.S @@ -174,6 +174,9 @@ .globl mem_init mem_init: + /* Preserve Boot Flags */ + movl %ebx, %ebp + /* initialize dram controller registers */ xorw %ax, %ax movl $DBCTL, %edi @@ -517,6 +520,8 @@ bad_ram: jmp bad_reint dram_done: + /* Restore Boot Flags */ + movl %ebx, %ebp jmp mem_init_ret #if CONFIG_SYS_SDRAM_ECC_ENABLE @@ -579,7 +584,7 @@ bank0: movl (%edi), %eax jz bank1 andl $0x0000007f, %eax shll $22, %eax - movl %eax, %ebx + movl %eax, %edx bank1: movl (%edi), %eax movl %eax, %ecx @@ -587,7 +592,7 @@ bank1: movl (%edi), %eax jz bank2 andl $0x00007f00, %eax shll $14, %eax - movl %eax, %ebx + movl %eax, %edx bank2: movl (%edi), %eax movl %eax, %ecx @@ -595,7 +600,7 @@ bank2: movl (%edi), %eax jz bank3 andl $0x007f0000, %eax shll $6, %eax - movl %eax, %ebx + movl %eax, %edx bank3: movl (%edi), %eax movl %eax, %ecx @@ -603,8 +608,8 @@ bank3: movl (%edi), %eax jz done andl $0x7f000000, %eax shrl $2, %eax - movl %eax, %ebx + movl %eax, %edx done: - movl %ebx, %eax + movl %edx, %eax jmp get_mem_size_ret diff --git a/arch/i386/cpu/start.S b/arch/i386/cpu/start.S index 551965f42e..63f733421b 100644 --- a/arch/i386/cpu/start.S +++ b/arch/i386/cpu/start.S @@ -118,8 +118,8 @@ mem_ok: cmpl $0, %eax jne die push $0x55aa55aa - popl %ebx - cmpl $0x55aa55aa, %ebx + popl %ecx + cmpl $0x55aa55aa, %ecx jne die wbinvd From 5a3876d2ac0aaaf16d50ce91b03c2030822da66f Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:28 +1100 Subject: [PATCH 14/20] x86: Dont clobber %eax after getting memory size By using another register, reduce code size by one instruction --- arch/i386/cpu/start.S | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/i386/cpu/start.S b/arch/i386/cpu/start.S index 63f733421b..66ff4f3e06 100644 --- a/arch/i386/cpu/start.S +++ b/arch/i386/cpu/start.S @@ -114,8 +114,8 @@ mem_ok: /* Test the stack */ pushl $0 - popl %eax - cmpl $0, %eax + popl %ecx + cmpl $0, %ecx jne die push $0x55aa55aa popl %ecx @@ -125,7 +125,6 @@ mem_ok: wbinvd /* Set the upper memory limit parameter */ - movl %esp, %eax subl $CONFIG_SYS_STACK_SIZE, %eax call board_init_f /* Enter, U-boot! */ From 161b3589ea19ad262a2eebbf7b4f10aeb6812f35 Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:29 +1100 Subject: [PATCH 15/20] x86: Place global data below stack before entering C By reserving space for the Global Data immediately below the stack during assembly level initialisation, the C declaration of the static global data can be removed, along with the 'RAM Bootstrap' function. This results in cleaner code, and the ability to pass boot-up flags from assembler into C --- arch/i386/cpu/start.S | 8 ++++++ arch/i386/include/asm/global_data.h | 24 +++++++++++++++-- arch/i386/lib/board.c | 42 +++++------------------------ 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/arch/i386/cpu/start.S b/arch/i386/cpu/start.S index 66ff4f3e06..cff4637589 100644 --- a/arch/i386/cpu/start.S +++ b/arch/i386/cpu/start.S @@ -25,6 +25,7 @@ #include #include +#include .section .text @@ -127,6 +128,13 @@ mem_ok: /* Set the upper memory limit parameter */ subl $CONFIG_SYS_STACK_SIZE, %eax + /* Reserve space for global data */ + subl $(GD_SIZE * 4), %eax + + /* %eax points to the global data structure */ + movl %esp, (GD_RAM_SIZE * 4)(%eax) + movl %ebx, (GD_FLAGS * 4)(%eax) + call board_init_f /* Enter, U-boot! */ /* indicate (lack of) progress */ diff --git a/arch/i386/include/asm/global_data.h b/arch/i386/include/asm/global_data.h index 3a9adc9c66..456f606ec8 100644 --- a/arch/i386/include/asm/global_data.h +++ b/arch/i386/include/asm/global_data.h @@ -33,6 +33,8 @@ * Keep it *SMALL* and remember to set CONFIG_SYS_GBL_DATA_SIZE > sizeof(gd_t) */ +#ifndef __ASSEMBLY__ + typedef struct { bd_t *bd; unsigned long flags; @@ -49,6 +51,26 @@ typedef struct { char env_buf[32]; /* buffer for getenv() before reloc. */ } gd_t; +extern gd_t *gd; + +#endif + +/* Word Offsets into Global Data - MUST match struct gd_t */ +#define GD_BD 0 +#define GD_FLAGS 1 +#define GD_BAUDRATE 2 +#define GD_HAVE_CONSOLE 3 +#define GD_RELOC_OFF 4 +#define GD_ENV_ADDR 5 +#define GD_ENV_VALID 6 +#define GD_CPU_CLK 7 +#define GD_BUS_CLK 8 +#define GD_RAM_SIZE 9 +#define GD_RESET_STATUS 10 +#define GD_JT 11 + +#define GD_SIZE 12 + /* * Global Data Flags */ @@ -61,8 +83,6 @@ typedef struct { #define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */ #define GD_FLG_ENV_READY 0x00080 /* Environment imported into hash table */ -extern gd_t *gd; - #define DECLARE_GLOBAL_DATA_PTR #endif /* __ASM_GBL_DATA_H */ diff --git a/arch/i386/lib/board.c b/arch/i386/lib/board.c index 5002203ec8..00976a5d49 100644 --- a/arch/i386/lib/board.c +++ b/arch/i386/lib/board.c @@ -54,8 +54,6 @@ extern ulong _i386boot_rel_dyn_end; extern ulong _i386boot_bss_start; extern ulong _i386boot_bss_size; -void ram_bootstrap (void *, ulong); - const char version_string[] = U_BOOT_VERSION" (" U_BOOT_DATE " - " U_BOOT_TIME ")"; @@ -164,13 +162,12 @@ init_fnc_t *init_sequence[] = { NULL, }; -static gd_t gd_data; gd_t *gd; /* * Load U-Boot into RAM, initialize BSS, perform relocation adjustments */ -void board_init_f (ulong stack_limit) +void board_init_f (ulong gdp) { void *text_start = &_i386boot_text_start; void *u_boot_cmd_end = &__u_boot_cmd_end; @@ -184,12 +181,9 @@ void board_init_f (ulong stack_limit) ulong rel_offset; Elf32_Rel *re; - void (*start_func)(void *, ulong); - uboot_size = (ulong)u_boot_cmd_end - (ulong)text_start; - dest_addr = (void *)stack_limit - (uboot_size + (ulong)bss_size); + dest_addr = (void *)gdp - (uboot_size + (ulong)bss_size); rel_offset = text_start - dest_addr; - start_func = ram_bootstrap - rel_offset; /* First stage CPU initialization */ if (cpu_init_f() != 0) @@ -213,38 +207,16 @@ void board_init_f (ulong stack_limit) *(ulong *)(re->r_offset - rel_offset) -= (Elf32_Addr)rel_offset; } + ((gd_t *)gdp)->reloc_off = rel_offset; + ((gd_t *)gdp)->flags |= GD_FLG_RELOC; + /* Enter the relocated U-Boot! */ - start_func(dest_addr, rel_offset); + (board_init_r - rel_offset)((gd_t *)gdp, (ulong)dest_addr); + /* NOTREACHED - board_init_f() does not return */ while(1); } -/* - * We cannot initialize gd_data in board_init_f() because we would be - * attempting to write to flash (I have even tried using manual relocation - * adjustments on pointers but it just won't work) and board_init_r() does - * not have enough arguments to allow us to pass the relocation offset - * straight up. This bootstrap function (which runs in RAM) is used to - * setup gd_data in order to pass the relocation offset to the rest of - * U-Boot. - * - * TODO: The compiler optimization barrier is intended to stop GCC from - * optimizing this function into board_init_f(). It seems to work without - * it, but I've left it in to be sure. I think also that the barrier in - * board_init_r() is no longer needed, but left it in 'just in case' - */ -void ram_bootstrap (void *dest_addr, ulong rel_offset) -{ - /* compiler optimization barrier needed for GCC >= 3.4 */ - __asm__ __volatile__("": : :"memory"); - - /* tell others: relocation done */ - gd_data.reloc_off = rel_offset; - gd_data.flags |= GD_FLG_RELOC; - - board_init_r(&gd_data, (ulong)dest_addr); -} - void board_init_r(gd_t *id, ulong dest_addr) { char *s; From c81b26beb87c5dbf6b5f68b779e529915178b17c Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:30 +1100 Subject: [PATCH 16/20] x86: Set cold/warm boot flag --- arch/i386/cpu/start.S | 19 ++++++------------- arch/i386/cpu/start16.S | 7 ++++--- arch/i386/include/asm/global_data.h | 3 +++ 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/arch/i386/cpu/start.S b/arch/i386/cpu/start.S index cff4637589..8fdcd81c1e 100644 --- a/arch/i386/cpu/start.S +++ b/arch/i386/cpu/start.S @@ -51,7 +51,7 @@ _i386boot_start: wbinvd /* Tell 32-bit code it is being entered from an in-RAM copy */ - movw $0x0000, %bx + movw $GD_FLG_WARM_BOOT, %bx _start: /* This is the 32-bit cold-reset entry point */ @@ -66,18 +66,10 @@ _start: /* Clear the interupt vectors */ lidt blank_idt_ptr - /* - * Skip low-level board and memory initialization if not starting - * from cold-reset. This allows us to do a fail safe boot-strap - * into a new build of U-Boot from a known-good boot flash - */ - movw $0x0001, %ax - cmpw %ax, %bx - jne mem_init_ret - - /* We call a few functions in the board support package - * since we have no stack yet we'll have to use %ebp - * to store the return address */ + /* Skip low-level initialization if not starting from cold-reset */ + movl %ebx, %ecx + andl $GD_FLG_COLD_BOOT, %ecx + jz skip_mem_init /* Early platform init (setup gpio, etc ) */ jmp early_board_init @@ -89,6 +81,7 @@ early_board_init_ret: .globl mem_init_ret mem_init_ret: +skip_mem_init: /* fetch memory size (into %eax) */ jmp get_mem_size .globl get_mem_size_ret diff --git a/arch/i386/cpu/start16.S b/arch/i386/cpu/start16.S index 0de4d09398..0a5823d3c2 100644 --- a/arch/i386/cpu/start16.S +++ b/arch/i386/cpu/start16.S @@ -22,6 +22,7 @@ * MA 02111-1307 USA */ +#include #define BOOT_SEG 0xffff0000 /* linear segment of boot code */ #define a32 .byte 0x67; @@ -31,6 +32,9 @@ .code16 .globl start16 start16: + /* Set the Cold Boot / Hard Reset flag */ + movl $GD_FLG_COLD_BOOT, %ebx + /* * First we let the BSP do some early initialization * this code have to map the flash to its final position @@ -57,9 +61,6 @@ o32 cs lgdt gdt_ptr /* Flush the prefetch queue */ jmp ff ff: - /* Tell 32-bit code it is being entered from hard-reset */ - movw $0x0001, %bx - /* Finally jump to the 32bit initialization code */ movw $code32start, %ax movw %ax, %bp diff --git a/arch/i386/include/asm/global_data.h b/arch/i386/include/asm/global_data.h index 456f606ec8..a15c5981c6 100644 --- a/arch/i386/include/asm/global_data.h +++ b/arch/i386/include/asm/global_data.h @@ -82,6 +82,9 @@ extern gd_t *gd; #define GD_FLG_LOGINIT 0x00020 /* Log Buffer has been initialized */ #define GD_FLG_DISABLE_CONSOLE 0x00040 /* Disable console (in & out) */ #define GD_FLG_ENV_READY 0x00080 /* Environment imported into hash table */ +#define GD_FLG_COLD_BOOT 0x00100 /* Cold Boot */ +#define GD_FLG_WARM_BOOT 0x00200 /* Warm Boot */ + #define DECLARE_GLOBAL_DATA_PTR From 067f9b10710e4edee97a9220b2ea8841c646368b Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:31 +1100 Subject: [PATCH 17/20] x86: Rename linker script symbols Create more generic names for the symbols exported from the linker script --- arch/i386/lib/bios_setup.c | 14 +++++++------- arch/i386/lib/board.c | 20 ++++++++++---------- arch/i386/lib/realmode.c | 14 +++++++------- board/eNET/u-boot.lds | 21 +++++++++------------ 4 files changed, 33 insertions(+), 36 deletions(-) diff --git a/arch/i386/lib/bios_setup.c b/arch/i386/lib/bios_setup.c index a92b77ea23..75407c173c 100644 --- a/arch/i386/lib/bios_setup.c +++ b/arch/i386/lib/bios_setup.c @@ -45,8 +45,8 @@ DECLARE_GLOBAL_DATA_PTR; #define BIOS_BASE ((char*)0xf0000) #define BIOS_CS 0xf000 -extern ulong _i386boot_bios; -extern ulong _i386boot_bios_size; +extern ulong __bios_start; +extern ulong __bios_size; /* these are defined in a 16bit segment and needs * to be accessed with the RELOC_16_xxxx() macros below @@ -141,8 +141,8 @@ static void setvector(int vector, u16 segment, void *handler) int bios_setup(void) { - ulong i386boot_bios = (ulong)&_i386boot_bios + gd->reloc_off; - ulong i386boot_bios_size = (ulong)&_i386boot_bios_size; + ulong bios_start = (ulong)&__bios_start + gd->reloc_off; + ulong bios_size = (ulong)&__bios_size; static int done=0; int vector; @@ -154,13 +154,13 @@ int bios_setup(void) } done = 1; - if (i386boot_bios_size > 65536) { + if (bios_size > 65536) { printf("BIOS too large (%ld bytes, max is 65536)\n", - i386boot_bios_size); + bios_size); return -1; } - memcpy(BIOS_BASE, (void*)i386boot_bios, i386boot_bios_size); + memcpy(BIOS_BASE, (void*)bios_start, bios_size); /* clear bda */ memset(BIOS_DATA, 0, BIOS_DATA_SIZE); diff --git a/arch/i386/lib/board.c b/arch/i386/lib/board.c index 00976a5d49..e7a363da70 100644 --- a/arch/i386/lib/board.c +++ b/arch/i386/lib/board.c @@ -48,11 +48,11 @@ DECLARE_GLOBAL_DATA_PTR; /* Exports from the Linker Script */ -extern ulong _i386boot_text_start; -extern ulong _i386boot_rel_dyn_start; -extern ulong _i386boot_rel_dyn_end; -extern ulong _i386boot_bss_start; -extern ulong _i386boot_bss_size; +extern ulong __text_start; +extern ulong __rel_dyn_start; +extern ulong __rel_dyn_end; +extern ulong __bss_start; +extern ulong __bss_size; const char version_string[] = U_BOOT_VERSION" (" U_BOOT_DATE " - " U_BOOT_TIME ")"; @@ -169,12 +169,12 @@ gd_t *gd; */ void board_init_f (ulong gdp) { - void *text_start = &_i386boot_text_start; + void *text_start = &__text_start; void *u_boot_cmd_end = &__u_boot_cmd_end; - Elf32_Rel *rel_dyn_start = (Elf32_Rel *)&_i386boot_rel_dyn_start; - Elf32_Rel *rel_dyn_end = (Elf32_Rel *)&_i386boot_rel_dyn_end; - void *bss_start = &_i386boot_bss_start; - ulong bss_size = (ulong)&_i386boot_bss_size; + Elf32_Rel *rel_dyn_start = (Elf32_Rel *)&__rel_dyn_start; + Elf32_Rel *rel_dyn_end = (Elf32_Rel *)&__rel_dyn_end; + void *bss_start = &__bss_start; + ulong bss_size = (ulong)&__bss_size; ulong uboot_size; void *dest_addr; diff --git a/arch/i386/lib/realmode.c b/arch/i386/lib/realmode.c index b3f51230a5..60fe1816a1 100644 --- a/arch/i386/lib/realmode.c +++ b/arch/i386/lib/realmode.c @@ -31,23 +31,23 @@ #define REALMODE_MAILBOX ((char*)0xe00) -extern ulong _i386boot_realmode; -extern ulong _i386boot_realmode_size; +extern ulong __realmode_start; +extern ulong __realmode_size; extern char realmode_enter; int realmode_setup(void) { - ulong i386boot_realmode = (ulong)&_i386boot_realmode + gd->reloc_off; - ulong i386boot_realmode_size = (ulong)&_i386boot_realmode_size; + ulong realmode_start = (ulong)&__realmode_start + gd->reloc_off; + ulong realmode_size = (ulong)&__realmode_size; /* copy the realmode switch code */ - if (i386boot_realmode_size > (REALMODE_MAILBOX-REALMODE_BASE)) { + if (realmode_size > (REALMODE_MAILBOX-REALMODE_BASE)) { printf("realmode switch too large (%ld bytes, max is %d)\n", - i386boot_realmode_size, (REALMODE_MAILBOX-REALMODE_BASE)); + realmode_size, (REALMODE_MAILBOX-REALMODE_BASE)); return -1; } - memcpy(REALMODE_BASE, (void*)i386boot_realmode, i386boot_realmode_size); + memcpy(REALMODE_BASE, (void*)realmode_start, realmode_size); asm("wbinvd\n"); return 0; diff --git a/board/eNET/u-boot.lds b/board/eNET/u-boot.lds index 7b211a8d9a..ef5d9417a2 100644 --- a/board/eNET/u-boot.lds +++ b/board/eNET/u-boot.lds @@ -28,13 +28,12 @@ ENTRY(_start) SECTIONS { . = TEXT_BASE; /* Location of bootcode in flash */ - _i386boot_text_start = .; + __text_start = .; .text : { *(.text); } . = ALIGN(4); .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } - _i386boot_text_size = SIZEOF(.text) + SIZEOF(.rodata); . = ALIGN(4); .data : { *(.data) } @@ -65,28 +64,27 @@ SECTIONS .u_boot_cmd : { *(.u_boot_cmd) } . = ALIGN(4); __u_boot_cmd_end = .; - _i386boot_cmd_start = LOADADDR(.u_boot_cmd); - _i386boot_rel_dyn_start = .; + __rel_dyn_start = .; .rel.dyn : { *(.rel.dyn) } - _i386boot_rel_dyn_end = .; + __rel_dyn_end = .; . = ALIGN(4); - _i386boot_bss_start = ABSOLUTE(.); + __bss_start = ABSOLUTE(.); .bss (NOLOAD) : { *(.bss) } - _i386boot_bss_size = SIZEOF(.bss); + __bss_size = SIZEOF(.bss); /* 16bit realmode trampoline code */ .realmode 0x7c0 : AT ( LOADADDR(.rel.dyn) + SIZEOF(.rel.dyn) ) { KEEP(*(.realmode)) } - _i386boot_realmode = LOADADDR(.realmode); - _i386boot_realmode_size = SIZEOF(.realmode); + __realmode_start = LOADADDR(.realmode); + __realmode_size = SIZEOF(.realmode); /* 16bit BIOS emulation code (just enough to boot Linux) */ .bios 0 : AT ( LOADADDR(.realmode) + SIZEOF(.realmode) ) { KEEP(*(.bios)) } - _i386boot_bios = LOADADDR(.bios); - _i386boot_bios_size = SIZEOF(.bios); + __bios_start = LOADADDR(.bios); + __bios_size = SIZEOF(.bios); /* The load addresses below assumes that the flash * will be mapped so that 0x387f0000 == 0xffff0000 @@ -105,5 +103,4 @@ SECTIONS . = 0xfff0; .resetvec : AT (TEXT_BASE + 0x3fff0) { KEEP(*(.resetvec)); } - _i386boot_end = (LOADADDR(.resetvec) + SIZEOF(.resetvec) ); } From 221914265860a47a0ba8bfa6956097cb045d9b39 Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:32 +1100 Subject: [PATCH 18/20] x86: Rearrange linker script Tidy up the linker script and discard some sections to save space --- arch/i386/lib/board.c | 5 ++-- board/eNET/u-boot.lds | 61 ++++++++++++++++++++----------------------- 2 files changed, 32 insertions(+), 34 deletions(-) diff --git a/arch/i386/lib/board.c b/arch/i386/lib/board.c index e7a363da70..3e89ef4282 100644 --- a/arch/i386/lib/board.c +++ b/arch/i386/lib/board.c @@ -49,6 +49,7 @@ DECLARE_GLOBAL_DATA_PTR; /* Exports from the Linker Script */ extern ulong __text_start; +extern ulong __data_end; extern ulong __rel_dyn_start; extern ulong __rel_dyn_end; extern ulong __bss_start; @@ -170,7 +171,7 @@ gd_t *gd; void board_init_f (ulong gdp) { void *text_start = &__text_start; - void *u_boot_cmd_end = &__u_boot_cmd_end; + void *data_end = &__data_end; Elf32_Rel *rel_dyn_start = (Elf32_Rel *)&__rel_dyn_start; Elf32_Rel *rel_dyn_end = (Elf32_Rel *)&__rel_dyn_end; void *bss_start = &__bss_start; @@ -181,7 +182,7 @@ void board_init_f (ulong gdp) ulong rel_offset; Elf32_Rel *re; - uboot_size = (ulong)u_boot_cmd_end - (ulong)text_start; + uboot_size = (ulong)data_end - (ulong)text_start; dest_addr = (void *)gdp - (uboot_size + (ulong)bss_size); rel_offset = text_start - dest_addr; diff --git a/board/eNET/u-boot.lds b/board/eNET/u-boot.lds index ef5d9417a2..3c52010651 100644 --- a/board/eNET/u-boot.lds +++ b/board/eNET/u-boot.lds @@ -29,51 +29,48 @@ SECTIONS { . = TEXT_BASE; /* Location of bootcode in flash */ __text_start = .; - .text : { *(.text); } + .text : { *(.text*); } . = ALIGN(4); - .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } - - . = ALIGN(4); - - .data : { *(.data) } - . = ALIGN(4); - - .interp : { *(.interp) } - . = ALIGN(4); - - .dynsym : { *(.dynsym) } - . = ALIGN(4); - - .dynstr : { *(.dynstr) } - . = ALIGN(4); - - .hash : { *(.hash) } - . = ALIGN(4); - - .got : { *(.got) } - . = ALIGN(4); - - .got.plt : { *(.got.plt) } - . = ALIGN(4); - - .dynamic (NOLOAD) : { *(.dynamic) } - . = ALIGN(4); - __u_boot_cmd_start = .; .u_boot_cmd : { *(.u_boot_cmd) } . = ALIGN(4); __u_boot_cmd_end = .; - __rel_dyn_start = .; - .rel.dyn : { *(.rel.dyn) } - __rel_dyn_end = .; + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(4); + .data : { *(.data*) } + + . = ALIGN(4); + .dynsym : { *(.dynsym*) } + + . = ALIGN(4); + .hash : { *(.hash*) } + + . = ALIGN(4); + .got : { *(.got*) } + + . = ALIGN(4); + __data_end = .; . = ALIGN(4); __bss_start = ABSOLUTE(.); .bss (NOLOAD) : { *(.bss) } __bss_size = SIZEOF(.bss); + . = ALIGN(4); + __rel_dyn_start = .; + .rel.dyn : { *(.rel.dyn) } + __rel_dyn_end = .; + + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu*) } + /* 16bit realmode trampoline code */ .realmode 0x7c0 : AT ( LOADADDR(.rel.dyn) + SIZEOF(.rel.dyn) ) { KEEP(*(.realmode)) } From f2ff75c0a25eb78b4b86fd96c5f0be9dd327e2d7 Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:33 +1100 Subject: [PATCH 19/20] x86: Use loops instead of memcpy/memset in board_init_f Provides a small speed increase and prepares for fully relocatable image. Downside is the TEXT_BASE, bss, load address etc must ALL be aligned on a a 4-byte boundary which is not such a terrible restriction as everything is already 4-byte aligned anyway --- arch/i386/lib/board.c | 47 ++++++++++++++++++++++++++++--------------- board/eNET/u-boot.lds | 3 ++- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/arch/i386/lib/board.c b/arch/i386/lib/board.c index 3e89ef4282..9c2f77fd54 100644 --- a/arch/i386/lib/board.c +++ b/arch/i386/lib/board.c @@ -53,7 +53,7 @@ extern ulong __data_end; extern ulong __rel_dyn_start; extern ulong __rel_dyn_end; extern ulong __bss_start; -extern ulong __bss_size; +extern ulong __bss_end; const char version_string[] = U_BOOT_VERSION" (" U_BOOT_DATE " - " U_BOOT_TIME ")"; @@ -172,18 +172,22 @@ void board_init_f (ulong gdp) { void *text_start = &__text_start; void *data_end = &__data_end; - Elf32_Rel *rel_dyn_start = (Elf32_Rel *)&__rel_dyn_start; - Elf32_Rel *rel_dyn_end = (Elf32_Rel *)&__rel_dyn_end; + void *rel_dyn_start = &__rel_dyn_start; + void *rel_dyn_end = &__rel_dyn_end; void *bss_start = &__bss_start; - ulong bss_size = (ulong)&__bss_size; + void *bss_end = &__bss_end; + + ulong *dst_addr; + ulong *src_addr; + ulong *end_addr; - ulong uboot_size; void *dest_addr; ulong rel_offset; - Elf32_Rel *re; + Elf32_Rel *re_src; + Elf32_Rel *re_end; - uboot_size = (ulong)data_end - (ulong)text_start; - dest_addr = (void *)gdp - (uboot_size + (ulong)bss_size); + /* Calculate destination RAM Address and relocation offset */ + dest_addr = (void *)gdp - (bss_end - text_start); rel_offset = text_start - dest_addr; /* First stage CPU initialization */ @@ -195,18 +199,29 @@ void board_init_f (ulong gdp) hang(); /* Copy U-Boot into RAM */ - memcpy(dest_addr, text_start, uboot_size); + dst_addr = (ulong *)dest_addr; + src_addr = (ulong *)text_start; + end_addr = (ulong *)data_end; + + while (src_addr < end_addr) + *dst_addr++ = *src_addr++; /* Clear BSS */ - memset(bss_start - rel_offset, 0, bss_size); + dst_addr = (ulong *)(bss_start - rel_offset); + end_addr = (ulong *)(bss_end - rel_offset); + + while (dst_addr < end_addr) + *dst_addr++ = 0x00000000; /* Perform relocation adjustments */ - for (re = rel_dyn_start; re < rel_dyn_end; re++) - { - if (re->r_offset >= TEXT_BASE) - if (*(ulong *)re->r_offset >= TEXT_BASE) - *(ulong *)(re->r_offset - rel_offset) -= (Elf32_Addr)rel_offset; - } + re_src = (Elf32_Rel *)rel_dyn_start; + re_end = (Elf32_Rel *)rel_dyn_end; + + do { + if (re_src->r_offset >= TEXT_BASE) + if (*(Elf32_Addr *)(re_src->r_offset - rel_offset) >= TEXT_BASE) + *(Elf32_Addr *)(re_src->r_offset - rel_offset) -= rel_offset; + } while (re_src++ < re_end); ((gd_t *)gdp)->reloc_off = rel_offset; ((gd_t *)gdp)->flags |= GD_FLG_RELOC; diff --git a/board/eNET/u-boot.lds b/board/eNET/u-boot.lds index 3c52010651..b414079bc1 100644 --- a/board/eNET/u-boot.lds +++ b/board/eNET/u-boot.lds @@ -58,7 +58,8 @@ SECTIONS . = ALIGN(4); __bss_start = ABSOLUTE(.); .bss (NOLOAD) : { *(.bss) } - __bss_size = SIZEOF(.bss); + . = ALIGN(4); + __bss_end = ABSOLUTE(.); . = ALIGN(4); __rel_dyn_start = .; From c868af3e57610b41c6ed4fd8d8744d8cc0a21b29 Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Thu, 7 Oct 2010 20:03:33 +1100 Subject: [PATCH 20/20] x86: Implement fully relocatable image u-boot.bin can be loaded at any 4-byte aligned memory location and directly 'jumped' to using the 'go' command using the load address as the start address. Doing so performs a 'warm boot' which skips memory initialisation and other low-level initialisations, relocates U-Boot to upper memory and starts U-Boot in RAM as per normal 'cold boot' --- arch/i386/cpu/start.S | 6 ++++++ arch/i386/include/asm/global_data.h | 28 +++++++++++++++------------- arch/i386/lib/board.c | 23 +++++++++++++---------- 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/arch/i386/cpu/start.S b/arch/i386/cpu/start.S index 8fdcd81c1e..829468fe7e 100644 --- a/arch/i386/cpu/start.S +++ b/arch/i386/cpu/start.S @@ -118,6 +118,11 @@ mem_ok: wbinvd + /* Determine our load offset */ + call 1f +1: popl %ecx + subl $1b, %ecx + /* Set the upper memory limit parameter */ subl $CONFIG_SYS_STACK_SIZE, %eax @@ -127,6 +132,7 @@ mem_ok: /* %eax points to the global data structure */ movl %esp, (GD_RAM_SIZE * 4)(%eax) movl %ebx, (GD_FLAGS * 4)(%eax) + movl %ecx, (GD_LOAD_OFF * 4)(%eax) call board_init_f /* Enter, U-boot! */ diff --git a/arch/i386/include/asm/global_data.h b/arch/i386/include/asm/global_data.h index a15c5981c6..597112318f 100644 --- a/arch/i386/include/asm/global_data.h +++ b/arch/i386/include/asm/global_data.h @@ -41,6 +41,7 @@ typedef struct { unsigned long baudrate; unsigned long have_console; /* serial_init() was called */ unsigned long reloc_off; /* Relocation Offset */ + unsigned long load_off; /* Load Offset */ unsigned long env_addr; /* Address of Environment struct */ unsigned long env_valid; /* Checksum of Environment valid? */ unsigned long cpu_clk; /* CPU clock in Hz! */ @@ -56,20 +57,21 @@ extern gd_t *gd; #endif /* Word Offsets into Global Data - MUST match struct gd_t */ -#define GD_BD 0 -#define GD_FLAGS 1 -#define GD_BAUDRATE 2 -#define GD_HAVE_CONSOLE 3 -#define GD_RELOC_OFF 4 -#define GD_ENV_ADDR 5 -#define GD_ENV_VALID 6 -#define GD_CPU_CLK 7 -#define GD_BUS_CLK 8 -#define GD_RAM_SIZE 9 -#define GD_RESET_STATUS 10 -#define GD_JT 11 +#define GD_BD 0 +#define GD_FLAGS 1 +#define GD_BAUDRATE 2 +#define GD_HAVE_CONSOLE 3 +#define GD_RELOC_OFF 4 +#define GD_LOAD_OFF 5 +#define GD_ENV_ADDR 6 +#define GD_ENV_VALID 7 +#define GD_CPU_CLK 8 +#define GD_BUS_CLK 9 +#define GD_RAM_SIZE 10 +#define GD_RESET_STATUS 11 +#define GD_JT 12 -#define GD_SIZE 12 +#define GD_SIZE 13 /* * Global Data Flags diff --git a/arch/i386/lib/board.c b/arch/i386/lib/board.c index 9c2f77fd54..1129918fe2 100644 --- a/arch/i386/lib/board.c +++ b/arch/i386/lib/board.c @@ -190,18 +190,21 @@ void board_init_f (ulong gdp) dest_addr = (void *)gdp - (bss_end - text_start); rel_offset = text_start - dest_addr; - /* First stage CPU initialization */ - if (cpu_init_f() != 0) - hang(); + /* Perform low-level initialization only when cold booted */ + if (((gd_t *)gdp)->flags & GD_FLG_COLD_BOOT) { + /* First stage CPU initialization */ + if (cpu_init_f() != 0) + hang(); - /* First stage Board initialization */ - if (board_early_init_f() != 0) - hang(); + /* First stage Board initialization */ + if (board_early_init_f() != 0) + hang(); + } /* Copy U-Boot into RAM */ dst_addr = (ulong *)dest_addr; - src_addr = (ulong *)text_start; - end_addr = (ulong *)data_end; + src_addr = (ulong *)(text_start + ((gd_t *)gdp)->load_off); + end_addr = (ulong *)(data_end + ((gd_t *)gdp)->load_off); while (src_addr < end_addr) *dst_addr++ = *src_addr++; @@ -214,8 +217,8 @@ void board_init_f (ulong gdp) *dst_addr++ = 0x00000000; /* Perform relocation adjustments */ - re_src = (Elf32_Rel *)rel_dyn_start; - re_end = (Elf32_Rel *)rel_dyn_end; + re_src = (Elf32_Rel *)(rel_dyn_start + ((gd_t *)gdp)->load_off); + re_end = (Elf32_Rel *)(rel_dyn_end + ((gd_t *)gdp)->load_off); do { if (re_src->r_offset >= TEXT_BASE)