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;
+    }
+
+  grub_dprintf ("xen_loader", "Providing Xen module via 
EFI_LOAD_FILE2_PROTOCOL\n");
+
+  src = (void *) xen_boot_address_align (binary->start, binary->align);
+  grub_memcpy(buffer, src, size);
+
+  return GRUB_EFI_SUCCESS;
+}
+
 static grub_command_t cmd_xen_hypervisor;
 static grub_command_t cmd_xen_module;
 
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index b686e8afe..7d0641ade 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -374,6 +374,11 @@
     { 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68 } \
   }
 
+#define XEN_EFI_KERNEL_MEDIA_GUID \
+  { 0x2a4847d3, 0x990b, 0x4cf2, \
+    { 0x6b, 0xb5, 0x55, 0x71, 0xb4, 0x72, 0x17, 0x21 } \
+  }
+
 #define GRUB_EFI_VENDOR_BOOT_LOADER_INTERFACE_GUID \
   { 0x4a67b082, 0x0a4c, 0x41cf, \
     {0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } \
-- 
2.43.0


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

Reply via email to