IA64 support.
* Makefile.util.def (libgrubmods.a): Add grub-core/kern/ia64/dl_helper.c * configure.ac: Add ia64-efi target. Probe for __ia64_trampoline, __udivsi3, __umoddi3, __udivdi3, __divsi3, __modsi3, __umodsi3, __moddi3 and __divdi3 symbols. * gentpl.py: Add ia64_efi platform. Rename x86_efi to efi and Add ia64-efi. All users updated. * grub-core/Makefile.am: Set KERNEL_HEADER_FILES for ia64-efi. * grub-core/Makefile.core.def (kernel.img): Add compile flags for ia64. Remove kern/generic/rtc_get_time_ms.c on EFI. Add kern/ia64/efi/startup.S, kern/ia64/efi/init.c, kern/ia64/dl.c, kern/ia64/dl_helper.c on ia64-efi. Add kern/emu/cache.c on emu. (linux): Use on loader/ia64/efi/linux.c on ia64. * grub-core/gensymlist.sh (grub_register_exported_symbols): Check whether symbol is a function. * grub-core/kern/dl.c [GRUB_MACHINE_EMU]: Include sys/mman.h. (grub_symbol): New field 'isfunc'. (grub_dl_resolve_symbol): Return whole symbol rather than just address. (grub_dl_register_symbol): New argument 'isfunc'. All users updated. (grub_dl_load_segments): Place all sections into the same region. [__ia64__]: Create trampolines and got. [GRUB_MACHINE_EMU]: Call mprotect. (grub_dl_resolve_symbols): Resolve symbol type as well. [__ia64__]: Create function descriptors. * grub-core/kern/efi/efi.c (grub_get_rtc): Renamed to ... (grub_rtc_get_time_ms): ... this. Expressions simplified. (grub_get_rtc): New function. * grub-core/kern/emu/cache.c [__ia64__]: New file. * grub-core/kern/emu/cache.S: Renamed to ... * grub-core/kern/emu/cache_s.S: ... this. [__ia64__]: Add a nop. * grub-core/kern/emu/full.c (grub_arch_dl_get_tramp_got_size) [__ia64__]: New function. * grub-core/kern/emu/lite.c [__ia64__]: Include ../ia64/dl.c. * grub-core/kern/ia64/dl.c: New file. * grub-core/kern/ia64/dl_helper.c: Likewise. * grub-core/kern/ia64/efi/init.c: New file. * grub-core/kern/ia64/efi/startup.S: Likewise. * grub-core/lib/efi/halt.c [__ia64__]: Don't try acpi. * grub-core/lib/ia64/longjmp.S: New file (from glibc). * grub-core/lib/ia64/setjmp.S: Likewise (from glibc). * grub-core/lib/setjmp.S [__ia64__]: Include ./ia64/setjmp.S. * grub-core/loader/ia64/efi/linux.c: New file. * include/grub/dl.h (GRUB_MOD_NAME): Redefined using C rather than asm. (GRUB_MOD_DEP): Likewise. (grub_dl) [__ia64__]: New fields got and tramp. (grub_dl): New field 'base'. (grub_dl_register_symbol): New argument isfunc. All users updated. (GRUB_IA64_DL_TRAMP_ALIGN): New definition. (GRUB_IA64_DL_TRAMP_SIZE): Likewise. (GRUB_IA64_DL_GOT_ALIGN): Likewise. (grub_ia64_dl_get_tramp_got_size): New proto. (GRUB_ARCH_DL_TRAMP_ALIGN) [__ia64__]: Likewise (GRUB_ARCH_DL_GOT_ALIGN) [__ia64__]: Likewise (grub_arch_dl_get_tramp_got_size) [__ia64__]: Likewise * include/grub/efi/api.h: Skip call wrappers on ia64. * include/grub/efi/pe32.h (GRUB_PE32_MACHINE_IA64): New definition. * include/grub/efi/time.h (GRUB_TICKS_PER_SECOND): Change to 1000. * include/grub/elf.h (ELF_ST_INFO): New definition. * include/grub/ia64/efi/kernel.h: New file. * include/grub/ia64/efi/memory.h: Likewise. * include/grub/ia64/efi/time.h: Likewise. * include/grub/ia64/kernel.h: Likewise. * include/grub/ia64/setjmp.h: Likewise (from glibc). * include/grub/ia64/time.h: New file. * include/grub/ia64/types.h: Likewise. * include/grub/libgcc.h (__udivsi3, __umodsi3, __umoddi3, __udivdi3, __moddi3, __divdi3, __divsi3, __modsi3, __ia64_trampoline): New protos. * include/grub/offsets.h (GRUB_KERNEL_IA64_EFI_PREFIX): New definition. (GRUB_KERNEL_IA64_EFI_PREFIX_END): Likewise. * include/grub/types.h (PRIxGRUB_ADDR): Likewise. * util/grub-mkimage.c (image_target_desc): New field pe_target. All users updated. (EFI64_HEADER_SIZE): New definition. All users updated. (image_targets): Add ia64-efi. * util/grub-mkimagexx.c (relocate_symbols): New arguments jumpers and jumpers_addr. All users updated. Create function descriptors. (count_funcs): New function. (unaligned_uint32): New struct. (MASK20): New definition. (MASK19): Likewise. (MASKF21): Likewise. (add_value_to_slot_20b): New function. (add_value_to_slot_21_real): Likewise. (add_value_to_slot_21): Likewise. (ia64_kernel_trampoline): New struct. (nopm): New variable. (jump): Likewise. (make_trampoline): New function. (relocate_addresses): Handle ia64. (make_reloc_section): Likewise. (load_image): Likewise. Also-By: Robert Millan <rmh.grub@aybabtu.com> Also-By: Vladimir Serbinenko <phcoder@gmail.com>
This commit is contained in:
commit
32297d5ff7
39 changed files with 2526 additions and 124 deletions
|
@ -37,6 +37,10 @@
|
|||
#define GRUB_MODULES_MACHINE_READONLY
|
||||
#endif
|
||||
|
||||
#ifdef GRUB_MACHINE_EMU
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
grub_dl_t grub_dl_head = 0;
|
||||
|
@ -86,6 +90,7 @@ struct grub_symbol
|
|||
struct grub_symbol *next;
|
||||
const char *name;
|
||||
void *addr;
|
||||
int isfunc;
|
||||
grub_dl_t mod; /* The module to which this symbol belongs. */
|
||||
};
|
||||
typedef struct grub_symbol *grub_symbol_t;
|
||||
|
@ -110,21 +115,22 @@ grub_symbol_hash (const char *s)
|
|||
|
||||
/* Resolve the symbol name NAME and return the address.
|
||||
Return NULL, if not found. */
|
||||
static void *
|
||||
static grub_symbol_t
|
||||
grub_dl_resolve_symbol (const char *name)
|
||||
{
|
||||
grub_symbol_t sym;
|
||||
|
||||
for (sym = grub_symtab[grub_symbol_hash (name)]; sym; sym = sym->next)
|
||||
if (grub_strcmp (sym->name, name) == 0)
|
||||
return sym->addr;
|
||||
return sym;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Register a symbol with the name NAME and the address ADDR. */
|
||||
grub_err_t
|
||||
grub_dl_register_symbol (const char *name, void *addr, grub_dl_t mod)
|
||||
grub_dl_register_symbol (const char *name, void *addr, int isfunc,
|
||||
grub_dl_t mod)
|
||||
{
|
||||
grub_symbol_t sym;
|
||||
unsigned k;
|
||||
|
@ -147,6 +153,7 @@ grub_dl_register_symbol (const char *name, void *addr, grub_dl_t mod)
|
|||
|
||||
sym->addr = addr;
|
||||
sym->mod = mod;
|
||||
sym->isfunc = isfunc;
|
||||
|
||||
k = grub_symbol_hash (name);
|
||||
sym->next = grub_symtab[k];
|
||||
|
@ -225,6 +232,48 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
|||
{
|
||||
unsigned i;
|
||||
Elf_Shdr *s;
|
||||
grub_size_t tsize = 0, talign = 1;
|
||||
#ifdef __ia64__
|
||||
grub_size_t tramp;
|
||||
grub_size_t got;
|
||||
#endif
|
||||
char *ptr;
|
||||
|
||||
for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
|
||||
{
|
||||
tsize += ALIGN_UP (s->sh_size, s->sh_addralign);
|
||||
if (talign < s->sh_addralign)
|
||||
talign = s->sh_addralign;
|
||||
}
|
||||
|
||||
#ifdef __ia64__
|
||||
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);
|
||||
if (talign < GRUB_ARCH_DL_TRAMP_ALIGN)
|
||||
talign = GRUB_ARCH_DL_TRAMP_ALIGN;
|
||||
tsize += ALIGN_UP (got, GRUB_ARCH_DL_GOT_ALIGN);
|
||||
if (talign < GRUB_ARCH_DL_GOT_ALIGN)
|
||||
talign = GRUB_ARCH_DL_GOT_ALIGN;
|
||||
#endif
|
||||
|
||||
#ifdef GRUB_MACHINE_EMU
|
||||
if (talign < 8192 * 16)
|
||||
talign = 8192 * 16;
|
||||
tsize = ALIGN_UP (tsize, 8192 * 16);
|
||||
#endif
|
||||
|
||||
mod->base = grub_memalign (talign, tsize);
|
||||
if (!mod->base)
|
||||
return grub_errno;
|
||||
ptr = mod->base;
|
||||
|
||||
#ifdef GRUB_MACHINE_EMU
|
||||
mprotect (mod->base, tsize, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
#endif
|
||||
|
||||
for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
|
||||
i < e->e_shnum;
|
||||
|
@ -242,12 +291,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
|||
{
|
||||
void *addr;
|
||||
|
||||
addr = grub_memalign (s->sh_addralign, s->sh_size);
|
||||
if (! addr)
|
||||
{
|
||||
grub_free (seg);
|
||||
return grub_errno;
|
||||
}
|
||||
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign);
|
||||
addr = ptr;
|
||||
ptr += s->sh_size;
|
||||
|
||||
switch (s->sh_type)
|
||||
{
|
||||
|
@ -270,6 +316,14 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
|
|||
mod->segment = seg;
|
||||
}
|
||||
}
|
||||
#ifdef __ia64__
|
||||
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_TRAMP_ALIGN);
|
||||
mod->tramp = ptr;
|
||||
ptr += tramp;
|
||||
ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, GRUB_ARCH_DL_GOT_ALIGN);
|
||||
mod->got = ptr;
|
||||
ptr += got;
|
||||
#endif
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
@ -320,17 +374,20 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
|
|||
/* Resolve a global symbol. */
|
||||
if (sym->st_name != 0 && sym->st_shndx == 0)
|
||||
{
|
||||
sym->st_value = (Elf_Addr) grub_dl_resolve_symbol (name);
|
||||
if (! sym->st_value)
|
||||
grub_symbol_t nsym = grub_dl_resolve_symbol (name);
|
||||
if (! nsym)
|
||||
return grub_error (GRUB_ERR_BAD_MODULE,
|
||||
"symbol not found: `%s'", name);
|
||||
sym->st_value = (Elf_Addr) nsym->addr;
|
||||
if (nsym->isfunc)
|
||||
sym->st_info = ELF_ST_INFO (bind, STT_FUNC);
|
||||
}
|
||||
else
|
||||
{
|
||||
sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
|
||||
sym->st_shndx);
|
||||
if (bind != STB_LOCAL)
|
||||
if (grub_dl_register_symbol (name, (void *) sym->st_value, mod))
|
||||
if (grub_dl_register_symbol (name, (void *) sym->st_value, 0, mod))
|
||||
return grub_errno;
|
||||
}
|
||||
break;
|
||||
|
@ -338,10 +395,21 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
|
|||
case STT_FUNC:
|
||||
sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
|
||||
sym->st_shndx);
|
||||
#ifdef __ia64__
|
||||
{
|
||||
/* FIXME: free descriptor once it's not used anymore. */
|
||||
char **desc;
|
||||
desc = grub_malloc (2 * sizeof (char *));
|
||||
if (!desc)
|
||||
return grub_errno;
|
||||
desc[0] = (void *) sym->st_value;
|
||||
desc[1] = mod->base;
|
||||
sym->st_value = (grub_addr_t) desc;
|
||||
}
|
||||
#endif
|
||||
if (bind != STB_LOCAL)
|
||||
if (grub_dl_register_symbol (name, (void *) sym->st_value, mod))
|
||||
if (grub_dl_register_symbol (name, (void *) sym->st_value, 1, mod))
|
||||
return grub_errno;
|
||||
|
||||
if (grub_strcmp (name, "grub_mod_init") == 0)
|
||||
mod->init = (void (*) (grub_dl_t)) sym->st_value;
|
||||
else if (grub_strcmp (name, "grub_mod_fini") == 0)
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include <grub/efi/console_control.h>
|
||||
#include <grub/efi/pe32.h>
|
||||
#include <grub/machine/time.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/term.h>
|
||||
#include <grub/kernel.h>
|
||||
#include <grub/mm.h>
|
||||
|
@ -193,8 +194,8 @@ grub_efi_set_virtual_address_map (grub_efi_uintn_t memory_map_size,
|
|||
return grub_error (GRUB_ERR_IO, "set_virtual_address_map failed");
|
||||
}
|
||||
|
||||
grub_uint32_t
|
||||
grub_get_rtc (void)
|
||||
grub_uint64_t
|
||||
grub_rtc_get_time_ms (void)
|
||||
{
|
||||
grub_efi_time_t time;
|
||||
grub_efi_runtime_services_t *r;
|
||||
|
@ -204,9 +205,14 @@ grub_get_rtc (void)
|
|||
/* What is possible in this case? */
|
||||
return 0;
|
||||
|
||||
return (((time.minute * 60 + time.second) * 1000
|
||||
+ time.nanosecond / 1000000)
|
||||
* GRUB_TICKS_PER_SECOND / 1000);
|
||||
return ((time.minute * 60 + time.second) * 1000
|
||||
+ time.nanosecond / 1000000);
|
||||
}
|
||||
|
||||
grub_uint32_t
|
||||
grub_get_rtc (void)
|
||||
{
|
||||
return grub_rtc_get_time_ms ();
|
||||
}
|
||||
|
||||
/* Search the mods section from the PE32/PE32+ image. This code uses
|
||||
|
|
13
grub-core/kern/emu/cache.c
Normal file
13
grub-core/kern/emu/cache.c
Normal file
|
@ -0,0 +1,13 @@
|
|||
|
||||
#if defined(__ia64__)
|
||||
#include <grub/cache.h>
|
||||
|
||||
void __clear_cache (char *beg, char *end);
|
||||
|
||||
void
|
||||
grub_arch_sync_caches (void *address, grub_size_t len)
|
||||
{
|
||||
__clear_cache (address, (char *) address + len);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -23,6 +23,7 @@ FUNCTION (grub_arch_sync_caches)
|
|||
.set macro
|
||||
#elif defined(__powerpc__)
|
||||
#include "../powerpc/cache.S"
|
||||
#elif defined(__ia64__)
|
||||
#else
|
||||
#error "No target cpu type is defined"
|
||||
#endif
|
|
@ -50,6 +50,15 @@ grub_emu_init (void)
|
|||
grub_no_autoload = 1;
|
||||
}
|
||||
|
||||
#ifdef __ia64__
|
||||
void grub_arch_dl_get_tramp_got_size (const void *ehdr __attribute__ ((unused)),
|
||||
grub_size_t *tramp, grub_size_t *got)
|
||||
{
|
||||
*tramp = 0;
|
||||
*got = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GRUB_LINKER_HAVE_INIT
|
||||
void
|
||||
grub_arch_dl_init_linker (void)
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include "../mips/dl.c"
|
||||
#elif defined(__powerpc__)
|
||||
#include "../powerpc/dl.c"
|
||||
#elif defined(__ia64__)
|
||||
#include "../ia64/dl.c"
|
||||
#else
|
||||
#error "No target cpu type is defined"
|
||||
#endif
|
||||
|
|
276
grub-core/kern/ia64/dl.c
Normal file
276
grub-core/kern/ia64/dl.c
Normal file
|
@ -0,0 +1,276 @@
|
|||
/* dl.c - arch-dependent part of loadable module support */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2002,2004,2005,2007,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/elf.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
/* Check if EHDR is a valid ELF header. */
|
||||
grub_err_t
|
||||
grub_arch_dl_check_header (void *ehdr)
|
||||
{
|
||||
Elf_Ehdr *e = ehdr;
|
||||
|
||||
/* Check the magic numbers. */
|
||||
if (e->e_ident[EI_CLASS] != ELFCLASS64
|
||||
|| e->e_ident[EI_DATA] != ELFDATA2LSB
|
||||
|| e->e_machine != EM_IA_64)
|
||||
return grub_error (GRUB_ERR_BAD_OS, "invalid arch specific ELF magic");
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
#define MASK20 ((1 << 20) - 1)
|
||||
#define MASK19 ((1 << 19) - 1)
|
||||
|
||||
struct unaligned_uint32
|
||||
{
|
||||
grub_uint32_t val;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static grub_uint8_t nopm[5] =
|
||||
{
|
||||
/* [MLX] nop.m 0x0 */
|
||||
0x05, 0x00, 0x00, 0x00, 0x01
|
||||
};
|
||||
|
||||
static grub_uint8_t jump[0x20] =
|
||||
{
|
||||
/* ld8 r16=[r15],8 */
|
||||
0x02, 0x80, 0x20, 0x1e, 0x18, 0x14,
|
||||
/* mov r14=r1;; */
|
||||
0xe0, 0x00, 0x04, 0x00, 0x42, 0x00,
|
||||
/* nop.i 0x0 */
|
||||
0x00, 0x00, 0x04, 0x00,
|
||||
/* 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
|
||||
};
|
||||
|
||||
struct ia64_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 void
|
||||
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));
|
||||
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));
|
||||
}
|
||||
|
||||
/* Relocate symbols. */
|
||||
grub_err_t
|
||||
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
|
||||
{
|
||||
Elf_Ehdr *e = ehdr;
|
||||
Elf_Shdr *s;
|
||||
Elf_Word entsize;
|
||||
unsigned i;
|
||||
grub_uint64_t *gp, *gpptr;
|
||||
struct ia64_trampoline *tr;
|
||||
|
||||
gp = (grub_uint64_t *) mod->base;
|
||||
gpptr = (grub_uint64_t *) mod->got;
|
||||
tr = mod->tramp;
|
||||
|
||||
/* 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 grub_error (GRUB_ERR_BAD_MODULE, "no symtab found");
|
||||
|
||||
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)
|
||||
{
|
||||
grub_dl_segment_t seg;
|
||||
|
||||
/* Find the target segment. */
|
||||
for (seg = mod->segment; seg; seg = seg->next)
|
||||
if (seg->section == s->sh_info)
|
||||
break;
|
||||
|
||||
if (seg)
|
||||
{
|
||||
Elf_Rela *rel, *max;
|
||||
|
||||
for (rel = (Elf_Rela *) ((char *) e + s->sh_offset),
|
||||
max = rel + s->sh_size / s->sh_entsize;
|
||||
rel < max;
|
||||
rel++)
|
||||
{
|
||||
grub_addr_t addr;
|
||||
Elf_Sym *sym;
|
||||
grub_uint64_t value;
|
||||
|
||||
if (seg->size < (rel->r_offset & ~3))
|
||||
return grub_error (GRUB_ERR_BAD_MODULE,
|
||||
"reloc offset is out of the segment");
|
||||
|
||||
addr = (grub_addr_t) seg->addr + rel->r_offset;
|
||||
sym = (Elf_Sym *) ((char *) mod->symtab
|
||||
+ entsize * ELF_R_SYM (rel->r_info));
|
||||
|
||||
/* On the PPC the value does not have an explicit
|
||||
addend, add it. */
|
||||
value = sym->st_value + rel->r_addend;
|
||||
|
||||
switch (ELF_R_TYPE (rel->r_info))
|
||||
{
|
||||
case R_IA64_PCREL21B:
|
||||
{
|
||||
grub_uint64_t noff;
|
||||
make_trampoline (tr, value);
|
||||
noff = ((char *) tr - (char *) (addr & ~3)) >> 4;
|
||||
tr++;
|
||||
if (noff & ~MASK19)
|
||||
return grub_error (GRUB_ERR_BAD_OS,
|
||||
"trampoline offset too big (%lx)", noff);
|
||||
add_value_to_slot_20b (addr, noff);
|
||||
}
|
||||
break;
|
||||
case R_IA64_SEGREL64LSB:
|
||||
*(grub_uint64_t *) addr += value - (grub_addr_t) seg->addr;
|
||||
break;
|
||||
case R_IA64_FPTR64LSB:
|
||||
case R_IA64_DIR64LSB:
|
||||
*(grub_uint64_t *) addr += value;
|
||||
break;
|
||||
case R_IA64_PCREL64LSB:
|
||||
*(grub_uint64_t *) addr += value - addr;
|
||||
break;
|
||||
case R_IA64_GPREL22:
|
||||
add_value_to_slot_21 (addr, value - (grub_addr_t) gp);
|
||||
break;
|
||||
|
||||
case R_IA64_LTOFF22X:
|
||||
case R_IA64_LTOFF22:
|
||||
if (ELF_ST_TYPE (sym->st_info) == STT_FUNC)
|
||||
value = *(grub_uint64_t *) sym->st_value + rel->r_addend;
|
||||
case R_IA64_LTOFF_FPTR22:
|
||||
*gpptr = value;
|
||||
add_value_to_slot_21 (addr, (grub_addr_t) gpptr - (grub_addr_t) gp);
|
||||
gpptr++;
|
||||
break;
|
||||
|
||||
/* We treat LTOFF22X as LTOFF22, so we can ignore LDXMOV. */
|
||||
case R_IA64_LDXMOV:
|
||||
break;
|
||||
default:
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"this relocation (0x%x) is not implemented yet",
|
||||
ELF_R_TYPE (rel->r_info));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
73
grub-core/kern/ia64/dl_helper.c
Normal file
73
grub-core/kern/ia64/dl_helper.c
Normal file
|
@ -0,0 +1,73 @@
|
|||
/* dl.c - arch-dependent part of loadable module support */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2002,2004,2005,2007,2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/elf.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/mm.h>
|
||||
|
||||
void
|
||||
grub_ia64_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;
|
||||
*got = cntg;
|
||||
}
|
||||
|
60
grub-core/kern/ia64/efi/init.c
Normal file
60
grub-core/kern/ia64/efi/init.c
Normal file
|
@ -0,0 +1,60 @@
|
|||
/* init.c - initialize an ia64-based EFI system */
|
||||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/types.h>
|
||||
#include <grub/misc.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/cache.h>
|
||||
#include <grub/kernel.h>
|
||||
#include <grub/efi/efi.h>
|
||||
|
||||
void
|
||||
grub_machine_init (void)
|
||||
{
|
||||
grub_efi_init ();
|
||||
grub_install_get_time_ms (grub_rtc_get_time_ms);
|
||||
}
|
||||
|
||||
void
|
||||
grub_machine_fini (void)
|
||||
{
|
||||
grub_efi_fini ();
|
||||
}
|
||||
|
||||
void
|
||||
grub_machine_set_prefix (void)
|
||||
{
|
||||
grub_efi_set_prefix ();
|
||||
}
|
||||
|
||||
void
|
||||
grub_arch_sync_caches (void *address, grub_size_t len)
|
||||
{
|
||||
/* Cache line length is at least 32. */
|
||||
grub_uint64_t a = (grub_uint64_t)address & ~0x1f;
|
||||
|
||||
/* Flush data. */
|
||||
for (len = (len + 31) & ~0x1f; len > 0; len -= 0x20, a += 0x20)
|
||||
asm volatile ("fc.i %0" : : "r" (a));
|
||||
/* Sync and serialize. Maybe extra. */
|
||||
asm volatile (";; sync.i;; srlz.i;;");
|
||||
}
|
54
grub-core/kern/ia64/efi/startup.S
Normal file
54
grub-core/kern/ia64/efi/startup.S
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <grub/symbol.h>
|
||||
#include <grub/offsets.h>
|
||||
|
||||
.text
|
||||
.psr abi64
|
||||
.psr lsb
|
||||
.lsb
|
||||
|
||||
.global _start
|
||||
.proc _start
|
||||
_start:
|
||||
alloc loc0=ar.pfs,2,4,0,0
|
||||
mov loc1=rp
|
||||
addl loc2=@gprel(grub_efi_image_handle),gp
|
||||
addl loc3=@gprel(grub_efi_system_table),gp
|
||||
;;
|
||||
st8 [loc2]=in0
|
||||
st8 [loc3]=in1
|
||||
br.call.sptk.few rp=grub_main
|
||||
;;
|
||||
mov ar.pfs=loc0
|
||||
mov rp=loc1
|
||||
;;
|
||||
br.ret.sptk.few rp
|
||||
|
||||
.endp _start
|
||||
|
||||
. = _start + GRUB_KERNEL_MACHINE_PREFIX
|
||||
VARIABLE(grub_prefix)
|
||||
.byte 0
|
||||
/* to be filled by grub-mkimage */
|
||||
|
||||
/*
|
||||
* Leave some breathing room for the prefix.
|
||||
*/
|
||||
. = _start + GRUB_KERNEL_MACHINE_PREFIX_END
|
Loading…
Add table
Add a link
Reference in a new issue