diff options
author | Simon Glass <sjg@chromium.org> | 2017-01-16 07:04:15 -0700 |
---|---|---|
committer | Bin Meng <bmeng.cn@gmail.com> | 2017-02-06 11:38:46 +0800 |
commit | fa5fcb3bc60c3c188b91f704b7d0d6b3810c9047 (patch) | |
tree | 9dd3c13424ee132d4acd9c53543a66884a2f161f | |
parent | c2bf0dfaa3b313b941e52e565f6a2d20c02fe11a (diff) |
x86: Support jumping from SPL to U-Boot
Add a rough function to handle jumping from 32-bit SPL to 64-bit U-Boot.
This still needs work to clean it up.
Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
-rw-r--r-- | arch/x86/cpu/call64.S | 3 | ||||
-rw-r--r-- | arch/x86/cpu/i386/cpu.c | 64 | ||||
-rw-r--r-- | arch/x86/include/asm/cpu.h | 9 |
3 files changed, 76 insertions, 0 deletions
diff --git a/arch/x86/cpu/call64.S b/arch/x86/cpu/call64.S index 08dc473d6a..970c461508 100644 --- a/arch/x86/cpu/call64.S +++ b/arch/x86/cpu/call64.S @@ -81,6 +81,9 @@ lret_target: jmp *%eax /* Jump to the 64-bit target */ .data + .align 16 + .globl gdt64 +gdt64: gdt: .word gdt_end - gdt - 1 .long gdt /* Fixed up by code above */ diff --git a/arch/x86/cpu/i386/cpu.c b/arch/x86/cpu/i386/cpu.c index 09a5b919e0..aabdc94bb0 100644 --- a/arch/x86/cpu/i386/cpu.c +++ b/arch/x86/cpu/i386/cpu.c @@ -503,6 +503,70 @@ int cpu_jump_to_64bit(ulong setup_base, ulong target) return -EFAULT; } +/* + * Jump from SPL to U-Boot + * + * This function is work-in-progress with many issues to resolve. + * + * It works by setting up several regions: + * ptr - a place to put the code that jumps into 64-bit mode + * gdt - a place to put the global descriptor table + * pgtable - a place to put the page tables + * + * The cpu_call64() code is copied from ROM and then manually patched so that + * it has the correct GDT address in RAM. U-Boot is copied from ROM into + * its pre-relocation address. Then we jump to the cpu_call64() code in RAM, + * which changes to 64-bit mode and starts U-Boot. + */ +int cpu_jump_to_64bit_uboot(ulong target) +{ + typedef void (*func_t)(ulong pgtable, ulong setup_base, ulong target); + uint32_t *pgtable; + func_t func; + + /* TODO(sjg@chromium.org): Find a better place for this */ + pgtable = (uint32_t *)0x1000000; + if (!pgtable) + return -ENOMEM; + + build_pagetable(pgtable); + + /* TODO(sjg@chromium.org): Find a better place for this */ + char *ptr = (char *)0x3000000; + char *gdt = (char *)0x3100000; + + extern char gdt64[]; + + memcpy(ptr, cpu_call64, 0x1000); + memcpy(gdt, gdt64, 0x100); + + /* + * TODO(sjg@chromium.org): This manually inserts the pointers into + * the code. Tidy this up to avoid this. + */ + func = (func_t)ptr; + ulong ofs = (ulong)cpu_call64 - (ulong)ptr; + *(ulong *)(ptr + 7) = (ulong)gdt; + *(ulong *)(ptr + 0xc) = (ulong)gdt + 2; + *(ulong *)(ptr + 0x13) = (ulong)gdt; + *(ulong *)(ptr + 0x117 - 0xd4) -= ofs; + + /* + * Copy U-Boot from ROM + * TODO(sjg@chromium.org): Figure out a way to get the text base + * correctly here, and in the device-tree binman definition. + * + * Also consider using FIT so we get the correct image length and + * parameters. + */ + memcpy((char *)target, (char *)0xfff00000, 0x100000); + + /* Jump to U-Boot */ + func((ulong)pgtable, 0, (ulong)target); + + return -EFAULT; +} + #ifdef CONFIG_SMP static int enable_smis(struct udevice *cpu, void *unused) { diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h index b408515582..c651f2f594 100644 --- a/arch/x86/include/asm/cpu.h +++ b/arch/x86/include/asm/cpu.h @@ -264,6 +264,15 @@ void cpu_call32(ulong code_seg32, ulong target, ulong table); int cpu_jump_to_64bit(ulong setup_base, ulong target); /** + * cpu_jump_to_64bit_uboot() - special function to jump from SPL to U-Boot + * + * This handles calling from 32-bit SPL to 64-bit U-Boot. + * + * @target: Address of U-Boot in RAM + */ +int cpu_jump_to_64bit_uboot(ulong target); + +/** * cpu_get_family_model() - Get the family and model for the CPU * * @return the CPU ID masked with 0x0fff0ff0 |