>From 8d09f47e47fa2fd46c32014be1edec61e76489a9 Mon Sep 17 00:00:00 2001
From: Fu Wei <fu.wei@linaro.org>
Date: Tue, 17 Jun 2014 00:34:57 +0800
Subject: [PATCH] Add multiboot/module command support in linux module for
 aarch64 Xen(fdt) boot.

But it also can easily expand these commands to support other images by
implementing "struct multiboot_function".

- the implementation for Xen is following  <Multiboot on ARM Specification>:
http://wiki.xen.org/wiki/Xen_ARM_with_Virtualization_Extensions/Multiboot
and xen/docs/misc/arm/device-tree/booting.txt in Xen source code.

- Add multiboot command for loading multiboot kernel image.
  Usage:  multiboot <the path of kernel image file> [cmdline]

- Add module command for loading multiboot module.
  Usage:  module [option] <the path of module file> [cmdline]

  The [option]  for Xen is [--type <compatible stream in FDT>].
  For now, the <compatible stream in FDT> could be :
  "multiboot,kernel", "multiboot,ramdisk", "multiboot,module",
  "xen,xsm-policy" or the custom compatible stream

- Add some common functions of non-stub kernel boot for arm64:
  void grub_arm64_prepare_platform (void); (#include <grub/arm64/system.h>)

  in kernel module of GRUB for arm64:
  void grub_arch_disable_interrupts (void);
  void grub_arm64_disable_caches_mmu (void);

- Add stub-kernel boot support for arm64:
  support stub-kernel detection and alignment info detection
  provide device_handle data in loaded_image
  provide file_path data in loaded_image

- The reason of adding this functionality to the existing "linux" module
rather than "multiboot(2)"

  The multiboot specification is defined for x86. The multiboot2 does not
  describe an ARM port, but talks only about x86 and MIPS, and for several
  reasons this seems to be overkill.
  So we add multiboot commands into the "linux" module to avoid using the code
  of the "multiboot(2)" mudule.

- The example of this support is <How to boot Xen with GRUB on AArch64 FVP_base model>
  https://wiki.linaro.org/LEG/Engineering/Grub2/Xen_booting_on_FVP_Base_AEMv8A
---
 grub-core/Makefile.am                  |   4 +
 grub-core/Makefile.core.def            |   4 +
 grub-core/kern/arm64/cache_flush.S     |  31 ++
 grub-core/kern/arm64/misc.c            |  34 ++
 grub-core/kern/arm64/misc_irq.S        |  35 ++
 grub-core/loader/arm64/linux.c         |  27 ++
 grub-core/loader/arm64/multiboot.c     | 693 +++++++++++++++++++++++++++++++++
 grub-core/loader/arm64/multiboot_fdt.c | 302 ++++++++++++++
 include/grub/arm64/linux.h             |   8 +
 include/grub/arm64/multiboot.h         | 100 +++++
 include/grub/arm64/multiboot_fdt.h     |  72 ++++
 include/grub/arm64/system.h            |   7 +
 12 files changed, 1317 insertions(+)
 create mode 100644 grub-core/kern/arm64/misc.c
 create mode 100644 grub-core/kern/arm64/misc_irq.S
 create mode 100644 grub-core/loader/arm64/multiboot.c
 create mode 100644 grub-core/loader/arm64/multiboot_fdt.c
 create mode 100644 include/grub/arm64/multiboot.h
 create mode 100644 include/grub/arm64/multiboot_fdt.h
 create mode 100644 include/grub/arm64/system.h

diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
index 5c087c8..5a82b64 100644
--- a/grub-core/Makefile.am
+++ b/grub-core/Makefile.am
@@ -238,6 +238,10 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h
 endif
 
+if COND_arm64
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/arm64/system.h
+endif
+
 if COND_emu
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/datetime.h
 KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/emu/misc.h
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 42443bc..342bb45 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -269,6 +269,8 @@ kernel = {
   arm64 = kern/arm64/cache_flush.S;
   arm64 = kern/arm64/dl.c;
   arm64 = kern/arm64/dl_helper.c;
+  arm64 = kern/arm64/misc.c;
+  arm64 = kern/arm64/misc_irq.S;
 
   emu = disk/host.c;
   emu = kern/emu/cache_s.S;
@@ -1673,6 +1675,8 @@ module = {
   ia64_efi = loader/ia64/efi/linux.c;
   arm = loader/arm/linux.c;
   arm64 = loader/arm64/linux.c;
+  arm64 = loader/arm64/multiboot.c;
+  arm64 = loader/arm64/multiboot_fdt.c;
   fdt = lib/fdt.c;
   common = loader/linux.c;
   common = lib/cmdline.c;
diff --git a/grub-core/kern/arm64/cache_flush.S b/grub-core/kern/arm64/cache_flush.S
index e064f7e..b5caa71 100644
--- a/grub-core/kern/arm64/cache_flush.S
+++ b/grub-core/kern/arm64/cache_flush.S
@@ -21,6 +21,10 @@
 	.file	"cache_flush.S"
 	.text
 
+.set CTRL_M_BIT,      (1 << 0)
+.set CTRL_C_BIT,      (1 << 2)
+.set CTRL_I_BIT,      (1 << 12)
+
 /*
  * Simple cache maintenance functions
  */
@@ -53,3 +57,30 @@ FUNCTION(grub_arch_invalidate_icache_range)
 2:	dsb	ish
 	isb
 	ret
+
+FUNCTION(grub_arm64_disable_caches_mmu)
+    mrs    x1, CurrentEL
+    cmp    x1, #0x8
+    b.eq   2f
+    cmp    x1, #0x4
+    b.ne   .                     // We should never get here
+
+1:  mrs     x0, sctlr_el1        // Get control register EL1
+    b       3f
+2:  mrs     x0, sctlr_el2        // Get control register EL2
+3:  bic     x0, x0, #CTRL_M_BIT  // Disable MMU
+    bic     x0, x0, #CTRL_C_BIT  // Disable D Cache
+    bic     x0, x0, #CTRL_I_BIT  // Disable I Cache
+
+    mrs    x1, CurrentEL
+    cmp    x1, #0x8
+    b.eq   2f
+    cmp    x1, #0x4
+    b.ne   .                     // We should never get here
+
+1:  msr     sctlr_el1, x0        // Write back control register EL1
+    b       3f
+2:  msr     sctlr_el2, x0        // Write back control register EL2
+3:  dsb     sy
+    isb
+    ret
diff --git a/grub-core/kern/arm64/misc.c b/grub-core/kern/arm64/misc.c
new file mode 100644
index 0000000..73e6d57
--- /dev/null
+++ b/grub-core/kern/arm64/misc.c
@@ -0,0 +1,34 @@
+/* misc.c - various system functions for an arm64-based system */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2014 Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/misc.h>
+#include <grub/cpu/system.h>
+
+void grub_arch_disable_interrupts (void);
+void grub_arm64_disable_caches_mmu (void);
+
+void
+grub_arm64_prepare_platform (void)
+{
+  grub_arch_disable_interrupts();
+  grub_arm64_disable_caches_mmu();
+
+  grub_dprintf("linux", "Caches and MMU are disabled\n");
+}
+
diff --git a/grub-core/kern/arm64/misc_irq.S b/grub-core/kern/arm64/misc_irq.S
new file mode 100644
index 0000000..60465a5
--- /dev/null
+++ b/grub-core/kern/arm64/misc_irq.S
@@ -0,0 +1,35 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2014  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+
+	.file	"misc.S"
+	.text
+
+.set DAIF_FIQ_BIT,   (1 << 0)
+.set DAIF_IRQ_BIT,   (1 << 1)
+.set DAIF_INT_BITS,  (DAIF_FIQ_BIT | DAIF_IRQ_BIT)
+
+/*
+ * Simple misc maintenance functions
+ */
+
+FUNCTION(grub_arch_disable_interrupts)
+    msr   daifset, #DAIF_INT_BITS
+    isb
+    ret
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
index f1d10a1..e6bd564 100644
--- a/grub-core/loader/arm64/linux.c
+++ b/grub-core/loader/arm64/linux.c
@@ -26,6 +26,7 @@
 #include <grub/mm.h>
 #include <grub/types.h>
 #include <grub/cpu/linux.h>
+#include <grub/cpu/multiboot.h>
 #include <grub/efi/efi.h>
 #include <grub/efi/pe32.h>
 #include <grub/i18n.h>
@@ -54,6 +55,27 @@ static grub_addr_t initrd_end;
 static void *loaded_fdt;
 static void *fdt;
 
+/* The accessor functions for dtb and the "loaded" flag */
+static void get_fdt (void);
+
+int grub_arm64_linux_get_loaded (void)
+{
+  return (loaded);
+}
+
+void grub_arm64_linux_set_loaded (int loaded_flag)
+{
+  loaded = loaded_flag;
+}
+
+void *grub_arm64_linux_get_fdt (void)
+{
+  get_fdt ();
+  return (fdt);
+}
+/********************************************************/
+
+
 static void *
 get_firmware_fdt (void)
 {
@@ -476,6 +498,9 @@ GRUB_MOD_INIT (linux)
   cmd_devicetree =
     grub_register_command ("devicetree", grub_cmd_devicetree, 0,
 			   N_("Load DTB file."));
+
+  grub_arm64_linux_register_multiboot_command (mod);
+
   my_mod = mod;
 }
 
@@ -484,4 +509,6 @@ GRUB_MOD_FINI (linux)
   grub_unregister_command (cmd_linux);
   grub_unregister_command (cmd_initrd);
   grub_unregister_command (cmd_devicetree);
+
+  grub_arm64_linux_unregister_multiboot_command ();
 }
diff --git a/grub-core/loader/arm64/multiboot.c b/grub-core/loader/arm64/multiboot.c
new file mode 100644
index 0000000..5020530
--- /dev/null
+++ b/grub-core/loader/arm64/multiboot.c
@@ -0,0 +1,693 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2014  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/cache.h>
+#include <grub/charset.h>
+#include <grub/command.h>
+#include <grub/err.h>
+#include <grub/file.h>
+#include <grub/fdt.h>
+#include <grub/linux.h>
+#include <grub/list.h>
+#include <grub/loader.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/types.h>
+#include <grub/cpu/linux.h>
+#include <grub/cpu/multiboot.h>
+#include <grub/cpu/multiboot_fdt.h>
+#include <grub/cpu/system.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/disk.h>
+#include <grub/efi/pe32.h>
+#include <grub/i18n.h>
+#include <grub/lib/cmdline.h>
+#include <grub/net.h>
+
+#define GRUB_EFI_PE_MAGIC  (0x5A4D)
+
+static grub_dl_t linux_mod;
+static multiboot_function_t *multiboot_function;
+static multiboot_module_t kernel = NULL;
+static multiboot_module_t module_head = NULL;
+static int is_stub_kernel = 0;
+static grub_efi_device_path_t *file_path = 0;
+static char *multiboot_filename = NULL;
+
+static void
+copy_file_path (grub_efi_file_path_device_path_t *fp,
+		const char *str, grub_efi_uint16_t len)
+{
+  grub_efi_char16_t *p;
+  grub_efi_uint16_t size;
+
+  fp->header.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE;
+  fp->header.subtype = GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE;
+
+  size = grub_utf8_to_utf16 (fp->path_name, len * GRUB_MAX_UTF16_PER_UTF8,
+			     (const grub_uint8_t *) str, len, 0);
+  for (p = fp->path_name; p < fp->path_name + size; p++)
+    if (*p == '/')
+      *p = '\\';
+
+  fp->header.length = size * sizeof (grub_efi_char16_t) + sizeof (*fp);
+}
+
+static grub_efi_device_path_t *
+make_file_path (grub_efi_device_path_t *dp, const char *filename)
+{
+  char *dir_start;
+  char *dir_end;
+  grub_size_t size;
+  grub_efi_device_path_t *d;
+
+  dir_start = grub_strchr (filename, ')');
+  if (! dir_start)
+    dir_start = (char *) filename;
+  else
+    dir_start++;
+
+  dir_end = grub_strrchr (dir_start, '/');
+  if (! dir_end)
+    {
+      grub_error (GRUB_ERR_BAD_FILENAME, "invalid EFI file path");
+      return 0;
+    }
+
+  size = 0;
+  d = dp;
+  while (1)
+    {
+      size += GRUB_EFI_DEVICE_PATH_LENGTH (d);
+      if ((GRUB_EFI_END_ENTIRE_DEVICE_PATH (d)))
+	break;
+      d = GRUB_EFI_NEXT_DEVICE_PATH (d);
+    }
+
+  file_path = grub_malloc (size
+			   + ((grub_strlen (dir_start) + 1)
+			      * GRUB_MAX_UTF16_PER_UTF8
+			      * sizeof (grub_efi_char16_t))
+			   + sizeof (grub_efi_file_path_device_path_t) * 2);
+  if (! file_path)
+    return 0;
+
+  grub_memcpy (file_path, dp, size);
+
+  /* Fill the file path for the directory.  */
+  d = (grub_efi_device_path_t *) ((char *) file_path
+				  + ((char *) d - (char *) dp));
+  grub_efi_print_device_path (d);
+  copy_file_path ((grub_efi_file_path_device_path_t *) d,
+		  dir_start, dir_end - dir_start);
+
+  /* Fill the file path for the file.  */
+  d = GRUB_EFI_NEXT_DEVICE_PATH (d);
+  copy_file_path ((grub_efi_file_path_device_path_t *) d,
+		  dir_end + 1, grub_strlen (dir_end + 1));
+
+  /* Fill the end of device path nodes.  */
+  d = GRUB_EFI_NEXT_DEVICE_PATH (d);
+  d->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+  d->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+  d->length = sizeof (*d);
+
+  return file_path;
+}
+
+static grub_multiboot_type_t
+identify_kernel_type (grub_file_t file __attribute__ ((unused)))
+{
+  grub_multiboot_type_t type = GRUB_MULTIBOOT_FDT;
+  grub_dprintf ("linux", "Assuming the kernel image launched is using fdt!\n");
+  /* identify the more supported kernel files here */
+
+  return (type);
+}
+
+static grub_err_t
+init_multiboot_function (grub_multiboot_type_t type)
+{
+  switch (type)
+    {
+    case GRUB_MULTIBOOT_FDT:
+      multiboot_function = &multiboot_function_fdt;
+      break;
+
+    /*add the more support here*/
+
+    default:
+      return (grub_error (GRUB_ERR_BAD_ARGUMENT,
+          N_("Unsupported multiboot kernle type!")));
+    }
+
+  return (GRUB_ERR_NONE);
+}
+
+static grub_err_t
+check_multiboot_kernel (stub_header_t sh)
+{
+  if (sh->efi_head.magic != GRUB_ARM64_LINUX_MAGIC)
+    return (grub_error(GRUB_ERR_BAD_OS, "invalid magic number"));
+
+  if ((sh->efi_head.code0 & 0xffff) == GRUB_EFI_PE_MAGIC)
+    {
+      is_stub_kernel = 1;
+      grub_dprintf ("linux", "UEFI stub kernel:\n");
+      grub_dprintf ("linux", "text_offset = 0x%012llx\n",
+                    (long long unsigned) sh->efi_head.text_offset);
+      grub_dprintf ("linux", "PE/COFF header @ %08x\n", sh->efi_head.hdr_offset);
+    }
+  else
+    {
+      is_stub_kernel = 0;
+      grub_dprintf ("linux", "non-stub kernel\n");
+    }
+
+  return (GRUB_ERR_NONE);
+}
+
+static void
+sync_caches (void)
+{
+  static multiboot_module_t module;
+
+  if (multiboot_function->params_sync_caches)
+    multiboot_function->params_sync_caches ();
+
+  FOR_LIST_ELEMENTS (module, module_head)
+  {
+    if (module->start_unaligned && module->size > 0)
+      grub_arch_sync_caches ((void *) module->start_unaligned,
+          module->size + module->align);
+
+    if (module->cmdline && module->cmdline_size > 0)
+      grub_arch_sync_caches ((void *) module->cmdline, module->cmdline_size);
+  }
+}
+
+static void *
+finalize_params_multiboot (void)
+{
+  multiboot_module_t module;
+  grub_err_t retval;
+  void *params_blob = NULL;
+
+  /* Set Multiboot Kernel params info */
+  module = (multiboot_module_t) grub_named_list_find (
+      GRUB_AS_NAMED_LIST (module_head),
+      GRUB_MULTIBOOT_KERNEL_NAME);
+
+  if (module)
+    {
+      kernel = module;
+      if (multiboot_function->prepare_kernel_params)
+        {
+          retval = multiboot_function->prepare_kernel_params (module);
+          if (retval != GRUB_ERR_NONE)
+            goto failure_kernel;
+        }
+      grub_list_remove(GRUB_AS_LIST (module));
+    }
+  else
+    {
+      grub_dprintf ("linux", "Please load Multiboot Kernel first!\n");
+      goto failure;
+    }
+
+  /* Set module params info */
+  FOR_LIST_ELEMENTS (module, module_head)
+  {
+    if (module->start && module->size > 0)
+      {
+        grub_dprintf ("linux", "Module %s @ 0x%lx size:0x%lx\n",
+            module->name, module->start, module->size);
+        if (multiboot_function->prepare_module_params)
+          {
+            retval = multiboot_function->prepare_module_params (module);
+            if (retval != GRUB_ERR_NONE)
+              goto failure_module;
+          }
+      }
+    else
+      {
+        grub_dprintf ("linux", "Module info error: %s!\n", module->name);
+        goto failure_module;
+      }
+  }
+  grub_list_push (GRUB_AS_LIST_P (&module_head), GRUB_AS_LIST (kernel));
+
+  if (multiboot_function->install_all_params)
+    params_blob = (void *)multiboot_function->install_all_params ();
+
+  if (!params_blob)
+    {
+      goto failure_kernel;
+    }
+  else
+    {
+      return (params_blob);
+    }
+
+ failure_module:
+  grub_list_push (GRUB_AS_LIST_P (&module_head), GRUB_AS_LIST (kernel));
+ failure_kernel:
+  if (multiboot_function->clean_all_params)
+    multiboot_function->clean_all_params ();
+ failure:
+  return (params_blob);
+}
+
+static grub_err_t
+grub_multiboot_boot (void)
+{
+  void *params_blob;
+  kernel_entry_t linuxmain;
+
+  grub_efi_memory_mapped_device_path_t *mempath;
+  grub_efi_handle_t image_handle;
+  grub_efi_boot_services_t *b;
+  grub_efi_status_t status;
+  grub_efi_loaded_image_t *loaded_image;
+  grub_efi_handle_t dev_handle = NULL;
+  grub_device_t root_dev = NULL;
+  grub_efi_device_path_t *dp = 0;
+  int len;
+
+
+  params_blob = finalize_params_multiboot();
+  if (!params_blob)
+    return (grub_error (GRUB_ERR_BAD_OS, "failed to finalize boot params"));
+
+  if (!is_stub_kernel)
+    {
+      grub_dprintf ("linux", "Jumping to non-stub Kernel @ 0x%lx\n",
+                    kernel->start);
+
+      /* Boot the ARM64 system.
+       *   Arguments to Multiboot Kernel:
+       *     x0 - address of params blob (e.g. DTB)
+       *     x1 - 0 (reserved for future use)
+       *     x2 - 0 (reserved for future use)
+       *     x3 - 0 (reserved for future use)
+       */
+      linuxmain = (kernel_entry_t) kernel->start;
+
+      sync_caches ();
+      grub_arm64_prepare_platform ();
+
+      linuxmain (params_blob, 0, 0, 0);
+    }
+  else
+    {
+      mempath = grub_zalloc (2 * sizeof (grub_efi_memory_mapped_device_path_t));
+      if (!mempath)
+        return (grub_errno);
+
+      mempath[0].header.type = GRUB_EFI_HARDWARE_DEVICE_PATH_TYPE;
+      mempath[0].header.subtype = GRUB_EFI_MEMORY_MAPPED_DEVICE_PATH_SUBTYPE;
+      mempath[0].header.length = grub_cpu_to_le16_compile_time (sizeof (*mempath));
+      mempath[0].memory_type = GRUB_EFI_LOADER_DATA;
+      mempath[0].start_address = kernel->start;
+      mempath[0].end_address = kernel->start + kernel->size;
+
+      mempath[1].header.type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+      mempath[1].header.subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+      mempath[1].header.length = sizeof (grub_efi_device_path_t);
+
+      b = grub_efi_system_table->boot_services;
+      status = b->load_image (0, grub_efi_image_handle,
+                              (grub_efi_device_path_t *) mempath,
+                              (void *)kernel->start, kernel->size,
+                              &image_handle);
+      if (status != GRUB_EFI_SUCCESS)
+        return (grub_error (GRUB_ERR_BAD_OS, "cannot load stub-kernel image"));
+
+      /* Set command line to NULL, we have added this info to params blob */
+      loaded_image = grub_efi_get_loaded_image (image_handle);
+      if (! loaded_image)
+        return (grub_error (GRUB_ERR_BAD_OS, "no loaded image available"));
+
+      loaded_image->load_options_size = len = 0;
+      loaded_image->load_options = NULL;
+
+      /* Get the root device's device path.  */
+      root_dev = grub_device_open (0);
+      if (! root_dev)
+        return (grub_error (GRUB_ERR_BAD_OS, "cannot get root device"));
+
+      if (root_dev->disk)
+        {
+          dev_handle = grub_efidisk_get_device_handle (root_dev->disk);
+          grub_dprintf("linux", "got device handle from disk @ %p\n", dev_handle);
+        }
+      else if (root_dev->net && root_dev->net->server)
+        {
+          grub_net_network_level_address_t addr;
+          struct grub_net_network_level_interface *inf;
+          grub_net_network_level_address_t gateway;
+          grub_err_t err;
+
+          err = grub_net_resolve_address (root_dev->net->server, &addr);
+          if (err)
+            return (grub_error (GRUB_ERR_BAD_OS, "cannot resolve address"));
+
+          err = grub_net_route_address (addr, &gateway, &inf);
+          if (err)
+            return (grub_error (GRUB_ERR_BAD_OS, "cannot get gateway address"));
+
+          dev_handle = grub_efinet_get_device_handle (inf->card);
+          grub_dprintf("linux", "got device handle from net @ %p\n", dev_handle);
+        }
+      if (! dev_handle)
+        return (grub_error (GRUB_ERR_BAD_OS, "cannot get root device handle"));
+
+      loaded_image->device_handle = dev_handle;
+
+      if (dev_handle)
+        dp = grub_efi_get_device_path (dev_handle);
+
+      if (! dp)
+	return (grub_error (GRUB_ERR_BAD_DEVICE, "not a valid root device"));
+
+      file_path = make_file_path (dp, multiboot_filename);
+      if (! file_path)
+	return (grub_error (GRUB_ERR_BAD_DEVICE, "cannot make file path"));
+
+      grub_printf ("file path: ");
+      grub_efi_print_device_path (file_path);
+      loaded_image->file_path = file_path;
+
+      grub_dprintf("linux", "starting stub-kernel @ %p\n", image_handle);
+      status = b->start_image (image_handle, 0, NULL);
+
+      /* When successful, not reached */
+      b->unload_image (image_handle);
+    }
+
+  return (grub_error (GRUB_ERR_BAD_OS, "Multiboot call returned"));
+}
+
+static void
+single_module_unload (multiboot_module_t module)
+{
+  if (module && module->start_unaligned && module->size > 0)
+    {
+      grub_efi_free_pages ((grub_efi_physical_address_t) module->start_unaligned,
+          BYTES_TO_PAGES (module->size + module->align));
+    }
+  if (module && module->cmdline && module->cmdline_size > 0)
+    {
+      grub_free (module->cmdline);
+      grub_dprintf ("linux", "Module %s cmdline memory free @ %p size: %d\n",
+          module->name, module->cmdline, module->cmdline_size);
+    }
+  if (module)
+    {
+      if (multiboot_function->clean_extra_info)
+        multiboot_function->clean_extra_info(module);
+      grub_list_remove (GRUB_AS_LIST (module));
+      grub_dprintf ("linux", "Module %s struct memory free @ %p size: 0x%lx\n",
+          module->name, module, sizeof(module));
+      grub_free (module);
+    }
+  return;
+}
+
+static grub_err_t
+grub_module_unload (char *name)
+{
+  multiboot_module_t module;
+
+  if (name)
+    {
+      module = (multiboot_module_t) grub_named_list_find
+          (GRUB_AS_NAMED_LIST (module_head), name);
+      single_module_unload (module);
+    }
+  else
+    {
+      FOR_LIST_ELEMENTS (module, module_head)
+        {
+          single_module_unload (module);
+        }
+    }
+  return (GRUB_ERR_NONE);
+}
+
+static grub_err_t
+grub_multiboot_unload (void)
+{
+  grub_dl_unref (linux_mod);
+
+  grub_arm64_linux_set_loaded(0);
+  grub_module_unload (NULL);
+
+  if (multiboot_function->clean_all_params)
+    multiboot_function->clean_all_params();
+
+  return (GRUB_ERR_NONE);
+}
+
+static grub_err_t
+grub_module_load (multiboot_module_t module, grub_file_t file,
+                  int argc, char *argv[])
+{
+  grub_ssize_t temp = 0;
+
+  module->size = grub_file_size (file);
+  grub_dprintf ("linux", "Multiboot %s file size: 0x%lx\n",
+      module->name, module->size);
+
+  module->start_unaligned = (grub_addr_t) grub_efi_allocate_pages (0,
+      (BYTES_TO_PAGES (module->size + module->align)));
+  if (!module->start_unaligned)
+    return (grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")));
+
+  grub_dprintf ("linux", "Multiboot %s numpages: 0x%lx\n",
+      module->name, BYTES_TO_PAGES (module->size + module->align));
+
+  if (module->align)
+    module->start = ALIGN_UP(module->start_unaligned, module->align);
+  else
+    module->start = module->start_unaligned;
+
+  grub_dprintf ("linux", "Multiboot %s address align(0x%lx) from 0x%lx to 0x%lx\n",
+      module->name, module->align, module->start_unaligned, module->start);
+
+  temp = grub_file_read (file, (void *)module->start, module->size);
+  if (temp != (grub_ssize_t) module->size)
+    {
+      grub_dprintf ("linux", "Multiboot %s(%p) load fail size: %ld,(expect  0x%lx)\n",
+        module->name, file, temp, module->size);
+      single_module_unload(module);
+      return (grub_error (GRUB_ERR_BAD_OS,
+          N_("premature end of file %s"), argv[0]));
+    }
+
+  grub_dprintf ("linux", "Multiboot %s loaded to 0x%lx size: 0x%lx\n",
+      module->name, module->start, temp);
+
+  /* Skip the multiboot module file name */
+  argc--;
+  argv++;
+
+  if (argc > 0)
+    {
+      module->cmdline_size = grub_loader_cmdline_size (argc, argv);
+      module->cmdline = grub_zalloc (module->cmdline_size);
+      if (!module->cmdline)
+        {
+          single_module_unload(module);
+          return (grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")));
+        }
+      grub_create_loader_cmdline (argc, argv,
+          module->cmdline, module->cmdline_size);
+      grub_dprintf ("linux", "Multiboot %s cmdline @ %p %s, size: %d\n",
+          module->name, module->cmdline, module->cmdline, module->cmdline_size);
+    }
+  else
+    {
+      module->cmdline_size = 0;
+      module->cmdline = NULL;
+      grub_dprintf ("linux", "Multiboot %s has not cmdline\n", module->name);
+    }
+
+  return (GRUB_ERR_NONE);
+}
+
+static grub_err_t
+grub_cmd_module (grub_command_t cmd __attribute__ ((unused)),
+		 int argc, char *argv[])
+{
+
+  grub_file_t file = 0;
+  multiboot_module_t module = NULL;
+
+  if (argc == 0)
+    {
+      grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+      goto fail;
+    }
+
+  if (!grub_arm64_linux_get_loaded())
+    {
+      grub_error (GRUB_ERR_BAD_ARGUMENT,
+          N_("Please use multiboot command first"));
+      goto fail;
+    }
+
+  module = (multiboot_module_t) grub_zalloc (sizeof(struct multiboot_module));
+  if (!module)
+    return (grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")));
+
+  /* for more specific   */
+  if (multiboot_function->init_module_info)
+    {
+      grub_errno = multiboot_function->init_module_info(module_head,
+          module, &argc, &argv);
+      if (grub_errno != GRUB_ERR_NONE)
+        goto fail;
+    }
+
+  file = grub_file_open (argv[0]);
+  if (!file)
+    goto fail;
+
+  grub_errno = grub_module_load (module, file, argc, argv);
+
+  if (grub_errno == GRUB_ERR_NONE)
+    grub_list_push (GRUB_AS_LIST_P (&module_head), GRUB_AS_LIST (module));
+
+ fail:
+  if (file)
+    grub_file_close (file);
+  if (grub_errno != GRUB_ERR_NONE)
+    single_module_unload(module);
+
+  return (grub_errno);
+}
+
+static grub_err_t
+grub_cmd_multiboot (grub_command_t cmd __attribute__ ((unused)),
+		    int argc, char *argv[])
+{
+  grub_file_t file = NULL;
+  multiboot_module_t module = NULL;
+  grub_multiboot_type_t multiboot_type = GRUB_MULTIBOOT_OTHER;
+  grub_err_t retval;
+  struct stub_header sh;
+
+  grub_dprintf ("linux", "Multiboot for ARM64 @ %s %s\n", __DATE__,__TIME__);
+
+  grub_dl_ref (linux_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_dprintf ("linux", "Multiboot kernel: struct grub_file at %p\n", file);
+
+  multiboot_filename = grub_zalloc (grub_strlen (argv[0]) + 1);
+  grub_memcpy (multiboot_filename, argv[0], grub_strlen (argv[0]));
+
+
+  if (grub_file_read (file, &sh, sizeof (sh)) < (long) sizeof (sh))
+    return (grub_errno);
+  if (check_multiboot_kernel (&sh) != GRUB_ERR_NONE)
+    goto fail;
+  grub_file_seek (file, 0);
+
+  grub_loader_unset();
+
+  multiboot_type = identify_kernel_type(file);
+  retval = init_multiboot_function(multiboot_type);
+  if (retval != GRUB_ERR_NONE)
+    goto fail;
+
+  grub_module_unload (NULL);
+
+  module = (multiboot_module_t) grub_zalloc (sizeof(struct multiboot_module));
+  if (!module)
+    return (grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")));
+
+  module->name = GRUB_MULTIBOOT_KERNEL_NAME;
+
+  /* for more specific   */
+  if (multiboot_function->init_kernel_info)
+    {
+      retval = multiboot_function->init_kernel_info (module_head, module,
+                                                     &argc, &argv);
+      if (retval != GRUB_ERR_NONE)
+        grub_dprintf ("linux", "Multiboot init_kernel_info fail %d\n", retval);
+    }
+
+  if (is_stub_kernel)
+    {
+      module->align =(grub_size_t) sh.optional_header.section_alignment;
+      grub_dprintf ("linux", "Reload alignment from stub header: 0x%lx\n",
+                    module->align);
+    }
+
+  grub_errno = grub_module_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_loader_set (grub_multiboot_boot, grub_multiboot_unload, 0);
+      grub_arm64_linux_set_loaded(1);
+    }
+
+ fail:
+  if (file)
+    grub_file_close (file);
+  if (grub_errno != GRUB_ERR_NONE)
+    {
+      grub_dl_unref (linux_mod);
+      grub_arm64_linux_set_loaded(0);
+      grub_module_unload (NULL);
+    }
+
+  return (grub_errno);
+}
+
+static grub_command_t cmd_multiboot, cmd_module;
+
+void
+grub_arm64_linux_register_multiboot_command (grub_dl_t mod)
+{
+  cmd_multiboot =
+    grub_register_command ("multiboot", grub_cmd_multiboot, 0,
+			   N_("Load a multiboot kernel."));
+  cmd_module =
+    grub_register_command ("module", grub_cmd_module, 0,
+			   N_("Load a multiboot module."));
+  linux_mod = mod;
+}
+
+void
+grub_arm64_linux_unregister_multiboot_command (void)
+{
+  grub_unregister_command (cmd_multiboot);
+  grub_unregister_command (cmd_module);
+}
diff --git a/grub-core/loader/arm64/multiboot_fdt.c b/grub-core/loader/arm64/multiboot_fdt.c
new file mode 100644
index 0000000..2cae33d
--- /dev/null
+++ b/grub-core/loader/arm64/multiboot_fdt.c
@@ -0,0 +1,302 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2014  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/cache.h>
+#include <grub/err.h>
+#include <grub/fdt.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/cpu/linux.h>
+#include <grub/cpu/multiboot.h>
+#include <grub/cpu/multiboot_fdt.h>
+
+static grub_efi_guid_t fdt_guid = GRUB_EFI_DEVICE_TREE_GUID;
+
+const struct compatible_struct default_compatible[] =
+  {
+    FDT_COMPATIBLE(FDT_MODULE_IMAGE_COMPATIBLE),
+    FDT_COMPATIBLE(FDT_MODULE_INITRD_COMPATIBLE),
+    FDT_COMPATIBLE(FDT_MODULE_OTHER_COMPATIBLE),
+    FDT_COMPATIBLE(FDT_MODULE_CUSTOM_COMPATIBLE)
+  };
+
+const grub_size_t align_info[] =
+  {
+    FDT_MODULE_IMAGE_MIN_ALIGN,
+    FDT_MODULE_INITRD_MIN_ALIGN,
+    FDT_MODULE_OTHER_MIN_ALIGN,
+    FDT_MODULE_CUSTOM_MIN_ALIGN
+  };
+
+static fdt_module_type_t module_type = FDT_MODULE_IMAGE;
+static void *multiboot_fdt = NULL;
+static grub_size_t multiboot_fdt_size = 0;
+static int chosen_node = 0;
+
+static grub_err_t
+clean_extra_info_fdt (multiboot_module_t module)
+{
+  if (module && module->extra_info)
+    {
+      grub_free (module->extra_info);
+      module->extra_info = NULL;
+    }
+  return (GRUB_ERR_NONE);
+}
+
+static grub_err_t
+set_fdt_module_type (multiboot_module_t module, int *argc, char **argv[])
+{
+  fdt_node_info_t node_info = (fdt_node_info_t) module->extra_info;
+  char *temp_string = node_info->compatible_custom;
+
+  if ((*argc) >= 3 && grub_strcmp (*argv[0], "--type") == 0)
+    {
+      node_info->type = FDT_MODULE_CUSTOM;
+      while ((*argc) > 1)
+        {
+          (*argc)--;
+          (*argv)++;
+          if (grub_strcmp (*argv[0], "--type") == 0)
+            continue;
+          grub_strcpy (temp_string, *argv[0]);
+          node_info->compatible_size +=
+              (grub_size_t)(grub_strlen(*argv[0]) + 1);
+          temp_string += grub_strlen(*argv[0]);
+          *temp_string = '\0';
+          temp_string++;
+        }
+    }
+  else
+    {
+      node_info->type = module_type++;
+      if (module_type > FDT_MODULE_OTHER)
+        module_type = FDT_MODULE_OTHER;
+    }
+
+  return (GRUB_ERR_NONE);
+}
+
+static grub_err_t
+params_sync_caches_fdt (void)
+{
+  if (multiboot_fdt && multiboot_fdt_size > 0)
+    grub_arch_sync_caches ((void *) multiboot_fdt, multiboot_fdt_size);
+
+  return (GRUB_ERR_NONE);
+}
+
+static grub_err_t
+prepare_kernel_params_fdt (multiboot_module_t module)
+{
+  int retval;
+
+  multiboot_fdt = grub_arm64_linux_get_fdt ();
+  multiboot_fdt_size = grub_fdt_get_totalsize (multiboot_fdt);
+  if (!multiboot_fdt)
+    return (grub_error(GRUB_ERR_BAD_OS, "failed to get FDT"));
+
+  chosen_node = grub_fdt_find_subnode (multiboot_fdt, 0, "chosen");
+  if (chosen_node < 0)
+    chosen_node = grub_fdt_add_subnode (multiboot_fdt, 0, "chosen");
+
+  if (chosen_node < 1)
+    return (grub_error(GRUB_ERR_BAD_OS, "failed to get chosen node"));
+
+  grub_dprintf ("linux", "Multiboot Kernel cmdline : %s @ %p size:%d\n",
+      module->cmdline, module->cmdline, module->cmdline_size);
+
+  retval = grub_fdt_set_prop (multiboot_fdt, chosen_node,
+      FDT_MODULE_BOOTARGS, module->cmdline, module->cmdline_size);
+
+  if (retval)
+    return (grub_error(GRUB_ERR_BAD_OS,
+        "failed to set kernel cmdline info to chosen node"));
+
+  return (GRUB_ERR_NONE);
+}
+
+static grub_err_t
+prepare_module_params_fdt (multiboot_module_t module)
+{
+  int retval, module_node = 0;
+  fdt_node_info_t node_info = NULL;
+  char module_name[FDT_MODULE_NAME_MAX_SIZE];
+  grub_uint64_t reg_64[2];
+
+  if (module && module->extra_info)
+    {
+      node_info = (fdt_node_info_t) module->extra_info;
+    }
+  else
+    {
+      return (grub_error (GRUB_ERR_BAD_ARGUMENT, N_("failed to get module")));
+    }
+
+  retval = grub_snprintf(module_name, FDT_MODULE_NAME_MAX_SIZE,
+      "module@%lx", module->start);
+  grub_dprintf ("linux", "Module node name %s \n", module_name);
+
+  if (retval <(int) sizeof("module@"))
+    return (grub_error(GRUB_ERR_BAD_OS,
+        N_("failed to set node name for module")));
+
+  module_node = grub_fdt_find_subnode (multiboot_fdt, chosen_node, module_name);
+  if (module_node < 0)
+    module_node = grub_fdt_add_subnode (multiboot_fdt, chosen_node, module_name);
+
+  retval = grub_fdt_set_prop (multiboot_fdt, module_node, "compatible",
+      node_info->compatible,
+      (grub_uint32_t)node_info->compatible_size);
+  if (retval)
+    return (grub_error(GRUB_ERR_BAD_OS,
+        N_("failed to get module node in chosen node")));
+
+  grub_dprintf ("linux", "Module %s compatible = %s size = %lx\n",
+      module->name,
+      node_info->compatible,
+      node_info->compatible_size);
+
+  reg_64[0] = grub_cpu_to_be64(module->start);
+  reg_64[1] = grub_cpu_to_be64(module->size);
+  retval = grub_fdt_set_prop (multiboot_fdt, module_node, "reg", reg_64, 16);
+  if (retval)
+    return (grub_error(GRUB_ERR_BAD_OS,
+        N_("failed to set reg info in module node")));
+
+  if ((module->cmdline) && (module->cmdline_size > 0))
+    {
+      grub_dprintf ("linux", "Module %s cmdline : %s @ %p size:%d\n",
+          module->name, module->cmdline, module->cmdline, module->cmdline_size);
+
+      retval = grub_fdt_set_prop (multiboot_fdt, module_node,
+          FDT_MODULE_BOOTARGS, module->cmdline, module->cmdline_size + 1);
+      if (retval)
+        return (grub_error (GRUB_ERR_BAD_OS,
+            "failed to set module cmdline info to chosen node"));
+    }
+  else
+    {
+      grub_dprintf ("linux", "Module %s has not bootargs!\n", module->name);
+    }
+
+  return (GRUB_ERR_NONE);
+}
+
+static void *
+install_all_params_fdt (void)
+{
+  grub_efi_boot_services_t *b;
+  grub_efi_status_t status;
+
+  b = grub_efi_system_table->boot_services;
+  status = b->install_configuration_table (&fdt_guid, multiboot_fdt);
+  if (status != GRUB_EFI_SUCCESS)
+    {
+      grub_dprintf ("linux", "Installed/updated FDT configuration table fail %p\n",
+                    multiboot_fdt);
+      return NULL;
+    }
+
+  grub_dprintf ("linux", "Installed/updated FDT configuration table @ %p\n",
+                multiboot_fdt);
+  return ((void *)multiboot_fdt);
+}
+
+static grub_err_t
+clean_all_params_fdt (void)
+{
+  if (multiboot_fdt)
+    {
+      grub_efi_free_pages ((grub_efi_physical_address_t) multiboot_fdt,
+          BYTES_TO_PAGES (multiboot_fdt_size));
+      multiboot_fdt = NULL;
+      multiboot_fdt_size = 0;
+    }
+  return (GRUB_ERR_NONE);
+}
+
+static grub_err_t
+init_module_info_fdt (multiboot_module_t module_head __attribute__ ((unused)),
+                      multiboot_module_t module, int *argc, char **argv[])
+{
+  fdt_node_info_t node_info =
+      (fdt_node_info_t) grub_zalloc (sizeof(struct fdt_node_info));
+  if (!node_info)
+    return (grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")));
+  module->extra_info = (void *) node_info;
+
+  /* get module type */
+  grub_errno = set_fdt_module_type (module, argc, argv);
+  if (grub_errno != GRUB_ERR_NONE)
+    return (grub_errno);
+
+  switch (node_info->type)
+    {
+    case FDT_MODULE_IMAGE:
+    case FDT_MODULE_INITRD:
+    case FDT_MODULE_OTHER:
+      node_info->compatible = default_compatible[node_info->type].compatible;
+      node_info->compatible_size = default_compatible[node_info->type].size;
+      break;
+
+    case FDT_MODULE_CUSTOM:
+      node_info->compatible = node_info->compatible_custom;
+      /* node_info->compatible_size has set in set_fdt_module_type() */
+      break;
+
+    default:
+      return (grub_error (GRUB_ERR_BAD_ARGUMENT, N_("error module type")));
+    }
+  module->name = node_info->compatible;
+  module->align = align_info[node_info->type];
+
+  grub_dprintf ("linux", "Init %s module and node info:\n"
+                "compatible %s\ncompatible_size %lx\n",
+                module->name,
+                node_info->compatible,
+                node_info->compatible_size);
+
+  return (GRUB_ERR_NONE);
+}
+
+static grub_err_t
+init_kernel_info_fdt (multiboot_module_t module_head __attribute__ ((unused)),
+                      multiboot_module_t module,
+                      int *argc __attribute__ ((unused)),
+                      char **argv[] __attribute__ ((unused)))
+{
+  module->extra_info = NULL;
+  module->align = FDT_KERNEL_MIN_ALIGN;
+
+  grub_dprintf ("linux", "Init %s info successfully\n", module->name);
+
+  return (GRUB_ERR_NONE);
+}
+
+struct multiboot_function multiboot_function_fdt =
+    {
+        .init_kernel_info = init_kernel_info_fdt,
+        .init_module_info = init_module_info_fdt,
+        .clean_extra_info = clean_extra_info_fdt,
+        .prepare_kernel_params = prepare_kernel_params_fdt,
+        .prepare_module_params = prepare_module_params_fdt,
+        .install_all_params = install_all_params_fdt,
+        .params_sync_caches = params_sync_caches_fdt,
+        .clean_all_params = clean_all_params_fdt
+    };
diff --git a/include/grub/arm64/linux.h b/include/grub/arm64/linux.h
index 864e5dc..c54dfaf 100644
--- a/include/grub/arm64/linux.h
+++ b/include/grub/arm64/linux.h
@@ -38,4 +38,12 @@ struct grub_arm64_linux_kernel_header
   grub_uint32_t hdr_offset;	/* Offset of PE/COFF header */
 };
 
+/****The accessor functions for dtb and the "loaded" flag****/
+void EXPORT_FUNC (*grub_arm64_linux_get_fdt) (void);
+
+int EXPORT_FUNC (grub_arm64_linux_get_loaded) (void);
+
+void EXPORT_FUNC (grub_arm64_linux_set_loaded) (int loaded_flag);
+/************************************/
+
 #endif /* ! GRUB_LINUX_CPU_HEADER */
diff --git a/include/grub/arm64/multiboot.h b/include/grub/arm64/multiboot.h
new file mode 100644
index 0000000..d9a0d52
--- /dev/null
+++ b/include/grub/arm64/multiboot.h
@@ -0,0 +1,100 @@
+/*  multiboot.h - Multiboot header file.  */
+/*  Copyright (C) 2014  Free Software Foundation, Inc.
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to
+ *  deal in the Software without restriction, including without limitation the
+ *  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ *  sell copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in
+ *  all copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY
+ *  DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+ *  IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef MULTIBOOT_HEADER
+#define MULTIBOOT_HEADER 1
+
+#include <grub/list.h>
+#include <grub/efi/pe32.h>
+
+#define GRUB_EFI_PAGE_SHIFT  12
+#define BYTES_TO_PAGES(bytes)  (((bytes) + 0xfff) >> GRUB_EFI_PAGE_SHIFT)
+
+/* Reserved for Future Use */
+/* #define GRUB_MULTIBOOT_FLAGS_* (0x*) */
+
+#define GRUB_MULTIBOOT_KERNEL_NAME  "multiboot_kernel"
+
+enum grub_multiboot_type
+{
+  GRUB_MULTIBOOT_FDT,
+  /* we can add more types here to support more images those need multiboot */
+  GRUB_MULTIBOOT_OTHER
+};
+typedef enum grub_multiboot_type grub_multiboot_type_t;
+
+struct stub_header
+{
+  struct grub_arm64_linux_kernel_header efi_head;
+
+  /* This is always PE\0\0.  */
+  char signature[GRUB_PE32_SIGNATURE_SIZE];
+  /* The COFF file header.  */
+  struct grub_pe32_coff_header coff_header;
+  /* The Optional header.  */
+  struct grub_pe64_optional_header optional_header;
+};
+typedef struct stub_header *stub_header_t;
+
+struct multiboot_module
+{
+  struct multiboot_module *next;
+  struct multiboot_module **prev;
+  const char *name;
+
+  /* int flags; */
+
+  grub_addr_t start_unaligned;
+  grub_addr_t start;
+  grub_size_t size;
+  grub_size_t align;
+
+  char *cmdline;
+  int cmdline_size;
+
+  /* for more info */
+  void *extra_info;
+};
+typedef struct multiboot_module *multiboot_module_t;
+
+struct multiboot_function
+{
+  grub_err_t (*init_kernel_info) (multiboot_module_t module_head,
+      multiboot_module_t module, int *argc, char **argv[]);
+  grub_err_t (*init_module_info) (multiboot_module_t module_head,
+      multiboot_module_t module, int *argc, char **argv[]);
+  grub_err_t (*clean_extra_info) (multiboot_module_t module);
+  grub_err_t (*prepare_kernel_params) (multiboot_module_t module);
+  grub_err_t (*prepare_module_params) (multiboot_module_t module);
+  void *(*install_all_params) (void);
+  grub_err_t (*clean_all_params) (void);
+  grub_err_t (*params_sync_caches) (void);
+};
+
+typedef struct multiboot_function multiboot_function_t;
+
+typedef void (*kernel_entry_t) (void *, int, int, int);
+
+void grub_arm64_linux_register_multiboot_command (grub_dl_t mod);
+
+void grub_arm64_linux_unregister_multiboot_command (void);
+
+#endif /* ! MULTIBOOT_HEADER */
diff --git a/include/grub/arm64/multiboot_fdt.h b/include/grub/arm64/multiboot_fdt.h
new file mode 100644
index 0000000..0382240
--- /dev/null
+++ b/include/grub/arm64/multiboot_fdt.h
@@ -0,0 +1,72 @@
+/*  multiboot_fdt.h - Multiboot for fdt method header file.  */
+/*  Copyright (C) 2014  Free Software Foundation, Inc.
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a copy
+ *  of this software and associated documentation files (the "Software"), to
+ *  deal in the Software without restriction, including without limitation the
+ *  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ *  sell copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in
+ *  all copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL ANY
+ *  DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+ *  IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef MULTIBOOT_FDT_HEADER
+#define MULTIBOOT_FDT_HEADER 1
+
+#include <grub/types.h>
+#include <grub/cpu/multiboot.h>
+
+#define FDT_MODULE_DEFAULT_ALIGN  (0x0)
+#define FDT_KERNEL_MIN_ALIGN  (0x200000)
+#define FDT_MODULE_IMAGE_MIN_ALIGN  FDT_MODULE_DEFAULT_ALIGN
+#define FDT_MODULE_INITRD_MIN_ALIGN  FDT_MODULE_DEFAULT_ALIGN
+#define FDT_MODULE_OTHER_MIN_ALIGN  FDT_MODULE_DEFAULT_ALIGN
+#define FDT_MODULE_CUSTOM_MIN_ALIGN  FDT_MODULE_DEFAULT_ALIGN
+
+#define FDT_MODULE_IMAGE_COMPATIBLE  "multiboot,kernel\0multiboot,module"
+#define FDT_MODULE_INITRD_COMPATIBLE  "multiboot,ramdisk\0multiboot,module"
+#define FDT_MODULE_OTHER_COMPATIBLE  "multiboot,module"
+#define FDT_MODULE_CUSTOM_COMPATIBLE  ""
+
+#define FDT_COMPATIBLE_MAX_SIZE  (128)
+#define FDT_MODULE_NAME_MAX_SIZE  (32)
+#define FDT_MODULE_BOOTARGS  "bootargs"
+
+struct compatible_struct
+{
+  grub_size_t size;
+  const char *compatible;
+};
+#define FDT_COMPATIBLE(x) {.size = sizeof(x), .compatible = x}
+
+enum fdt_module_type
+{
+  FDT_MODULE_IMAGE,
+  FDT_MODULE_INITRD,
+  FDT_MODULE_OTHER,
+  FDT_MODULE_CUSTOM
+};
+typedef enum fdt_module_type fdt_module_type_t;
+
+struct fdt_node_info
+{
+  fdt_module_type_t type;
+
+  const char *compatible;
+  char compatible_custom[FDT_COMPATIBLE_MAX_SIZE];
+  grub_size_t compatible_size;
+};
+typedef struct fdt_node_info *fdt_node_info_t;
+
+multiboot_function_t multiboot_function_fdt;
+
+#endif /* ! MULTIBOOT_FDT_HEADER */
diff --git a/include/grub/arm64/system.h b/include/grub/arm64/system.h
new file mode 100644
index 0000000..950f9b0
--- /dev/null
+++ b/include/grub/arm64/system.h
@@ -0,0 +1,7 @@
+#ifndef GRUB_SYSTEM_CPU_HEADER
+#define GRUB_SYSTEM_CPU_HEADER	1
+
+void EXPORT_FUNC (grub_arm64_prepare_platform) (void);
+
+#endif /* ! GRUB_SYSTEM_CPU_HEADER */
+
-- 
2.0.2

