From 1c409bc7101a24ecd47a13a4e851845d66dc23ce Mon Sep 17 00:00:00 2001 From: Graeme Russ Date: Tue, 24 Nov 2009 20:04:21 +1100 Subject: [PATCH] i386: Final Relocation Signed-off-by: Graeme Russ --- board/eNET/config.mk | 2 + board/eNET/eNET.c | 11 ++- board/eNET/u-boot.lds | 34 +++++-- cpu/i386/cpu.c | 8 +- cpu/i386/interrupts.c | 4 +- cpu/i386/start.S | 132 ++++----------------------- include/asm-i386/u-boot-i386.h | 14 +-- include/configs/eNET.h | 2 + lib_i386/board.c | 157 +++++++++++++++++++-------------- lib_i386/interrupts.c | 4 +- lib_i386/timer.c | 2 +- 11 files changed, 158 insertions(+), 212 deletions(-) diff --git a/board/eNET/config.mk b/board/eNET/config.mk index c9703ea8e8..5c64804fb2 100644 --- a/board/eNET/config.mk +++ b/board/eNET/config.mk @@ -23,4 +23,6 @@ TEXT_BASE = 0x38040000 CFLAGS_dlmalloc.o += -Wa,--no-warn -fno-strict-aliasing +PLATFORM_RELFLAGS += -fvisibility=hidden PLATFORM_CPPFLAGS += -fno-dwarf2-cfi-asm +PLATFORM_LDFLAGS += -pic --emit-relocs -Bsymbolic -Bsymbolic-functions diff --git a/board/eNET/eNET.c b/board/eNET/eNET.c index 29cf29518a..6d0b15a0fa 100644 --- a/board/eNET/eNET.c +++ b/board/eNET/eNET.c @@ -47,7 +47,6 @@ void init_sc520_enet (void) { /* Set CPU Speed to 100MHz */ sc520_mmcr->cpuctl = 0x01; - gd->cpu_clk = 100000000; /* wait at least one millisecond */ asm("movl $0x2000,%%ecx\n" @@ -67,7 +66,7 @@ void init_sc520_enet (void) /* * Miscellaneous platform dependent initializations */ -int board_init(void) +int board_early_init_f(void) { init_sc520_enet(); @@ -117,6 +116,14 @@ int board_init(void) sc520_mmcr->sysarbctl = 0x06; sc520_mmcr->sysarbmenb = 0x0003; + return 0; +} + +int board_early_init_r(void) +{ + /* CPU Speed to 100MHz */ + gd->cpu_clk = 100000000; + /* Crystal is 33.000MHz */ gd->bus_clk = 33000000; diff --git a/board/eNET/u-boot.lds b/board/eNET/u-boot.lds index 4ea424d320..0d740215ce 100644 --- a/board/eNET/u-boot.lds +++ b/board/eNET/u-boot.lds @@ -28,28 +28,48 @@ ENTRY(_start) SECTIONS { . = 0x38040000; /* Location of bootcode in flash */ + _i386boot_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) } + . = ALIGN(4); + + .interp : { *(.interp) } + . = ALIGN(4); + + .dynsym : { *(.dynsym) } + . = ALIGN(4); - . = 0x03FF0000; /* Ram data segment to use */ - _i386boot_romdata_dest = ABSOLUTE(.); - .data : AT ( LOADADDR(.rodata) + SIZEOF(.rodata) ) { *(.data) } - _i386boot_romdata_start = LOADADDR(.data); + .dynstr : { *(.dynstr) } + . = ALIGN(4); + + .hash : { *(.hash) } + . = ALIGN(4); + .got : { *(.got) } . = ALIGN(4); - .got : AT ( LOADADDR(.data) + SIZEOF(.data) ) { *(.got) } + .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 = .; _i386boot_cmd_start = LOADADDR(.u_boot_cmd); - _i386boot_romdata_size = SIZEOF(.data) + SIZEOF(.got) + SIZEOF(.u_boot_cmd); + _i386boot_rel_dyn_start = .; + .rel.dyn : { *(.rel.dyn) } + _i386boot_rel_dyn_end = .; . = ALIGN(4); _i386boot_bss_start = ABSOLUTE(.); @@ -57,7 +77,7 @@ SECTIONS _i386boot_bss_size = SIZEOF(.bss); /* 16bit realmode trampoline code */ - .realmode 0x7c0 : AT ( LOADADDR(.got) + SIZEOF(.got) + SIZEOF(.u_boot_cmd)) { *(.realmode) } + .realmode 0x7c0 : AT ( LOADADDR(.rel.dyn) + SIZEOF(.rel.dyn) ) { *(.realmode) } _i386boot_realmode = LOADADDR(.realmode); _i386boot_realmode_size = SIZEOF(.realmode); diff --git a/cpu/i386/cpu.c b/cpu/i386/cpu.c index 4b681057a0..3010519e74 100644 --- a/cpu/i386/cpu.c +++ b/cpu/i386/cpu.c @@ -37,7 +37,7 @@ #include #include -int cpu_init(void) +int cpu_init_f(void) { /* initialize FPU, reset EM, set MP and NE */ asm ("fninit\n" \ @@ -46,9 +46,13 @@ int cpu_init(void) "orl $0x22, %eax\n" \ "movl %eax, %cr0\n" ); + return 0; +} + +int cpu_init_r(void) +{ /* Initialize core interrupt and exception functionality of CPU */ cpu_init_interrupts (); - return 0; } diff --git a/cpu/i386/interrupts.c b/cpu/i386/interrupts.c index cbf1c41e17..4b57437193 100644 --- a/cpu/i386/interrupts.c +++ b/cpu/i386/interrupts.c @@ -63,8 +63,8 @@ static inline void load_idt(const struct desc_ptr *dtr) void set_vector(u8 intnum, void *routine) { - idt[intnum].base_high = (u16)((u32)(routine + gd->reloc_off) >> 16); - idt[intnum].base_low = (u16)((u32)(routine + gd->reloc_off) & 0xffff); + idt[intnum].base_high = (u16)((u32)(routine) >> 16); + idt[intnum].base_low = (u16)((u32)(routine) & 0xffff); } void irq_0(void); diff --git a/cpu/i386/start.S b/cpu/i386/start.S index 59089ef59b..25d32e658e 100644 --- a/cpu/i386/start.S +++ b/cpu/i386/start.S @@ -63,11 +63,8 @@ early_board_init_ret: jmp mem_init mem_init_ret: - /* check ammount of configured memory - * (we need atleast bss start+bss size+stack size) */ - movl $_i386boot_bss_start, %ecx /* BSS start */ - addl $_i386boot_bss_size, %ecx /* BSS size */ - addl $CONFIG_SYS_STACK_SIZE, %ecx + /* Check we have enough memory for stack */ + movl $CONFIG_SYS_STACK_SIZE, %ecx cmpl %ecx, %eax jae mem_ok @@ -78,6 +75,8 @@ mem_init_ret: .progress0a: jmp die mem_ok: + /* Set stack pointer to upper memory limit*/ + movl %eax, %esp /* indicate progress */ movw $0x02, %ax @@ -85,12 +84,7 @@ mem_ok: jmp show_boot_progress_asm .progress1: - /* create a stack after the bss */ - movl $_i386boot_bss_start, %eax - addl $_i386boot_bss_size, %eax - addl $CONFIG_SYS_STACK_SIZE, %eax - movl %eax, %esp - + /* Test the stack */ pushl $0 popl %eax cmpl $0, %eax @@ -116,115 +110,19 @@ stack_ok: jmp show_boot_progress_asm .progress2: - /* copy data section to ram, size must be 4-byte aligned */ - movl $_i386boot_romdata_dest, %edi /* destination address */ - movl $_i386boot_romdata_start, %esi /* source address */ - movl $_i386boot_romdata_size, %ecx /* number of bytes to copy */ - movl %ecx, %eax - andl $3, %eax - jnz data_fail - - shrl $2, %ecx /* copy 4 byte each time */ - cld - cmpl $0, %ecx - je data_ok -data_segment: - movsl - loop data_segment - jmp data_ok -data_fail: - /* indicate (lack of) progress */ - movw $0x83, %ax - movl $.progress2a, %ebp - jmp show_boot_progress_asm -.progress2a: - jmp die - -data_ok: - - /* indicate progress */ - movw $0x04, %ax - movl $.progress3, %ebp - jmp show_boot_progress_asm -.progress3: - - /* clear bss section in ram, size must be 4-byte aligned */ - movl $_i386boot_bss_start, %edi /* MK_CHG BSS start */ - movl $_i386boot_bss_size, %ecx /* BSS size */ - movl %ecx, %eax - andl $3, %eax - jnz bss_fail - shrl $2, %ecx /* clear 4 byte each time */ - cld - cmpl $0, %ecx - je bss_ok -bss: - movl $0, (%edi) - add $4, %edi - loop bss - jmp bss_ok - -bss_fail: - /* indicate (lack of) progress */ - movw $0x84, %ax - movl $.progress3a, %ebp - jmp show_boot_progress_asm -.progress3a: - jmp die - -bss_ok: -#ifndef CONFIG_SKIP_RELOCATE_UBOOT - /* indicate progress */ - movw $0x06, %ax - movl $.progress6, %ebp - jmp show_boot_progress_asm -.progress6: - - /* copy text section to ram, size must be 4-byte aligned */ - movl $CONFIG_SYS_BL_START_RAM, %edi /* destination address */ - movl $TEXT_BASE, %esi /* source address */ - movl $_i386boot_text_size, %ecx /* number of bytes to copy */ - movl %ecx, %eax - andl $3, %eax - jz text_copy /* Already 4-byte aligned */ - subl $4, %eax /* Add extra bytes to size */ - addl %eax, %ecx -text_copy: - shrl $2, %ecx /* copy 4 byte each time */ - cld - cmpl $0, %ecx - je text_ok -text_segment: - movsl - loop text_segment - jmp text_ok -text_fail: - /* indicate (lack of) progress */ - movw $0x86, %ax - movl $.progress5a, %ebp - jmp show_boot_progress_asm -.progress5a: - jmp die - -text_ok: -#endif wbinvd + /* Get upper memory limit */ + movl %esp, %ecx + subl $CONFIG_SYS_STACK_SIZE, %ecx - /* indicate progress */ - movw $0x05, %ax - movl $.progress4, %ebp - jmp show_boot_progress_asm -.progress4: - -#ifndef CONFIG_SKIP_RELOCATE_UBOOT - /* Jump to the RAM copy of start_i386boot */ - movl $start_i386boot, %ebp - addl $(CONFIG_SYS_BL_START_RAM - TEXT_BASE), %ebp - call *%ebp /* Enter, U-boot! */ -#else - call start_i386boot /* Enter, U-boot! */ -#endif + /* 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 */ movw $0x85, %ax diff --git a/include/asm-i386/u-boot-i386.h b/include/asm-i386/u-boot-i386.h index 1e8def77d5..7c99c8c57d 100644 --- a/include/asm-i386/u-boot-i386.h +++ b/include/asm-i386/u-boot-i386.h @@ -24,19 +24,9 @@ #ifndef _U_BOOT_I386_H_ #define _U_BOOT_I386_H_ 1 -/* for the following variables, see start.S */ -extern ulong i386boot_start; /* code start (in flash) */ -extern ulong i386boot_end; /* code end (in flash) */ -extern ulong i386boot_romdata_start;/* datasegment in flash (also code+rodata end) */ -extern ulong i386boot_romdata_dest; /* data location segment in ram */ -extern ulong i386boot_romdata_size; /* size of data segment */ -extern ulong i386boot_bss_start; /* bss start */ -extern ulong i386boot_bss_size; /* bss size */ -extern ulong i386boot_stack_end; /* first usable RAM address after bss and stack */ -extern ulong i386boot_ram_end; /* end of ram */ - /* cpu/.../cpu.c */ -int cpu_init(void); +int cpu_init_r(void); +int cpu_init_f(void); /* cpu/.../timer.c */ void timer_isr(void *); diff --git a/include/configs/eNET.h b/include/configs/eNET.h index 0a86550861..6a68bf4938 100644 --- a/include/configs/eNET.h +++ b/include/configs/eNET.h @@ -28,6 +28,8 @@ #ifndef __CONFIG_H #define __CONFIG_H +#define CONFIG_RELOC_FIXUP_WORKS + /* * Stuff still to be dealt with - */ diff --git a/lib_i386/board.c b/lib_i386/board.c index 44fa0e31a4..f3b6348551 100644 --- a/lib_i386/board.c +++ b/lib_i386/board.c @@ -38,6 +38,7 @@ #include #include #include +#include #ifdef CONFIG_BITBANGMII #include @@ -45,41 +46,16 @@ DECLARE_GLOBAL_DATA_PTR; -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; - -/* 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 */ - +/* 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; +void ram_bootstrap (void *); const char version_string[] = U_BOOT_VERSION" (" U_BOOT_DATE " - " U_BOOT_TIME ")"; -static int heap_init(void) -{ - /* start malloc area right after the stack */ - ulong start = i386boot_bss_start + i386boot_bss_size + - CONFIG_SYS_STACK_SIZE; - - /* 4-byte aligned */ - start = (start+3)&~3; - - mem_malloc_init(start, CONFIG_SYS_MALLOC_LEN); - - return 0; -} - /************************************************************************ * Init Utilities * ************************************************************************ @@ -103,6 +79,7 @@ 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, @@ -111,6 +88,7 @@ static int display_banner (void) i386boot_bss_start+i386boot_bss_size, i386boot_bss_start+i386boot_bss_size+CONFIG_SYS_STACK_SIZE-1); +*/ return (0); } @@ -142,7 +120,6 @@ static void display_flash_config (ulong size) print_size (size, "\n"); } - /* * Breath some life into the board... * @@ -154,6 +131,7 @@ static void display_flash_config (ulong size) * 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 @@ -169,13 +147,12 @@ static void display_flash_config (ulong size) typedef int (init_fnc_t) (void); init_fnc_t *init_sequence[] = { - cpu_init, /* basic cpu dependent setup */ - board_init, /* basic board dependent setup */ + serial_init, + cpu_init_r, /* basic cpu dependent setup */ + board_early_init_r, /* basic board dependent setup */ dram_init, /* configure available RAM banks */ - heap_init, /* dependant on dram_init */ interrupt_init, /* set up exceptions */ timer_init, - serial_init, env_init, /* initialize environment */ init_baudrate, /* initialze baudrate settings */ serial_init, /* serial communications setup */ @@ -187,21 +164,86 @@ init_fnc_t *init_sequence[] = { gd_t *gd; -void start_i386boot (void) +/* + * Load U-Boot into RAM, initialize BSS, perform relocation adjustments + */ +void board_init_f (ulong stack_limit) +{ + void *text_start = &_i386boot_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; + void *bss_size = &_i386boot_bss_size; + + size_t uboot_size; + void *ram_start; + ulong rel_offset; + Elf32_Rel *re; + + void (*start_func)(void *); + + /* compiler optimization barrier needed for GCC >= 3.4 */ + __asm__ __volatile__("": : :"memory"); + + uboot_size = (size_t)u_boot_cmd_end - (size_t)text_start; + ram_start = (void *)stack_limit - (uboot_size + (ulong)bss_size); + rel_offset = text_start - ram_start; + start_func = ram_bootstrap - rel_offset; + + /* First stage CPU initialization */ + if (cpu_init_f() != 0) + hang(); + + /* First stage Board initialization */ + if (board_early_init_f() != 0) + hang(); + + /* Copy U-Boot into RAM */ + memcpy(ram_start, text_start, (size_t)uboot_size); + + /* Clear BSS */ + memset(bss_start - rel_offset, 0, (size_t)bss_size); + + /* 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; + } + + start_func(ram_start); + + /* NOTREACHED - relocate_code() does not return */ + while(1); +} + +/* + * All attempts to jump straight from board_init_f() to board_init_r() + * have failed, hence this special 'bootstrap' function. + */ +void ram_bootstrap (void *ram_start) +{ + static gd_t gd_data; + + /* compiler optimization barrier needed for GCC >= 3.4 */ + __asm__ __volatile__("": : :"memory"); + + board_init_r(&gd_data, (ulong)ram_start); +} + +void board_init_r(gd_t *id, ulong ram_start) { char *s; int i; ulong size; - static gd_t gd_data; static bd_t bd_data; init_fnc_t **init_fnc_ptr; -#ifndef CONFIG_SKIP_RELOCATE_UBOOT - cmd_tbl_t *p; -#endif show_boot_progress(0x21); - gd = &gd_data; + gd = id; /* compiler optimization barrier needed for GCC >= 3.4 */ __asm__ __volatile__("": : :"memory"); @@ -212,10 +254,11 @@ void start_i386boot (void) gd->baudrate = CONFIG_BAUDRATE; -#ifndef CONFIG_SKIP_RELOCATE_UBOOT - /* Need to set relocation offset here for interrupt initialization */ - gd->reloc_off = CONFIG_SYS_BL_START_RAM - TEXT_BASE; -#endif + gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */ + + mem_malloc_init((((ulong)ram_start - CONFIG_SYS_MALLOC_LEN)+3)&~3, + CONFIG_SYS_MALLOC_LEN); + for (init_fnc_ptr = init_sequence, i=0; *init_fnc_ptr; ++init_fnc_ptr, i++) { show_boot_progress(0xa130|i); @@ -225,26 +268,6 @@ void start_i386boot (void) } show_boot_progress(0x23); -#ifndef CONFIG_SKIP_RELOCATE_UBOOT - for (p = &__u_boot_cmd_start; p != &__u_boot_cmd_end; p++) { - ulong addr; - addr = (ulong) (p->cmd) + gd->reloc_off; - p->cmd = (int (*)(struct cmd_tbl_s *, int, int, char *[]))addr; - addr = (ulong)(p->name) + gd->reloc_off; - p->name = (char *)addr; - - if (p->usage != NULL) { - addr = (ulong)(p->usage) + gd->reloc_off; - p->usage = (char *)addr; - } - #ifdef CONFIG_SYS_LONGHELP - if (p->help != NULL) { - addr = (ulong)(p->help) + gd->reloc_off; - p->help = (char *)addr; - } - #endif - } -#endif /* configure available FLASH banks */ size = flash_init(); display_flash_config(size); diff --git a/lib_i386/interrupts.c b/lib_i386/interrupts.c index efbad72202..51def59954 100644 --- a/lib_i386/interrupts.c +++ b/lib_i386/interrupts.c @@ -70,12 +70,12 @@ void irq_install_handler(int irq, interrupt_handler_t *handler, void *arg) if (irq_handlers[irq].handler != NULL) printf("irq_install_handler: 0x%08lx replacing 0x%08lx\n", - (ulong) handler + gd->reloc_off, + (ulong) handler, (ulong) irq_handlers[irq].handler); status = disable_interrupts (); - irq_handlers[irq].handler = handler + gd->reloc_off; + irq_handlers[irq].handler = handler; irq_handlers[irq].arg = arg; irq_handlers[irq].count = 0; diff --git a/lib_i386/timer.c b/lib_i386/timer.c index 58a0212ad9..5cb1f54fb5 100644 --- a/lib_i386/timer.c +++ b/lib_i386/timer.c @@ -51,7 +51,7 @@ int register_timer_isr (timer_fnc_t *isr_func) if (new_func == NULL) return 1; - new_func->isr_func = isr_func + gd->reloc_off; + new_func->isr_func = isr_func; new_func->next = NULL; /* -- 2.30.2