On Wed, Jul 9, 2025 at 4:21 PM Frediano Ziglio
<frediano.zig...@cloud.com> wrote:
>
> On Wed, Jul 9, 2025 at 2:08 PM Ross Lagerwall <ross.lagerw...@citrix.com> 
> wrote:
> >
> > On Tue, Jul 8, 2025 at 9:02 PM Frediano Ziglio via Grub-devel
> > <grub-devel@gnu.org> wrote:
> > >
> > > Allows to load modules using LoadFile2 protocol.
> > > Add and use a new GUID for kernel media device.
> > > This will allow Xen to pick up additional modules using
> > > EFI interface instead of using multiboot2 interface (not
> > > available on x86_64).
> > >
> > > Signed-off-by: Frediano Ziglio <frediano.zig...@cloud.com>
> > > ---
> > >  grub-core/loader/arm64/xen_boot.c | 172 +++++++++++++++++++++++++++++-
> > >  include/grub/efi/api.h            |   5 +
> > >  2 files changed, 176 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/grub-core/loader/arm64/xen_boot.c 
> > > b/grub-core/loader/arm64/xen_boot.c
> > > index 2975a546e..64f685de6 100644
> > > --- a/grub-core/loader/arm64/xen_boot.c
> > > +++ b/grub-core/loader/arm64/xen_boot.c
> > > @@ -68,6 +68,56 @@ enum module_type
> > >  };
> > >  typedef enum module_type module_type_t;
> > >
> > > +static grub_guid_t load_file2_guid = GRUB_EFI_LOAD_FILE2_PROTOCOL_GUID;
> > > +static grub_guid_t device_path_guid = GRUB_EFI_DEVICE_PATH_GUID;
> > > +
> > > +static initrd_media_device_path_t 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 initrd_media_device_path_t kernel_lf2_device_path = {
> > > +  {
> > > +    {
> > > +      GRUB_EFI_MEDIA_DEVICE_PATH_TYPE,
> > > +      GRUB_EFI_VENDOR_MEDIA_DEVICE_PATH_SUBTYPE,
> > > +      sizeof(grub_efi_vendor_media_device_path_t),
> > > +    },
> > > +    XEN_EFI_KERNEL_MEDIA_GUID
> > > +  }, {
> > > +    GRUB_EFI_END_DEVICE_PATH_TYPE,
> > > +    GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE,
> > > +    sizeof(grub_efi_device_path_t)
> > > +  }
> > > +};
> > > +
> > > +typedef struct lf2
> > > +{
> > > +  grub_efi_load_file2_t lf2;
> > > +  grub_efi_handle_t handle;
> > > +  initrd_media_device_path_t *media;
> > > +} lf2_t;
> > > +
> > > +static grub_efi_status_t __grub_efi_api
> > > +grub_efi_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 void lf2_init(lf2_t *lf2, initrd_media_device_path_t *media);
> > > +static grub_err_t lf2_start(lf2_t *lf2);
> > > +static void lf2_done(lf2_t *lf2);
> > > +
> > >  struct xen_boot_binary
> > >  {
> > >    struct xen_boot_binary *next;
> > > @@ -80,6 +130,8 @@ struct xen_boot_binary
> > >
> > >    char *cmdline;
> > >    int cmdline_size;
> > > +
> > > +  lf2_t lf2;
> > >  };
> > >
> > >  static grub_dl_t my_mod;
> > > @@ -289,6 +341,8 @@ single_binary_unload (struct xen_boot_binary *binary)
> > >                     binary->cmdline, binary->cmdline_size);
> > >      }
> > >
> > > +  lf2_done (&binary->lf2);
> > > +
> > >    if (!binary->is_hypervisor)
> > >      grub_list_remove (GRUB_AS_LIST (binary));
> > >
> > > @@ -393,6 +447,7 @@ grub_cmd_xen_module (grub_command_t cmd 
> > > __attribute__((unused)),
> > >    struct xen_boot_binary *module = NULL;
> > >    grub_file_t file = 0;
> > >    int nounzip = 0;
> > > +  initrd_media_device_path_t *media;
> > >
> > >    if (!argc)
> > >      {
> > > @@ -427,6 +482,19 @@ grub_cmd_xen_module (grub_command_t cmd 
> > > __attribute__((unused)),
> > >
> > >    module->is_hypervisor = false;
> > >    module->align = 4096;
> > > +  switch (grub_list_length (GRUB_AS_LIST (module_head)))
> > > +    {
> > > +    case MODULE_IMAGE:
> > > +      media = &kernel_lf2_device_path;
> > > +      break;
> > > +    case MODULE_INITRD:
> > > +      media = &initrd_lf2_device_path;
> > > +      break;
> > > +    default:
> > > +      media = NULL;
> > > +      break;
> > > +    }
> > > +  lf2_init(&module->lf2, media);
> > >
> > >    grub_dprintf ("xen_loader", "Init module and node info\n");
> > >
> > > @@ -438,7 +506,10 @@ grub_cmd_xen_module (grub_command_t cmd 
> > > __attribute__((unused)),
> > >
> > >    xen_boot_binary_load (module, file, argc, argv);
> > >    if (grub_errno == GRUB_ERR_NONE)
> > > -    grub_list_push (GRUB_AS_LIST_P (&module_head), GRUB_AS_LIST 
> > > (module));
> > > +    {
> > > +      grub_list_push (GRUB_AS_LIST_P (&module_head), GRUB_AS_LIST 
> > > (module));
> > > +      lf2_start (&module->lf2);
> > > +    }
> > >
> > >   fail:
> > >    if (file)
> > > @@ -505,6 +576,105 @@ fail:
> > >    return grub_errno;
> > >  }
> > >
> > > +static void
> > > +lf2_init(lf2_t *lf2, initrd_media_device_path_t *media)
> > > +{
> > > +  lf2->lf2.load_file = grub_efi_load_file2;
> > > +  lf2->handle = NULL;
> > > +  lf2->media = media;
> > > +}
> > > +
> > > +static grub_err_t
> > > +lf2_start(lf2_t *lf2)
> > > +{
> > > +  grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
> > > +  grub_efi_status_t status;
> > > +
> > > +  if (lf2->handle)
> > > +    return GRUB_ERR_NONE;
> > > +
> > > +  status = b->install_multiple_protocol_interfaces (&lf2->handle,
> > > +                                                   &load_file2_guid,
> > > +                                                   &lf2->lf2,
> > > +                                                   &device_path_guid,
> > > +                                                   lf2->media,
> > > +                                                   NULL);
> > > +  if (status == GRUB_EFI_OUT_OF_RESOURCES)
> > > +    {
> > > +      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
> > > +      return grub_errno;
> > > +    }
> > > +  else if (status != GRUB_EFI_SUCCESS)
> > > +    {
> > > +      grub_error (GRUB_ERR_BAD_ARGUMENT, N_("failed to install 
> > > protocols"));
> > > +      return grub_errno;
> > > +    }
> > > +
> > > +  return GRUB_ERR_NONE;
> > > +}
> > > +
> > > +static void
> > > +lf2_done(lf2_t *lf2)
> > > +{
> > > +  grub_efi_boot_services_t *b = grub_efi_system_table->boot_services;
> > > +
> > > +  if (!lf2->handle)
> > > +    return;
> > > +
> > > +  b->uninstall_multiple_protocol_interfaces (lf2->handle,
> > > +                                            &load_file2_guid,
> > > +                                            &lf2->lf2,
> > > +                                            &device_path_guid,
> > > +                                            lf2->media,
> > > +                                            NULL);
> > > +  lf2->handle = NULL;
> > > +}
> > > +
> > > +
> > > +static grub_efi_status_t __grub_efi_api
> > > +grub_efi_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_uintn_t size;
> > > +  struct xen_boot_binary *binary, *module;
> > > +  const void *src;
> > > +
> > > +  binary = NULL;
> > > +  FOR_LIST_ELEMENTS (module, module_head)
> > > +    if (this == &module->lf2.lf2)
> > > +      {
> > > +        binary = module;
> > > +        break;
> > > +      }
> > > +
> > > +  if (!binary || buffer_size == NULL)
> > > +    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;
> > > +
> > > +  size = binary->size;
> > > +  if (buffer == NULL || *buffer_size < size)
> > > +    {
> > > +      *buffer_size = size;
> > > +      return GRUB_EFI_BUFFER_TOO_SMALL;
> > > +    }
> > > +
> >
> > This is not compliant with the spec:
> >
> > > BufferSize ... On output with a return code of EFI_SUCCESS, the amount of
> > > data transferred to Buffer.
> >
>
> From 
> https://uefi.org/specs/UEFI/2.10/13_Protocols_Media_Access.html#efi-load-file-protocol-loadfile
>
> BufferSize On input the size of Buffer in bytes. On output with a
> return code of EFI_SUCCESS, the amount of data transferred to Buffer.
> On output with a return code of EFI_BUFFER_TOO_SMALL, the size of
> Buffer required to retrieve the requested file.
>
> It's coherent with the second sentence. Otherwise how does Linux get
> the size of the file?
>

Well it is half compliant. It sets the size when returning
EFI_BUFFER_TOO_SMALL which is enough to make Linux function, but doesn't
set the size when returning EFI_SUCCESS which is not compliant with the
spec.

Ross

_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to