more or less functional ia64 grub-mkimage

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-05-08 12:39:08 +02:00
parent 7021cb3e16
commit 5452733f35
7 changed files with 358 additions and 98 deletions

View file

@ -98,6 +98,7 @@ library = {
common = grub-core/script/main.c; common = grub-core/script/main.c;
common = grub-core/script/script.c; common = grub-core/script/script.c;
common = grub-core/script/argv.c; common = grub-core/script/argv.c;
common = grub-core/kern/ia64/dl_helper.c;
}; };
program = { program = {

View file

@ -128,6 +128,7 @@ kernel = {
ia64_efi = kern/ia64/efi/startup.S; ia64_efi = kern/ia64/efi/startup.S;
ia64_efi = kern/ia64/efi/init.c; ia64_efi = kern/ia64/efi/init.c;
ia64_efi = kern/ia64/dl.c; ia64_efi = kern/ia64/dl.c;
ia64_efi = kern/ia64/dl_helper.c;
i386_pc = kern/i386/pc/init.c; i386_pc = kern/i386/pc/init.c;
i386_pc = kern/i386/pc/mmap.c; i386_pc = kern/i386/pc/mmap.c;

View file

@ -247,6 +247,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
#ifdef __ia64__ #ifdef __ia64__
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;
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)
talign = GRUB_ARCH_DL_TRAMP_ALIGN; talign = GRUB_ARCH_DL_TRAMP_ALIGN;

View file

@ -54,15 +54,18 @@ add_value_to_slot_20b (grub_addr_t addr, grub_uint32_t value)
{ {
case 0: case 0:
p = (struct unaligned_uint32 *) ((addr & ~3ULL) + 2); p = (struct unaligned_uint32 *) ((addr & ~3ULL) + 2);
p->val = (((((p->val >> 2) & MASK20) + value) & MASK20) << 2) | (p->val & ~(MASK20 << 2)); p->val = ((((((p->val >> 2) & MASK20) + value) & MASK20) << 2)
| (p->val & ~(MASK20 << 2)));
break; break;
case 1: case 1:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 7); p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 7);
p->val = (((((p->val >> 3) & MASK20) + value) & MASK20) << 3) | (p->val & ~(MASK20 << 3)); p->val = ((((((p->val >> 3) & MASK20) + value) & MASK20) << 3)
| (p->val & ~(MASK20 << 3)));
break; break;
case 2: case 2:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 12); p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 12);
p->val = (((((p->val >> 4) & MASK20) + value) & MASK20) << 4) | (p->val & ~(MASK20 << 4)); p->val = ((((((p->val >> 4) & MASK20) + value) & MASK20) << 4)
| (p->val & ~(MASK20 << 4)));
break; break;
} }
} }
@ -137,6 +140,8 @@ struct ia64_trampoline
static void static void
make_trampoline (struct ia64_trampoline *tr, grub_uint64_t addr) make_trampoline (struct ia64_trampoline *tr, grub_uint64_t addr)
{ {
COMPILE_TIME_ASSERT (sizeof (struct ia64_trampoline)
== GRUB_IA64_DL_TRAMP_SIZE);
grub_memcpy (tr->nop, nopm, sizeof (tr->nop)); grub_memcpy (tr->nop, nopm, sizeof (tr->nop));
tr->addr_hi[0] = ((addr & 0xc00000) >> 16); tr->addr_hi[0] = ((addr & 0xc00000) >> 16);
tr->addr_hi[1] = (addr >> 24) & 0xff; tr->addr_hi[1] = (addr >> 24) & 0xff;
@ -146,60 +151,13 @@ make_trampoline (struct ia64_trampoline *tr, grub_uint64_t addr)
tr->addr_hi[5] = (addr >> 56) & 0xff; tr->addr_hi[5] = (addr >> 56) & 0xff;
tr->e0 = 0xe0; tr->e0 = 0xe0;
tr->addr_lo[0] = ((addr & 0x000f) << 4) | 0x01; tr->addr_lo[0] = ((addr & 0x000f) << 4) | 0x01;
tr->addr_lo[1] = ((addr & 0x0070) >> 4) | ((addr & 0x070000) >> 11) | ((addr & 0x200000) >> 17); tr->addr_lo[1] = (((addr & 0x0070) >> 4) | ((addr & 0x070000) >> 11)
| ((addr & 0x200000) >> 17));
tr->addr_lo[2] = ((addr & 0x1f80) >> 5) | ((addr & 0x180000) >> 19); tr->addr_lo[2] = ((addr & 0x1f80) >> 5) | ((addr & 0x180000) >> 19);
tr->addr_lo[3] = ((addr & 0xe000) >> 13) | 0x60; tr->addr_lo[3] = ((addr & 0xe000) >> 13) | 0x60;
grub_memcpy (tr->jump, jump, sizeof (tr->jump)); grub_memcpy (tr->jump, jump, sizeof (tr->jump));
} }
void
grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, grub_size_t *got)
{
const Elf_Ehdr *e = ehdr;
grub_size_t cntt = 0, cntg = 0;;
const Elf_Shdr *s;
Elf_Word entsize;
unsigned i;
/* Find a symbol table. */
for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *) ((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 = (Elf_Shdr *) ((char *) e + e->e_shoff);
i < e->e_shnum;
i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
if (s->sh_type == SHT_RELA)
{
Elf_Rela *rel, *max;
for (rel = (Elf_Rela *) ((char *) e + s->sh_offset),
max = rel + s->sh_size / s->sh_entsize;
rel < max; rel++)
switch (ELF_R_TYPE (rel->r_info))
{
case R_IA64_PCREL21B:
cntt++;
break;
case R_IA64_LTOFF_FPTR22:
case R_IA64_LTOFF22X:
case R_IA64_LTOFF22:
cntg++;
break;
}
}
*tramp = cntt * sizeof (struct ia64_trampoline);
*got = cntg * sizeof (grub_uint64_t);
}
/* Relocate symbols. */ /* Relocate symbols. */
grub_err_t grub_err_t
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
@ -279,7 +237,7 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
} }
break; break;
case R_IA64_SEGREL64LSB: case R_IA64_SEGREL64LSB:
*(grub_uint64_t *) addr += value - rel->r_offset; *(grub_uint64_t *) addr += value - (grub_addr_t) seg->addr;
break; break;
case R_IA64_FPTR64LSB: case R_IA64_FPTR64LSB:
case R_IA64_DIR64LSB: case R_IA64_DIR64LSB:
@ -296,8 +254,6 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
case R_IA64_LTOFF22X: case R_IA64_LTOFF22X:
case R_IA64_LTOFF22: case R_IA64_LTOFF22:
*gpptr = value; *gpptr = value;
if ((addr & 0xffff) == 0x4301)
grub_dprintf ("modules", "off = %lx\n", (grub_addr_t) gpptr - (grub_addr_t) gp);
add_value_to_slot_21 (addr, (grub_addr_t) gpptr - (grub_addr_t) gp); add_value_to_slot_21 (addr, (grub_addr_t) gpptr - (grub_addr_t) gp);
gpptr++; gpptr++;
break; break;

View file

@ -126,12 +126,18 @@ grub_err_t grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr);
void grub_arch_dl_init_linker (void); void grub_arch_dl_init_linker (void);
#endif #endif
#ifdef __ia64__ #define GRUB_IA64_DL_TRAMP_ALIGN 16
void grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, grub_size_t *got); #define GRUB_IA64_DL_TRAMP_SIZE 48
#define GRUB_IA64_DL_GOT_ALIGN 16
void
grub_ia64_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp,
grub_size_t *got);
#ifdef __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
#else #else
#endif #endif

View file

@ -29,6 +29,7 @@
#include <grub/util/resolve.h> #include <grub/util/resolve.h>
#include <grub/misc.h> #include <grub/misc.h>
#include <grub/offsets.h> #include <grub/offsets.h>
#include <grub/dl.h>
#include <time.h> #include <time.h>
#include <stdio.h> #include <stdio.h>
@ -89,6 +90,13 @@ struct image_target_desc
grub_uint16_t pe_target; grub_uint16_t pe_target;
}; };
#define EFI64_HEADER_SIZE ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE \
+ GRUB_PE32_SIGNATURE_SIZE \
+ sizeof (struct grub_pe32_coff_header) \
+ sizeof (struct grub_pe64_optional_header) \
+ 4 * sizeof (struct grub_pe32_section_table), \
GRUB_PE32_SECTION_ALIGNMENT)
struct image_target_desc image_targets[] = struct image_target_desc image_targets[] =
{ {
{ {
@ -248,12 +256,7 @@ struct image_target_desc image_targets[] =
.kernel_image_size = TARGET_NO_FIELD, .kernel_image_size = TARGET_NO_FIELD,
.compressed_size = TARGET_NO_FIELD, .compressed_size = TARGET_NO_FIELD,
.section_align = GRUB_PE32_SECTION_ALIGNMENT, .section_align = GRUB_PE32_SECTION_ALIGNMENT,
.vaddr_offset = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE .vaddr_offset = EFI64_HEADER_SIZE,
+ GRUB_PE32_SIGNATURE_SIZE
+ sizeof (struct grub_pe32_coff_header)
+ sizeof (struct grub_pe64_optional_header)
+ 4 * sizeof (struct grub_pe32_section_table),
GRUB_PE32_SECTION_ALIGNMENT),
.install_dos_part = TARGET_NO_FIELD, .install_dos_part = TARGET_NO_FIELD,
.install_bsd_part = TARGET_NO_FIELD, .install_bsd_part = TARGET_NO_FIELD,
.pe_target = GRUB_PE32_MACHINE_X86_64, .pe_target = GRUB_PE32_MACHINE_X86_64,
@ -372,12 +375,7 @@ struct image_target_desc image_targets[] =
.kernel_image_size = TARGET_NO_FIELD, .kernel_image_size = TARGET_NO_FIELD,
.compressed_size = TARGET_NO_FIELD, .compressed_size = TARGET_NO_FIELD,
.section_align = GRUB_PE32_SECTION_ALIGNMENT, .section_align = GRUB_PE32_SECTION_ALIGNMENT,
.vaddr_offset = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE .vaddr_offset = EFI64_HEADER_SIZE,
+ GRUB_PE32_SIGNATURE_SIZE
+ sizeof (struct grub_pe32_coff_header)
+ sizeof (struct grub_pe64_optional_header)
+ 4 * sizeof (struct grub_pe32_section_table),
GRUB_PE32_SECTION_ALIGNMENT),
.install_dos_part = TARGET_NO_FIELD, .install_dos_part = TARGET_NO_FIELD,
.install_bsd_part = TARGET_NO_FIELD, .install_bsd_part = TARGET_NO_FIELD,
.pe_target = GRUB_PE32_MACHINE_IA64, .pe_target = GRUB_PE32_MACHINE_IA64,
@ -930,12 +928,7 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[],
+ 4 * sizeof (struct grub_pe32_section_table), + 4 * sizeof (struct grub_pe32_section_table),
GRUB_PE32_SECTION_ALIGNMENT); GRUB_PE32_SECTION_ALIGNMENT);
else else
header_size = ALIGN_UP (GRUB_PE32_MSDOS_STUB_SIZE header_size = EFI64_HEADER_SIZE;
+ GRUB_PE32_SIGNATURE_SIZE
+ sizeof (struct grub_pe32_coff_header)
+ sizeof (struct grub_pe64_optional_header)
+ 4 * sizeof (struct grub_pe32_section_table),
GRUB_PE32_SECTION_ALIGNMENT);
reloc_addr = ALIGN_UP (header_size + core_size, reloc_addr = ALIGN_UP (header_size + core_size,
image_target->section_align); image_target->section_align);

View file

@ -56,6 +56,7 @@ static Elf_Addr
SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections, SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections,
Elf_Shdr *symtab_section, Elf_Addr *section_addresses, Elf_Shdr *symtab_section, Elf_Addr *section_addresses,
Elf_Half section_entsize, Elf_Half num_sections, Elf_Half section_entsize, Elf_Half num_sections,
void *jumpers, Elf_Addr jumpers_addr,
struct image_target_desc *image_target) struct image_target_desc *image_target)
{ {
Elf_Word symtab_size, sym_size, num_syms; Elf_Word symtab_size, sym_size, num_syms;
@ -65,6 +66,7 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections,
Elf_Word i; Elf_Word i;
Elf_Shdr *strtab_section; Elf_Shdr *strtab_section;
const char *strtab; const char *strtab;
grub_uint64_t *jptr = jumpers;
strtab_section strtab_section
= (Elf_Shdr *) ((char *) sections = (Elf_Shdr *) ((char *) sections
@ -103,6 +105,16 @@ SUFFIX (relocate_symbols) (Elf_Ehdr *e, Elf_Shdr *sections,
sym->st_value = (grub_target_to_host (sym->st_value) sym->st_value = (grub_target_to_host (sym->st_value)
+ section_addresses[index]); + section_addresses[index]);
if (image_target->elf_target == EM_IA_64 && ELF_ST_TYPE (sym->st_info)
== STT_FUNC)
{
*jptr = sym->st_value;
sym->st_value = (char *) jptr - (char *) jumpers + jumpers_addr;
jptr++;
*jptr = 0;
jptr++;
}
grub_util_info ("locating %s at 0x%x", name, sym->st_value, section_addresses[index]); grub_util_info ("locating %s at 0x%x", name, sym->st_value, section_addresses[index]);
if (! start_address) if (! start_address)
@ -134,6 +146,152 @@ SUFFIX (get_target_address) (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset,
return (Elf_Addr *) ((char *) e + grub_target_to_host32 (s->sh_offset) + offset); return (Elf_Addr *) ((char *) e + grub_target_to_host32 (s->sh_offset) + offset);
} }
static Elf_Addr
SUFFIX (count_funcs) (Elf_Ehdr *e, Elf_Shdr *symtab_section,
struct image_target_desc *image_target)
{
Elf_Word symtab_size, sym_size, num_syms;
Elf_Off symtab_offset;
Elf_Addr start_address = 0;
Elf_Sym *sym;
Elf_Word i;
int ret = 0;
symtab_size = grub_target_to_host (symtab_section->sh_size);
sym_size = grub_target_to_host (symtab_section->sh_entsize);
symtab_offset = grub_target_to_host (symtab_section->sh_offset);
num_syms = symtab_size / sym_size;
for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset);
i < num_syms;
i++, sym = (Elf_Sym *) ((char *) sym + sym_size))
if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
ret++;
return ret;
}
#ifdef MKIMAGE_ELF64
struct unaligned_uint32
{
grub_uint32_t val;
} __attribute__ ((packed));
#define MASK20 ((1 << 20) - 1)
#define MASK19 ((1 << 19) - 1)
static void
add_value_to_slot_20b (grub_addr_t addr, grub_uint32_t value)
{
struct unaligned_uint32 *p;
switch (addr & 3)
{
case 0:
p = (struct unaligned_uint32 *) ((addr & ~3ULL) + 2);
p->val = ((((((p->val >> 2) & MASK20) + value) & MASK20) << 2)
| (p->val & ~(MASK20 << 2)));
break;
case 1:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 7);
p->val = ((((((p->val >> 3) & MASK20) + value) & MASK20) << 3)
| (p->val & ~(MASK20 << 3)));
break;
case 2:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 12);
p->val = ((((((p->val >> 4) & MASK20) + value) & MASK20) << 4)
| (p->val & ~(MASK20 << 4)));
break;
}
}
#define MASKF21 ( ((1 << 23) - 1) & ~((1 << 7) | (1 << 8)) )
static grub_uint32_t
add_value_to_slot_21_real (grub_uint32_t a, grub_uint32_t value)
{
grub_uint32_t high, mid, low, c;
low = (a & 0x00007f);
mid = (a & 0x7fc000) >> 7;
high = (a & 0x003e00) << 7;
c = (low | mid | high) + value;
return (c & 0x7f) | ((c << 7) & 0x7fc000) | ((c >> 7) & 0x0003e00); //0x003e00
}
static void
add_value_to_slot_21 (grub_addr_t addr, grub_uint32_t value)
{
struct unaligned_uint32 *p;
switch (addr & 3)
{
case 0:
p = (struct unaligned_uint32 *) ((addr & ~3ULL) + 2);
p->val = ((add_value_to_slot_21_real (((p->val >> 2) & MASKF21), value) & MASKF21) << 2) | (p->val & ~(MASKF21 << 2));
break;
case 1:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 7);
p->val = ((add_value_to_slot_21_real (((p->val >> 3) & MASKF21), value) & MASKF21) << 3) | (p->val & ~(MASKF21 << 3));
break;
case 2:
p = (struct unaligned_uint32 *) ((grub_uint8_t *) (addr & ~3ULL) + 12);
p->val = ((add_value_to_slot_21_real (((p->val >> 4) & MASKF21), value) & MASKF21) << 4) | (p->val & ~(MASKF21 << 4));
break;
}
}
struct ia64_kernel_trampoline
{
/* nop.m */
grub_uint8_t nop[5];
/* movl r15 = addr*/
grub_uint8_t addr_hi[6];
grub_uint8_t e0;
grub_uint8_t addr_lo[4];
grub_uint8_t jump[0x20];
};
static grub_uint8_t nopm[5] =
{
/* [MLX] nop.m 0x0 */
0x05, 0x00, 0x00, 0x00, 0x01
};
static grub_uint8_t jump[0x20] =
{
/* [MMI] add r15=r15,r1;; */
0x0b, 0x78, 0x3c, 0x02, 0x00, 0x20,
/* ld8 r16=[r15],8 */
0x00, 0x41, 0x3c, 0x30, 0x28, 0xc0,
/* mov r14=r1;; */
0x01, 0x08, 0x00, 0x84,
/* [MIB] ld8 r1=[r15] */
0x11, 0x08, 0x00, 0x1e, 0x18, 0x10,
/* mov b6=r16 */
0x60, 0x80, 0x04, 0x80, 0x03, 0x00,
/* br.few b6;; */
0x60, 0x00, 0x80, 0x00
};
static void
make_trampoline (struct ia64_kernel_trampoline *tr, grub_uint64_t addr)
{
grub_memcpy (tr->nop, nopm, sizeof (tr->nop));
tr->addr_hi[0] = ((addr & 0xc00000) >> 16);
tr->addr_hi[1] = (addr >> 24) & 0xff;
tr->addr_hi[2] = (addr >> 32) & 0xff;
tr->addr_hi[3] = (addr >> 40) & 0xff;
tr->addr_hi[4] = (addr >> 48) & 0xff;
tr->addr_hi[5] = (addr >> 56) & 0xff;
tr->e0 = 0xe0;
tr->addr_lo[0] = ((addr & 0x000f) << 4) | 0x01;
tr->addr_lo[1] = (((addr & 0x0070) >> 4) | ((addr & 0x070000) >> 11)
| ((addr & 0x200000) >> 17));
tr->addr_lo[2] = ((addr & 0x1f80) >> 5) | ((addr & 0x180000) >> 19);
tr->addr_lo[3] = ((addr & 0xe000) >> 13) | 0x60;
grub_memcpy (tr->jump, jump, sizeof (tr->jump));
}
#endif
/* Deal with relocation information. This function relocates addresses /* Deal with relocation information. This function relocates addresses
within the virtual address space starting from 0. So only relative within the virtual address space starting from 0. So only relative
addresses can be fully resolved. Absolute addresses must be relocated addresses can be fully resolved. Absolute addresses must be relocated
@ -142,10 +300,15 @@ static void
SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections, SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
Elf_Addr *section_addresses, Elf_Addr *section_addresses,
Elf_Half section_entsize, Elf_Half num_sections, Elf_Half section_entsize, Elf_Half num_sections,
const char *strtab, struct image_target_desc *image_target) const char *strtab,
char *pe_target, Elf_Addr tramp_off,
Elf_Addr got_off,
struct image_target_desc *image_target)
{ {
Elf_Half i; Elf_Half i;
Elf_Shdr *s; Elf_Shdr *s;
struct ia64_kernel_trampoline *tr = (void *) (pe_target + tramp_off);
grub_uint64_t *gpptr = (void *) (pe_target + got_off);
for (i = 0, s = sections; for (i = 0, s = sections;
i < num_sections; i < num_sections;
@ -274,15 +437,69 @@ SUFFIX (relocate_addresses) (Elf_Ehdr *e, Elf_Shdr *sections,
break; break;
} }
break; break;
#ifdef MKIMAGE_ELF64
case EM_IA_64: case EM_IA_64:
switch (ELF_R_TYPE (info)) switch (ELF_R_TYPE (info))
{ {
case R_IA64_PCREL21B:
{
grub_uint64_t noff;
make_trampoline (tr, addend + sym_addr);
noff = ((char *) tr - (char *) pe_target
- target_section_addr - (offset & ~3)
- image_target->vaddr_offset) >> 4;
tr++;
if (noff & ~MASK19)
grub_util_error ("trampoline offset too big (%lx)",
noff);
add_value_to_slot_20b ((grub_addr_t) target, noff);
}
break;
case R_IA64_LTOFF_FPTR22:
case R_IA64_LTOFF22X:
case R_IA64_LTOFF22:
*gpptr = grub_host_to_target64 (addend + sym_addr);
add_value_to_slot_21 ((grub_addr_t) target,
(char *) gpptr - (char *) pe_target);
gpptr++;
break;
case R_IA64_GPREL22:
add_value_to_slot_21 ((grub_addr_t) target,
addend + sym_addr);
break;
case R_IA64_PCREL64LSB:
*target = grub_host_to_target64 (grub_target_to_host64 (*target)
+ addend + sym_addr
- target_section_addr - offset
- image_target->vaddr_offset);
break;
case R_IA64_SEGREL64LSB:
*target = grub_host_to_target64 (grub_target_to_host64 (*target)
+ addend + sym_addr - target_section_addr);
break;
case R_IA64_DIR64LSB:
case R_IA64_FPTR64LSB:
*target = grub_host_to_target64 (grub_target_to_host64 (*target)
+ addend + sym_addr);
grub_util_info ("relocating a direct entry to 0x%"
PRIxGRUB_UINT64_T " at the offset 0x%x",
*target, offset);
break;
/* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV. */
case R_IA64_LDXMOV:
break;
default: default:
grub_util_error ("unknown relocation type 0x%x", grub_util_error ("unknown relocation type 0x%x",
ELF_R_TYPE (info)); ELF_R_TYPE (info));
break; break;
} }
break; break;
#endif
default: default:
grub_util_error ("unknown architecture type %d", grub_util_error ("unknown architecture type %d",
image_target->elf_target); image_target->elf_target);
@ -329,7 +546,7 @@ SUFFIX (add_fixup_entry) (struct fixup_block_list **cblock, grub_uint16_t type,
b->block_size += 2; b->block_size += 2;
} }
} }
else if (b->block_size & (8 - 1)) else while (b->block_size & (8 - 1))
{ {
/* If not aligned with a 32-bit boundary, add /* If not aligned with a 32-bit boundary, add
a padding entry. */ a padding entry. */
@ -391,9 +608,11 @@ static Elf_Addr
SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out, SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
Elf_Addr *section_addresses, Elf_Shdr *sections, Elf_Addr *section_addresses, Elf_Shdr *sections,
Elf_Half section_entsize, Elf_Half num_sections, Elf_Half section_entsize, Elf_Half num_sections,
const char *strtab, struct image_target_desc *image_target) const char *strtab,
Elf_Addr jumpers, grub_size_t njumpers,
struct image_target_desc *image_target)
{ {
Elf_Half i; unsigned i;
Elf_Shdr *s; Elf_Shdr *s;
struct fixup_block_list *lst, *lst0; struct fixup_block_list *lst, *lst0;
Elf_Addr current_address = 0; Elf_Addr current_address = 0;
@ -401,8 +620,7 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
lst = lst0 = xmalloc (sizeof (*lst) + 2 * 0x1000); lst = lst0 = xmalloc (sizeof (*lst) + 2 * 0x1000);
memset (lst, 0, sizeof (*lst) + 2 * 0x1000); memset (lst, 0, sizeof (*lst) + 2 * 0x1000);
for (i = 0, s = sections; for (i = 0, s = sections; i < num_sections;
i < num_sections;
i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
if ((s->sh_type == grub_cpu_to_le32 (SHT_REL)) || if ((s->sh_type == grub_cpu_to_le32 (SHT_REL)) ||
(s->sh_type == grub_cpu_to_le32 (SHT_RELA))) (s->sh_type == grub_cpu_to_le32 (SHT_RELA)))
@ -470,12 +688,56 @@ SUFFIX (make_reloc_section) (Elf_Ehdr *e, void **out,
image_target); image_target);
} }
break; break;
case EM_IA_64:
switch (ELF_R_TYPE (info))
{
case R_IA64_PCREL64LSB:
case R_IA64_LDXMOV:
case R_IA64_PCREL21B:
case R_IA64_LTOFF_FPTR22:
case R_IA64_LTOFF22X:
case R_IA64_LTOFF22:
case R_IA64_GPREL22:
case R_IA64_SEGREL64LSB:
break;
case R_IA64_FPTR64LSB:
case R_IA64_DIR64LSB:
#if 1
{
Elf_Addr addr;
addr = section_address + offset;
grub_util_info ("adding a relocation entry for 0x%llx", addr);
current_address
= SUFFIX (add_fixup_entry) (&lst,
GRUB_PE32_REL_BASED_DIR64,
addr,
0, current_address,
image_target);
}
#endif
break;
default:
grub_util_error ("unknown relocation type 0x%x",
ELF_R_TYPE (info));
break;
}
break;
default: default:
grub_util_error ("unknown machine type 0x%x", image_target->elf_target); grub_util_error ("unknown machine type 0x%x", image_target->elf_target);
} }
} }
} }
if (image_target->elf_target == EM_IA_64)
for (i = 0; i < njumpers; i++)
current_address = SUFFIX (add_fixup_entry) (&lst,
GRUB_PE32_REL_BASED_DIR64,
jumpers + 8 * i,
0, current_address,
image_target);
current_address = SUFFIX (add_fixup_entry) (&lst, 0, 0, 1, current_address, image_target); current_address = SUFFIX (add_fixup_entry) (&lst, 0, 0, 1, current_address, image_target);
{ {
@ -637,7 +899,10 @@ SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size,
Elf_Off section_offset; Elf_Off section_offset;
Elf_Half section_entsize; Elf_Half section_entsize;
grub_size_t kernel_size; grub_size_t kernel_size;
grub_size_t ia64jmp_off = 0, ia64_toff = 0, ia64_got_off = 0;
unsigned ia64jmpnum = 0;
Elf_Shdr *symtab_section; Elf_Shdr *symtab_section;
grub_size_t got = 0;
*start = 0; *start = 0;
@ -716,23 +981,31 @@ SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size,
break; break;
} }
#ifdef MKIMAGE_ELF64
if (image_target->elf_target == EM_IA_64)
{
grub_size_t tramp;
*kernel_sz = ALIGN_UP (*kernel_sz, 16);
grub_ia64_dl_get_tramp_got_size (e, &tramp, &got);
tramp *= sizeof (struct ia64_kernel_trampoline);
ia64_toff = *kernel_sz;
*kernel_sz += ALIGN_UP (tramp, 16);
ia64jmp_off = *kernel_sz;
ia64jmpnum = SUFFIX (count_funcs) (e, symtab_section,
image_target);
*kernel_sz += 16 * ia64jmpnum;
ia64_got_off = *kernel_sz;
*kernel_sz += ALIGN_UP (got * sizeof (grub_uint64_t), 16);
}
#endif
if (! symtab_section) if (! symtab_section)
grub_util_error ("no symbol table"); grub_util_error ("no symbol table");
*start = SUFFIX (relocate_symbols) (e, sections, symtab_section,
section_vaddresses, section_entsize,
num_sections, image_target);
if (*start == 0)
grub_util_error ("start symbol is not defined");
/* Resolve addresses in the virtual address space. */
SUFFIX (relocate_addresses) (e, sections, section_addresses, section_entsize,
num_sections, strtab, image_target);
*reloc_size = SUFFIX (make_reloc_section) (e, reloc_section,
section_vaddresses, sections,
section_entsize, num_sections,
strtab, image_target);
} }
else else
{ {
@ -742,6 +1015,34 @@ SUFFIX (load_image) (const char *kernel_path, grub_size_t *exec_size,
out_img = xmalloc (*kernel_sz + total_module_size); out_img = xmalloc (*kernel_sz + total_module_size);
if (image_target->id == IMAGE_EFI)
{
*start = SUFFIX (relocate_symbols) (e, sections, symtab_section,
section_vaddresses, section_entsize,
num_sections,
(char *) out_img + ia64jmp_off,
ia64jmp_off
+ image_target->vaddr_offset,
image_target);
if (*start == 0)
grub_util_error ("start symbol is not defined");
/* Resolve addresses in the virtual address space. */
SUFFIX (relocate_addresses) (e, sections, section_addresses,
section_entsize,
num_sections, strtab,
out_img, ia64_toff, ia64_got_off,
image_target);
*reloc_size = SUFFIX (make_reloc_section) (e, reloc_section,
section_vaddresses, sections,
section_entsize, num_sections,
strtab, ia64jmp_off
+ image_target->vaddr_offset,
2 * ia64jmpnum + got,
image_target);
}
for (i = 0, s = sections; for (i = 0, s = sections;
i < num_sections; i < num_sections;
i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) i++, s = (Elf_Shdr *) ((char *) s + section_entsize))