Index | Thread | Search

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

Download raw body.

Thread
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 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
>
>