Hi,

efi_cleanup() invokes ExitBootServices, which changes the memory map on some 
EFI machines.

Since mem_pass() is called prior to efi_cleanup(), the kernel boots with an 
obsolete memory map.

The problem can be fixed by calling mem_pass() after efi_cleanup().

Here's the report history with more detailed information:

https://marc.info/?l=openbsd-bugs&m=148253785924157&w=2
https://marc.info/?l=openbsd-tech&m=148653092621349&w=2
https://marc.info/?l=openbsd-bugs&m=151887483824518&w=2

This patch should correct the problem. I've been using it since 6.0 on several 
machines (BIOS and EFI) without any issues.


Index: src/sys/arch/amd64/stand/libsa/exec_i386.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/stand/libsa/exec_i386.c,v
retrieving revision 1.22
diff -u -p -u -r1.22 exec_i386.c
--- src/sys/arch/amd64/stand/libsa/exec_i386.c  18 Apr 2018 16:34:42 -0000      
1.22
+++ src/sys/arch/amd64/stand/libsa/exec_i386.c  21 Apr 2018 05:57:48 -0000
@@ -78,7 +78,7 @@ run_loadfile(u_long *marks, int howto)
        bios_bootsr_t bootsr;
        struct sr_boot_volume *bv;
 #endif
-#if defined(EFIBOOT)
+#ifdef EFIBOOT
        int i;
        u_long delta;
        extern u_long efi_loadaddr;
@@ -86,6 +86,7 @@ run_loadfile(u_long *marks, int howto)
        if ((av = alloc(ac)) == NULL)
                panic("alloc for bootarg");
        efi_makebootargs();
+       delta = DEFAULT_KERNEL_ADDRESS - efi_loadaddr;
 #endif
        if (sa_cleanup != NULL)
                (*sa_cleanup)();
@@ -124,6 +125,17 @@ run_loadfile(u_long *marks, int howto)
        sr_clear_keys();
 #endif
 
+       entry = marks[MARK_ENTRY] & 0x0fffffff;
+#ifdef EFIBOOT
+       entry += delta;
+#endif
+
+       printf("entry point at 0x%lx\n", entry);
+
+#ifdef EFIBOOT
+       /* Sync the memory map and call ExitBootServices() */
+       efi_cleanup();
+#endif
        /* Pass memory map to the kernel */
        mem_pass();
 
@@ -137,33 +149,24 @@ run_loadfile(u_long *marks, int howto)
        makebootargs(av, &ac);
 #endif
 
-       entry = marks[MARK_ENTRY] & 0x0fffffff;
-
-       printf("entry point at 0x%lx\n", entry);
-
-#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
+#ifdef EFIBOOT
        /*
         * Move the loaded kernel image to the usual place after calling
         * ExitBootServices().
         */
-       delta = DEFAULT_KERNEL_ADDRESS - efi_loadaddr;
-       efi_cleanup();
        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;
+#endif
+
 #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);
-#endif
 #endif
        /* not reached */
 }

Reply via email to