I am very interested in trying out OpenBSD on my machine as a desktop
system.

I flashed install60.fs to a pendrive, and attempted to boot my amd64 UEFI
system with it.

It displays the kernel entry point information, followed by the message
"ExitBootServices" and then instantly reboots the machine.


Here is the code where the problem happens:

http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/arch/amd64/stand/efiboot/efiboot.c?rev=1.14&content-type=text/x-cvsweb-markup

void
efi_cleanup(void)
{
        EFI_STATUS       status;

        efi_memprobe_internal();        /* sync the current map */
        status = EFI_CALL(BS->ExitBootServices, IH, mmap_key);
        if (status != EFI_SUCCESS)
                panic("ExitBootServices");
}

I spliced in some debugging code and found that the call to
ExitBootServices is returning a status code of 2 (EFI_INVALID_PARAMETER),
which causes the panic and reboot.

Here's a description of this problem in the UEFI Specification [1] (page
221):

"An EFI OS loader must ensure that it has the system's current memory map
at the time it calls ExitBootServices(). This is done by passing in the
current memory map's MapKey value as returned by
EFI_BOOT_SERVICES.GetMemoryMap(). Care must be taken to ensure that the
memory map does not change between these two calls. It is suggested that
GetMemoryMap() be called immediately before calling ExitBootServices(). If
MapKey value is incorrect, ExitBootServices() returns EFI_INVALID_PARAMETER
and GetMemoryMap() with ExitBootServices() must be called again."

I spliced in some more debugging code and found that the MapKey value
(mmap_key) does indeed change during the call to ExitBootServices.

That isolates the problem: ExitBootServices is changing the memory map. The
simple solution seems to be to just retry calling GetMemoryMap to get the
updated MapKey, and then call ExitBootServices a second time. However, I
did some more research before attempting this solution on my machine.


I found this quote from a Linux mailing list archive where they were
discussing the same issue [2]:

"ExitBootServices() can legitimately fail if any of the event handlers
that are signaled by its invocation change the memory map. In that case,
we need to get the memory map and exit boot services again. Only retry
once so that we don't get stuck if ExitBootServices() is returning a
genuine error value."

This tells me that it's normal behaviour for ExitBootServices to fail in
such a way, so I am more confident that this is a legitimate bug and the
code needs to be prepared to call ExitBootServices a second time in case of
failure.


I also found some more directly relevant quotes where the same problem was
being discussed in relation to FreeBSD [3]:

"[the solution] Is not quite that easy -- the memory map itself is passed
as module metadata to the kernel (bi_load_efi_data), so that needs to be
redone as well."

I did some more investigating and found that this appears to be the case in
OpenBSD too:

http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/sys/arch/amd64/stand/libsa/exec_i386.c?rev=1.18&content-type=text/x-cvsweb-markup

        /* Pass memory map to the kernel */
        mem_pass();


and shortly afterwards:

        /*
         * Move the loaded kernel image to the usual place after calling
         * ExitBootServices().
         */
        delta = DEFAULT_KERNEL_ADDRESS - efi_loadaddr;
        efi_cleanup();


It appears that the memory map is passed to the kernel before calling
ExitBootServices (which changes the memory map again, leaving the kernel
with an obsolete copy).


I am very hesitant to attempt any self-made solutions to this problem after
reading this quote, again from [3]:

"... if the memory map has actually changed the kernel will now possibly
corrupt firmware data (or the firmware will corrupt OS/user data)."

It seems that a proper and safe solution may require rearranging a
significant chunk of code to ensure that ExitBootServices is successfully
called prior to passing the memory map to the kernel.

At least, that's my take on it. I am not a strong coder and nowhere near
experienced enough to attempt any such fixes myself, so I thought it would
be best to send this in as a bug report.


[1] (www.uefi.org/sites/default/files/resources/UEFI%202_5.pdf)
[2] (http://www.gossamer-threads.com/lists/linux/kernel/1727968)
[3] (https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=202455)

Reply via email to