]> git.sur5r.net Git - u-boot/blobdiff - arch/x86/lib/bootm.c
Merge tag 'signed-efi-next' of git://github.com/agraf/u-boot
[u-boot] / arch / x86 / lib / bootm.c
index 4c5c7f5aa796bc679cf2bb91f6f16f64de128098..54c22fe6de3f50414446514d06bcda0412e5cfba 100644 (file)
@@ -1,34 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * (C) Copyright 2002
  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
  * Marius Groeger <mgroeger@sysgo.de>
  *
  * Copyright (C) 2001  Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
 #include <command.h>
+#include <dm/device.h>
+#include <dm/root.h>
+#include <errno.h>
 #include <fdt_support.h>
 #include <image.h>
 #include <u-boot/zlib.h>
 #include <asm/bootparam.h>
+#include <asm/cpu.h>
 #include <asm/byteorder.h>
 #include <asm/zimage.h>
 #ifdef CONFIG_SYS_COREBOOT
 #include <asm/arch/timestamp.h>
 #endif
 
-#define COMMAND_LINE_OFFSET 0x9000
+DECLARE_GLOBAL_DATA_PTR;
 
-/*
- * Implement a weak default function for boards that optionally
- * need to clean up the system before jumping to the kernel.
- */
-__weak void board_final_cleanup(void)
-{
-}
+#define COMMAND_LINE_OFFSET 0x9000
 
 void bootm_announce_and_cleanup(void)
 {
@@ -41,7 +38,13 @@ void bootm_announce_and_cleanup(void)
 #ifdef CONFIG_BOOTSTAGE_REPORT
        bootstage_report();
 #endif
-       board_final_cleanup();
+
+       /*
+        * Call remove function of all devices with a removal flag set.
+        * This may be useful for last-stage operations, like cancelling
+        * of DMA operation or releasing device internal buffers.
+        */
+       dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
 }
 
 #if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL)
@@ -109,17 +112,17 @@ static int boot_prep_linux(bootm_headers_t *images)
        }
 
        if (is_zimage) {
-               void *load_address;
+               ulong load_address;
                char *base_ptr;
 
                base_ptr = (char *)load_zimage(data, len, &load_address);
-               images->os.load = (ulong)load_address;
+               images->os.load = load_address;
                cmd_line_dest = base_ptr + COMMAND_LINE_OFFSET;
                images->ep = (ulong)base_ptr;
        } else if (images->ep) {
                cmd_line_dest = (void *)images->ep + COMMAND_LINE_OFFSET;
        } else {
-               printf("## Kernel loading failed (no setup) ...\n");
+               printf("## Kernel loading failed (missing x86 kernel setup) ...\n");
                goto error;
        }
 
@@ -139,16 +142,62 @@ error:
        return 1;
 }
 
+int boot_linux_kernel(ulong setup_base, ulong load_address, bool image_64bit)
+{
+       bootm_announce_and_cleanup();
+
+#ifdef CONFIG_SYS_COREBOOT
+       timestamp_add_now(TS_U_BOOT_START_KERNEL);
+#endif
+       if (image_64bit) {
+               if (!cpu_has_64bit()) {
+                       puts("Cannot boot 64-bit kernel on 32-bit machine\n");
+                       return -EFAULT;
+               }
+               /* At present 64-bit U-Boot does not support booting a
+                * kernel.
+                * TODO(sjg@chromium.org): Support booting both 32-bit and
+                * 64-bit kernels from 64-bit U-Boot.
+                */
+#if !CONFIG_IS_ENABLED(X86_64)
+               return cpu_jump_to_64bit(setup_base, load_address);
+#endif
+       } else {
+               /*
+               * Set %ebx, %ebp, and %edi to 0, %esi to point to the
+               * boot_params structure, and then jump to the kernel. We
+               * assume that %cs is 0x10, 4GB flat, and read/execute, and
+               * the data segments are 0x18, 4GB flat, and read/write.
+               * U-Boot is setting them up that way for itself in
+               * arch/i386/cpu/cpu.c.
+               *
+               * Note that we cannot currently boot a kernel while running as
+               * an EFI application. Please use the payload option for that.
+               */
+#ifndef CONFIG_EFI_APP
+               __asm__ __volatile__ (
+               "movl $0, %%ebp\n"
+               "cli\n"
+               "jmp *%[kernel_entry]\n"
+               :: [kernel_entry]"a"(load_address),
+               [boot_params] "S"(setup_base),
+               "b"(0), "D"(0)
+               );
+#endif
+       }
+
+       /* We can't get to here */
+       return -EFAULT;
+}
+
 /* Subcommand: GO */
 static int boot_jump_linux(bootm_headers_t *images)
 {
        debug("## Transferring control to Linux (at address %08lx, kernel %08lx) ...\n",
              images->ep, images->os.load);
 
-       boot_zimage((struct boot_params *)images->ep, (void *)images->os.load);
-       /* does not return */
-
-       return 1;
+       return boot_linux_kernel(images->ep, images->os.load,
+                                images->os.arch == IH_ARCH_X86_64);
 }
 
 int do_bootm_linux(int flag, int argc, char * const argv[],
@@ -161,10 +210,8 @@ int do_bootm_linux(int flag, int argc, char * const argv[],
        if (flag & BOOTM_STATE_OS_PREP)
                return boot_prep_linux(images);
 
-       if (flag & BOOTM_STATE_OS_GO) {
-               boot_jump_linux(images);
-               return 0;
-       }
+       if (flag & BOOTM_STATE_OS_GO)
+               return boot_jump_linux(images);
 
        return boot_jump_linux(images);
 }