From: Nick Owens Subject: amd64: allocate efiboot trampoline as EfiLoaderCode To: tech@openbsd.org Date: Wed, 30 Sep 2026 08:37:08 -0700 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 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