>From 9c05aaf80489b7fbec19feee91d9a89c0b0298d2 Mon Sep 17 00:00:00 2001
From: Fu Wei <fu.wei@linaro.org>
Date: Wed, 12 Mar 2014 15:39:26 +0800
Subject: [PATCH] Add multiboot/module command support in linux.c for aarch64.

---
 grub-core/loader/arm64/linux.c | 558 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 556 insertions(+), 2 deletions(-)

diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
index 65129c2..ac40375 100644
--- a/grub-core/loader/arm64/linux.c
+++ b/grub-core/loader/arm64/linux.c
@@ -30,6 +30,9 @@
 #include <grub/efi/pe32.h>
 #include <grub/i18n.h>
 #include <grub/lib/cmdline.h>
+#include <grub/misc.h>
+#include <grub/cache.h>
+
 
 GRUB_MOD_LICENSE ("GPLv3+");
 
@@ -37,6 +40,21 @@ GRUB_MOD_LICENSE ("GPLv3+");
 #define BYTES_TO_PAGES(bytes)   (((bytes) + 0xfff) >> GRUB_EFI_PAGE_SHIFT)
 #define GRUB_EFI_PE_MAGIC	0x5A4D
 
+/* #define for multiboot Xen */
+#define ADDRESS_ALIGN(addr,size) ((void *)((((grub_int64_t)addr)+(size)-1)&\
+		(~((size)-1))))
+
+#ifdef XEN_MULTIBOOT_LOAD_ADDR_DEFAULT
+#define XEN_BASE_ADDR  (0x80A00000)
+#define DOM0_KERNEL_BASE_ADDR  (0x80080000)
+#define DTB_BASE_ADDR  (0x88000000)
+#else
+#define XEN_BASE_ADDR  (0)
+#define DOM0_KERNEL_BASE_ADDR  (0)
+#define DTB_BASE_ADDR  (0)
+#endif
+/******************************/
+
 static grub_efi_guid_t fdt_guid = GRUB_EFI_DEVICE_TREE_GUID;
 
 static grub_dl_t my_mod;
@@ -51,6 +69,47 @@ static grub_uint32_t cmdline_size;
 static grub_addr_t initrd_start;
 static grub_addr_t initrd_end;
 
+/* variables for multiboot Xen */
+static int dom0_loaded;
+
+static void *xen_addr_unaligned;
+static void *xen_addr;
+static grub_uint64_t xen_size;
+
+static char *xen_args;
+static grub_uint32_t xen_cmdline_size;
+
+static void *dom0_kernel_addr;
+static grub_uint64_t dom0_kernel_size;
+
+static char *dom0_args;
+static grub_uint32_t dom0_cmdline_size;
+
+static grub_addr_t dom0_initrd_addr;
+static grub_uint64_t dom0_initrd_size;
+
+typedef void (*kernel_entry_t) (void *, int, int, int);
+/* Enumerations.  */
+enum grub_multiboot_module_type
+  {
+    GRUB_MULTIBOOT_MODULE_KERNEL,
+    GRUB_MULTIBOOT_MODULE_INITRD,
+    GRUB_MULTIBOOT_MODULE_OTHER
+  };
+typedef enum grub_multiboot_module_type grub_multiboot_module_type_t;
+static grub_multiboot_module_type_t type = GRUB_MULTIBOOT_MODULE_KERNEL;
+
+enum grub_multiboot_unload_type
+  {
+    GRUB_MULTIBOOT_UNLOAD_NONE,
+    GRUB_MULTIBOOT_UNLOAD_XEN,
+    GRUB_MULTIBOOT_UNLOAD_KERNEL,
+    GRUB_MULTIBOOT_UNLOAD_INITRD,
+    GRUB_MULTIBOOT_UNLOAD_ALL
+  };
+typedef enum grub_multiboot_unload_type grub_multiboot_unload_type_t;
+/******************************/
+
 static void *loaded_fdt;
 static void *fdt;
 
@@ -68,7 +127,7 @@ get_firmware_fdt (void)
     if (grub_memcmp (&tables[i].vendor_guid, &fdt_guid, sizeof (fdt_guid)) == 0)
       {
 	firmware_fdt = tables[i].vendor_table;
-	grub_dprintf ("linux", "found registered FDT @ 0x%p\n", firmware_fdt);
+	grub_dprintf ("linux", "found registered FDT @ %p\n", firmware_fdt);
 	break;
       }
 
@@ -97,7 +156,7 @@ get_fdt (void)
   size += 0x400;
 
   grub_dprintf ("linux", "allocating %ld bytes for fdt\n", size);
-  fdt = grub_efi_allocate_pages (0, BYTES_TO_PAGES (size));
+  fdt = grub_efi_allocate_pages (DTB_BASE_ADDR, BYTES_TO_PAGES (size));
   if (!fdt)
     return;
 
@@ -464,8 +523,495 @@ fail:
   return grub_errno;
 }
 
+/**** for booting Xen on arm64 ****/
+static grub_err_t
+finalize_params_xen (void)
+{
+  grub_efi_boot_services_t *b;
+  grub_efi_status_t status;
+  int chosen_node, module_node_0, module_node_1, retval;
+
+  get_fdt ();
+  if (!fdt)
+      goto failure;
+
+  chosen_node = grub_fdt_find_subnode (fdt, 0, "chosen");
+  if (chosen_node < 0)
+      chosen_node = grub_fdt_add_subnode (fdt, 0, "chosen");
+
+  if (chosen_node < 1)
+      goto failure;
+
+  retval = grub_fdt_set_prop32 (fdt, chosen_node, "#address-cells", 0x1);
+  retval = grub_fdt_set_prop32 (fdt, chosen_node, "#size-cells", 0x1);
+
+  if (retval)
+      goto failure;
+
+  /* Set Xen kernel bootargs info */
+  if (xen_args && xen_cmdline_size > 0)
+    {
+      grub_dprintf ("linux", "Xen cmdline : %s @ %p size:%d\n",
+            xen_args, xen_args, xen_cmdline_size);
+
+      retval = grub_fdt_set_prop (fdt, chosen_node, "xen,xen-bootargs",
+                    xen_args, xen_cmdline_size);
+      if (retval)
+          goto failure;
+
+    } else {
+      grub_dprintf ("linux", "Please set Xen bootargs!\n");
+      goto failure;
+    }
+
+  /* Set dom0 kernel info */
+  if (dom0_kernel_addr && dom0_kernel_size > 0)
+    {
+      grub_dprintf ("linux", "Dom0 kernel @ %p size:0x%lx\n",
+              dom0_kernel_addr, dom0_kernel_size);
+
+      module_node_0 = grub_fdt_find_subnode (fdt, chosen_node, "module@0");
+      if (module_node_0 < 0)
+          module_node_0 = grub_fdt_add_subnode (fdt, chosen_node, "module@0");
+
+      retval = grub_fdt_set_prop (fdt, module_node_0, "compatible",
+             "xen,linux-zimage\0xen,multiboot-module",
+             sizeof("xen,linux-zimage\0xen,multiboot-module"));
+      if (retval)
+          goto failure;
+
+      grub_dprintf ("linux", "Dom0 kernel compatible = %s size = %ld\n",
+              "xen,linux-zimage xen,multiboot-module",
+              sizeof("xen,linux-zimage\0xen,multiboot-module"));
+
+      grub_uint32_t dom0_kernel_reg[2];
+      grub_uint64_t temp_addr = (grub_uint64_t)dom0_kernel_addr;
+      dom0_kernel_reg[0] = grub_cpu_to_be32((grub_uint32_t)temp_addr);
+      dom0_kernel_reg[1] = grub_cpu_to_be32((grub_uint32_t)dom0_kernel_size);
+
+      grub_fdt_set_prop (fdt, module_node_0, "reg", dom0_kernel_reg, 8);
+      if (retval)
+          goto failure;
+      grub_dprintf ("linux", "Dom0 kernel reg = <0x%012lx 0x%012lx>\n",
+              (long unsigned int) dom0_kernel_addr, dom0_kernel_size);
+
+      if (dom0_args && dom0_cmdline_size > 0)
+        {
+          grub_dprintf ("linux", "Dom0 cmdline : %s @ %p size:%d\n",
+                  dom0_args, dom0_args, dom0_cmdline_size);
+          retval = grub_fdt_set_prop (fdt, module_node_0, "bootargs",
+                  dom0_args, grub_strlen (dom0_args) + 1);
+          if (retval)
+              goto failure;
+        }
+    } else {
+      grub_dprintf ("linux", "Please load Dom0 kernel with cmdline by module command!\n");
+      goto failure;
+    }
+
+  /* Set dom0 initrd info (optional)*/
+  if (dom0_initrd_addr && dom0_initrd_size > 0)
+    {
+      grub_dprintf ("linux", "Dom0 Initrd @ 0x%012lx-0x%012lx\n",
+              dom0_initrd_addr, dom0_initrd_addr + dom0_initrd_size);
+
+      module_node_1 = grub_fdt_find_subnode (fdt, chosen_node, "module@1");
+      if (module_node_1 < 0)
+          module_node_1 = grub_fdt_add_subnode (fdt, chosen_node, "module@1");
+
+      retval = grub_fdt_set_prop (fdt, module_node_1, "compatible",
+              "xen,linux-initrd\0xen,multiboot-module",
+              sizeof("xen,linux-initrd\0xen,multiboot-module"));
+      if (retval)
+          goto failure;
+
+      grub_uint32_t dom0_initrd_reg[2];
+      grub_uint64_t temp_addr = (grub_uint64_t)dom0_initrd_addr;
+      dom0_initrd_reg[0] = grub_cpu_to_be32((grub_uint32_t)temp_addr);
+      dom0_initrd_reg[1] = grub_cpu_to_be32((grub_uint32_t)dom0_initrd_size);
+
+      grub_fdt_set_prop (fdt, module_node_1, "reg", dom0_initrd_reg, 8);
+      if (retval)
+          goto failure;
+
+      grub_dprintf ("linux", "Dom0 initrd reg = <0x%012lx 0x%012lx>\n",
+              (long unsigned int)dom0_initrd_addr, dom0_initrd_size);
+    }
+
+  b = grub_efi_system_table->boot_services;
+  status = b->install_configuration_table (&fdt_guid, fdt);
+  if (status != GRUB_EFI_SUCCESS)
+      goto failure;
+
+  grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n",
+        fdt);
+
+  return (GRUB_ERR_NONE);
+
+failure:
+  grub_efi_free_pages ((grub_efi_physical_address_t) fdt,
+		       BYTES_TO_PAGES (grub_fdt_get_totalsize (fdt)));
+  fdt = NULL;
+  return (grub_error(GRUB_ERR_BAD_OS, "failed to install/update FDT"));
+}
+
+static grub_err_t
+grub_xen_boot (void)
+{
+  grub_err_t retval;
+  kernel_entry_t linuxmain;
+
+  retval = finalize_params_xen();
+  if (retval != GRUB_ERR_NONE)
+      return (retval);
+
+#if 0
+  /* FIXME: I am not sure if I really need this, grub works fine without it*/
+  grub_arch_sync_caches ((void *) xen_addr, xen_size);
+  if (xen_args && xen_cmdline_size > 0) {
+      grub_arch_sync_caches ((void *) xen_args, xen_cmdline_size);
+  }
+  if (dom0_kernel_addr && dom0_kernel_size > 0) {
+      grub_arch_sync_caches ((void *) dom0_kernel_addr, dom0_kernel_size);
+  }
+  if (dom0_args && dom0_cmdline_size > 0) {
+      grub_arch_sync_caches ((void *) dom0_args, dom0_cmdline_size);
+  }
+
+  if (dom0_initrd_addr && dom0_initrd_size > 0) {
+      grub_arch_sync_caches ((void *) dom0_initrd_addr, dom0_initrd_size);
+  }
+#endif
+
+  grub_dprintf ("linux", "Jumping to Xen... (@ %p)\n", xen_addr);
+
+   /* Boot the kernel.
+    *   Arguments to Xen:
+    *     x0 - address of DTB
+    *     x1 - 0 (reserved for future use)
+    *     x2 - 0 (reserved for future use)
+    *     x3 - 0 (reserved for future use)
+    */
+   linuxmain = (kernel_entry_t) xen_addr;
+
+  /* FIXME: I am not sure if I really need this, grub works fine without it*/
+//  grub_arm64_disable_caches_mmu ();
+
+   linuxmain (fdt, 0, 0, 0);
+
+   return (grub_error (GRUB_ERR_BAD_OS, "Linux call returned"));
+}
+
+static grub_err_t
+grub_module_unload (grub_multiboot_unload_type_t unload_type)
+{
+  if (dom0_initrd_addr &&
+         (unload_type == GRUB_MULTIBOOT_UNLOAD_INITRD ||
+          unload_type == GRUB_MULTIBOOT_UNLOAD_ALL)) {
+      grub_efi_free_pages ((grub_efi_physical_address_t) dom0_initrd_addr,
+              BYTES_TO_PAGES (dom0_initrd_size));
+      grub_dprintf ("linux", "Dom0 initrd memory free @ %p size: %lld\n",
+              (void *)dom0_initrd_addr, (long long) dom0_initrd_size);
+      dom0_initrd_size = 0;
+      dom0_initrd_addr = (grub_addr_t)0;
+      type = GRUB_MULTIBOOT_MODULE_INITRD;
+  }
+
+  if (dom0_kernel_addr &&
+         (unload_type == GRUB_MULTIBOOT_UNLOAD_KERNEL ||
+          unload_type == GRUB_MULTIBOOT_UNLOAD_ALL)) {
+      grub_efi_free_pages ((grub_efi_physical_address_t) dom0_kernel_addr,
+            BYTES_TO_PAGES (dom0_kernel_size));
+      grub_dprintf ("linux", "Dom0 kernel memory free @ %p size: %lld\n",
+              dom0_kernel_addr, (long long) dom0_kernel_size);
+      dom0_kernel_size = 0;
+      dom0_kernel_addr = (void *)0;
+      type = GRUB_MULTIBOOT_MODULE_KERNEL;
+      if (dom0_args) {
+          grub_free (dom0_args);
+              grub_dprintf ("linux", "Dom0 args memory free @ %p size: %lld\n",
+                      dom0_args, (long long) dom0_cmdline_size);
+          dom0_cmdline_size = 0;
+          dom0_args = (char *)0;
+      }
+  }
+
+  if (xen_addr_unaligned &&
+         (unload_type == GRUB_MULTIBOOT_UNLOAD_XEN ||
+          unload_type == GRUB_MULTIBOOT_UNLOAD_ALL)) {
+      grub_efi_free_pages ((grub_efi_physical_address_t) xen_addr_unaligned,
+            (BYTES_TO_PAGES (xen_size) + BYTES_TO_PAGES (0x200000)));
+      grub_dprintf ("linux", "Xen memory free pages @ %p size: %ld\n",
+              xen_addr_unaligned,
+              (BYTES_TO_PAGES (xen_size) + BYTES_TO_PAGES (0x200000)));
+      xen_size = 0;
+      xen_addr = (void *)0;
+      type = GRUB_MULTIBOOT_MODULE_KERNEL;
+      if (xen_args) {
+          grub_free (xen_args);
+          grub_dprintf ("linux", "Xen args memory free @ %p size: %lld\n",
+                  xen_args, (long long) xen_cmdline_size);
+          xen_cmdline_size = 0;
+          xen_args = (char *)0;
+      }
+  }
+
+  return (GRUB_ERR_NONE);
+}
+
+static grub_err_t
+grub_multiboot_unload (void)
+{
+  grub_dl_unref (my_mod);
+  loaded = 0;
+  dom0_loaded = 0;
+  grub_module_unload (GRUB_MULTIBOOT_UNLOAD_ALL);
+  type = GRUB_MULTIBOOT_MODULE_KERNEL;
+  if (fdt)
+    grub_efi_free_pages ((grub_efi_physical_address_t) fdt,
+            BYTES_TO_PAGES (grub_fdt_get_totalsize (fdt)));
+
+  return (GRUB_ERR_NONE);
+}
+
+static grub_err_t
+grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
+		 int argc, char *argv[])
+{
+  struct grub_linux_initrd_context initrd_ctx;
+  int initrd_size, initrd_pages;
+  void *initrd_mem = NULL;
+  grub_multiboot_unload_type_t unload_type = GRUB_MULTIBOOT_UNLOAD_NONE;
+  grub_file_t file = 0;
+
+  if (argc == 0)
+    {
+      grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename(and option) expected"));
+      goto fail;
+    }
+
+  if (!loaded)
+    {
+      grub_error (GRUB_ERR_BAD_ARGUMENT,
+          N_("you need to load the Xen kernel first"));
+      goto fail;
+    }
+
+  /* get module type */
+  if (argc >= 3 && grub_strcmp (argv[0], "--type") == 0)
+    {
+      argc--;
+      argv++;
+      if (grub_strcmp (argv[0], "kernel") == 0) {
+          type = GRUB_MULTIBOOT_MODULE_KERNEL;
+      } else if (grub_strcmp (argv[0], "initrd") == 0) {
+              type = GRUB_MULTIBOOT_MODULE_INITRD;
+          } else {
+              grub_error (GRUB_ERR_BAD_ARGUMENT,
+                  N_("please check your module type [kernel, initrd]\n"));
+              goto fail;
+          }
+      argc--;
+      argv++;
+    }
+
+  if (type != GRUB_MULTIBOOT_MODULE_KERNEL &&
+          type != GRUB_MULTIBOOT_MODULE_INITRD) {
+      grub_error (GRUB_ERR_BAD_ARGUMENT,
+          N_("Do not support this module type!\n"
+             "Or you have loaded dom0 kernel and initrd.\n"
+             "If you want to reload any of them, "
+             "please use --type <kernel/initrd>"));
+      goto fail;
+    }
+
+  if (type == GRUB_MULTIBOOT_MODULE_KERNEL) {
+      if (argc == 0)
+        {
+          grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+          goto fail;
+        }
+
+      file = grub_file_open (argv[0]);
+      if (!file)
+          goto fail;
+      unload_type = GRUB_MULTIBOOT_UNLOAD_KERNEL;
+      grub_module_unload (unload_type);
+
+      dom0_kernel_size = grub_file_size (file);
+
+      grub_dprintf ("linux", "Dom0 kernel file size: %lld\n",
+              (long long) dom0_kernel_size);
+      dom0_kernel_addr = (void *) ((unsigned long)grub_efi_allocate_pages (
+              DOM0_KERNEL_BASE_ADDR ,
+              BYTES_TO_PAGES(dom0_kernel_size)));
+      grub_dprintf ("linux", "Dom0 kernel numpages: %lld\n",
+            (long long) BYTES_TO_PAGES (dom0_kernel_size));
+      if (!dom0_kernel_addr)
+        {
+          grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+          goto fail_all;
+        }
+
+      if (grub_file_read (file, dom0_kernel_addr, dom0_kernel_size)
+          < (grub_int64_t) dom0_kernel_size)
+        {
+            if (!grub_errno)
+            grub_error (GRUB_ERR_BAD_OS,
+                    N_("premature end of file %s"), argv[0]);
+            goto fail_all;
+        }
+
+      grub_dprintf ("linux", "Dom0 kernel @ %p\n", dom0_kernel_addr);
+
+      /* FIXME: Do we need to have "BOOT_IMAGE="?? */
+      dom0_cmdline_size = grub_loader_cmdline_size (argc, argv) +
+              sizeof (LINUX_IMAGE);
+      dom0_args = grub_malloc (dom0_cmdline_size);
+      if (!dom0_args)
+        {
+            grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+            goto fail_all;
+        }
+      grub_memcpy (dom0_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+      grub_create_loader_cmdline (argc, argv,
+              dom0_args + sizeof (LINUX_IMAGE) - 1,
+              dom0_cmdline_size);
+      grub_dprintf ("linux", "Dom0 kernel cmdline @ %p %s, size: %d\n",
+              dom0_args, dom0_args, dom0_cmdline_size);
+
+      dom0_loaded = 1;
+      type++;
+  } else {
+	  if (argc >= 2) {
+          grub_error (GRUB_ERR_BAD_ARGUMENT,
+          N_("some useless arguments after initrd file name!\n"
+             "If you want to reload dom0 kernel, "
+             "please use \"--type kernel\" argument!"));
+          goto fail;
+	  }
+      if (grub_initrd_init (argc, argv, &initrd_ctx))
+        goto fail;
+
+      unload_type = GRUB_MULTIBOOT_UNLOAD_INITRD;
+      grub_module_unload (unload_type);
+
+      initrd_size = grub_get_initrd_size (&initrd_ctx);
+      grub_dprintf ("linux", "Loading Dom0 initrd\n");
+
+      initrd_pages = (BYTES_TO_PAGES (initrd_size));
+      initrd_mem = grub_efi_allocate_pages (0, initrd_pages);
+      if (!initrd_mem)
+        {
+            grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+            goto fail_initrd;
+        }
+
+      if (grub_initrd_load (&initrd_ctx, argv, initrd_mem))
+        goto fail_initrd;
+
+      dom0_initrd_addr = (grub_addr_t) initrd_mem;
+      dom0_initrd_size = (grub_uint64_t)initrd_size;
+      grub_dprintf ("linux", "Dom0 Initrd [addr=%p, size=0x%lx]\n",
+            (void *) dom0_initrd_addr, dom0_initrd_size);
+
+      type++;
+      grub_initrd_close (&initrd_ctx);
+  }
+
+ fail_all:
+    if (file)
+        grub_file_close (file);
+// fail_kernel:
+    if (!dom0_loaded && dom0_kernel_addr)
+        grub_module_unload (GRUB_MULTIBOOT_UNLOAD_KERNEL);
+ fail_initrd:
+    if (!dom0_initrd_addr && initrd_mem)
+        grub_module_unload (GRUB_MULTIBOOT_UNLOAD_INITRD);
+ fail:
+  return (grub_errno);
+}
+
+static grub_err_t
+grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)),
+		int argc, char *argv[])
+{
+  grub_file_t file = 0;
+
+  grub_dl_ref (my_mod);
+
+  if (argc == 0)
+    {
+      grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+      goto fail;
+    }
+
+  file = grub_file_open (argv[0]);
+  if (!file)
+    goto fail;
+
+  grub_module_unload (GRUB_MULTIBOOT_UNLOAD_XEN);
+
+  xen_size = grub_file_size (file);
+
+  grub_loader_unset();
+
+  grub_dprintf ("linux", "Xen kernel file size: %lld\n", (long long) xen_size);
+  xen_addr_unaligned = (void *) ((unsigned long)grub_efi_allocate_pages (
+          XEN_BASE_ADDR,
+          (BYTES_TO_PAGES (xen_size) + BYTES_TO_PAGES (0x200000))));
+  xen_addr = ADDRESS_ALIGN(xen_addr_unaligned, 0x200000);
+  grub_dprintf ("linux", "Xen kernel numpages: %lld\n",
+        (long long) BYTES_TO_PAGES (xen_size));
+  if (!xen_addr)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+      goto fail;
+    }
+
+  if (grub_file_read (file, xen_addr, xen_size)
+      < (grub_int64_t) xen_size)
+    {
+      if (!grub_errno)
+	grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"), argv[0]);
+      goto fail;
+    }
+
+  grub_dprintf ("linux", "Xen kernel @ %p\n", xen_addr);
+
+  /* FIXME: Do we really need to have "BOOT_IMAGE="?? */
+  xen_cmdline_size = grub_loader_cmdline_size (argc, argv);
+  xen_args = grub_malloc (xen_cmdline_size);
+  if (!xen_args)
+    {
+      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+      goto fail;
+    }
+  grub_memcpy (xen_args, "BOOT_IMAGE=", sizeof ("BOOT_IMAGE="));
+  grub_create_loader_cmdline (argc-1, argv+1,
+          xen_args,
+          xen_cmdline_size);
+  grub_dprintf ("linux", "Xen cmdline @ %p %s, size: %d\n",
+          xen_args, xen_args, xen_cmdline_size);
+  if (grub_errno == GRUB_ERR_NONE)
+    {
+      grub_loader_set (grub_xen_boot, grub_multiboot_unload, 0);
+      loaded = 1;
+    }
+
+fail:
+  if (file)
+    grub_file_close (file);
+  if (grub_errno != GRUB_ERR_NONE)
+    {
+      grub_module_unload (GRUB_MULTIBOOT_UNLOAD_ALL);
+    }
+
+  return (grub_errno);
+}
 
 static grub_command_t cmd_linux, cmd_initrd, cmd_devicetree;
+static grub_command_t cmd_multiboot, cmd_module;
 
 GRUB_MOD_INIT (linux)
 {
@@ -476,6 +1022,12 @@ GRUB_MOD_INIT (linux)
   cmd_devicetree =
     grub_register_command ("devicetree", grub_cmd_devicetree, 0,
 			   N_("Load DTB file."));
+  cmd_multiboot =
+    grub_register_command ("multiboot", grub_cmd_multiboot, 0,
+			   N_("Load Xen kernel file."));
+  cmd_module =
+    grub_register_command ("module", grub_cmd_module, 0,
+			   N_("Load module file for Xen."));
   my_mod = mod;
 }
 
@@ -484,4 +1036,6 @@ GRUB_MOD_FINI (linux)
   grub_unregister_command (cmd_linux);
   grub_unregister_command (cmd_initrd);
   grub_unregister_command (cmd_devicetree);
+  grub_unregister_command (cmd_multiboot);
+  grub_unregister_command (cmd_module);
 }
-- 
1.8.3.1


