x86: Support booting a 64-bit kernel from 64-bit U-Boot
Add the missing code to handle this. For a 64-bit kernel the entry
address is 0x200 bytes after the normal entry.
Rename the parameter to boot_linux_kernel() accordingly. Update the
comments to indicate that these are addresses, not pointers.
Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c
index 873e2bc..9beb376 100644
--- a/arch/x86/lib/bootm.c
+++ b/arch/x86/lib/bootm.c
@@ -149,7 +149,7 @@
return 1;
}
-int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit)
+int boot_linux_kernel(ulong setup_base, ulong entry, bool image_64bit)
{
bootm_announce_and_cleanup();
@@ -161,14 +161,23 @@
puts("Cannot boot 64-bit kernel on 32-bit machine\n");
return -EFAULT;
}
- /* At present 64-bit U-Boot does not support booting a
+ /*
+ * At present 64-bit U-Boot only supports booting a 64-bit
* kernel.
- * TODO(sjg@chromium.org): Support booting both 32-bit and
- * 64-bit kernels from 64-bit U-Boot.
+ *
+ * TODO(sjg@chromium.org): Support booting 32-bit kernels from
+ * 64-bit U-Boot
*/
-#if !CONFIG_IS_ENABLED(X86_64)
- return cpu_jump_to_64bit(setup_base, load_address);
-#endif
+ if (CONFIG_IS_ENABLED(X86_64)) {
+ typedef void (*h_func)(ulong zero, ulong setup);
+ h_func func;
+
+ /* jump to Linux with rdi=0, rsi=setup_base */
+ func = (h_func)entry;
+ func(0, setup_base);
+ } else {
+ return cpu_jump_to_64bit(setup_base, entry);
+ }
} else {
/*
* Set %ebx, %ebp, and %edi to 0, %esi to point to the
@@ -190,7 +199,7 @@
"movl $0, %%ebp\n"
"cli\n"
"jmp *%[kernel_entry]\n"
- :: [kernel_entry]"a"(load_address),
+ :: [kernel_entry]"a"(entry),
[boot_params] "S"(setup_base),
"b"(0), "D"(0)
);
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c
index a6d9151..e5ea512 100644
--- a/arch/x86/lib/zimage.c
+++ b/arch/x86/lib/zimage.c
@@ -504,13 +504,24 @@
static int do_zboot_go(struct cmd_tbl *cmdtp, int flag, int argc,
char *const argv[])
{
+ struct boot_params *params = state.base_ptr;
+ struct setup_header *hdr = ¶ms->hdr;
+ bool image_64bit;
+ ulong entry;
int ret;
disable_interrupts();
+ entry = state.load_address;
+ image_64bit = false;
+ if (IS_ENABLED(CONFIG_X86_RUN_64BIT) &&
+ (hdr->xloadflags & XLF_KERNEL_64)) {
+ entry += 0x200;
+ image_64bit = true;
+ }
+
/* we assume that the kernel is in place */
- ret = boot_linux_kernel((ulong)state.base_ptr, state.load_address,
- false);
+ ret = boot_linux_kernel((ulong)state.base_ptr, entry, image_64bit);
printf("Kernel returned! (err=%d)\n", ret);
return CMD_RET_FAILURE;