diff options
Diffstat (limited to 'arch/x86/lib')
-rw-r--r-- | arch/x86/lib/board.c | 3 | ||||
-rw-r--r-- | arch/x86/lib/init_helpers.c | 49 | ||||
-rw-r--r-- | arch/x86/lib/init_wrappers.c | 1 | ||||
-rw-r--r-- | arch/x86/lib/relocate.c | 37 | ||||
-rw-r--r-- | arch/x86/lib/timer.c | 9 |
5 files changed, 81 insertions, 18 deletions
diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 22bc26dde9..2441a66ae2 100644 --- a/arch/x86/lib/board.c +++ b/arch/x86/lib/board.c @@ -32,6 +32,7 @@ */ #include <common.h> +#include <fdtdec.h> #include <watchdog.h> #include <stdio_dev.h> #include <asm/u-boot-x86.h> @@ -131,6 +132,7 @@ init_fnc_t *init_sequence_f[] = { init_fnc_t *init_sequence_f_r[] = { init_cache_f_r, copy_uboot_to_ram, + copy_fdt_to_ram, clear_bss, do_elf_reloc_fixups, @@ -217,6 +219,7 @@ static void do_init_loop(init_fnc_t **init_fnc_ptr) void board_init_f(ulong boot_flags) { + gd->fdt_blob = gd->arch.new_fdt = NULL; gd->flags = boot_flags; do_init_loop(init_sequence_f); diff --git a/arch/x86/lib/init_helpers.c b/arch/x86/lib/init_helpers.c index 3eec9a61d6..414fdcc4c9 100644 --- a/arch/x86/lib/init_helpers.c +++ b/arch/x86/lib/init_helpers.c @@ -22,6 +22,7 @@ */ #include <common.h> #include <command.h> +#include <fdtdec.h> #include <stdio_dev.h> #include <version.h> #include <malloc.h> @@ -73,26 +74,52 @@ int init_baudrate_f(void) return 0; } -__weak int calculate_relocation_address(void) +/* Get the top of usable RAM */ +__weak ulong board_get_usable_ram_top(ulong total_size) { - ulong text_start = (ulong)&__text_start; - ulong bss_end = (ulong)&__bss_end; + return gd->ram_size; +} + +int calculate_relocation_address(void) +{ + const ulong uboot_size = (uintptr_t)&__bss_end - + (uintptr_t)&__text_start; + ulong total_size; ulong dest_addr; + ulong fdt_size = 0; +#if defined(CONFIG_OF_SEPARATE) && defined(CONFIG_OF_CONTROL) + if (gd->fdt_blob) + fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32); +#endif + total_size = ALIGN(uboot_size, 1 << 12) + CONFIG_SYS_MALLOC_LEN + + CONFIG_SYS_STACK_SIZE + fdt_size; + + dest_addr = board_get_usable_ram_top(total_size); /* * NOTE: All destination address are rounded down to 16-byte * boundary to satisfy various worst-case alignment * requirements */ - - /* Stack is at top of available memory */ - dest_addr = gd->ram_size; - - /* U-Boot is at the top */ - dest_addr -= (bss_end - text_start); dest_addr &= ~15; + +#if defined(CONFIG_OF_SEPARATE) && defined(CONFIG_OF_CONTROL) + /* + * If the device tree is sitting immediate above our image then we + * must relocate it. If it is embedded in the data section, then it + * will be relocated with other data. + */ + if (gd->fdt_blob) { + dest_addr -= fdt_size; + gd->arch.new_fdt = (void *)dest_addr; + dest_addr &= ~15; + } +#endif + /* U-Boot is below the FDT */ + dest_addr -= uboot_size; + dest_addr &= ~((1 << 12) - 1); gd->relocaddr = dest_addr; - gd->reloc_off = (dest_addr - text_start); + gd->reloc_off = dest_addr - (uintptr_t)&__text_start; /* Stack is at the bottom, so it can grow down */ gd->start_addr_sp = dest_addr - CONFIG_SYS_MALLOC_LEN; @@ -180,7 +207,7 @@ int find_fdt(void) gd->fdt_blob = _binary_dt_dtb_start; #elif defined CONFIG_OF_SEPARATE /* FDT is at end of image */ - gd->fdt_blob = (void *)(_end_ofs + _TEXT_BASE); + gd->fdt_blob = (ulong *)&_end; #endif /* Allow the early environment to override the fdt address */ gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16, diff --git a/arch/x86/lib/init_wrappers.c b/arch/x86/lib/init_wrappers.c index cca018fa9b..19af875c0e 100644 --- a/arch/x86/lib/init_wrappers.c +++ b/arch/x86/lib/init_wrappers.c @@ -22,6 +22,7 @@ */ #include <common.h> #include <environment.h> +#include <fdtdec.h> #include <serial.h> #include <kgdb.h> #include <scsi.h> diff --git a/arch/x86/lib/relocate.c b/arch/x86/lib/relocate.c index 23edca9526..3e370f2906 100644 --- a/arch/x86/lib/relocate.c +++ b/arch/x86/lib/relocate.c @@ -32,6 +32,7 @@ */ #include <common.h> +#include <libfdt.h> #include <malloc.h> #include <asm/u-boot-x86.h> #include <asm/relocate.h> @@ -46,6 +47,22 @@ int copy_uboot_to_ram(void) return 0; } +int copy_fdt_to_ram(void) +{ + if (gd->arch.new_fdt) { + ulong fdt_size; + + fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32); + + memcpy(gd->arch.new_fdt, gd->fdt_blob, fdt_size); + debug("Relocated fdt from %p to %p, size %lx\n", + gd->fdt_blob, gd->arch.new_fdt, fdt_size); + gd->fdt_blob = gd->arch.new_fdt; + } + + return 0; +} + int clear_bss(void) { ulong dst_addr = (ulong)&__bss_start + gd->reloc_off; @@ -56,12 +73,16 @@ int clear_bss(void) return 0; } +/* + * This function has more error checking than you might expect. Please see + * the commit message for more informaiton. + */ int do_elf_reloc_fixups(void) { Elf32_Rel *re_src = (Elf32_Rel *)(&__rel_dyn_start); Elf32_Rel *re_end = (Elf32_Rel *)(&__rel_dyn_end); - Elf32_Addr *offset_ptr_rom; + Elf32_Addr *offset_ptr_rom, *last_offset = NULL; Elf32_Addr *offset_ptr_ram; /* The size of the region of u-boot that runs out of RAM. */ @@ -72,7 +93,8 @@ int do_elf_reloc_fixups(void) offset_ptr_rom = (Elf32_Addr *)re_src->r_offset; /* Check that the location of the relocation is in .text */ - if (offset_ptr_rom >= (Elf32_Addr *)CONFIG_SYS_TEXT_BASE) { + if (offset_ptr_rom >= (Elf32_Addr *)CONFIG_SYS_TEXT_BASE && + offset_ptr_rom > last_offset) { /* Switch to the in-RAM version */ offset_ptr_ram = (Elf32_Addr *)((ulong)offset_ptr_rom + @@ -83,8 +105,19 @@ int do_elf_reloc_fixups(void) *offset_ptr_ram <= (CONFIG_SYS_TEXT_BASE + size)) { *offset_ptr_ram += gd->reloc_off; + } else { + debug(" %p: rom reloc %x, ram %p, value %x," + " limit %lx\n", re_src, + re_src->r_offset, offset_ptr_ram, + *offset_ptr_ram, + CONFIG_SYS_TEXT_BASE + size); } + } else { + debug(" %p: rom reloc %x, last %p\n", re_src, + re_src->r_offset, last_offset); } + last_offset = offset_ptr_rom; + } while (++re_src < re_end); return 0; diff --git a/arch/x86/lib/timer.c b/arch/x86/lib/timer.c index a13424b3e3..1f8ce609e2 100644 --- a/arch/x86/lib/timer.c +++ b/arch/x86/lib/timer.c @@ -37,7 +37,6 @@ struct timer_isr_function { static struct timer_isr_function *first_timer_isr; static unsigned long system_ticks; -static uint64_t base_value; /* * register_timer_isr() allows multiple architecture and board specific @@ -102,7 +101,7 @@ ulong get_timer(ulong base) void timer_set_tsc_base(uint64_t new_base) { - base_value = new_base; + gd->arch.tsc_base = new_base; } uint64_t timer_get_tsc(void) @@ -110,8 +109,8 @@ uint64_t timer_get_tsc(void) uint64_t time_now; time_now = rdtsc(); - if (!base_value) - base_value = time_now; + if (!gd->arch.tsc_base) + gd->arch.tsc_base = time_now; - return time_now - base_value; + return time_now - gd->arch.tsc_base; } |