Index | Thread | Search

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

Download raw body.

Thread
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