On Thu, 6 Oct 2022 at 13:03, Borislav Petkov <bp@xxxxxxxxx> wrote: > > On Wed, Sep 21, 2022 at 04:54:09PM +0200, Ard Biesheuvel wrote: > > Move the logic that chooses between the different EFI entrypoints out of > > the 32-bit boot path, and into a 64-bit helper that can perform the same > > task much more cleanly. While at it, document the mixed mode boot flow > > in a code comment. > > > > Signed-off-by: Ard Biesheuvel <ardb@xxxxxxxxxx> > > --- > > arch/x86/boot/compressed/efi_mixed.S | 43 ++++++++++++++++++++ > > arch/x86/boot/compressed/head_64.S | 24 ++--------- > > 2 files changed, 47 insertions(+), 20 deletions(-) > > > > diff --git a/arch/x86/boot/compressed/efi_mixed.S b/arch/x86/boot/compressed/efi_mixed.S > > index 67e7edcdfea8..77e77c3ea393 100644 > > --- a/arch/x86/boot/compressed/efi_mixed.S > > +++ b/arch/x86/boot/compressed/efi_mixed.S > > @@ -22,6 +22,49 @@ > > > > .code64 > > .text > > +/* > > + * When booting in 64-bit mode on 32-bit EFI firmware, startup_64_mixedmode() > > + * is the first thing that runs after switching to long mode. Depending on > > + * whether the EFI handover protocol or the compat entry point was used to > > + * enter the kernel, it will either branch to the 64-bit EFI handover > > + * entrypoint at offset 0x390 in the image, or to the 64-bit EFI PE/COFF > > + * entrypoint efi_pe_entry(). In the former case, the bootloader must provide a > > + * struct bootparams pointer as the third argument, so the presence of such a > > + * pointer is used to disambiguate. > > + * > > + * +--------------+ > > + * +------------------+ +------------+ +------>| efi_pe_entry | > > + * | efi32_pe_entry |---->| | | +-----------+--+ > > + * +------------------+ | | +------+---------------+ | > > + * | startup_32 |---->| startup_64_mixedmode | | > > + * +------------------+ | | +------+---------------+ V > > + * | efi32_stub_entry |---->| | | +------------------+ > > + * +------------------+ +------------+ +---->| efi64_stub_entry | > > + * +-------------+----+ > > + * +------------+ +----------+ | > > + * | startup_64 |<----| efi_main |<--------------+ > > + * +------------+ +----------+ > > + */ > > That is much appreciated. > > Questions: > > - is this whole handover ABI documented somewhere? > Documentation/x86/boot.rst has a section on this (at the end), but we should really stop using it. It is only implemented by out-of-tree GRUB at the moment (last time I checked) and leaking all those struct bootparams specific details into every bootloader is not great, especially the ones that intend to be generic and boot any EFI OS on any EFI arch. > - efi32_pe_entry() is the 32-bit PE/COFF entry point? I.e., that is > called by a 32-bit EFI fw when the kernel is a PE/COFF executable? > Yes. But I should note that this is actually something that goes outside of the EFI spec as well: 32-bit firmware can /load/ 64-bit PE/COFF binaries but not *start* them. Commit 97aa276579b28b86f4a3e235b50762c0191c2ac3 has some more background. This is currently implement by 32-bit OVMF, and systemd-boot. > But then Documentation/admin-guide/efi-stub.rst talks about the EFI stub > and exactly that. Hmm, so what is efi32_pe_entry() then? > That is the same thing. The EFI stub is what enables the kernel (or decompressor) to masquerade as a PE/COFF executable. In short, every EFI stub kernel on every architecture has a native PE/COFF entry point that calls the EFI stub, and the EFi stub does the arch-specific bootloader work and boots it. In addition, the x86_64 EFI stub kernel has an extra, non-native PE/COFF entry point, which is exposed in a way that is not covered by the EFI spec, but which allows Linux specific loaders such as systemd-boot to boot such kernels on 32-bit firmware without having to do the whole struct bootparams dance in the bootloader.