Grub Development Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Enable multiboot2 support on arm64-efi target
@ 2020-10-28 19:45 Chris Plant
  2020-10-28 19:47 ` [PATCH 01/05] " Chris Plant
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Chris Plant @ 2020-10-28 19:45 UTC (permalink / raw)
  To: Grub-devel; +Cc: chris

Hello,

As you may have guessed from my musings on the mailing list to date,
I've been creating a patch to enable the multiboot2 loader on
ARM64/aarch64.

Why?  I am playing with GNU Mach (not sure why - blame COVID-19) on
Raspberry PI.  I guess the key driver for why it's interesting to a
wider audience came from Krystian Hebel - "MB2 is one of the most
commonly used (if not the most common) boot protocols for hobby OSes.",
so I propose we should support it on a platform which in it's various
guises is very easily available to hobby programmers.

As part of this effort, I've also found that definition of "struct
multiboot_tag_elf_sections" does not match the multiboot2 specification
documentation and does not align the elf sections to a 8 byte boundary.
 This causes issues on aarch64 as the 64 bit numbers within the elf
sections are then misaligned throughout.  Although the version of the
structure document in the multiboot2 documentation would align it
correctly, the grub and reference implemntations do not match the
documentation.

Hence, I have created a new struct multiboot_tag_elf64_sections which
is correctly aligned, and also given the next available tag number.  I
have prepared an update to the multiboot2 specification to document
this, which will follow seperately.

This sequence of patches:
01 - Updates multiboot2 definitions to include the new elf64 tag, adds
awareness of the ARCHITECTURE_AARCH64 to multiboot2.
02 - Add relocator code for ARM64, based on MIPS code
03 - Adds mmap_ functions on ARM64 to support multiboot loader 
04 - Adds aarch64 target to the ifdefs in multiboot loader code
05 - Updates Makefile.core.def to compile the multiboot2 loader on the
arm-efi target.

I apologise for any inadvertant breach of ettique in the way these
patches are presented - I'm a bit new to this text patch process but
I've tried my best.

Signed-off-by: Chris Plant <chris@monkeyircd.org>



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 01/05] Enable multiboot2 support on arm64-efi target
  2020-10-28 19:45 [PATCH] Enable multiboot2 support on arm64-efi target Chris Plant
@ 2020-10-28 19:47 ` Chris Plant
  2020-10-28 19:49 ` [PATCH 03/05] " Chris Plant
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Chris Plant @ 2020-10-28 19:47 UTC (permalink / raw)
  To: Grub-devel; +Cc: chris

Define MULTIBOOT2_ARCHITECTURE_AARCH64 to support AARCH64 architecture
+ Define MULTIBOOT2_TAG_TYPE_ELF64_SECTIONS and struct
multiboot_tag_elf64_sections   as a version of elf_sections which
correctly aligns the elf section headers   to a 64 bit boundary

Signed-off-by: Chris Plant <chris@monkeyircd.org>
---
 include/multiboot2.h | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/include/multiboot2.h b/include/multiboot2.h
index 5693923c0..e5071f6f6 100644
--- a/include/multiboot2.h
+++ b/include/multiboot2.h
@@ -63,6 +63,7 @@
 #define MULTIBOOT_TAG_TYPE_EFI32_IH          19
 #define MULTIBOOT_TAG_TYPE_EFI64_IH          20
 #define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR    21
+#define MULTIBOOT_TAG_TYPE_ELF64_SECTIONS 	 22
 
 #define MULTIBOOT_HEADER_TAG_END  0
 #define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST  1
@@ -77,6 +78,7 @@
 
 #define MULTIBOOT2_ARCHITECTURE_I386  0
 #define MULTIBOOT2_ARCHITECTURE_MIPS32  4
+#define MULTIBOOT2_ARCHITECTURE_AARCH64 8
 #define MULTIBOOT_HEADER_TAG_OPTIONAL 1
 
 #define MULTIBOOT_LOAD_PREFERENCE_NONE 0
@@ -321,6 +323,18 @@ struct multiboot_tag_elf_sections
   char sections[0];
 };
 
+struct multiboot_tag_elf64_sections
+{
+  multiboot_uint32_t type;
+  multiboot_uint32_t size;
+  multiboot_uint32_t num;
+  multiboot_uint32_t entsize;
+  multiboot_uint32_t shndx;
+	multiboot_uint32_t reserved;
+  char sections[0];
+};
+
+
 struct multiboot_tag_apm
 {
   multiboot_uint32_t type;
-- 
2.28.0



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 03/05] Enable multiboot2 support on arm64-efi target
  2020-10-28 19:45 [PATCH] Enable multiboot2 support on arm64-efi target Chris Plant
  2020-10-28 19:47 ` [PATCH 01/05] " Chris Plant
@ 2020-10-28 19:49 ` Chris Plant
  2020-10-28 19:50 ` [PATCH 04/05] " Chris Plant
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Chris Plant @ 2020-10-28 19:49 UTC (permalink / raw)
  To: Grub-devel; +Cc: chris

Add ARM64 versions of the mmap functions to generate memory map for
multiboot2

Signed-off-by: Chris Plant <chris@monkeyircd.org>

---
 grub-core/mmap/arm64/uppermem.c | 72 +++++++++++++++++++++++++++++++++
 include/grub/arm64/memory.h     | 60 +++++++++++++++++++++++++++
 2 files changed, 132 insertions(+)
 create mode 100644 grub-core/mmap/arm64/uppermem.c
 create mode 100644 include/grub/arm64/memory.h

diff --git a/grub-core/mmap/arm64/uppermem.c b/grub-
core/mmap/arm64/uppermem.c
new file mode 100644
index 000000000..a980e0719
--- /dev/null
+++ b/grub-core/mmap/arm64/uppermem.c
@@ -0,0 +1,72 @@
+/* Compute amount of lower and upper memory till the first hole. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2009  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/memory.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/cpu/memory.h>
+
+/* Helper for grub_mmap_get_lower.  */
+static int
+lower_hook (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t
type,
+	    void *data)
+{
+  grub_uint64_t *lower = data;
+
+  if (type != GRUB_MEMORY_AVAILABLE)
+    return 0;
+  if (addr == 0)
+    *lower = size;
+  return 0;
+}
+
+grub_uint64_t
+grub_mmap_get_lower (void)
+{
+  grub_uint64_t lower = 0;
+
+  grub_mmap_iterate (lower_hook, &lower);
+  if (lower > GRUB_ARCH_LOWMEMMAXSIZE)
+    lower = GRUB_ARCH_LOWMEMMAXSIZE;
+  return lower;
+}
+
+/* Helper for grub_mmap_get_upper.  */
+static int
+upper_hook (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t
type,
+	    void *data)
+{
+  grub_uint64_t *upper = data;
+
+  if (type != GRUB_MEMORY_AVAILABLE)
+    return 0;
+  if (addr <= GRUB_ARCH_HIGHMEMPSTART && addr + size
+      > GRUB_ARCH_HIGHMEMPSTART)
+    *upper = addr + size - GRUB_ARCH_HIGHMEMPSTART;
+  return 0;
+}
+
+grub_uint64_t
+grub_mmap_get_upper (void)
+{
+  grub_uint64_t upper = 0;
+
+  grub_mmap_iterate (upper_hook, &upper);
+  return upper;
+}
diff --git a/include/grub/arm64/memory.h b/include/grub/arm64/memory.h
new file mode 100644
index 000000000..7811f3449
--- /dev/null
+++ b/include/grub/arm64/memory.h
@@ -0,0 +1,60 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2009 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/>;.
+ */
+
+#ifndef GRUB_MEMORY_CPU_HEADER
+#define GRUB_MEMORY_CPU_HEADER	1
+
+#ifndef ASM_FILE
+#include <grub/symbol.h>
+#include <grub/err.h>
+#include <grub/types.h>
+#endif
+
+#define GRUB_ARCH_LOWMEMVSTART 0x80000000
+#define GRUB_ARCH_LOWMEMPSTART 0x00000000
+#define GRUB_ARCH_LOWMEMMAXSIZE 0x10000000
+#define GRUB_ARCH_HIGHMEMPSTART 0x10000000
+
+#ifndef ASM_FILE
+
+typedef grub_addr_t grub_phys_addr_t;
+
+static inline grub_phys_addr_t
+grub_vtop (void *a)
+{
+  return (grub_phys_addr_t) a;
+}
+
+static inline void *
+grub_map_memory (grub_phys_addr_t a, grub_size_t size __attribute__
((unused)))
+{
+  return (void *) a;
+}
+
+static inline void
+grub_unmap_memory (void *a __attribute__ ((unused)),
+		   grub_size_t size __attribute__ ((unused)))
+{
+}
+
+grub_uint64_t grub_mmap_get_lower (void);
+grub_uint64_t grub_mmap_get_upper (void);
+
+#endif
+
+#endif
-- 
2.28.0



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 04/05] Enable multiboot2 support on arm64-efi target
  2020-10-28 19:45 [PATCH] Enable multiboot2 support on arm64-efi target Chris Plant
  2020-10-28 19:47 ` [PATCH 01/05] " Chris Plant
  2020-10-28 19:49 ` [PATCH 03/05] " Chris Plant
@ 2020-10-28 19:50 ` Chris Plant
  2020-10-28 19:51 ` [PATCH 05/05] " Chris Plant
  2020-10-28 19:52 ` [PATCH 02/05] " Chris Plant
  4 siblings, 0 replies; 6+ messages in thread
From: Chris Plant @ 2020-10-28 19:50 UTC (permalink / raw)
  To: Grub-devel; +Cc: chris

Enable ARM64/aarch64 support in multiboot2 loader

Signed-off-by: Chris Plant <chris@monkeyircd.org>

---
 grub-core/loader/multiboot.c       |  2 +-
 grub-core/loader/multiboot_elfxx.c |  2 +-
 grub-core/loader/multiboot_mbi2.c  | 34 +++++++++++++++---
 include/grub/arm64/multiboot.h     | 56 ++++++++++++++++++++++++++++++
 4 files changed, 87 insertions(+), 7 deletions(-)
 create mode 100644 include/grub/arm64/multiboot.h

diff --git a/grub-core/loader/multiboot.c b/grub-
core/loader/multiboot.c
index facb13f3d..e88a4a7f7 100644
--- a/grub-core/loader/multiboot.c
+++ b/grub-core/loader/multiboot.c
@@ -127,7 +127,7 @@ GRUB_MULTIBOOT (set_video_mode) (void)
 }
 
 #ifdef GRUB_MACHINE_EFI
-#ifdef __x86_64__
+#if defined (__x86_64__) || defined (__arch64__)
 #define grub_relocator_efi_boot		grub_relocator64_efi_bo
ot
 #define grub_relocator_efi_state	grub_relocator64_efi_state
 #endif
diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-
core/loader/multiboot_elfxx.c
index f2318e0d1..851b09164 100644
--- a/grub-core/loader/multiboot_elfxx.c
+++ b/grub-core/loader/multiboot_elfxx.c
@@ -205,7 +205,7 @@ CONCAT(grub_multiboot_load_elf, XX)
(mbi_load_data_t *mld)
   if (i == ehdr->e_phnum)
     return grub_error (GRUB_ERR_BAD_OS, "entry point isn't in a
segment");
 
-#if defined (__i386__) || defined (__x86_64__)
+#if defined (__i386__) || defined (__x86_64__) || defined
(__aarch64__)
   
 #elif defined (__mips)
   GRUB_MULTIBOOT (payload_eip) |= 0x80000000;
diff --git a/grub-core/loader/multiboot_mbi2.c b/grub-
core/loader/multiboot_mbi2.c
index 9a943d7bd..6ca195a87 100644
--- a/grub-core/loader/multiboot_mbi2.c
+++ b/grub-core/loader/multiboot_mbi2.c
@@ -186,6 +186,7 @@ grub_multiboot2_load (grub_file_t file, const char
*filename)
 	      case MULTIBOOT_TAG_TYPE_EFI32_IH:
 	      case MULTIBOOT_TAG_TYPE_EFI64_IH:
 	      case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR:
+				case MULTIBOOT_TAG_TYPE_ELF64_SECTIONS:
 		break;
 
 	      default:
@@ -445,8 +446,13 @@ grub_multiboot2_get_mbi_size (void)
     + ALIGN_UP (sizeof (struct multiboot_tag_basic_meminfo),
 		MULTIBOOT_TAG_ALIGN)
     + ALIGN_UP (sizeof (struct multiboot_tag_bootdev),
MULTIBOOT_TAG_ALIGN)
+#if defined (__i386__) || defined (__x86_64__) || defined (__mips)
+		/* This tag doesn't align correct for aarch64/arm64 */
     + ALIGN_UP (sizeof (struct multiboot_tag_elf_sections),
MULTIBOOT_TAG_ALIGN)
-    + ALIGN_UP (elf_sec_entsize * elf_sec_num, MULTIBOOT_TAG_ALIGN)
+	    + ALIGN_UP (elf_sec_entsize * elf_sec_num,
MULTIBOOT_TAG_ALIGN)
+#endif
+  	+ ALIGN_UP (sizeof (struct multiboot_tag_elf64_sections),
MULTIBOOT_TAG_ALIGN)
+		  + ALIGN_UP (elf_sec_entsize * elf_sec_num,
MULTIBOOT_TAG_ALIGN)
     + ALIGN_UP ((sizeof (struct multiboot_tag_mmap)
 		 + grub_multiboot2_get_mmap_count ()
 		 * sizeof (struct multiboot_mmap_entry)),
MULTIBOOT_TAG_ALIGN)
@@ -721,7 +727,7 @@ grub_multiboot2_make_mbi (grub_uint32_t *target)
     return err;
 
   ptrorig = get_virtual_current_address (ch);
-#if defined (__i386__) || defined (__x86_64__)
+#if defined (__i386__) || defined (__x86_64__) || defined
(__aarch64__)
   *target = get_physical_target_address (ch);
 #elif defined (__mips)
   *target = get_physical_target_address (ch) | 0x80000000;
@@ -815,7 +821,8 @@ grub_multiboot2_make_mbi (grub_uint32_t *target)
 	/ sizeof (grub_properly_aligned_t);
     }
 
-  {
+#if defined (__i386__) || defined (__x86_64__) || defined (__mips)
+	{
     struct multiboot_tag_elf_sections *tag
       = (struct multiboot_tag_elf_sections *) ptrorig;
     tag->type = MULTIBOOT_TAG_TYPE_ELF_SECTIONS;
@@ -828,6 +835,23 @@ grub_multiboot2_make_mbi (grub_uint32_t *target)
     ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
       / sizeof (grub_properly_aligned_t);
   }
+#endif
+  
+  {
+    struct multiboot_tag_elf64_sections *tag
+      = (struct multiboot_tag_elf64_sections *) ptrorig;
+    tag->type = MULTIBOOT_TAG_TYPE_ELF64_SECTIONS;
+    tag->size = sizeof (struct multiboot_tag_elf64_sections)
+      + elf_sec_entsize * elf_sec_num;
+    grub_memcpy (tag->sections, elf_sections, elf_sec_entsize *
elf_sec_num);
+    tag->num = elf_sec_num;
+    tag->entsize = elf_sec_entsize;
+    tag->shndx = elf_sec_shstrndx;
+		grub_memset (&(tag->reserved), 0,
sizeof(multiboot_uint32_t));
+    ptrorig += ALIGN_UP (tag->size, MULTIBOOT_TAG_ALIGN)
+      / sizeof (grub_properly_aligned_t);
+  }
+
 
   if (!keep_bs)
     {
@@ -882,7 +906,7 @@ grub_multiboot2_make_mbi (grub_uint32_t *target)
       }
   }
 
-#if defined (GRUB_MACHINE_EFI) && defined (__x86_64__)
+#if defined (GRUB_MACHINE_EFI) && (defined (__x86_64__) ||
defined(__aarch64__))
   {
     struct multiboot_tag_efi64 *tag = (struct multiboot_tag_efi64 *)
ptrorig;
     tag->type = MULTIBOOT_TAG_TYPE_EFI64;
@@ -981,7 +1005,7 @@ grub_multiboot2_make_mbi (grub_uint32_t *target)
       }
 #endif
 
-#ifdef __x86_64__
+#if defined ( __x86_64__) || defined (__aarch64__)
       {
 	struct multiboot_tag_efi64_ih *tag = (struct
multiboot_tag_efi64_ih *) ptrorig;
 	tag->type = MULTIBOOT_TAG_TYPE_EFI64_IH;
diff --git a/include/grub/arm64/multiboot.h
b/include/grub/arm64/multiboot.h
new file mode 100644
index 000000000..427dca07f
--- /dev/null
+++ b/include/grub/arm64/multiboot.h
@@ -0,0 +1,56 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2002,2003,2004,2007,2008,2009  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/>;.
+ */
+
+#ifndef GRUB_MULTIBOOT_CPU_HEADER
+#define GRUB_MULTIBOOT_CPU_HEADER	1
+
+#define MULTIBOOT2_INITIAL_STATE  { .w[0] =
MULTIBOOT2_BOOTLOADER_MAGIC,	\
+    .w[2] = 0,								
\
+    .w[3] = 0,								
\
+	.pc_reg = 8							
	\
+}
+#define MULTIBOOT_INITIAL_STATE  { .w[0] = MULTIBOOT_BOOTLOADER_MAGIC,
	\
+    .w[2] = 0,								
\
+    .w[3] = 0,								
\
+	.pc_reg = 8							
	\
+      }
+#define MULTIBOOT_ENTRY_REGISTER w[8]
+#define MULTIBOOT_MBI_REGISTER w[1]
+#define MULTIBOOT2_ARCHITECTURE_CURRENT
MULTIBOOT2_ARCHITECTURE_AARCH64
+
+#ifdef GRUB_MACHINE_EFI
+
+#define MULTIBOOT_EFI_INITIAL_STATE  { .w[0] =
MULTIBOOT_BOOTLOADER_MAGIC,	\
+    .w[2] = 0,								
\
+    .w[3] = 0,								
\
+	.pc_reg = 8							
	\
+      }
+#define MULTIBOOT2_EFI_INITIAL_STATE  { .w[0] =
MULTIBOOT2_BOOTLOADER_MAGIC,	\
+    .w[2] = 0,								
\
+    .w[3] = 0,								
\
+	.pc_reg = 8							
	\
+      }
+#define MULTIBOOT_EFI_ENTRY_REGISTER w[8]
+#define MULTIBOOT_EFI_MBI_REGISTER w[1]
+
+#endif /* GRUB_MACHINE_EFI */
+
+#define MULTIBOOT_ELF32_MACHINE	EM_AARCH64
+#define MULTIBOOT_ELF64_MACHINE EM_AARCH64
+
+#endif /* ! GRUB_MULTIBOOT_CPU_HEADER */
-- 
2.28.0



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 05/05] Enable multiboot2 support on arm64-efi target
  2020-10-28 19:45 [PATCH] Enable multiboot2 support on arm64-efi target Chris Plant
                   ` (2 preceding siblings ...)
  2020-10-28 19:50 ` [PATCH 04/05] " Chris Plant
@ 2020-10-28 19:51 ` Chris Plant
  2020-10-28 19:52 ` [PATCH 02/05] " Chris Plant
  4 siblings, 0 replies; 6+ messages in thread
From: Chris Plant @ 2020-10-28 19:51 UTC (permalink / raw)
  To: Grub-devel; +Cc: chris

Enable multiboot2 support for arm64-efi target

Signed-off-by: Chris Plant <chris@monkeyircd.org>

---
 grub-core/Makefile.core.def | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index b5f47fc41..2c0bec83d 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1674,6 +1674,8 @@ module = {
   x86_64_xen = lib/x86_64/xen/relocator.S;
   xen = lib/i386/relocator_common_c.c;
   x86_64_efi = lib/x86_64/efi/relocator.c;
+  arm64_efi = lib/arm64/relocator.c;
+  arm64_efi = lib/arm64/relocator_asm.S;
 
   extra_dist = lib/i386/relocator_common.S;
   extra_dist = kern/powerpc/cache_flush.S;
@@ -1683,6 +1685,7 @@ module = {
   enable = x86;
   enable = i386_xen_pvh;
   enable = xen;
+  enable = arm64_efi;
 };
 
 module = {
@@ -1783,6 +1786,7 @@ module = {
   enable = x86;
   enable = i386_xen_pvh;
   enable = mips;
+  enable = arm64_efi;
 };
 
 module = {
@@ -1907,6 +1911,8 @@ module = {
 
   mips = mmap/mips/uppermem.c;
 
+  arm64_efi = mmap/arm64/uppermem.c;
+
   enable = x86;
   enable = i386_xen_pvh;
   enable = ia64_efi;
-- 
2.28.0



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 02/05] Enable multiboot2 support on arm64-efi target
  2020-10-28 19:45 [PATCH] Enable multiboot2 support on arm64-efi target Chris Plant
                   ` (3 preceding siblings ...)
  2020-10-28 19:51 ` [PATCH 05/05] " Chris Plant
@ 2020-10-28 19:52 ` Chris Plant
  4 siblings, 0 replies; 6+ messages in thread
From: Chris Plant @ 2020-10-28 19:52 UTC (permalink / raw)
  To: Grub-devel; +Cc: chris

Add ARM64 relocator code to support multiboot2 loader

Signed-off-by: Chris plant <chris@monkeyircd.org>

---
 grub-core/lib/arm64/relocator.c     | 267 ++++++++++++++++++++++++++++
 grub-core/lib/arm64/relocator_asm.S |  57 ++++++
 include/grub/arm64/relocator.h      |  52 ++++++
 3 files changed, 376 insertions(+)
 create mode 100644 grub-core/lib/arm64/relocator.c
 create mode 100644 grub-core/lib/arm64/relocator_asm.S
 create mode 100644 include/grub/arm64/relocator.h

diff --git a/grub-core/lib/arm64/relocator.c b/grub-
core/lib/arm64/relocator.c
new file mode 100644
index 000000000..a287bd5ff
--- /dev/null
+++ b/grub-core/lib/arm64/relocator.c
@@ -0,0 +1,267 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2020  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/mm.h>
+#include <grub/misc.h>
+
+#include <grub/types.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/cache.h>
+
+#include <grub/arm64/relocator.h>
+#include <grub/relocator_private.h>
+
+
+/* Defines to simplify creating machine code instructions */
+
+#define AARCH64_INSTR_MOVZ_64	0xd2800000
+#define AARCH64_INSTR_MOVK_64	0xf2800000
+#define AARCH64_INSTR_MOVZ_32	0x52800000
+#define AARCH64_INSTR_MOVK_32	0x72800000
+#define AARCH64_INSTR_BR		0xd61f0000
+#define AARCH64_INSTR_NOP		0xd503201f
+
+#define AARCH64_INSTR_SHIFT_16	1 << 21
+#define AARCH64_INSTR_SHIFT_32  2 << 21
+#define AARCH64_INSTR_SHIFT_48	3 << 21
+
+extern grub_uint8_t grub_relocator_forward_start;
+extern grub_uint8_t grub_relocator_forward_end;
+extern grub_uint8_t grub_relocator_backward_start;
+extern grub_uint8_t grub_relocator_backward_end;
+extern grub_uint32_t grub_relocator_check_endian;
+
+#define REGW32_SIZEOF (2 * sizeof (grub_uint32_t))
+#define REGW64_SIZEOF (4 * sizeof (grub_uint32_t))
+#define JUMP_SIZEOF (2 * sizeof (grub_uint32_t))
+
+#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator_##x##_end \
+				 - &grub_relocator_##x##_start)
+#define RELOCATOR_SIZEOF(x)	(RELOCATOR_SRC_SIZEOF(x) \
+				 + REGW32_SIZEOF * 3)
+grub_size_t grub_relocator_align = sizeof (grub_uint32_t);
+grub_size_t grub_relocator_forward_size;
+grub_size_t grub_relocator_backward_size;
+grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW64_SIZEOF;
+
+void
+grub_cpu_relocator_init (void)
+{
+  grub_relocator_forward_size = RELOCATOR_SIZEOF(forward);
+  grub_relocator_backward_size = RELOCATOR_SIZEOF(backward);
+}
+
+/*
+ * Create machine code in memory @ *target to write val 
+ * to register regn using 64 bit register width 
+ */
+static void
+write_reg64 (int regn, grub_uint64_t val, void **target)
+{
+	grub_uint16_t hword;
+
+	hword = val >> 48 & 0xFFFF;
+	*(grub_uint32_t *) *target = AARCH64_INSTR_MOVZ_64 |
AARCH64_INSTR_SHIFT_48 |
+							 	 (hword
<< 5) | regn;
+	*target = ((grub_uint32_t *) *target) + 1;
+
+	hword = val >> 32 & 0xFFFF;
+	*(grub_uint32_t *) *target = AARCH64_INSTR_MOVK_64 |
AARCH64_INSTR_SHIFT_32 |
+							 	 (hword
<< 5) | regn;
+	*target = ((grub_uint32_t *) *target) + 1;
+
+	hword = val >> 16 & 0xFFFF;
+	*(grub_uint32_t *) *target = AARCH64_INSTR_MOVK_64 |
AARCH64_INSTR_SHIFT_16 |
+							 	 (hword
<< 5) | regn;
+	*target = ((grub_uint32_t *) *target) + 1;
+
+	hword = val >> 0 & 0xFFFF;
+	*(grub_uint32_t *) *target = AARCH64_INSTR_MOVK_64 | (hword <<
5) | regn;
+	*target = ((grub_uint32_t *) *target) + 1;
+}
+
+/*
+ * Create machine code in memory @ *target to write val 
+ * to register regn using 32 bit register width 
+ */
+static void
+write_reg32 (int regn, grub_uint32_t val, void **target)
+{
+  grub_uint16_t hword;
+
+  hword = val >> 16  & 0xFFFF;
+  *(grub_uint32_t *) *target = AARCH64_INSTR_MOVZ_32 |
AARCH64_INSTR_SHIFT_16 |
+							 	 (hword
<< 5) | regn;
+  *target = ((grub_uint32_t *) *target) + 1;
+
+
+  hword = val & 0xFFFF;
+  *(grub_uint32_t *) *target = AARCH64_INSTR_MOVK_32 | (hword << 5) |
regn;
+
+  *target = ((grub_uint32_t *) *target) + 1;
+}
+
+
+
+/*
+ * Create machine code in memory @ *target to jump to the
+ * address in register regn
+ */
+static void
+write_jump (int regn, void **target)
+{
+
+  /* br x(regn) */
+  *(grub_uint32_t *) *target = AARCH64_INSTR_BR | (regn << 5);
+  *target = ((grub_uint32_t *) *target) + 1;
+
+  /* nop.  */
+  *(grub_uint32_t *) *target = AARCH64_INSTR_NOP;
+  *target = ((grub_uint32_t *) *target) + 1;
+}
+
+
+/*
+ * Write machine code to load a 64 bit memory location to 
+ * a register and then jump to it
+ */
+void
+grub_cpu_relocator_jumper (void *rels, grub_addr_t addr)
+{
+  /* Write address to the register */
+  write_reg64(8,addr,&rels);
+
+  /* Jump to the address in the register */
+  write_jump(8,&rels);
+}
+
+/*
+ * Use general purpose registers to pass variables
+ * src = x8, dest = x9, size = x10
+ */
+void
+grub_cpu_relocator_backward (void *ptr, void *src, void *dest,
+			     grub_size_t size)
+{
+
+  write_reg64(8,(grub_uint64_t) src, &ptr);
+  write_reg64(9,(grub_uint64_t) dest, &ptr);
+  write_reg64(10,(grub_uint64_t) size, &ptr);
+
+  grub_memcpy (ptr, &grub_relocator_backward_start,
+	       RELOCATOR_SRC_SIZEOF (backward));
+}
+
+
+void
+grub_cpu_relocator_forward (void *ptr, void *src, void *dest,
+			     grub_size_t size)
+{
+  write_reg64(8,(grub_uint64_t) src, &ptr);
+  write_reg64(9,(grub_uint64_t) dest, &ptr);
+  write_reg64(10,(grub_uint64_t) size, &ptr);
+
+  grub_memcpy (ptr, &grub_relocator_forward_start, 
+	       RELOCATOR_SRC_SIZEOF (forward));
+}
+
+
+grub_err_t
+grub_relocator32_boot (struct grub_relocator *rel,
+		       struct grub_relocator32_state state)
+{
+  grub_relocator_chunk_t ch;
+  void *ptr;
+  grub_err_t err;
+  void *relst;
+  grub_size_t relsize;
+  grub_size_t stateset_size = 32 * REGW32_SIZEOF + JUMP_SIZEOF;
+  unsigned i;
+  grub_addr_t vtarget;
+
+  err = grub_relocator_alloc_chunk_align (rel, &ch, 0,
+                      (0xffffffff - stateset_size)
+                      + 1, stateset_size,
+                      sizeof (grub_uint32_t),
+                      GRUB_RELOCATOR_PREFERENCE_NONE, 0);
+
+  if (err)
+    return err;
+
+  ptr = get_virtual_current_address (ch);
+
+  for (i = 0; i < 32; i++)
+    write_reg32 (i, state.w[i], &ptr);
+  
+  write_jump (state.pc_reg, &ptr);
+
+  vtarget = (grub_addr_t) grub_map_memory (get_physical_target_address
(ch),
+					   stateset_size);
+
+  err = grub_relocator_prepare_relocs (rel, vtarget, &relst,
&relsize);
+  if (err)
+    return err;
+
+  grub_arch_sync_caches ((void *) relst, relsize);
+
+  ((void (*) (void))  (relst)) ();
+
+  /* Not reached.  */
+  return GRUB_ERR_NONE;
+
+}
+
+grub_err_t
+grub_relocator64_boot (struct grub_relocator *rel,
+		       struct grub_relocator64_state state)
+{
+  grub_relocator_chunk_t ch;
+  void *ptr;
+  grub_err_t err;
+  void *relst;
+  grub_size_t relsize;
+  grub_size_t stateset_size = 32 * REGW64_SIZEOF + JUMP_SIZEOF;
+  unsigned i;
+
+  err = grub_relocator_alloc_chunk_align (rel, &ch, 0,
+                      (0xffffffff - stateset_size)
+                      + 1, stateset_size,
+                      sizeof (grub_uint32_t),
+                      GRUB_RELOCATOR_PREFERENCE_NONE, 0);
+  if (err)
+    return err;
+
+  ptr = get_virtual_current_address (ch);
+  for (i = 0; i < 32; i++)
+    write_reg64 (i, state.x[i], &ptr);
+  write_jump (state.pc_reg, &ptr);
+  
+  err = grub_relocator_prepare_relocs (rel,
get_physical_target_address(ch), &relst, &relsize);
+  if (err)
+    return err;
+
+  grub_arch_sync_caches ((void *) relst, relsize);
+
+  ((void (*) (void)) relst) ();
+
+  /* Not reached.  */
+  return GRUB_ERR_NONE;
+
+
+}
diff --git a/grub-core/lib/arm64/relocator_asm.S b/grub-
core/lib/arm64/relocator_asm.S
new file mode 100644
index 000000000..117f98dbe
--- /dev/null
+++ b/grub-core/lib/arm64/relocator_asm.S
@@ -0,0 +1,57 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2020  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/>;.
+ */
+
+/*
+ * aarch64/ARM64 relocator code, heavily based on MIPS code
+ * adapted by Chris Plant
+ */
+
+#include <grub/symbol.h>
+	
+	.p2align	4	/* force 16-byte alignment */
+
+VARIABLE (grub_relocator_forward_start)
+
+copycont1:	
+	ldr x11,[x8]
+	str	x11,[x9]
+	add	x8,x8,#1
+	add x9,x9,#1
+	sub x10,x10,#1
+	cbnz x10, copycont1
+
+VARIABLE (grub_relocator_forward_end)
+
+VARIABLE (grub_relocator_backward_start)
+
+	add	x9,x9,x10
+	add x8,x8,x10
+	/* Backward movsl is implicitly off-by-one.  compensate
that.  */
+	sub x9,x9,#1
+	sub x8,x8,#1
+copycont2:	
+	ldr x11,[x8]
+	str x11,[x9]
+	sub x8,x8,#1
+	sub x9,x9,#1
+	sub x10,x10, #1
+	cbnz x10, copycont2
+
+
+VARIABLE (grub_relocator_backward_end)
+
diff --git a/include/grub/arm64/relocator.h
b/include/grub/arm64/relocator.h
new file mode 100644
index 000000000..4409c472a
--- /dev/null
+++ b/include/grub/arm64/relocator.h
@@ -0,0 +1,52 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2020 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/>;.
+ */
+
+#ifndef GRUB_RELOCATOR_CPU_HEADER
+#define GRUB_RELOCATOR_CPU_HEADER	1
+
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/relocator.h>
+
+struct grub_relocator64_state
+{
+  /* General Purpose Registers (xn)  */
+  grub_uint64_t x[32];
+
+  /* The register containing the new pc value */
+  int pc_reg;
+};
+
+struct grub_relocator32_state
+{
+  /* General Purpose Registers (xn)  */
+  grub_uint32_t w[32];
+
+  int pc_reg;
+};
+
+grub_err_t
+grub_relocator64_boot (struct grub_relocator *rel,
+		       struct grub_relocator64_state state);
+
+
+grub_err_t
+grub_relocator32_boot (struct grub_relocator *rel,
+		       struct grub_relocator32_state state);
+
+#endif /* ! GRUB_RELOCATOR_CPU_HEADER */
-- 
2.28.0



^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-10-28 19:52 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-10-28 19:45 [PATCH] Enable multiboot2 support on arm64-efi target Chris Plant
2020-10-28 19:47 ` [PATCH 01/05] " Chris Plant
2020-10-28 19:49 ` [PATCH 03/05] " Chris Plant
2020-10-28 19:50 ` [PATCH 04/05] " Chris Plant
2020-10-28 19:51 ` [PATCH 05/05] " Chris Plant
2020-10-28 19:52 ` [PATCH 02/05] " Chris Plant

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox