]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Implement sparc64 trampolines (needed for sparc64-emu).
authorVladimir Serbinenko <phcoder@gmail.com>
Mon, 9 Dec 2013 23:01:27 +0000 (00:01 +0100)
committerVladimir Serbinenko <phcoder@gmail.com>
Mon, 9 Dec 2013 23:01:27 +0000 (00:01 +0100)
ChangeLog
grub-core/kern/dl.c
grub-core/kern/emu/full.c
grub-core/kern/sparc64/dl.c
include/grub/dl.h

index 2b9f300bb0d90dda9aa57b78a5cfa5e51463ff6d..36d1d941d9ad5970b58c4ec236656b79c6beac1e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2013-12-09  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Implement sparc64 trampolines (needed for sparc64-emu).
+
 2013-12-09  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * grub-core/kern/sparc64/dl.c (grub_arch_dl_relocate_symbols): Check
index 90589f75b3aa37de900fb4cae04b3217ed58a3ea..98f858a38b1d36afc426d85f10b7c53a7f5614ab 100644 (file)
@@ -225,7 +225,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
   unsigned i;
   Elf_Shdr *s;
   grub_size_t tsize = 0, talign = 1;
-#if !defined (__i386__) && !defined (__x86_64__) && !defined (__sparc__)
+#if !defined (__i386__) && !defined (__x86_64__)
   grub_size_t tramp;
   grub_size_t got;
   grub_err_t err;
@@ -241,7 +241,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
        talign = s->sh_addralign;
     }
 
-#if !defined (__i386__) && !defined (__x86_64__) && !defined (__sparc__)
+#if !defined (__i386__) && !defined (__x86_64__)
   err = grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
   if (err)
     return err;
@@ -304,7 +304,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
          mod->segment = seg;
        }
     }
-#if !defined (__i386__) && !defined (__x86_64__) && !defined (__sparc__)
+#if !defined (__i386__) && !defined (__x86_64__)
   ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
   mod->tramp = ptr;
   mod->trampptr = ptr;
index 03888d8ece6c29d495f889734aa4b774e66e2bfb..e8d63b1f5f9e1253fe124b664fbdccc241e88de0 100644 (file)
@@ -49,7 +49,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
   return GRUB_ERR_BAD_MODULE;
 }
 
-#if !defined (__i386__) && !defined (__x86_64__) && !defined (__sparc__)
+#if !defined (__i386__) && !defined (__x86_64__)
 grub_err_t
 grub_arch_dl_get_tramp_got_size (const void *ehdr __attribute__ ((unused)),
                                 grub_size_t *tramp, grub_size_t *got)
index c6cac6838c78e33c2c10e376f231fd06daa863cc..d25c15e10dd464849257cf8a0351306133df276a 100644 (file)
@@ -40,6 +40,61 @@ grub_arch_dl_check_header (void *ehdr)
 
 #pragma GCC diagnostic ignored "-Wcast-align"
 
+struct trampoline
+{
+  grub_uint8_t code[0x28];
+  grub_uint64_t addr;
+};
+
+static const grub_uint8_t trampoline_code[0x28] =
+{
+  /* 0:  */ 0x82, 0x10, 0x00, 0x0f,    /* mov  %o7, %g1 */
+  /* 4:  */ 0x40, 0x00, 0x00, 0x02,    /* call  0xc */
+  /* 8:  */ 0x01, 0x00, 0x00, 0x00,    /* nop */
+  /* c:  */ 0x9e, 0x1b, 0xc0, 0x01,    /* xor  %o7, %g1, %o7 */
+  /* 10: */ 0x82, 0x18, 0x40, 0x0f,    /* xor  %g1, %o7, %g1 */
+  /* 14: */ 0x9e, 0x1b, 0xc0, 0x01,    /* xor  %o7, %g1, %o7 */
+  /* 18: */ 0xc2, 0x58, 0x60, 0x24,    /* ldx  [ %g1 + 0x24 ], %g1 */
+  /* 1c: */ 0x81, 0xc0, 0x40, 0x00,    /* jmp  %g1 */
+  /* 20: */ 0x01, 0x00, 0x00, 0x00,    /* nop */
+  /* 24: */ 0x01, 0x00, 0x00, 0x00,    /* nop */
+};
+
+grub_err_t
+grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
+                                grub_size_t *got)
+{
+  const Elf_Ehdr *e = ehdr;
+  const Elf_Shdr *s;
+  unsigned i;
+
+  *tramp = 0;
+  *got = 0;
+
+  for (i = 0, s = (const Elf_Shdr *) ((grub_addr_t) e + e->e_shoff);
+       i < e->e_shnum;
+       i++, s = (const Elf_Shdr *) ((grub_addr_t) s + e->e_shentsize))
+    if (s->sh_type == SHT_REL || s->sh_type == SHT_RELA)
+      {
+       const Elf_Rel *rel, *max;
+
+       for (rel = (const Elf_Rel *) ((grub_addr_t) e + s->sh_offset),
+              max = rel + s->sh_size / s->sh_entsize;
+            rel < max;
+            rel = (const Elf_Rel *) ((grub_addr_t) rel + s->sh_entsize))
+         switch (ELF_R_TYPE (rel->r_info))
+           {
+           case R_SPARC_WDISP30:
+             {
+               *tramp += sizeof (struct trampoline);
+               break;
+             }
+           }
+      }
+
+  return GRUB_ERR_NONE;
+}
+
 /* Relocate symbols.  */
 grub_err_t
 grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
@@ -74,6 +129,17 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
          *addr = value;
          break;
        case R_SPARC_WDISP30: /* 7 V-disp30 */
+         if (((value - (Elf_Addr) addr) & 0xFFFFFFFF00000000) &&
+              (((value - (Elf_Addr) addr) & 0xFFFFFFFF00000000)
+               != 0xFFFFFFFF00000000))
+           {
+             struct trampoline *tp = mod->trampptr;
+             mod->trampptr = tp + 1;
+             grub_memcpy (tp->code, trampoline_code, sizeof (tp->code));
+             tp->addr = value;
+             value = (Elf_Addr) tp;
+           }
+
          if (((value - (Elf_Addr) addr) & 0xFFFFFFFF00000000) &&
              (((value - (Elf_Addr) addr) & 0xFFFFFFFF00000000)
               != 0xFFFFFFFF00000000))
index 58b636f16ca8d4cc8dbc10cd451de641b1f075cd..d29a899f52c85ed856b71f24abd21b00bdf270c0 100644 (file)
@@ -180,7 +180,7 @@ struct grub_dl
   grub_size_t symsize;
   void (*init) (struct grub_dl *mod);
   void (*fini) (void);
-#if !defined (__i386__) && !defined (__x86_64__) && !defined (__sparc__)
+#if !defined (__i386__) && !defined (__x86_64__)
   void *got;
   void *gotptr;
   void *tramp;
@@ -278,7 +278,7 @@ grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
 #define GRUB_ARCH_DL_GOT_ALIGN 4
 #endif
 
-#if defined (__aarch64__)
+#if defined (__aarch64__) || defined (__sparc__)
 #define GRUB_ARCH_DL_TRAMP_ALIGN 8
 #define GRUB_ARCH_DL_GOT_ALIGN 8
 #endif