Fix efiboot not to use the usual kernel load address. Load the kernel in
authoryasuoka <yasuoka@openbsd.org>
Mon, 5 Oct 2015 22:59:39 +0000 (22:59 +0000)
committeryasuoka <yasuoka@openbsd.org>
Mon, 5 Oct 2015 22:59:39 +0000 (22:59 +0000)
an allocated region and also move the stack to the end of the heap region.
Then move the kernel to the usual place just before run the kernel, after
calling ExitBootService().

report/test Toby Slight, Brian Conway

sys/arch/amd64/include/loadfile_machdep.h
sys/arch/amd64/stand/efiboot/efiboot.c
sys/arch/amd64/stand/libsa/exec_i386.c

index 65a9249..1b51946 100644 (file)
@@ -1,5 +1,5 @@
 /* XXX - DSR */
-/*     $OpenBSD: loadfile_machdep.h,v 1.5 2015/07/17 20:44:38 miod Exp $       */
+/*     $OpenBSD: loadfile_machdep.h,v 1.6 2015/10/05 22:59:39 yasuoka Exp $    */
 /*     $NetBSD: loadfile_machdep.h,v 1.1 1999/04/29 03:17:12 tsubai Exp $      */
 
 /*-
 #define LOAD_KERNEL            LOAD_ALL
 #define COUNT_KERNEL           COUNT_ALL
 
+#ifdef EFIBOOT
+extern u_long                  efi_loadaddr;
+#define LOADADDR(a)            (((((u_long)(a)) + offset)&0xfffffff) + \
+                                   efi_loadaddr)
+#else
 #define LOADADDR(a)            ((((u_long)(a)) + offset)&0xfffffff)
+#endif
 #define ALIGNENTRY(a)          ((u_long)(a))
 #define READ(f, b, c)          read((f), (void *)LOADADDR(b), (c))
 #define BCOPY(s, d, c)         memcpy((void *)LOADADDR(d), (void *)(s), (c))
index 086d0a4..a28818f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: efiboot.c,v 1.5 2015/09/23 03:29:26 yasuoka Exp $     */
+/*     $OpenBSD: efiboot.c,v 1.6 2015/10/05 22:59:39 yasuoka Exp $     */
 
 /*
  * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
@@ -36,6 +36,8 @@
 #include "eficall.h"
 #include "run_i386.h"
 
+#define        KERN_LOADSPACE_SIZE     (32 * 1024 * 1024)
+
 EFI_SYSTEM_TABLE       *ST;
 EFI_BOOT_SERVICES      *BS;
 EFI_RUNTIME_SERVICES   *RS;
@@ -46,6 +48,7 @@ UINTN                  heapsiz = 1 * 1024 * 1024;
 UINTN                   mmap_key;
 static EFI_GUID                 imgdp_guid = { 0xbc62157e, 0x3e33, 0x4fec,
                            { 0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf }};
+u_long                  efi_loadaddr;
 
 static void     efi_heap_init(void);
 static void     efi_memprobe_internal(void);
@@ -61,9 +64,10 @@ extern int bios_bootdev;
 EFI_STATUS
 efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
 {
-       extern char     *progname;
-       EFI_DEVICE_PATH *dp0 = NULL, *dp;
-       EFI_STATUS       status;
+       extern char             *progname;
+       EFI_DEVICE_PATH         *dp0 = NULL, *dp;
+       EFI_STATUS               status;
+       EFI_PHYSICAL_ADDRESS     stack;
 
        ST = systab;
        BS = ST->BootServices;
@@ -101,8 +105,23 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
 
        progname = "EFIBOOT";
 
-       boot(bios_bootdev);
-
+       /*
+        * Move the stack before calling boot().  UEFI on some machines
+        * locate the stack on our kernel load address.
+        */
+       stack = heap + heapsiz;
+#if defined(__amd64__)
+       asm("movq       %0, %%rsp;"
+           "mov        %1, %%edi;"
+           "call       boot;"
+           :: "r"(stack - 32), "r"(bios_bootdev));
+#else
+       asm("movl       %0, %%esp;"
+           "movl       %1, (%%esp);"
+           "call       boot;"
+           :: "r"(stack - 32), "r"(bios_bootdev));
+#endif
+       /* must not reach here */
        return (EFI_SUCCESS);
 }
 
@@ -212,6 +231,15 @@ efi_memprobe(void)
 {
        u_int            n = 0;
        bios_memmap_t   *bm;
+       EFI_STATUS       status;
+       EFI_PHYSICAL_ADDRESS
+                        addr = 0x10000000ULL;  /* Below 256MB */
+
+       status = EFI_CALL(BS->AllocatePages, AllocateMaxAddress, EfiLoaderData,
+           EFI_SIZE_TO_PAGES(KERN_LOADSPACE_SIZE), &addr);
+       if (status != EFI_SUCCESS)
+               panic("BS->AllocatePages()");
+       efi_loadaddr = addr;
 
        printf(" mem[");
        efi_memprobe_internal();
@@ -236,7 +264,7 @@ efi_memprobe_internal(void)
        UINT32                   mmver;
        EFI_MEMORY_DESCRIPTOR   *mm0, *mm;
        int                      i, n;
-       bios_memmap_t            *bm, bm0;
+       bios_memmap_t           *bm, bm0;
 
        cnvmem = extmem = 0;
        bios_memmap[0].type = BIOS_MAP_END;
index 687e543..9134844 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: exec_i386.c,v 1.14 2015/09/02 04:09:24 yasuoka Exp $  */
+/*     $OpenBSD: exec_i386.c,v 1.15 2015/10/05 22:59:39 yasuoka Exp $  */
 
 /*
  * Copyright (c) 1997-1998 Michael Shalayeff
@@ -72,8 +72,11 @@ run_loadfile(u_long *marks, int howto)
        bios_bootsr_t bootsr;
        struct sr_boot_volume *bv;
 #endif
+#if defined(EFIBOOT)
+       int i;
+       u_long delta;
+       extern u_long efi_loadaddr;
 
-#ifdef EFIBOOT
        if ((av = alloc(ac)) == NULL)
                panic("alloc for bootarg");
        efi_makebootargs();
@@ -131,17 +134,29 @@ run_loadfile(u_long *marks, int howto)
        printf("entry point at 0x%lx [%x, %x, %x, %x]\n", entry,
            ((int *)entry)[0], ((int *)entry)[1],
            ((int *)entry)[2], ((int *)entry)[3]);
-
-#if defined(EFIBOOT)
+#ifndef EFIBOOT
+       /* stack and the gung is ok at this point, so, no need for asm setup */
+       (*(startfuncp)entry)(howto, bootdev, BOOTARG_APIVER, marks[MARK_END],
+           extmem, cnvmem, ac, (int)av);
+#else
+       /*
+        * Move the loaded kernel image to the usual place after calling
+        * ExitBootServervice()
+        */
+       delta = DEFAULT_KERNEL_ADDRESS - efi_loadaddr;
        efi_cleanup();
-#endif
-#if defined(EFIBOOT) && defined(__amd64__)
+       memcpy((void *)marks[MARK_START] + delta, (void *)marks[MARK_START],
+           marks[MARK_END] - marks[MARK_START]);
+       for (i = 0; i < MARK_MAX; i++)
+               marks[i] += delta;
+       entry += delta;
+#ifdef __amd64__
        (*run_i386)((u_long)run_i386, entry, howto, bootdev, BOOTARG_APIVER,
            marks[MARK_END], extmem, cnvmem, ac, (intptr_t)av);
 #else
-       /* stack and the gung is ok at this point, so, no need for asm setup */
        (*(startfuncp)entry)(howto, bootdev, BOOTARG_APIVER, marks[MARK_END],
            extmem, cnvmem, ac, (int)av);
-       /* not reached */
 #endif
+#endif
+       /* not reached */
 }