Index | Thread | Search

From:
Nick Owens <mischief@offblast.org>
Subject:
Re: amd64: allocate efiboot trampoline as EfiLoaderCode
To:
Mike Larkin <mlarkin@nested.page>
Cc:
tech@openbsd.org
Date:
Wed, 30 Sep 2026 13:55:48 -0700

Download raw body.

Thread
On Wed, Sep 30, 2026 at 9:04 AM Mike Larkin <mlarkin@nested.page> wrote:
>
> On Wed, Sep 30, 2026 at 08:37:08AM -0700, Nick Owens wrote:
> > hi,
> >
> > amd64 efiboot faults under newer edk2 OVMF, similar to the way riscv64
> > does. see my other mail about it,
> > https://marc.info/?l=openbsd-tech&m=178386086560425&w=2
> >
> > the secure boot OVMF builds that Fedora, RHEL and Gentoo ship set
> > PcdDxeNxMemoryProtectionPolicy to 0xC000000000007FD5, which maps
> > EfiLoaderData non-executable. efiboot copies the run_i386 trampoline
>
> I don't understand this statement. OpenBSD doesn't use "secure boot OVMF
> shipped from Fedora, RHEL or Gentoo". I seriously doubt that laptop/desktop
> vendors do either.
>
> We do have an OVMF build that will be coming into play after release for use
> with UEFI vmm VMs but A) that isn't enabled yet and B) works fine when it will
> be enabled.
>
> So where is this a problem exactly?

i boot openbsd on gentoo with libvirt/qemu. these secureboot builds
set this, e.g. https://gitweb.gentoo.org/repo/gentoo.git/tree/sys-firmware/edk2/edk2-202608.ebuild#n193.
https://src.fedoraproject.org/rpms/edk2 sets this as well, but i don't
use Fedora. so the problem happens if you boot openbsd using a linux
host, using libvirt or bare qemu, and you have an edk2/ovmf firmware
that protects EfiLoaderData with NX.

>
> I do understand what you're claiming below, and I'm not generally opposed
> to the diff but I don't see where this could be failing today and your mail
> isn't clear about the failure mode.
>
> -ml
>
> > onto its heap, which is EfiLoaderData, so the call into it takes a page
> > fault on instruction fetch right after "entry point at 0x1001000".
> >
> > give the trampoline its own EfiLoaderCode pages instead. keep them below
> > 16MB: after ExitBootServices() the kernel is moved to 16MB and up
> > without regard for the memory map.
> >
> > tested with edk2 202608 secure boot OVMF under qemu and bootx64.efi; bsd
> > boots.  i did not test bootia32.
> >
> > diff --git a/sys/arch/amd64/stand/efiboot/efiboot.c b/sys/arch/amd64/stand/efiboot/efiboot.c
> > index 0401522e3a8..6b7a21b8da8 100644
> > --- a/sys/arch/amd64/stand/efiboot/efiboot.c
> > +++ b/sys/arch/amd64/stand/efiboot/efiboot.c
> > @@ -80,6 +80,9 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
> >       EFI_DEVICE_PATH         *dp0 = NULL, *dp;
> >       EFI_STATUS               status;
> >       EFI_PHYSICAL_ADDRESS     stack;
> > +#ifdef __amd64__
> > +     EFI_PHYSICAL_ADDRESS     addr;
> > +#endif
> >
> >       ST = systab;
> >       BS = ST->BootServices;
> > @@ -117,9 +120,17 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
> >       }
> >
> >  #ifdef __amd64__
> > -     /* allocate run_i386_start() on heap */
> > -     if ((run_i386 = alloc(run_i386_size)) == NULL)
> > -             panic("alloc() failed");
> > +     /*
> > +      * Copy run_i386_start() to its own EfiLoaderCode pages.  The heap
> > +      * is EfiLoaderData, which firmware may map non-executable.  Stay
> > +      * below 16MB, as the kernel is moved to 16MB and up.
> > +      */
> > +     addr = 16 * 1024 * 1024;
> > +     status = BS->AllocatePages(AllocateMaxAddress, EfiLoaderCode,
> > +         EFI_SIZE_TO_PAGES(run_i386_size), &addr);
> > +     if (status != EFI_SUCCESS)
> > +             panic("BS->AllocatePages()");
> > +     run_i386 = (void *)addr;
> >       memcpy(run_i386, run_i386_start, run_i386_size);
> >  #endif
> >
> >