[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[RFC PATCH 15/23] Add ppc64 relocations
From: |
Ram Pai |
Subject: |
[RFC PATCH 15/23] Add ppc64 relocations |
Date: |
Wed, 26 Feb 2014 10:31:14 -0800 |
From: Anton Blanchard <address@hidden>
Add ppc64 relocations
Signed-off-by: Ram Pai <address@hidden>
From: Anton Blanchard <address@hidden>
---
grub-core/kern/powerpc/dl.c | 179 +++++++++++++++++++++++++++++++++++++++++---
include/grub/elf.h | 3 +
2 files changed, 172 insertions(+), 10 deletions(-)
diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c
index 7677e5a..2a3b022 100644
--- a/grub-core/kern/powerpc/dl.c
+++ b/grub-core/kern/powerpc/dl.c
@@ -23,6 +23,20 @@
#include <grub/err.h>
#include <grub/i18n.h>
+#if defined( __powerpc64__ ) || defined( __powerpc64le__ )
+#define ELFCLASSXX ELFCLASS64
+#define ELFMACHINEXX EM_PPC64
+#else
+#define ELFCLASSXX ELFCLASS32
+#define ELFMACHINEXX EM_PPC32
+#endif
+
+#if defined( __powerpc64le__ )
+#define ELFDATA2XSB ELFDATA2LSB
+#else
+#define ELFDATA2XSB ELFDATA2MSB
+#endif
+
/* Check if EHDR is a valid ELF header. */
grub_err_t
grub_arch_dl_check_header (void *ehdr)
@@ -30,14 +44,77 @@ grub_arch_dl_check_header (void *ehdr)
Elf_Ehdr *e = ehdr;
/* Check the magic numbers. */
- if (e->e_ident[EI_CLASS] != ELFCLASS32
- || e->e_ident[EI_DATA] != ELFDATA2MSB
- || e->e_machine != EM_PPC)
+ if (e->e_ident[EI_CLASS] != ELFCLASSXX
+ || e->e_ident[EI_DATA] != ELFDATA2XSB
+ || e->e_machine != ELFMACHINEXX)
return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF
magic"));
return GRUB_ERR_NONE;
}
+
+
+
+#if defined( __powerpc64le__ )
+struct trampoline
+{
+ grub_uint32_t std;
+ grub_uint32_t addis;
+ grub_uint32_t addi;
+ grub_uint32_t mtctr;
+ grub_uint32_t bctr;
+};
+
+static const struct trampoline trampoline_template =
+ {
+ 0xf8410018, /* std r2,24(r1) */
+ 0x3d800000, /* addis r12,0,0 */
+ 0x398c0000, /* addi r12,r12,0 */
+ 0x7d8903a6, /* mtctr r12 */
+ 0x4e800420, /* bctr */
+ };
+
+#define PPC_NOP 0x60000000
+#define RESTORE_TOC 0xe8410018 /* ld r2,24(r1) */
+
+#define STO_PPC64_LOCAL_BIT 5
+#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT)
+
+static inline unsigned int
+ppc64_decode_local_entry(unsigned int other)
+{
+ return ((1 << other) >> 2) << 2;
+}
+
+#define PPC64_LOCAL_ENTRY_OFFSET(other) \
+ ppc64_decode_local_entry (((other) & STO_PPC64_LOCAL_MASK) \
+ >> STO_PPC64_LOCAL_BIT)
+
+
+
+#elif defined( __powerpc64__ )
+
+#error "NOT SUPPORTED YET"
+
+static int grub_arch_dl_is_in_opd (grub_dl_t mod, void *ehdr, unsigned long
addr)
+{
+ unsigned long start, end;
+ Elf_Shdr *s = grub_dl_find_section(ehdr, ".opd");
+
+ if (!s)
+ return 0;
+
+ start = (unsigned long)grub_dl_find_section_addr(mod, ehdr, ".opd");
+ end = start + s->sh_size;
+
+ if ((start <= addr) && (addr < end))
+ return 1;
+ else
+ return 0;
+}
+
+#else
+
/* For low-endian reverse lis and addr_high as well as ori and addr_low. */
struct trampoline
{
@@ -55,8 +132,20 @@ static const struct trampoline trampoline_template =
0x4e800420,
};
+#endif
+
#pragma GCC diagnostic ignored "-Wcast-align"
+static unsigned long grub_arch_dl_get_toc (grub_dl_t mod, void *ehdr)
+{
+ unsigned long i = (unsigned long)grub_dl_find_section_addr(mod, ehdr,
".toc");
+ if (!i)
+ return 0;
+
+ return i;
+}
+
+
grub_err_t
grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
grub_size_t *got)
@@ -89,12 +178,15 @@ grub_arch_dl_get_tramp_got_size (const void *ehdr,
grub_size_t *tramp,
return GRUB_ERR_NONE;
}
+#define PPC_LO(v) ((v) & 0xffff)
+#define PPC_HI(v) (((v) >> 16) & 0xffff)
+#define PPC_HA(v) PPC_HI ((v) + 0x8000)
+
/* Relocate symbols. */
grub_err_t
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
Elf_Shdr *s, grub_dl_segment_t seg)
{
-#ifdef powerpc
Elf_Rela *rel, *max;
for (rel = (Elf_Rela *) ((char *) ehdr + s->sh_offset),
@@ -104,7 +196,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
{
Elf_Word *addr;
Elf_Sym *sym;
- grub_uint32_t value;
+ Elf_Addr value;
if (seg->size < rel->r_offset)
return grub_error (GRUB_ERR_BAD_MODULE,
@@ -119,6 +211,76 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
value = sym->st_value + rel->r_addend;
switch (ELF_R_TYPE (rel->r_info))
{
+#ifdef __powerpc64le__
+ case GRUB_ELF_R_PPC_REL24:
+ {
+ struct trampoline *tptr = mod->trampptr;
+ Elf_Sword delta;
+ if (sym->st_shndx == SHN_UNDEF)
+ {
+ grub_memcpy (tptr, &trampoline_template, sizeof (*tptr));
+
+ tptr->addis |= PPC_HA(value);
+ tptr->addi |= PPC_LO(value);
+
+ mod->trampptr = tptr + 1;
+ delta = (grub_uint8_t *) tptr - (grub_uint8_t *) addr;
+
+ if (*(addr+1) != PPC_NOP)
+ return grub_error (GRUB_ERR_BAD_MODULE,
+ "Missing NOP after PPC_REL24 got %x", *(addr+1));
+ *(addr+1) = RESTORE_TOC;
+ } else
+ delta = (grub_uint8_t *)value - (grub_uint8_t *) addr +
+ PPC64_LOCAL_ENTRY_OFFSET(sym->st_other);
+
+
+ if (delta << 6 >> 6 != delta)
+ return grub_error (GRUB_ERR_BAD_MODULE,
+ "relocation overflow");
+
+ *(Elf_Word *) (addr) = (*addr & ~0x03fffffc) | (delta & 0x03fffffc);
+ }
+ break;
+
+ case GRUB_ELF_R_PPC64_ADDR64:
+ *(Elf_Xword *) addr = value;
+ break;
+
+ case GRUB_ELF_R_PPC64_TOC:
+ *(Elf_Xword *) addr = grub_arch_dl_get_toc(mod, ehdr);
+ break;
+
+ case GRUB_ELF_R_PPC64_TOC16_HA:
+ value -= grub_arch_dl_get_toc(mod, ehdr);
+ *(Elf_Half *) addr = PPC_HA(value);
+ break;
+
+ case GRUB_ELF_R_PPC64_TOC16_LO:
+ value -= grub_arch_dl_get_toc(mod, ehdr);
+ *(Elf_Half *) addr = PPC_LO(value);
+ break;
+
+ case GRUB_ELF_R_PPC64_TOC16_LO_DS:
+ value -= grub_arch_dl_get_toc(mod, ehdr);
+ if (value & 3)
+ return grub_error (GRUB_ERR_BAD_MODULE,
+ "bad TOC16_LO_DS relocation");
+
+ *(Elf_Half *) addr = ((*(Elf_Half *) addr) & ~0xfffc) | (value &
0xfffc);
+ break;
+
+ case GRUB_ELF_R_PPC64_REL16_HA:
+ value -= (unsigned long) addr;
+ *(Elf_Half *) addr = PPC_HA(value);
+ break;
+
+ case GRUB_ELF_R_PPC64_REL16_LO:
+ value -= (unsigned long) addr;
+ *(Elf_Half *) addr = PPC_LO(value);
+ break;
+#else
+
case GRUB_ELF_R_PPC_ADDR16_LO:
*(Elf_Half *) addr = value;
break;
@@ -156,6 +318,8 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
case GRUB_ELF_R_PPC_REL32:
*addr = value - (Elf_Word) addr;
break;
+#endif
+
default:
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
N_("relocation 0x%x is not implemented yet"),
@@ -164,9 +328,4 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
}
return GRUB_ERR_NONE;
-#else
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- N_("relocation is not implemented yet for module=%llx ehdr=%llx
Elf_Shdr=%llx seg=%llx"),
- mod, ehdr, s, seg);
-#endif
}
diff --git a/include/grub/elf.h b/include/grub/elf.h
index bee7583..224d164 100644
--- a/include/grub/elf.h
+++ b/include/grub/elf.h
@@ -1998,6 +1998,9 @@ typedef Elf32_Addr Elf32_Conflict;
#define GRUB_ELF_R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16
bit */
#define GRUB_ELF_R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted
high 16 */
+#define GRUB_ELF_R_PPC64_REL16_LO 250
+#define GRUB_ELF_R_PPC64_REL16_HA 252
+
/* This is a phony reloc to handle any old fashioned TOC16 references
that may still be in object files. */
#define GRUB_ELF_R_PPC_TOC16 255
--
1.8.5.3
- [RFC PATCH 06/23] Add IEEE1275_ADDR helper, (continued)
- [RFC PATCH 06/23] Add IEEE1275_ADDR helper, Ram Pai, 2014/02/26
- [RFC PATCH 05/23] set ABI version in e_flag of the PPC64LE ELF image., Ram Pai, 2014/02/26
- [RFC PATCH 07/23] Fix some more warnings when casting., Ram Pai, 2014/02/26
- [RFC PATCH 08/23] Add powerpc64 types, Ram Pai, 2014/02/26
- [RFC PATCH 09/23] Fix warnings when building powerpc linux loader 64bit, Ram Pai, 2014/02/26
- [RFC PATCH 11/23] Fix powerpc setjmp/longjmp 64bit issues, Ram Pai, 2014/02/26
- [RFC PATCH 10/23] GRUB_ELF_R_PPC_* processing is applicable only for 32 bit bootloader., Ram Pai, 2014/02/26
- [RFC PATCH 12/23] Add powerpc64 ieee1275 trampoline, Ram Pai, 2014/02/26
- [RFC PATCH 13/23] Add 64bit support to powerpc startup code, Ram Pai, 2014/02/26
- [RFC PATCH 14/23] Add grub_dl_find_section_addr, Ram Pai, 2014/02/26
- [RFC PATCH 15/23] Add ppc64 relocations,
Ram Pai <=
- [RFC PATCH 17/23] Use FUNC_START/FUNC_END for powerpc function definitions, Ram Pai, 2014/02/26
- [RFC PATCH 16/23] ppc64 doesn't need libgcc routines, Ram Pai, 2014/02/26
- [RFC PATCH 19/23] align .toc section on 4byte boundary., Ram Pai, 2014/02/26
- [RFC PATCH 18/23] .TOC. symbol is special in ppc64le, Ram Pai, 2014/02/26
- [RFC PATCH 20/23] fix parameter to firmware calls, Ram Pai, 2014/02/26
- [RFC PATCH 21/23] powerpc64 is not necessarily BigEndian anymore! :), Ram Pai, 2014/02/26
- [RFC PATCH 22/23] fix segfaults if initrd, Ram Pai, 2014/02/26
- [RFC PATCH 23/23] Optional: Power7 VSX instructions workaround., Ram Pai, 2014/02/26