[U-Boot] [PATCH v2 1/9] x86: Add function to get top of usable ram

The memory layout calculations are done in calculate_relocation_address(), and coreboot has its own version of this function. But in fact all we really need is to set the top of usable RAM, and then the base version will work as is.
So instead of allowing the whole calculate_relocation_address() function to be replaced, create board_get_usable_ram_top() which can be used by a board to specify the top of the area where U-Boot relocations to.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: None
arch/x86/cpu/coreboot/sdram.c | 18 ++++-------------- arch/x86/lib/init_helpers.c | 28 ++++++++++++++++++---------- 2 files changed, 22 insertions(+), 24 deletions(-)
diff --git a/arch/x86/cpu/coreboot/sdram.c b/arch/x86/cpu/coreboot/sdram.c index 76274cb..a8136a0 100644 --- a/arch/x86/cpu/coreboot/sdram.c +++ b/arch/x86/cpu/coreboot/sdram.c @@ -60,12 +60,8 @@ unsigned install_e820_map(unsigned max_entries, struct e820entry *entries) * address, and how far U-Boot is moved by relocation are set in the global * data structure. */ -int calculate_relocation_address(void) +ulong board_get_usable_ram_top(ulong total_size) { - const uint64_t uboot_size = (uintptr_t)&__bss_end - - (uintptr_t)&__text_start; - const uint64_t total_size = uboot_size + CONFIG_SYS_MALLOC_LEN + - CONFIG_SYS_STACK_SIZE; uintptr_t dest_addr = 0; int i;
@@ -87,21 +83,15 @@ int calculate_relocation_address(void) continue;
/* Use this address if it's the largest so far. */ - if (end - uboot_size > dest_addr) + if (end > dest_addr) dest_addr = end; }
/* If no suitable area was found, return an error. */ if (!dest_addr) - return 1; + panic("No available memory found for relocation");
- dest_addr -= uboot_size; - dest_addr &= ~((1 << 12) - 1); - gd->relocaddr = dest_addr; - gd->reloc_off = dest_addr - (uintptr_t)&__text_start; - gd->start_addr_sp = dest_addr - CONFIG_SYS_MALLOC_LEN; - - return 0; + return (ulong)dest_addr; }
int dram_init_f(void) diff --git a/arch/x86/lib/init_helpers.c b/arch/x86/lib/init_helpers.c index 3eec9a6..1a097f1 100644 --- a/arch/x86/lib/init_helpers.c +++ b/arch/x86/lib/init_helpers.c @@ -73,26 +73,34 @@ 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;
+ total_size = ALIGN(uboot_size, 1 << 12) + CONFIG_SYS_MALLOC_LEN + + CONFIG_SYS_STACK_SIZE; + /* * NOTE: All destination address are rounded down to 16-byte * boundary to satisfy various worst-case alignment * requirements */ + dest_addr = board_get_usable_ram_top(total_size);
- /* 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; + /* 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;

At present most x86 cache operations are undefined. Add a basic implementation for these.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: None
arch/x86/cpu/cpu.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 6a23974..1a2f85c 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -228,3 +228,26 @@ void flush_dcache_range(unsigned long start, unsigned long stop) void invalidate_dcache_range(unsigned long start, unsigned long stop) { } + +void dcache_enable(void) +{ + enable_caches(); +} + +void dcache_disable(void) +{ + disable_caches(); +} + +void icache_enable(void) +{ +} + +void icache_disable(void) +{ +} + +int icache_status(void) +{ + return 1; +}

It is useful to be able to access the timer before U-Boot has relocated so that we can fully support bootstage.
Add new global_data members to support this.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Put timer variables in arch_global_data instead of data section
arch/x86/cpu/coreboot/coreboot.c | 15 ++++++--------- arch/x86/cpu/interrupts.c | 7 +++---- arch/x86/include/asm/global_data.h | 3 +++ arch/x86/lib/timer.c | 9 ++++----- 4 files changed, 16 insertions(+), 18 deletions(-)
diff --git a/arch/x86/cpu/coreboot/coreboot.c b/arch/x86/cpu/coreboot/coreboot.c index 9c9431e..f8e28f0 100644 --- a/arch/x86/cpu/coreboot/coreboot.c +++ b/arch/x86/cpu/coreboot/coreboot.c @@ -68,24 +68,21 @@ int board_early_init_r(void) void show_boot_progress(int val) { #if MIN_PORT80_KCLOCKS_DELAY - static uint32_t prev_stamp; - static uint32_t base; - /* * Scale the time counter reading to avoid using 64 bit arithmetics. * Can't use get_timer() here becuase it could be not yet * initialized or even implemented. */ - if (!prev_stamp) { - base = rdtsc() / 1000; - prev_stamp = 0; + if (!gd->arch.tsc_prev) { + gd->arch.tsc_base_kclocks = rdtsc() / 1000; + gd->arch.tsc_prev = 0; } else { uint32_t now;
do { - now = rdtsc() / 1000 - base; - } while (now < (prev_stamp + MIN_PORT80_KCLOCKS_DELAY)); - prev_stamp = now; + now = rdtsc() / 1000 - gd->arch.tsc_base_kclocks; + } while (now < (gd->arch.tsc_prev + MIN_PORT80_KCLOCKS_DELAY)); + gd->arch.tsc_prev = now; } #endif outb(val, 0x80); diff --git a/arch/x86/cpu/interrupts.c b/arch/x86/cpu/interrupts.c index dd30a05..6dc74e3 100644 --- a/arch/x86/cpu/interrupts.c +++ b/arch/x86/cpu/interrupts.c @@ -626,13 +626,12 @@ asm(".globl irq_common_entry\n" \ */ u64 get_ticks(void) { - static u64 tick_base; u64 now_tick = rdtsc();
- if (!tick_base) - tick_base = now_tick; + if (!gd->arch.tsc_base) + gd->arch.tsc_base = now_tick;
- return now_tick - tick_base; + return now_tick - gd->arch.tsc_base; }
#define PLATFORM_INFO_MSR 0xce diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 8a96fc9..2f84abd 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -29,6 +29,9 @@ /* Architecture-specific global data */ struct arch_global_data { struct global_data *gd_addr; /* Location of Global Data */ + uint64_t tsc_base; /* Initial value returned by rdtsc() */ + uint32_t tsc_base_kclocks; /* Initial tsc as a kclocks value */ + uint32_t tsc_prev; /* For show_boot_progress() */ };
#endif diff --git a/arch/x86/lib/timer.c b/arch/x86/lib/timer.c index a13424b..1f8ce60 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; }

With this symbol we can easy append something (e.g. an FDT) to the U-Boot binary and access it from within U-Boot.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Use _end instead of __end to fit in with other archs
arch/x86/cpu/u-boot.lds | 2 ++ arch/x86/include/asm/u-boot-x86.h | 1 + arch/x86/lib/init_helpers.c | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/arch/x86/cpu/u-boot.lds b/arch/x86/cpu/u-boot.lds index 2313cd7..8e185f3 100644 --- a/arch/x86/cpu/u-boot.lds +++ b/arch/x86/cpu/u-boot.lds @@ -67,6 +67,8 @@ SECTIONS __rel_dyn_start = .; .rel.dyn : { *(.rel.dyn) } __rel_dyn_end = .; + . = ALIGN(4); + _end = .;
/DISCARD/ : { *(.dynstr*) } /DISCARD/ : { *(.dynamic*) } diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index 99062e5..948615d 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -31,6 +31,7 @@ extern ulong __rel_dyn_start; extern ulong __rel_dyn_end; extern ulong __bss_start; extern ulong __bss_end; +extern ulong _end;
/* cpu/.../cpu.c */ int x86_cpu_init_r(void); diff --git a/arch/x86/lib/init_helpers.c b/arch/x86/lib/init_helpers.c index 1a097f1..ff2d21f 100644 --- a/arch/x86/lib/init_helpers.c +++ b/arch/x86/lib/init_helpers.c @@ -188,7 +188,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,

At present BSS data is including in the image, which wastes binary space. Remove it by rearranging the sections so that BSS is last.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: None
arch/x86/cpu/u-boot.lds | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/arch/x86/cpu/u-boot.lds b/arch/x86/cpu/u-boot.lds index 8e185f3..54f2fb7 100644 --- a/arch/x86/cpu/u-boot.lds +++ b/arch/x86/cpu/u-boot.lds @@ -46,9 +46,6 @@ SECTIONS .data : { *(.data*) }
. = ALIGN(4); - .dynsym : { *(.dynsym*) } - - . = ALIGN(4); .hash : { *(.hash*) }
. = ALIGN(4); @@ -58,10 +55,7 @@ SECTIONS __data_end = .;
. = ALIGN(4); - __bss_start = ABSOLUTE(.); - .bss (NOLOAD) : { *(.bss) } - . = ALIGN(4); - __bss_end = ABSOLUTE(.); + .dynsym : { *(.dynsym*) }
. = ALIGN(4); __rel_dyn_start = .; @@ -70,6 +64,17 @@ SECTIONS . = ALIGN(4); _end = .;
+ . = ALIGN(4); + + __end = .; + .bss __rel_dyn_start (OVERLAY) : { + __bss_start = .; + *(.bss) + *(COM*) + . = ALIGN(4); + __bss_end = .; + } + /DISCARD/ : { *(.dynstr*) } /DISCARD/ : { *(.dynamic*) } /DISCARD/ : { *(.plt*) }

With CONFIG_OF_CONTROL we may have an FDT in the BSS region. Relocate it up with the rest of U-Boot to keep the rest of memory free.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Use arch-specific data for new fdt pointer
arch/x86/include/asm/global_data.h | 1 + arch/x86/include/asm/init_helpers.h | 2 ++ arch/x86/include/asm/relocate.h | 1 + arch/x86/lib/board.c | 3 +++ arch/x86/lib/init_helpers.c | 23 +++++++++++++++++++++-- arch/x86/lib/init_wrappers.c | 1 + arch/x86/lib/relocate.c | 17 +++++++++++++++++ 7 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 2f84abd..4fdb080 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -32,6 +32,7 @@ struct arch_global_data { uint64_t tsc_base; /* Initial value returned by rdtsc() */ uint32_t tsc_base_kclocks; /* Initial tsc as a kclocks value */ uint32_t tsc_prev; /* For show_boot_progress() */ + void *new_fdt; /* Relocated FDT */ };
#endif diff --git a/arch/x86/include/asm/init_helpers.h b/arch/x86/include/asm/init_helpers.h index 2f437e0..d018b29 100644 --- a/arch/x86/include/asm/init_helpers.h +++ b/arch/x86/include/asm/init_helpers.h @@ -38,5 +38,7 @@ int flash_init_r(void); int status_led_set_r(void); int set_load_addr_r(void); int init_func_spi(void); +int find_fdt(void); +int prepare_fdt(void);
#endif /* !_INIT_HELPERS_H_ */ diff --git a/arch/x86/include/asm/relocate.h b/arch/x86/include/asm/relocate.h index 33129ef..d371c9d 100644 --- a/arch/x86/include/asm/relocate.h +++ b/arch/x86/include/asm/relocate.h @@ -27,6 +27,7 @@ #include <common.h>
int copy_uboot_to_ram(void); +int copy_fdt_to_ram(void); int clear_bss(void); int do_elf_reloc_fixups(void);
diff --git a/arch/x86/lib/board.c b/arch/x86/lib/board.c index 22bc26d..2441a66 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 ff2d21f..414fdcc 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> @@ -85,17 +86,35 @@ int calculate_relocation_address(void) (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; + 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 */ - dest_addr = board_get_usable_ram_top(total_size); + 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); diff --git a/arch/x86/lib/init_wrappers.c b/arch/x86/lib/init_wrappers.c index cca018f..19af875 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 23edca9..3a38e52 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;

This does not actually change normal behaviour, but adds a check that should detect corruption of relocation data (e.g. by using BSS data prior to relocation).
Also add additional debugging output when enabled.
During this investigation, two situations have been seen: 1. calculate_relocation_address(): uintptr_t size = (uintptr_t)&__bss_end - (uintptr_t)&__text_start;
turns into 111166f: b8 83 c4 17 01 mov $0x117c483,%eax
whih is beyond the end of bss:
0117b484 g .bss 00000000 __bss_end
Somehow the __bss_end here is 255 bytes ahead.
2. do_elf_reloc_fixups():
uintptr_t size = (uintptr_t)&__bss_end - (uintptr_t)&__text_start;
Here the __text_start is 0 in the file:
1111d9f: bb a0 e0 13 01 mov $0x113e0a0,%ebx 1111da4: 81 ef 00 00 00 00 sub $0x0,%edi
As it happens, both of these are in pre-relocation code.
For these reasons we silent check and ignore bad relocations.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: None
arch/x86/lib/relocate.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/arch/x86/lib/relocate.c b/arch/x86/lib/relocate.c index 3a38e52..3e370f2 100644 --- a/arch/x86/lib/relocate.c +++ b/arch/x86/lib/relocate.c @@ -73,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. */ @@ -89,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 + @@ -100,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;

This is currently set to coreboot.dtsi, but we cannot support this on old device tree compilers (dtc <= 1.3), so adjust to use ARCH_CPU_DTS to let the Makefile preprocessor sort this out.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: None
board/chromebook-x86/dts/link.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/board/chromebook-x86/dts/link.dts b/board/chromebook-x86/dts/link.dts index af60f59..ae8217d 100644 --- a/board/chromebook-x86/dts/link.dts +++ b/board/chromebook-x86/dts/link.dts @@ -1,6 +1,6 @@ /dts-v1/;
-/include/ "coreboot.dtsi" +/include/ ARCH_CPU_DTS
/ { #address-cells = <1>;

Make use of a device tree on coreboot boards, and set the default to link.
Signed-off-by: Simon Glass sjg@chromium.org --- Changes in v2: - Drop patch which removes real mode code since it was already dealt with
include/configs/coreboot.h | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/include/configs/coreboot.h b/include/configs/coreboot.h index c7f36ff..49f05de 100644 --- a/include/configs/coreboot.h +++ b/include/configs/coreboot.h @@ -42,6 +42,12 @@ #define CONFIG_ZBOOT_32 #define CONFIG_PHYSMEM
+#define CONFIG_LMB +#define CONFIG_OF_LIBFDT +#define CONFIG_OF_CONTROL +#define CONFIG_OF_SEPARATE +#define CONFIG_DEFAULT_DEVICE_TREE link + /*----------------------------------------------------------------------- * Watchdog Configuration */
participants (1)
-
Simon Glass