On Fri, Mar 10, 2023 at 09:45:29AM +0100, Ard Biesheuvel wrote: > The use of a global singleton device path for describing the initrd to > be loaded by the kernel implies that only a single handle can exist that > carries the initrd LoadFile2 protocol implementation. > > This avoids the need on the part of the EFI stub to reason about which > initrd is the preferred one when several are being provided - we already > have initrd loading via the setup header on x86 and via DT on other > architectures, in addition to the initrd= command line option, and so > having a single loader provided initrd that supersedes all of them was > deemed preferable over having multiple sources. > > However, this means that intermediate loader stages cannot simply > install the LoadFile2 initrd device path, and will need to check for > failures and deal with them. It also means that such stages will have to > reason about whether or not the subsequent stage being loaded is the > final one, or whether it may attempt to install the initrd device path > itself. > > We can solve this by associating the initrd LoadFile2 protocol with the > loaded image instead of with a global singleton device path. That way, > each stage can associate any initrd it provides with the image that it > is loading. > > Signed-off-by: Ard Biesheuvel <ardb@xxxxxxxxxx> > --- > drivers/firmware/efi/libstub/efi-stub-helper.c | 42 ++++++++++++-------- > include/linux/efi.h | 2 +- > include/linux/pe.h | 2 +- > 3 files changed, 28 insertions(+), 18 deletions(-) > > diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c > index d47aa855398b39a6..a97c95a1d99e0b9d 100644 > --- a/drivers/firmware/efi/libstub/efi-stub-helper.c > +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c > @@ -482,10 +482,11 @@ static const struct { > }; > > /** > - * efi_load_initrd_dev_path() - load the initrd from the Linux initrd device path > - * @initrd: pointer of struct to store the address where the initrd was loaded > - * and the size of the loaded initrd > - * @max: upper limit for the initrd memory allocation > + * efi_load_initrd_lf2() - load the initrd from the Linux initrd device path > + * @image_handle: EFI handle of the loaded image > + * @initrd: pointer of struct to store the address where the initrd was > + * loaded and the size of the loaded initrd > + * @max: upper limit for the initrd memory allocation > * > * Return: > * * %EFI_SUCCESS if the initrd was loaded successfully, in which > @@ -495,24 +496,33 @@ static const struct { > * * %EFI_LOAD_ERROR in all other cases > */ > static > -efi_status_t efi_load_initrd_dev_path(struct linux_efi_initrd *initrd, > - unsigned long max) > +efi_status_t efi_load_initrd_lf2(efi_handle_t image_handle, > + struct linux_efi_initrd *initrd, > + unsigned long max) > { > efi_guid_t lf2_proto_guid = EFI_LOAD_FILE2_PROTOCOL_GUID; > + efi_guid_t initrd_lf2_proto_guid = LINUX_EFI_INITRD_LF2_PROTOCOL_GUID; > efi_device_path_protocol_t *dp; > efi_load_file2_protocol_t *lf2; > efi_handle_t handle; > efi_status_t status; > > - dp = (efi_device_path_protocol_t *)&initrd_dev_path; > - status = efi_bs_call(locate_device_path, &lf2_proto_guid, &dp, &handle); > - if (status != EFI_SUCCESS) > - return status; > - > - status = efi_bs_call(handle_protocol, handle, &lf2_proto_guid, > + /* first look for a initrd loading protocol specific to this image */ > + status = efi_bs_call(handle_protocol, image_handle, &initrd_lf2_proto_guid, > (void **)&lf2); > - if (status != EFI_SUCCESS) > - return status; > + if (status != EFI_SUCCESS) { > + /* look for the global singleton initrd loading protocol */ > + dp = (efi_device_path_protocol_t *)&initrd_dev_path; > + status = efi_bs_call(locate_device_path, &lf2_proto_guid, &dp, > + &handle); > + if (status != EFI_SUCCESS) > + return status; > + > + status = efi_bs_call(handle_protocol, handle, &lf2_proto_guid, > + (void **)&lf2); > + if (status != EFI_SUCCESS) > + return status; > + } > > initrd->size = 0; > status = efi_call_proto(lf2, load_file, dp, false, &initrd->size, NULL); > @@ -567,9 +577,9 @@ efi_status_t efi_load_initrd(efi_handle_t handle, > if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD) || efi_noinitrd) > return EFI_SUCCESS; > > - status = efi_load_initrd_dev_path(&initrd, hard_limit); > + status = efi_load_initrd_lf2(handle, &initrd, hard_limit); > if (status == EFI_SUCCESS) { > - efi_info("Loaded initrd from LINUX_EFI_INITRD_MEDIA_GUID device path\n"); > + efi_info("Loaded initrd using LoadFile2 protocol\n"); > if (initrd.size > 0 && > efi_measure_tagged_event(initrd.base, initrd.size, > EFISTUB_EVT_INITRD) == EFI_SUCCESS) > diff --git a/include/linux/efi.h b/include/linux/efi.h > index 04a733f0ba956211..83643d6aee755d85 100644 > --- a/include/linux/efi.h > +++ b/include/linux/efi.h > @@ -417,7 +417,7 @@ void efi_native_runtime_setup(void); > #define LINUX_EFI_MOK_VARIABLE_TABLE_GUID EFI_GUID(0xc451ed2b, 0x9694, 0x45d3, 0xba, 0xba, 0xed, 0x9f, 0x89, 0x88, 0xa3, 0x89) > #define LINUX_EFI_COCO_SECRET_AREA_GUID EFI_GUID(0xadf956ad, 0xe98c, 0x484c, 0xae, 0x11, 0xb5, 0x1c, 0x7d, 0x33, 0x64, 0x47) > #define LINUX_EFI_BOOT_MEMMAP_GUID EFI_GUID(0x800f683f, 0xd08b, 0x423a, 0xa2, 0x93, 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4) > - > +#define LINUX_EFI_INITRD_LF2_PROTOCOL_GUID EFI_GUID(0xf9e3378e, 0xb3b1, 0x423a, 0xbd, 0x9a, 0x2d, 0x08, 0x60, 0x28, 0x7f, 0x72) > #define RISCV_EFI_BOOT_PROTOCOL_GUID EFI_GUID(0xccd15fec, 0x6f73, 0x4eec, 0x83, 0x95, 0x3e, 0x69, 0xe4, 0xb9, 0x40, 0xbf) > > /* > diff --git a/include/linux/pe.h b/include/linux/pe.h > index 6ffabf1e6d039e67..934e3a15ea7ddc07 100644 > --- a/include/linux/pe.h > +++ b/include/linux/pe.h > @@ -29,7 +29,7 @@ > * handover_offset and xloadflags fields in the bootparams structure. > */ > #define LINUX_EFISTUB_MAJOR_VERSION 0x1 > -#define LINUX_EFISTUB_MINOR_VERSION 0x1 > +#define LINUX_EFISTUB_MINOR_VERSION 0x2 > > /* > * LINUX_PE_MAGIC appears at offset 0x38 into the MS-DOS header of EFI bootable > -- > 2.39.2 > Tested (with a slightly hacked version of u-boot) both paths. Tested-by: Ilias Apalodimas <ilias.apalodimas@xxxxxxxxxx> Reviewed-by: Ilias Apalodimas <ilias.apalodimas@xxxxxxxxxx>