Blame SOURCES/0281-arm64-Add-support-for-relocations-needed-for-linaro-.patch

28f7f8
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
28f7f8
From: Vladimir Serbinenko <phcoder@gmail.com>
28f7f8
Date: Fri, 22 Jan 2016 19:09:37 +0100
28f7f8
Subject: [PATCH] arm64: Add support for relocations needed for linaro gcc
28f7f8
28f7f8
---
28f7f8
 grub-core/kern/arm64/dl.c        | 18 ++++++++++++++++++
28f7f8
 grub-core/kern/arm64/dl_helper.c | 40 ++++++++++++++++++++++++++++++++++++++++
28f7f8
 util/grub-mkimagexx.c            | 31 +++++++++++++++++++++++++++++++
28f7f8
 util/grub-module-verifier.c      |  8 +++++++-
28f7f8
 include/grub/arm64/reloc.h       |  8 ++++++++
28f7f8
 include/grub/elf.h               |  3 +++
28f7f8
 6 files changed, 107 insertions(+), 1 deletion(-)
28f7f8
28f7f8
diff --git a/grub-core/kern/arm64/dl.c b/grub-core/kern/arm64/dl.c
28f7f8
index e19ba6a0d58..cf50d7250d9 100644
28f7f8
--- a/grub-core/kern/arm64/dl.c
28f7f8
+++ b/grub-core/kern/arm64/dl.c
28f7f8
@@ -132,6 +132,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
28f7f8
 	    *abs_place = (grub_uint64_t) sym_addr;
28f7f8
 	  }
28f7f8
 	  break;
28f7f8
+	case R_AARCH64_ADD_ABS_LO12_NC:
28f7f8
+	  grub_arm64_set_abs_lo12 (place, sym_addr);
28f7f8
+	  break;
28f7f8
+	case R_AARCH64_LDST64_ABS_LO12_NC:
28f7f8
+	  grub_arm64_set_abs_lo12_ldst64 (place, sym_addr);
28f7f8
+	  break;
28f7f8
 	case R_AARCH64_CALL26:
28f7f8
 	case R_AARCH64_JUMP26:
28f7f8
 	  {
28f7f8
@@ -154,6 +160,18 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
28f7f8
 	    grub_arm64_set_xxxx26_offset (place, offset);
28f7f8
 	  }
28f7f8
 	  break;
28f7f8
+	case R_AARCH64_ADR_PREL_PG_HI21:
28f7f8
+	  {
28f7f8
+	    grub_int64_t offset = (sym_addr & ~0xfffULL) - (((grub_uint64_t) place) & ~0xfffULL);
28f7f8
+
28f7f8
+	    if (!grub_arm64_check_hi21_signed (offset))
28f7f8
+		return grub_error (GRUB_ERR_BAD_MODULE,
28f7f8
+				   "HI21 out of range");
28f7f8
+
28f7f8
+	    grub_arm64_set_hi21 (place, offset);
28f7f8
+	  }
28f7f8
+	  break;
28f7f8
+
28f7f8
 	default:
28f7f8
 	  return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
28f7f8
 			     N_("relocation 0x%x is not implemented yet"),
28f7f8
diff --git a/grub-core/kern/arm64/dl_helper.c b/grub-core/kern/arm64/dl_helper.c
28f7f8
index d213ab93e88..f031b1ae921 100644
28f7f8
--- a/grub-core/kern/arm64/dl_helper.c
28f7f8
+++ b/grub-core/kern/arm64/dl_helper.c
28f7f8
@@ -53,3 +53,43 @@ grub_arm64_set_xxxx26_offset (grub_uint32_t *place, grub_int64_t offset)
28f7f8
   *place &= insmask;
28f7f8
   *place |= grub_cpu_to_le32 (offset >> 2) & ~insmask;
28f7f8
 }
28f7f8
+
28f7f8
+int
28f7f8
+grub_arm64_check_hi21_signed (grub_int64_t offset)
28f7f8
+{
28f7f8
+  if (offset != (grub_int64_t)(grub_int32_t)offset)
28f7f8
+    return 0;
28f7f8
+  return 1;
28f7f8
+}
28f7f8
+
28f7f8
+void
28f7f8
+grub_arm64_set_hi21 (grub_uint32_t *place, grub_int64_t offset)
28f7f8
+{
28f7f8
+  const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0x9f00001f);
28f7f8
+  grub_uint32_t val;
28f7f8
+
28f7f8
+  offset >>= 12;
28f7f8
+  
28f7f8
+  val = ((offset & 3) << 29) | (((offset >> 2) & 0x7ffff) << 5);
28f7f8
+  
28f7f8
+  *place &= insmask;
28f7f8
+  *place |= grub_cpu_to_le32 (val) & ~insmask;
28f7f8
+}
28f7f8
+
28f7f8
+void
28f7f8
+grub_arm64_set_abs_lo12 (grub_uint32_t *place, grub_int64_t target)
28f7f8
+{
28f7f8
+  const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xffc003ff);
28f7f8
+
28f7f8
+  *place &= insmask;
28f7f8
+  *place |= grub_cpu_to_le32 (target << 10) & ~insmask;
28f7f8
+}
28f7f8
+
28f7f8
+void
28f7f8
+grub_arm64_set_abs_lo12_ldst64 (grub_uint32_t *place, grub_int64_t target)
28f7f8
+{
28f7f8
+  const grub_uint32_t insmask = grub_cpu_to_le32_compile_time (0xfff803ff);
28f7f8
+
28f7f8
+  *place &= insmask;
28f7f8
+  *place |= grub_cpu_to_le32 (target << 7) & ~insmask;
28f7f8
+}
28f7f8
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
28f7f8
index 66e8576411e..d1bc95e350d 100644
28f7f8
--- a/util/grub-mkimagexx.c
28f7f8
+++ b/util/grub-mkimagexx.c
28f7f8
@@ -836,6 +836,14 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
28f7f8
 		       *target = grub_host_to_target64 (grub_target_to_host64 (*target) + sym_addr);
28f7f8
 		     }
28f7f8
 		     break;
28f7f8
+		   case R_AARCH64_ADD_ABS_LO12_NC:
28f7f8
+		     grub_arm64_set_abs_lo12 ((grub_uint32_t *) target,
28f7f8
+					      sym_addr);
28f7f8
+		     break;
28f7f8
+		   case R_AARCH64_LDST64_ABS_LO12_NC:
28f7f8
+		     grub_arm64_set_abs_lo12_ldst64 ((grub_uint32_t *) target,
28f7f8
+						     sym_addr);
28f7f8
+		     break;
28f7f8
 		   case R_AARCH64_JUMP26:
28f7f8
 		   case R_AARCH64_CALL26:
28f7f8
 		     {
28f7f8
@@ -848,6 +856,17 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
28f7f8
 						     sym_addr);
28f7f8
 		     }
28f7f8
 		     break;
28f7f8
+		   case R_AARCH64_ADR_PREL_PG_HI21:
28f7f8
+		     {
28f7f8
+		       sym_addr &= ~0xfffULL;
28f7f8
+		       sym_addr -= (offset + SUFFIX (entry_point)) & ~0xfffULL;
28f7f8
+		       if (!grub_arm64_check_hi21_signed (sym_addr))
28f7f8
+			 grub_util_error ("%s", "CALL26 Relocation out of range");
28f7f8
+
28f7f8
+		       grub_arm64_set_hi21((grub_uint32_t *)target,
28f7f8
+					   sym_addr);
28f7f8
+		     }
28f7f8
+		     break;
28f7f8
 		   default:
28f7f8
 		     grub_util_error (_("relocation 0x%x is not implemented yet"),
28f7f8
 				      (unsigned int) ELF_R_TYPE (info));
28f7f8
@@ -1200,6 +1219,15 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
28f7f8
 		  case R_AARCH64_CALL26:
28f7f8
 		  case R_AARCH64_JUMP26:
28f7f8
 		    break;
28f7f8
+		    /* Page-relative relocations do not require fixup entries. */
28f7f8
+		  case R_AARCH64_ADR_PREL_PG_HI21:
28f7f8
+		     /* We page-align the whole kernel, so no need
28f7f8
+			for fixup entries.
28f7f8
+		      */
28f7f8
+		  case R_AARCH64_ADD_ABS_LO12_NC:
28f7f8
+		  case R_AARCH64_LDST64_ABS_LO12_NC:
28f7f8
+		    break;
28f7f8
+
28f7f8
 		  default:
28f7f8
 		    grub_util_error (_("relocation 0x%x is not implemented yet"),
28f7f8
 				     (unsigned int) ELF_R_TYPE (info));
28f7f8
@@ -1343,6 +1371,9 @@ SUFFIX (locate_sections) (const char *kernel_path,
28f7f8
   Elf_Shdr *s;
28f7f8
 
28f7f8
   *all_align = 1;
28f7f8
+  /* Page-aligning simplifies relocation handling.  */
28f7f8
+  if (image_target->elf_target == EM_AARCH64)
28f7f8
+    *all_align = 4096;
28f7f8
 
28f7f8
   section_addresses = xmalloc (sizeof (*section_addresses) * num_sections);
28f7f8
   memset (section_addresses, 0, sizeof (*section_addresses) * num_sections);
28f7f8
diff --git a/util/grub-module-verifier.c b/util/grub-module-verifier.c
28f7f8
index e217dcddc07..405c9117051 100644
28f7f8
--- a/util/grub-module-verifier.c
28f7f8
+++ b/util/grub-module-verifier.c
28f7f8
@@ -107,7 +107,13 @@ struct grub_module_verifier_arch archs[] = {
28f7f8
       R_AARCH64_CALL26,
28f7f8
       R_AARCH64_JUMP26,
28f7f8
       -1
28f7f8
-    } },
28f7f8
+    }, (int[]){
28f7f8
+      R_AARCH64_ADR_PREL_PG_HI21,
28f7f8
+      R_AARCH64_ADD_ABS_LO12_NC,
28f7f8
+      R_AARCH64_LDST64_ABS_LO12_NC,
28f7f8
+      -1
28f7f8
+    }
28f7f8
+  },
28f7f8
 };
28f7f8
 
28f7f8
 
28f7f8
diff --git a/include/grub/arm64/reloc.h b/include/grub/arm64/reloc.h
28f7f8
index 4aed3d715e0..452c148226d 100644
28f7f8
--- a/include/grub/arm64/reloc.h
28f7f8
+++ b/include/grub/arm64/reloc.h
28f7f8
@@ -22,5 +22,13 @@
28f7f8
 int grub_arm_64_check_xxxx26_offset (grub_int64_t offset);
28f7f8
 void
28f7f8
 grub_arm64_set_xxxx26_offset (grub_uint32_t *place, grub_int64_t offset);
28f7f8
+int
28f7f8
+grub_arm64_check_hi21_signed (grub_int64_t offset);
28f7f8
+void
28f7f8
+grub_arm64_set_hi21 (grub_uint32_t *place, grub_int64_t offset);
28f7f8
+void
28f7f8
+grub_arm64_set_abs_lo12 (grub_uint32_t *place, grub_int64_t target);
28f7f8
+void
28f7f8
+grub_arm64_set_abs_lo12_ldst64 (grub_uint32_t *place, grub_int64_t target);
28f7f8
 
28f7f8
 #endif
28f7f8
diff --git a/include/grub/elf.h b/include/grub/elf.h
28f7f8
index caa79639082..db15acecf9f 100644
28f7f8
--- a/include/grub/elf.h
28f7f8
+++ b/include/grub/elf.h
28f7f8
@@ -2068,6 +2068,9 @@ typedef Elf32_Addr Elf32_Conflict;
28f7f8
 #define R_AARCH64_NONE			0	/* No relocation.  */
28f7f8
 #define R_AARCH64_ABS64			257	/* Direct 64 bit. */
28f7f8
 #define R_AARCH64_ABS32			258	/* Direct 32 bit.  */
28f7f8
+#define R_AARCH64_ADR_PREL_PG_HI21	275
28f7f8
+#define R_AARCH64_ADD_ABS_LO12_NC	277
28f7f8
+#define R_AARCH64_LDST64_ABS_LO12_NC	286
28f7f8
 #define R_AARCH64_JUMP26		282	/* 26-bit relative. */
28f7f8
 #define R_AARCH64_CALL26		283	/* 26-bit relative. */
28f7f8
 #define R_AARCH64_COPY			1024	/* Copy symbol at runtime.  */