forked from pool/grub2
34d48ebe82
- Build GRUB2 for ppc64le as LittleEndian and 64bit - Fix timeout issue on ppc64le (bnc#869166) - Add powerpc-utils requires to grub2-powerpc-ieee1275 - added patches: * grub2-ppc64-build-ppc64-32bit.patch * grub2-ppc64-qemu.patch * grub2-ppc64le-01-Add-Little-Endian-support-for-Power64-to-the-build.patch * grub2-ppc64le-02-Build-grub-as-O1-until-we-add-savegpr-and-restgpr-ro.patch * grub2-ppc64le-03-disable-creation-of-vsx-and-altivec-instructions.patch * grub2-ppc64le-04-powerpc64-LE-s-linker-knows-how-to-handle-the-undefi.patch * grub2-ppc64le-05-grub-install-can-now-recognize-and-install-a-LE-grub.patch * grub2-ppc64le-06-set-the-ABI-version-to-0x02-in-the-e_flag-of-the-PPC.patch * grub2-ppc64le-07-Add-IEEE1275_ADDR-helper.patch * grub2-ppc64le-08-Fix-some-more-warnings-when-casting.patch * grub2-ppc64le-09-Add-powerpc64-types.patch * grub2-ppc64le-10-powerpc64-is-not-necessarily-BigEndian-anymore.patch * grub2-ppc64le-11-Fix-warnings-when-building-powerpc-linux-loader-64bi.patch * grub2-ppc64le-12-GRUB_ELF_R_PPC_-processing-is-applicable-only-for-32.patch * grub2-ppc64le-13-Fix-powerpc-setjmp-longjmp-64bit-issues.patch * grub2-ppc64le-14-Add-powerpc64-ieee1275-trampoline.patch * grub2-ppc64le-15-Add-64bit-support-to-powerpc-startup-code.patch * grub2-ppc64le-16-Add-grub_dl_find_section_addr.patch * grub2-ppc64le-17-Add-ppc64-relocations.patch * grub2-ppc64le-18-ppc64-doesn-t-need-libgcc-routines.patch * grub2-ppc64le-19-Use-FUNC_START-FUNC_END-for-powerpc-function-definit.patch * grub2-ppc64le-20-.TOC.-symbol-is-special-in-ppc64le-.-It-maps-to-the-.patch * grub2-ppc64le-21-the-.toc-section-in-powerpc64le-modules-are-sometime.patch * grub2-ppc64le-22-all-parameter-to-firmware-calls-should-to-be-BigEndi.patch * grub2-ppc64le-23-grub-segfaults-if-initrd-is-specified-before-specify.patch * grub2-ppc64le-timeout.patch (forwarded request 229655 from k0da) OBS-URL: https://build.opensuse.org/request/show/229673 OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/grub2?expand=0&rev=89
311 lines
8.4 KiB
Diff
311 lines
8.4 KiB
Diff
From 96d6b8d370e653386982b808f10a2a67849f73f1 Mon Sep 17 00:00:00 2001
|
|
From: Anton Blanchard <anton@samba.org>
|
|
Date: Wed, 29 Jan 2014 10:44:46 +1100
|
|
Subject: [PATCH 17/23] Add ppc64 relocations
|
|
|
|
Add ppc64 relocations
|
|
|
|
Signed-off-by: Ram Pai <linuxram@us.ibm.com>
|
|
From: Anton Blanchard <anton@samba.org>
|
|
---
|
|
grub-core/kern/powerpc/dl.c | 185 ++++++++++++++++++++++++++++++++++++++++----
|
|
include/grub/elf.h | 3 +
|
|
2 files changed, 174 insertions(+), 14 deletions(-)
|
|
|
|
diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c
|
|
index 7677e5a..cc496d3 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_PPC
|
|
+#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,86 @@ 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 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;
|
|
+}
|
|
+
|
|
+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 IMPLEMENTED 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
|
|
{
|
|
@@ -47,7 +133,7 @@ struct trampoline
|
|
grub_uint32_t bctr;
|
|
};
|
|
|
|
-static const struct trampoline trampoline_template =
|
|
+static const struct trampoline trampoline_template =
|
|
{
|
|
0x3d800000,
|
|
0x618c0000,
|
|
@@ -55,6 +141,8 @@ static const struct trampoline trampoline_template =
|
|
0x4e800420,
|
|
};
|
|
|
|
+#endif
|
|
+
|
|
#pragma GCC diagnostic ignored "-Wcast-align"
|
|
|
|
grub_err_t
|
|
@@ -74,14 +162,13 @@ grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
|
if (s->sh_type == SHT_RELA)
|
|
{
|
|
const Elf_Rela *rel, *max;
|
|
-
|
|
+
|
|
for (rel = (const Elf_Rela *) ((const char *) e + s->sh_offset),
|
|
max = rel + s->sh_size / s->sh_entsize;
|
|
rel < max;
|
|
rel++)
|
|
if (ELF_R_TYPE (rel->r_info) == GRUB_ELF_R_PPC_REL24)
|
|
(*tramp)++;
|
|
-
|
|
}
|
|
|
|
*tramp *= sizeof (struct trampoline);
|
|
@@ -89,12 +176,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 +194,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 +209,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;
|
|
@@ -137,7 +297,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr,
|
|
tptr->ori |= ((value) & 0xffff);
|
|
mod->trampptr = tptr + 1;
|
|
}
|
|
-
|
|
+
|
|
if (delta << 6 >> 6 != delta)
|
|
return grub_error (GRUB_ERR_BAD_MODULE,
|
|
"relocation overflow");
|
|
@@ -156,6 +316,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 +326,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.3.1
|