Support trampoline jumps on powerpc.
* grub-core/kern/dl.c (grub_dl_load_segments) [__powerpc__]: Follow __ia64__ path. (grub_dl_load_segments): Set mod->sz. (grub_dl_flush_cache): Flush whole space occupied by module, not just segments. * grub-core/kern/ia64/dl.c (nopm): Make const while on it. (jump): Likewise. * grub-core/kern/powerpc/dl.c (grub_arch_dl_get_tramp_got_size): New function. (trampoline): New struct. (trampoline_template): New const. (grub_arch_dl_relocate_symbols): Create trampolines on overflow. * include/grub/dl.h (grub_dl): Add sz element. [__powerpc__]: Follow __ia64__. (GRUB_ARCH_DL_TRAMP_ALIGN): Define on ppc. (GRUB_ARCH_DL_GOT_ALIGN): Likewise. (GRUB_ARCH_DL_TRAMP_SIZE): Likewise. (grub_arch_dl_get_tramp_got_size) [__powerpc__]: New proto.
This commit is contained in:
parent
3084ede4c7
commit
ed64e9e279
5 changed files with 120 additions and 18 deletions
23
ChangeLog
23
ChangeLog
|
@ -1,3 +1,26 @@
|
||||||
|
2011-11-08 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
|
Support trampoline jumps on powerpc.
|
||||||
|
|
||||||
|
* grub-core/kern/dl.c (grub_dl_load_segments) [__powerpc__]: Follow
|
||||||
|
__ia64__ path.
|
||||||
|
(grub_dl_load_segments): Set mod->sz.
|
||||||
|
(grub_dl_flush_cache): Flush whole space occupied by module, not just
|
||||||
|
segments.
|
||||||
|
* grub-core/kern/ia64/dl.c (nopm): Make const while on it.
|
||||||
|
(jump): Likewise.
|
||||||
|
* grub-core/kern/powerpc/dl.c (grub_arch_dl_get_tramp_got_size): New
|
||||||
|
function.
|
||||||
|
(trampoline): New struct.
|
||||||
|
(trampoline_template): New const.
|
||||||
|
(grub_arch_dl_relocate_symbols): Create trampolines on overflow.
|
||||||
|
* include/grub/dl.h (grub_dl): Add sz element.
|
||||||
|
[__powerpc__]: Follow __ia64__.
|
||||||
|
(GRUB_ARCH_DL_TRAMP_ALIGN): Define on ppc.
|
||||||
|
(GRUB_ARCH_DL_GOT_ALIGN): Likewise.
|
||||||
|
(GRUB_ARCH_DL_TRAMP_SIZE): Likewise.
|
||||||
|
(grub_arch_dl_get_tramp_got_size) [__powerpc__]: New proto.
|
||||||
|
|
||||||
2011-11-06 Vladimir Serbinenko <phcoder@gmail.com>
|
2011-11-06 Vladimir Serbinenko <phcoder@gmail.com>
|
||||||
|
|
||||||
ZFS crypto support.
|
ZFS crypto support.
|
||||||
|
|
|
@ -233,7 +233,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
||||||
unsigned i;
|
unsigned i;
|
||||||
Elf_Shdr *s;
|
Elf_Shdr *s;
|
||||||
grub_size_t tsize = 0, talign = 1;
|
grub_size_t tsize = 0, talign = 1;
|
||||||
#ifdef __ia64__
|
#if defined (__ia64__) || defined (__powerpc__)
|
||||||
grub_size_t tramp;
|
grub_size_t tramp;
|
||||||
grub_size_t got;
|
grub_size_t got;
|
||||||
#endif
|
#endif
|
||||||
|
@ -248,9 +248,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
||||||
talign = s->sh_addralign;
|
talign = s->sh_addralign;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __ia64__
|
#if defined (__ia64__) || defined (__powerpc__)
|
||||||
grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
|
grub_arch_dl_get_tramp_got_size (e, &tramp, &got);
|
||||||
tramp *= GRUB_IA64_DL_TRAMP_SIZE;
|
tramp *= GRUB_ARCH_DL_TRAMP_SIZE;
|
||||||
got *= sizeof (grub_uint64_t);
|
got *= sizeof (grub_uint64_t);
|
||||||
tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN);
|
tsize += ALIGN_UP (tramp, GRUB_ARCH_DL_TRAMP_ALIGN);
|
||||||
if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
|
if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
|
||||||
|
@ -269,6 +269,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
||||||
mod->base = grub_memalign (talign, tsize);
|
mod->base = grub_memalign (talign, tsize);
|
||||||
if (!mod->base)
|
if (!mod->base)
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
|
mod->sz = tsize;
|
||||||
ptr = mod->base;
|
ptr = mod->base;
|
||||||
|
|
||||||
#ifdef GRUB_MACHINE_EMU
|
#ifdef GRUB_MACHINE_EMU
|
||||||
|
@ -316,7 +317,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
||||||
mod->segment = seg;
|
mod->segment = seg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef __ia64__
|
#if defined (__ia64__) || defined (__powerpc__)
|
||||||
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
|
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
|
||||||
mod->tramp = ptr;
|
mod->tramp = ptr;
|
||||||
ptr += tramp;
|
ptr += tramp;
|
||||||
|
@ -575,15 +576,9 @@ grub_dl_unref (grub_dl_t mod)
|
||||||
static void
|
static void
|
||||||
grub_dl_flush_cache (grub_dl_t mod)
|
grub_dl_flush_cache (grub_dl_t mod)
|
||||||
{
|
{
|
||||||
grub_dl_segment_t seg;
|
|
||||||
|
|
||||||
for (seg = mod->segment; seg; seg = seg->next) {
|
|
||||||
if (seg->size) {
|
|
||||||
grub_dprintf ("modules", "flushing 0x%lx bytes at %p\n",
|
grub_dprintf ("modules", "flushing 0x%lx bytes at %p\n",
|
||||||
(unsigned long) seg->size, seg->addr);
|
(unsigned long) mod->sz, mod->base);
|
||||||
grub_arch_sync_caches (seg->addr, seg->size);
|
grub_arch_sync_caches (mod->base, mod->sz);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load a module from core memory. */
|
/* Load a module from core memory. */
|
||||||
|
|
|
@ -104,13 +104,13 @@ add_value_to_slot_21 (grub_addr_t addr, grub_uint32_t value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static grub_uint8_t nopm[5] =
|
static const grub_uint8_t nopm[5] =
|
||||||
{
|
{
|
||||||
/* [MLX] nop.m 0x0 */
|
/* [MLX] nop.m 0x0 */
|
||||||
0x05, 0x00, 0x00, 0x00, 0x01
|
0x05, 0x00, 0x00, 0x00, 0x01
|
||||||
};
|
};
|
||||||
|
|
||||||
static grub_uint8_t jump[0x20] =
|
static const grub_uint8_t jump[0x20] =
|
||||||
{
|
{
|
||||||
/* ld8 r16=[r15],8 */
|
/* ld8 r16=[r15],8 */
|
||||||
0x02, 0x80, 0x20, 0x1e, 0x18, 0x14,
|
0x02, 0x80, 0x20, 0x1e, 0x18, 0x14,
|
||||||
|
|
|
@ -37,6 +37,65 @@ grub_arch_dl_check_header (void *ehdr)
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
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;
|
||||||
|
Elf_Word entsize;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
*tramp = 0;
|
||||||
|
*got = 0;
|
||||||
|
|
||||||
|
/* Find a symbol table. */
|
||||||
|
for (i = 0, s = (const Elf_Shdr *) ((const char *) e + e->e_shoff);
|
||||||
|
i < e->e_shnum;
|
||||||
|
i++, s = (const Elf_Shdr *) ((const char *) s + e->e_shentsize))
|
||||||
|
if (s->sh_type == SHT_SYMTAB)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (i == e->e_shnum)
|
||||||
|
return;
|
||||||
|
|
||||||
|
entsize = s->sh_entsize;
|
||||||
|
|
||||||
|
for (i = 0, s = (const Elf_Shdr *) ((const char *) e + e->e_shoff);
|
||||||
|
i < e->e_shnum;
|
||||||
|
i++, s = (const Elf_Shdr *) ((const char *) s + e->e_shentsize))
|
||||||
|
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) == R_PPC_REL24)
|
||||||
|
(*tramp)++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For low-endian reverse lis and addr_high as well as ori and addr_low. */
|
||||||
|
struct trampoline
|
||||||
|
{
|
||||||
|
grub_uint32_t lis;
|
||||||
|
grub_uint32_t ori;
|
||||||
|
grub_uint32_t mtctr;
|
||||||
|
grub_uint32_t bctr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct trampoline trampoline_template =
|
||||||
|
{
|
||||||
|
0x3c000000,
|
||||||
|
0x60000000,
|
||||||
|
0x7c0903a6,
|
||||||
|
0x4e800420,
|
||||||
|
};
|
||||||
|
|
||||||
/* Relocate symbols. */
|
/* Relocate symbols. */
|
||||||
grub_err_t
|
grub_err_t
|
||||||
|
@ -46,6 +105,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
||||||
Elf_Shdr *s;
|
Elf_Shdr *s;
|
||||||
Elf_Word entsize;
|
Elf_Word entsize;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
struct trampoline *tptr = mod->tramp;
|
||||||
|
|
||||||
/* Find a symbol table. */
|
/* Find a symbol table. */
|
||||||
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
|
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
|
||||||
|
@ -106,7 +166,20 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
||||||
Elf_Sword delta = value - (Elf_Word) addr;
|
Elf_Sword delta = value - (Elf_Word) addr;
|
||||||
|
|
||||||
if (delta << 6 >> 6 != delta)
|
if (delta << 6 >> 6 != delta)
|
||||||
return grub_error (GRUB_ERR_BAD_MODULE, "relocation overflow");
|
{
|
||||||
|
COMPILE_TIME_ASSERT (sizeof (struct trampoline)
|
||||||
|
== GRUB_ARCH_DL_TRAMP_SIZE);
|
||||||
|
grub_memcpy (tptr, &trampoline_template,
|
||||||
|
sizeof (*tptr));
|
||||||
|
delta = (grub_uint8_t *) tptr - (grub_uint8_t *) addr;
|
||||||
|
tptr->lis |= (((value) >> 16) & 0xffff);
|
||||||
|
tptr->ori |= ((value) & 0xffff);
|
||||||
|
tptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delta << 6 >> 6 != delta)
|
||||||
|
return grub_error (GRUB_ERR_BAD_MODULE,
|
||||||
|
"relocation overflow");
|
||||||
*addr = (*addr & 0xfc000003) | (delta & 0x3fffffc);
|
*addr = (*addr & 0xfc000003) | (delta & 0x3fffffc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,11 +136,12 @@ struct grub_dl
|
||||||
Elf_Sym *symtab;
|
Elf_Sym *symtab;
|
||||||
void (*init) (struct grub_dl *mod);
|
void (*init) (struct grub_dl *mod);
|
||||||
void (*fini) (void);
|
void (*fini) (void);
|
||||||
#ifdef __ia64__
|
#if defined (__ia64__) || defined (__powerpc__)
|
||||||
void *got;
|
void *got;
|
||||||
void *tramp;
|
void *tramp;
|
||||||
#endif
|
#endif
|
||||||
void *base;
|
void *base;
|
||||||
|
grub_size_t sz;
|
||||||
struct grub_dl *next;
|
struct grub_dl *next;
|
||||||
};
|
};
|
||||||
typedef struct grub_dl *grub_dl_t;
|
typedef struct grub_dl *grub_dl_t;
|
||||||
|
@ -176,10 +177,20 @@ void
|
||||||
grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
||||||
grub_size_t *got);
|
grub_size_t *got);
|
||||||
|
|
||||||
#ifdef __ia64__
|
#if defined (__ia64__)
|
||||||
#define GRUB_ARCH_DL_TRAMP_ALIGN 16
|
#define GRUB_ARCH_DL_TRAMP_ALIGN 16
|
||||||
#define GRUB_ARCH_DL_GOT_ALIGN 16
|
#define GRUB_ARCH_DL_GOT_ALIGN 16
|
||||||
#define grub_arch_dl_get_tramp_got_size grub_ia64_dl_get_tramp_got_size
|
#define grub_arch_dl_get_tramp_got_size grub_ia64_dl_get_tramp_got_size
|
||||||
|
#else
|
||||||
|
void
|
||||||
|
grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
|
||||||
|
grub_size_t *got);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __powerpc__
|
||||||
|
#define GRUB_ARCH_DL_TRAMP_SIZE 16
|
||||||
|
#define GRUB_ARCH_DL_TRAMP_ALIGN 4
|
||||||
|
#define GRUB_ARCH_DL_GOT_ALIGN 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue