All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniel Kiper <dkiper@net-space.pl>
To: Nikita Ermakov <arei@altlinux.org>
Cc: GRUB development mailing list <grub-devel@gnu.org>,
	Ard Biesheuvel <ard.biesheuvel@arm.com>,
	Heinrich Schuchardt <xypron.glpk@gmx.de>,
	Leif Lindholm <leif.lindholm@linaro.org>,
	Fu Wei <tekkamanninja@gmail.com>
Subject: Re: [PATCH v3 3/7] efi: implemented LoadFile2 initrd loading protocol for Linux
Date: Thu, 25 Nov 2021 16:52:09 +0100	[thread overview]
Message-ID: <20211125155209.t3kxzu7japkttsqq@tomti.i.net-space.pl> (raw)
In-Reply-To: <20211028203118.7908-4-arei@altlinux.org>

On Thu, Oct 28, 2021 at 11:31:16PM +0300, Nikita Ermakov wrote:
> From: Ard Biesheuvel <ard.biesheuvel@arm.com>
>
> 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 <ard.biesheuvel@arm.com>
> Signed-off-by: Nikita Ermakov <arei@altlinux.org>
> ---
>  grub-core/loader/arm64/linux.c | 117 ++++++++++++++++++++++++++++++++-
>  1 file changed, 116 insertions(+), 1 deletion(-)
>
> diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
> index aed7a200b..6b03455d1 100644
> --- a/grub-core/loader/arm64/linux.c
> +++ b/grub-core/loader/arm64/linux.c
> @@ -48,9 +48,18 @@ static grub_uint32_t cmdline_size;
>  static grub_addr_t initrd_start;
>  static grub_addr_t initrd_end;
>
> +static struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 };
> +static grub_efi_handle_t initrd_lf2_handle;
> +static int initrd_use_loadfile2;

Please explicitly initialize these two variables.

> +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;
> +
>  grub_err_t
>  grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh)
>  {
> +  struct grub_pe32_coff_header *coff_header;
> +  struct grub_pe32_optional_header *optional_header;
> +
>    if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE)
>      return grub_error(GRUB_ERR_BAD_OS, "invalid magic number");
>
> @@ -61,6 +70,21 @@ grub_arch_efi_linux_check_image (struct linux_arch_kernel_header * lh)
>    grub_dprintf ("linux", "UEFI stub kernel:\n");
>    grub_dprintf ("linux", "PE/COFF header @ %08x\n", lh->hdr_offset);
>
> +  coff_header = (struct grub_pe32_coff_header *)((unsigned long)lh + lh->hdr_offset);

coff_header = (struct grub_pe32_coff_header *) ((grub_addr_t) lh + lh->hdr_offset);

... please note missing spaces too.

> +  optional_header = (struct grub_pe32_optional_header *)(coff_header + 1);

(struct grub_pe32_optional_header *) (coff_header + 1);

> +  /*
> +   * Linux kernels built for any architecture are guaranteed to support the
> +   * LoadFile2 based initrd loading protocol if the image version is >= 1.
> +   */
> +  if (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;
>  }
>
> @@ -230,13 +254,86 @@ allocate_initrd_mem (int initrd_pages)
>  				       GRUB_EFI_LOADER_DATA);
>  }
>
> +struct initrd_media_device_path {
> +  grub_efi_vendor_media_device_path_t	vendor;
> +  grub_efi_device_path_t		end;
> +} GRUB_PACKED;

typedef struct initrd_media_device_path initrd_media_device_path_t;

And please use initrd_media_device_path_t instead of "struct initrd_media_device_path".

> +
> +#define LINUX_EFI_INITRD_MEDIA_GUID  \
> +  { 0x5568e427, 0x68fc, 0x4f3d, \
> +    { 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68 } \
> +  }

Please move struct initrd_media_device_path and
LINUX_EFI_INITRD_MEDIA_GUID definitions to the include/grub/efi/api.h file.

> +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)
> +  }
> +};

This declaration/initialization should be behind device_path_guid declaration.

> +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);

Please drop this...

> +
> +static grub_efi_load_file2_t initrd_lf2 = {
> +  grub_efi_initrd_load_file2
> +};

... and move this behind grub_efi_initrd_load_file2() definition.

> +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)

This works only because UEFI RISC-V/ARM and "normal" RISC-V/ARM calling
conventions are the same. This will not work on x86_64. So, we have to
introduce something like __grub_efi_api macro. It should be empty for
at least for RISC-V and ARM but it should be "__attribute__ ((ms_abi))"
for at least for x86_64. I think the __grub_efi_api macro should be
defined in include/grub/efi/api.h next to efi_call_* definitions.

> +{
> +  grub_efi_status_t status = GRUB_EFI_SUCCESS;
> +  grub_efi_uintn_t initrd_size;
> +
> +  if (!this || this != &initrd_lf2 || !buffer_size)

if (this == NULL || this != &initrd_lf2 || buffer_size == NULL)

Please use NULL explicitly below too...

> +    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");

s/LOAD_FILE2_PROTOCOL/EFI_LOAD_FILE2_PROTOCOL/

> +  if (grub_initrd_load (&initrd_ctx, buffer))

if (grub_initrd_load (&initrd_ctx, buffer) != GRUB_ERR_NONE))

> +    status = GRUB_EFI_LOAD_ERROR;

According to the UEFI spec this should be GRUB_EFI_DEVICE_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_boot_services_t *b = grub_efi_system_table->boot_services;

> +  grub_efi_status_t status;
>
>    if (argc == 0)
>      {
> @@ -254,6 +351,24 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
>    if (grub_initrd_init (argc, argv, &initrd_ctx))
>      goto fail;
>
> +  if (initrd_use_loadfile2 && !initrd_lf2_handle)
> +    {
> +      b = grub_efi_system_table->boot_services;

... then you can drop this.

> +      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;

s/return grub_errno/goto fail/ otherwise your are leaking memory.

Or you can move protocols installation to the beginning of the function
and return immediately in case of error.

> +	}

I think we should not ignore the other UEFI errors here.

> +      grub_dprintf ("linux", "LoadFile2 initrd loading protocol installed\n");
> +      return GRUB_ERR_NONE;
> +    }
> +
>    initrd_size = grub_get_initrd_size (&initrd_ctx);
>    grub_dprintf ("linux", "Loading initrd\n");

Daniel


  reply	other threads:[~2021-11-25 15:52 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-10-28 20:31 [PATCH v3 0/7] Add LoadFile2 and riscv Linux loader Nikita Ermakov
2021-10-28 20:31 ` [PATCH v3 1/7] loader: drop argv[] argument in grub_initrd_load() Nikita Ermakov
2021-11-25 13:23   ` Daniel Kiper
2021-10-28 20:31 ` [PATCH v3 2/7] efi: add definition of LoadFile2 protocol Nikita Ermakov
2021-11-25 13:30   ` Daniel Kiper
2021-10-28 20:31 ` [PATCH v3 3/7] efi: implemented LoadFile2 initrd loading protocol for Linux Nikita Ermakov
2021-11-25 15:52   ` Daniel Kiper [this message]
2022-04-15 20:00   ` dann frazier
2021-10-28 20:31 ` [PATCH v3 4/7] linux: ignore FDT unless we need to modify it Nikita Ermakov
2021-11-25 16:16   ` Daniel Kiper
2021-10-28 20:31 ` [PATCH v3 5/7] loader: Move arm64 linux loader to common code Nikita Ermakov
2021-11-25 16:20   ` Daniel Kiper
2021-10-28 20:31 ` [PATCH v3 6/7] RISC-V: Update image header Nikita Ermakov
2021-11-25 16:29   ` Daniel Kiper
2021-10-28 20:31 ` [PATCH v3 7/7] RISC-V: Use common linux loader Nikita Ermakov
2021-11-25 16:32   ` Daniel Kiper
2021-10-29  1:38 ` [PATCH v3 0/7] Add LoadFile2 and riscv Linux loader Heinrich Schuchardt
2021-11-24 14:50 ` Fu Wei

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=20211125155209.t3kxzu7japkttsqq@tomti.i.net-space.pl \
    --to=dkiper@net-space.pl \
    --cc=ard.biesheuvel@arm.com \
    --cc=arei@altlinux.org \
    --cc=grub-devel@gnu.org \
    --cc=leif.lindholm@linaro.org \
    --cc=tekkamanninja@gmail.com \
    --cc=xypron.glpk@gmx.de \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.