From 6e7a315eb67cb6c113cf37e1d66c4f11a51a2b3e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 18:29:51 +0200 Subject: Adding upstream version 2.06. Signed-off-by: Daniel Baumann --- grub-core/kern/sparc64/dl.c | 191 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 grub-core/kern/sparc64/dl.c (limited to 'grub-core/kern/sparc64/dl.c') diff --git a/grub-core/kern/sparc64/dl.c b/grub-core/kern/sparc64/dl.c new file mode 100644 index 0000000..f3d9601 --- /dev/null +++ b/grub-core/kern/sparc64/dl.c @@ -0,0 +1,191 @@ +/* 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 . + */ + +#include +#include +#include +#include +#include + +/* 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] != ELFDATA2MSB + || e->e_machine != EM_SPARCV9) + return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic")); + + return GRUB_ERR_NONE; +} + +#pragma GCC diagnostic ignored "-Wcast-align" + +struct trampoline +{ + grub_uint8_t code[0x28]; + grub_uint64_t addr; +}; + +static const grub_uint8_t trampoline_code[0x28] = +{ + /* 0: */ 0x82, 0x10, 0x00, 0x0f, /* mov %o7, %g1 */ + /* 4: */ 0x40, 0x00, 0x00, 0x02, /* call 0xc */ + /* 8: */ 0x01, 0x00, 0x00, 0x00, /* nop */ + /* c: */ 0x9e, 0x1b, 0xc0, 0x01, /* xor %o7, %g1, %o7 */ + /* 10: */ 0x82, 0x18, 0x40, 0x0f, /* xor %g1, %o7, %g1 */ + /* 14: */ 0x9e, 0x1b, 0xc0, 0x01, /* xor %o7, %g1, %o7 */ + /* 18: */ 0xc2, 0x58, 0x60, 0x24, /* ldx [ %g1 + 0x24 ], %g1 */ + /* 1c: */ 0x81, 0xc0, 0x40, 0x00, /* jmp %g1 */ + /* 20: */ 0x01, 0x00, 0x00, 0x00, /* nop */ + /* 24: */ 0x01, 0x00, 0x00, 0x00, /* nop */ +}; + +grub_err_t +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; + unsigned i; + + *tramp = 0; + *got = 0; + + for (i = 0, s = (const Elf_Shdr *) ((grub_addr_t) e + e->e_shoff); + i < e->e_shnum; + i++, s = (const Elf_Shdr *) ((grub_addr_t) s + e->e_shentsize)) + if (s->sh_type == SHT_REL || s->sh_type == SHT_RELA) + { + const Elf_Rel *rel, *max; + + for (rel = (const Elf_Rel *) ((grub_addr_t) e + s->sh_offset), + max = rel + s->sh_size / s->sh_entsize; + rel < max; + rel = (const Elf_Rel *) ((grub_addr_t) rel + s->sh_entsize)) + switch (ELF_R_TYPE (rel->r_info)) + { + case R_SPARC_WDISP30: + { + *tramp += sizeof (struct trampoline); + break; + } + } + } + + return GRUB_ERR_NONE; +} + +/* Relocate symbols. */ +grub_err_t +grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + Elf_Shdr *s, grub_dl_segment_t seg) +{ + Elf_Rela *rel, *max; + + for (rel = (Elf_Rela *) ((char *) ehdr + s->sh_offset), + max = (Elf_Rela *) ((char *) rel + s->sh_size); + rel < max; + rel = (Elf_Rela *) ((char *) rel + s->sh_entsize)) + { + Elf_Word *addr; + Elf_Sym *sym; + Elf_Addr value; + + if (seg->size < rel->r_offset) + return grub_error (GRUB_ERR_BAD_MODULE, + "reloc offset is out of the segment"); + + addr = (Elf_Word *) ((char *) seg->addr + rel->r_offset); + sym = (Elf_Sym *) ((char *) mod->symtab + + mod->symsize * ELF_R_SYM (rel->r_info)); + + value = sym->st_value + rel->r_addend; + switch (ELF_R_TYPE (rel->r_info) & 0xff) + { + case R_SPARC_32: /* 3 V-word32 */ + if (value & 0xFFFFFFFF00000000) + return grub_error (GRUB_ERR_BAD_MODULE, + "address out of 32 bits range"); + *addr = value; + break; + case R_SPARC_WDISP30: /* 7 V-disp30 */ + if (((value - (Elf_Addr) addr) & 0xFFFFFFFF00000000) && + (((value - (Elf_Addr) addr) & 0xFFFFFFFF00000000) + != 0xFFFFFFFF00000000)) + { + struct trampoline *tp = mod->trampptr; + mod->trampptr = tp + 1; + grub_memcpy (tp->code, trampoline_code, sizeof (tp->code)); + tp->addr = value; + value = (Elf_Addr) tp; + } + + if (((value - (Elf_Addr) addr) & 0xFFFFFFFF00000000) && + (((value - (Elf_Addr) addr) & 0xFFFFFFFF00000000) + != 0xFFFFFFFF00000000)) + return grub_error (GRUB_ERR_BAD_MODULE, + "displacement out of 30 bits range"); + *addr = (*addr & 0xC0000000) | + (((grub_int32_t) ((value - (Elf_Addr) addr) >> 2)) & + 0x3FFFFFFF); + break; + case R_SPARC_HH22: /* 9 V-imm22 */ + *addr = (*addr & 0xFFC00000) | ((value >> 42) & 0x3FFFFF); + break; + case R_SPARC_HM10: /* 12 T-simm13 */ + *addr = (*addr & 0xFFFFFC00) | ((value >> 32) & 0x3FF); + break; + case R_SPARC_HI22: /* 9 V-imm22 */ + if (value >> 32) + return grub_error (GRUB_ERR_BAD_MODULE, + "address out of 32 bits range"); + /* Fallthrough. */ + case R_SPARC_LM22: + *addr = (*addr & 0xFFC00000) | ((value >> 10) & 0x3FFFFF); + break; + case R_SPARC_LO10: /* 12 T-simm13 */ + *addr = (*addr & 0xFFFFFC00) | (value & 0x3FF); + break; + case R_SPARC_64: /* 32 V-xwords64 */ + *(Elf_Xword *) addr = value; + break; + case R_SPARC_OLO10: + *addr = (*addr & ~0x1fff) + | (((value & 0x3ff) + + (ELF_R_TYPE (rel->r_info) >> 8)) + & 0x1fff); + break; + default: + { + char rel_info[17]; /* log16(2^64) = 16, plus NUL. */ + + grub_snprintf (rel_info, sizeof (rel_info) - 1, "%" PRIxGRUB_UINT64_T, + ELF_R_TYPE (rel->r_info)); + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + N_("relocation 0x%s is not implemented yet"), rel_info); + } + } + } + + return GRUB_ERR_NONE; +} -- cgit v1.2.3