public inbox for linux-efi@vger.kernel.org
 help / color / mirror / Atom feed
From: Ilias Apalodimas <ilias.apalodimas@linaro.org>
To: Ard Biesheuvel <ardb@kernel.org>
Cc: grub-devel@nongnu.org, linux-efi@vger.kernel.org,
	grub-devel@gnu.org, Daniel Kiper <daniel.kiper@oracle.com>,
	Nikita Ermakov <arei@altlinux.org>,
	Atish Patra <atishp@atishpatra.org>,
	Huacai Chen <chenhuacai@loongson.cn>,
	Heinrich Schuchardt <heinrich.schuchardt@canonical.com>,
	dann frazier <dann.frazier@canonical.com>,
	Julian Andres Klode <julian.klode@canonical.com>
Subject: Re: [PATCH resend 8/9] efi: implement LoadFile2 initrd loading protocol for Linux
Date: Thu, 8 Sep 2022 10:29:56 +0300	[thread overview]
Message-ID: <YxmZ9INMSU6lc00b@hera> (raw)
In-Reply-To: <20220818085540.2075028-9-ardb@kernel.org>

Hi Ard,

On Thu, Aug 18, 2022 at 10:55:38AM +0200, Ard Biesheuvel wrote:
> Recent Linux kernels will invoke the LoadFile2 protocol installed on
> a well-known vendor media path to load the initrd if it is exposed by
> the firmware. Using this method is preferred for two reasons:
> - the Linux kernel is in charge of allocating the memory, and so it can
>   implement any placement policy it wants (given that these tend to
>   change between kernel versions),
> - it is no longer necessary to modify the device tree provided by the
>   firmware.
> 
> So let's install this protocol when handling the 'initrd' command if
> such a recent kernel was detected (based on the PE/COFF image version),
> and defer loading the initrd contents until the point where the kernel
> invokes the LoadFile2 protocol.
> 
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
>  grub-core/loader/arm64/linux.c | 129 +++++++++++++++++++-
>  1 file changed, 128 insertions(+), 1 deletion(-)
> 
> diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
> index 56ba8d0a6ea3..82c7558b4c4c 100644
> --- a/grub-core/loader/arm64/linux.c
> +++ b/grub-core/loader/arm64/linux.c
> @@ -48,6 +48,48 @@ static grub_uint32_t cmdline_size;
>  static grub_addr_t initrd_start;
>  static grub_addr_t initrd_end;
>  
> +static grub_efi_guid_t load_file2_guid = GRUB_EFI_LOAD_FILE2_PROTOCOL_GUID;
> +static grub_efi_guid_t device_path_guid = GRUB_EFI_DEVICE_PATH_GUID;
> +static struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 };
> +static grub_efi_handle_t initrd_lf2_handle;
> +static int initrd_use_loadfile2;
> +
> +struct initrd_media_device_path {
> +  grub_efi_vendor_media_device_path_t  vendor;
> +  grub_efi_device_path_t               end;
> +} GRUB_PACKED;
> +
> +#define LINUX_EFI_INITRD_MEDIA_GUID  \
> +  { 0x5568e427, 0x68fc, 0x4f3d, \
> +    { 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68 } \
> +  }
> +
> +static struct initrd_media_device_path initrd_lf2_device_path = {
> +  {
> +    {
> +      GRUB_EFI_MEDIA_DEVICE_PATH_TYPE,
> +      GRUB_EFI_VENDOR_MEDIA_DEVICE_PATH_SUBTYPE,
> +      sizeof(grub_efi_vendor_media_device_path_t),
> +    },
> +    LINUX_EFI_INITRD_MEDIA_GUID
> +  }, {
> +    GRUB_EFI_END_DEVICE_PATH_TYPE,
> +    GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE,
> +    sizeof(grub_efi_device_path_t)
> +  }
> +};
> +
> +static grub_efi_status_t
> +grub_efi_initrd_load_file2(grub_efi_load_file2_t *this,
> +                           grub_efi_device_path_t *device_path,
> +                           grub_efi_boolean_t boot_policy,
> +                           grub_efi_uintn_t *buffer_size,
> +                           void *buffer);
> +
> +static grub_efi_load_file2_t initrd_lf2 = {
> +  grub_efi_initrd_load_file2
> +};
> +
>  grub_err_t
>  grub_arch_efi_linux_load_image_header (grub_file_t file,
>                                        struct linux_arch_kernel_header * lh)
> @@ -78,6 +120,18 @@ grub_arch_efi_linux_load_image_header (grub_file_t file,
>         return grub_error(GRUB_ERR_FILE_READ_ERROR, "failed to read COFF image header");
>      }
>  
> +  /*
> +   * Linux kernels built for any architecture are guaranteed to support the
> +   * LoadFile2 based initrd loading protocol if the image version is >= 1.
> +   */
> +  if (lh->coff_image_header.optional_header.major_image_version >= 1)
> +    initrd_use_loadfile2 = 1;
> +   else
> +    initrd_use_loadfile2 = 0;
> +
> +  grub_dprintf ("linux", "LoadFile2 initrd loading %sabled\n",
> +                initrd_use_loadfile2 ? "en" : "dis");
> +
>    return GRUB_ERR_NONE;
>  }
>  
> @@ -197,6 +251,8 @@ grub_linux_boot (void)
>  static grub_err_t
>  grub_linux_unload (void)
>  {
> +  grub_efi_boot_services_t *b;
> +
>    grub_dl_unref (my_mod);
>    loaded = 0;
>    if (initrd_start)
> @@ -208,6 +264,19 @@ grub_linux_unload (void)
>      grub_efi_free_pages ((grub_addr_t) kernel_addr,
>  			 GRUB_EFI_BYTES_TO_PAGES (kernel_size));
>    grub_fdt_unload ();
> +
> +  if (initrd_lf2_handle)
> +    {
> +      b = grub_efi_system_table->boot_services;
> +      b->uninstall_multiple_protocol_interfaces (initrd_lf2_handle,
> +                                                 &load_file2_guid,
> +                                                 &initrd_lf2,
> +                                                 &device_path_guid,
> +                                                 &initrd_lf2_device_path,
> +                                                 NULL);
> +      initrd_lf2_handle = NULL;
> +      initrd_use_loadfile2 = 0;
> +    }
>    return GRUB_ERR_NONE;
>  }
>  
> @@ -247,13 +316,50 @@ allocate_initrd_mem (int initrd_pages)
>  				       GRUB_EFI_LOADER_DATA);
>  }
>  
> +static grub_efi_status_t
> +grub_efi_initrd_load_file2(grub_efi_load_file2_t *this,
> +                          grub_efi_device_path_t *device_path,
> +                          grub_efi_boolean_t boot_policy,
> +                          grub_efi_uintn_t *buffer_size,
> +                          void *buffer)
> +{
> +  grub_efi_status_t status = GRUB_EFI_SUCCESS;
> +  grub_efi_uintn_t initrd_size;
> +
> +  if (!this || this != &initrd_lf2 || !buffer_size)
> +    return GRUB_EFI_INVALID_PARAMETER;
> +
> +  if (device_path->type != GRUB_EFI_END_DEVICE_PATH_TYPE ||
> +      device_path->subtype != GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE)
> +    return GRUB_EFI_NOT_FOUND;
> +
> +  if (boot_policy)
> +    return GRUB_EFI_UNSUPPORTED;
> +
> +  initrd_size = grub_get_initrd_size (&initrd_ctx);
> +  if (!buffer || *buffer_size < initrd_size)
> +    {
> +      *buffer_size = initrd_size;
> +      return GRUB_EFI_BUFFER_TOO_SMALL;
> +    }
> +
> +  grub_dprintf ("linux", "Providing initrd via LOAD_FILE2_PROTOCOL\n");
> +
> +  if (grub_initrd_load (&initrd_ctx, buffer))
> +    status = GRUB_EFI_LOAD_ERROR;
> +
> +  grub_initrd_close (&initrd_ctx);
> +  return status;
> +}
> +
>  static grub_err_t
>  grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
>  		 int argc, char *argv[])
>  {
> -  struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 };
>    int initrd_size, initrd_pages;
>    void *initrd_mem = NULL;
> +  grub_efi_boot_services_t *b;
> +  grub_efi_status_t status;
>  
>    if (argc == 0)
>      {
> @@ -271,6 +377,27 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
>    if (grub_initrd_init (argc, argv, &initrd_ctx))
>      goto fail;
>  
> +  if (initrd_use_loadfile2)
> +    {
> +      if (!initrd_lf2_handle)
> +        {
> +          b = grub_efi_system_table->boot_services;
> +          status = b->install_multiple_protocol_interfaces (&initrd_lf2_handle,
> +                                                            &load_file2_guid,
> +                                                            &initrd_lf2,
> +                                                            &device_path_guid,
> +                                                            &initrd_lf2_device_path,
> +                                                            NULL);
> +          if (status == GRUB_EFI_OUT_OF_RESOURCES)
> +            {
> +              grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
> +              return grub_errno;
> +            }
> +        }
> +      grub_dprintf ("linux", "Using LoadFile2 initrd loading protocol\n");
> +      return GRUB_ERR_NONE;
> +    }
> +
>    initrd_size = grub_get_initrd_size (&initrd_ctx);
>    grub_dprintf ("linux", "Loading initrd\n");
>  
> -- 
> 2.35.1
> 

I tested this on u-boot n(which also support load_file2 for the initrd).
Even if the user misconfigures the whole thing and try to install the
protocol twice everything seems to be handled properly.

Tested-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Reviewed-by: Ilias Apalodimas <ilias.apalodimas@linaro.org>


  reply	other threads:[~2022-09-08  7:30 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-08-18  8:55 [PATCH resend 0/9] linux: implement LoadFile2 initrd loading Ard Biesheuvel
2022-08-18  8:55 ` [PATCH resend 1/9] loader: drop argv[] argument in grub_initrd_load() Ard Biesheuvel
2022-08-18  8:55 ` [PATCH resend 2/9] efi: move MS-DOS stub out of generic PE header definition Ard Biesheuvel
2022-08-18  8:55 ` [PATCH resend 3/9] arm64/linux: Remove magic number header field check Ard Biesheuvel
2022-08-18  8:55 ` [PATCH resend 4/9] linux/arm: unify ARM/arm64 vs Xen PE/COFF header handling Ard Biesheuvel
2022-08-18  8:55 ` [PATCH resend 5/9] linux/arm: account for COFF headers appearing at unexpected offsets Ard Biesheuvel
2022-08-18  8:55 ` [PATCH resend 6/9] efi: add definition of LoadFile2 protocol Ard Biesheuvel
2022-08-18  8:55 ` [PATCH resend 7/9] efi/efinet: Don't close connections at fini_hw() time Ard Biesheuvel
2022-08-18  8:55 ` [PATCH resend 8/9] efi: implement LoadFile2 initrd loading protocol for Linux Ard Biesheuvel
2022-09-08  7:29   ` Ilias Apalodimas [this message]
2022-08-18  8:55 ` [PATCH resend 9/9] linux: ignore FDT unless we need to modify it Ard Biesheuvel
2022-08-18  8:58 ` [PATCH resend 0/9] linux: implement LoadFile2 initrd loading Ard Biesheuvel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=YxmZ9INMSU6lc00b@hera \
    --to=ilias.apalodimas@linaro.org \
    --cc=ardb@kernel.org \
    --cc=arei@altlinux.org \
    --cc=atishp@atishpatra.org \
    --cc=chenhuacai@loongson.cn \
    --cc=daniel.kiper@oracle.com \
    --cc=dann.frazier@canonical.com \
    --cc=grub-devel@gnu.org \
    --cc=grub-devel@nongnu.org \
    --cc=heinrich.schuchardt@canonical.com \
    --cc=julian.klode@canonical.com \
    --cc=linux-efi@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox