diff options
author | James <james.mckenzie@citrix.com> | 2012-11-16 10:41:01 +0000 |
---|---|---|
committer | James <james.mckenzie@citrix.com> | 2012-11-16 10:41:01 +0000 |
commit | 041d1ea37802bf7178a31a53f96c26efa6b8fb7b (patch) | |
tree | c193e84ad1237f25a79d0f6a267722e44c73f56a /grub-core/kern/x86_64 | |
download | grub-1.99-041d1ea37802bf7178a31a53f96c26efa6b8fb7b.tar.gz grub-1.99-041d1ea37802bf7178a31a53f96c26efa6b8fb7b.tar.bz2 grub-1.99-041d1ea37802bf7178a31a53f96c26efa6b8fb7b.zip |
fish
Diffstat (limited to 'grub-core/kern/x86_64')
-rw-r--r-- | grub-core/kern/x86_64/dl.c | 119 | ||||
-rw-r--r-- | grub-core/kern/x86_64/efi/callwrap.S | 116 | ||||
-rw-r--r-- | grub-core/kern/x86_64/efi/startup.S | 63 |
3 files changed, 298 insertions, 0 deletions
diff --git a/grub-core/kern/x86_64/dl.c b/grub-core/kern/x86_64/dl.c new file mode 100644 index 0000000..090ad78 --- /dev/null +++ b/grub-core/kern/x86_64/dl.c @@ -0,0 +1,119 @@ +/* dl-x86_64.c - arch-dependent part of loadable module support */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,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> + +/* Check if EHDR is a valid ELF header. */ +grub_err_t +grub_arch_dl_check_header (void *ehdr) +{ + Elf64_Ehdr *e = ehdr; + + /* Check the magic numbers. */ + if (e->e_ident[EI_CLASS] != ELFCLASS64 + || e->e_ident[EI_DATA] != ELFDATA2LSB + || e->e_machine != EM_X86_64) + return grub_error (GRUB_ERR_BAD_OS, "invalid arch specific ELF magic"); + + return GRUB_ERR_NONE; +} + +/* Relocate symbols. */ +grub_err_t +grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) +{ + Elf64_Ehdr *e = ehdr; + Elf64_Shdr *s; + Elf64_Word entsize; + unsigned i; + + /* Find a symbol table. */ + for (i = 0, s = (Elf64_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf64_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 = (Elf64_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf64_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) + { + Elf64_Rela *rel, *max; + + for (rel = (Elf64_Rela *) ((char *) e + s->sh_offset), + max = rel + s->sh_size / s->sh_entsize; + rel < max; + rel++) + { + Elf64_Word *addr32; + Elf64_Xword *addr64; + Elf64_Sym *sym; + + if (seg->size < rel->r_offset) + return grub_error (GRUB_ERR_BAD_MODULE, + "reloc offset is out of the segment"); + + addr32 = (Elf64_Word *) ((char *) seg->addr + rel->r_offset); + addr64 = (Elf64_Xword *) addr32; + sym = (Elf64_Sym *) ((char *) mod->symtab + + entsize * ELF_R_SYM (rel->r_info)); + + switch (ELF_R_TYPE (rel->r_info)) + { + case R_X86_64_64: + *addr64 += rel->r_addend + sym->st_value; + break; + + case R_X86_64_PC32: + *addr32 += rel->r_addend + sym->st_value - + (Elf64_Xword) seg->addr - rel->r_offset; + break; + + case R_X86_64_32: + case R_X86_64_32S: + *addr32 += rel->r_addend + sym->st_value; + break; + + default: + grub_fatal ("Unrecognized relocation: %d\n", ELF_R_TYPE (rel->r_info)); + } + } + } + } + + return GRUB_ERR_NONE; +} diff --git a/grub-core/kern/x86_64/efi/callwrap.S b/grub-core/kern/x86_64/efi/callwrap.S new file mode 100644 index 0000000..aae2678 --- /dev/null +++ b/grub-core/kern/x86_64/efi/callwrap.S @@ -0,0 +1,116 @@ +/* callwrap.S - wrapper for x86_64 efi calls */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,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 <config.h> +#include <grub/symbol.h> +#include <grub/boot.h> + +/* + * x86_64 uses registry to pass parameters. Unfortunately, gcc and efi use + * different call conversion, so we need to do some conversion. + * + * gcc: + * %rdi, %esi, %rdx, %rcx, %r8, %r9, 8(%rsp), 16(%rsp), ... + * + * efi: + * %rcx, %rdx, %r8, %r9, 32(%rsp), 40(%rsp), 48(%rsp), ... + * + */ + + .file "callwrap.S" + .text + +FUNCTION(efi_wrap_0) + subq $48, %rsp + call *%rdi + addq $48, %rsp + ret + +FUNCTION(efi_wrap_1) + subq $48, %rsp + mov %rsi, %rcx + call *%rdi + addq $48, %rsp + ret + +FUNCTION(efi_wrap_2) + subq $48, %rsp + mov %rsi, %rcx + call *%rdi + addq $48, %rsp + ret + +FUNCTION(efi_wrap_3) + subq $48, %rsp + mov %rcx, %r8 + mov %rsi, %rcx + call *%rdi + addq $48, %rsp + ret + +FUNCTION(efi_wrap_4) + subq $48, %rsp + mov %r8, %r9 + mov %rcx, %r8 + mov %rsi, %rcx + call *%rdi + addq $48, %rsp + ret + +FUNCTION(efi_wrap_5) + subq $48, %rsp + mov %r9, 32(%rsp) + mov %r8, %r9 + mov %rcx, %r8 + mov %rsi, %rcx + call *%rdi + addq $48, %rsp + ret + +FUNCTION(efi_wrap_6) + subq $64, %rsp + mov 64+8(%rsp), %rax + mov %rax, 40(%rsp) + mov %r9, 32(%rsp) + mov %r8, %r9 + mov %rcx, %r8 + mov %rsi, %rcx + call *%rdi + addq $64, %rsp + ret + +FUNCTION(efi_wrap_10) + subq $96, %rsp + mov 96+40(%rsp), %rax + mov %rax, 72(%rsp) + mov 96+32(%rsp), %rax + mov %rax, 64(%rsp) + mov 96+24(%rsp), %rax + mov %rax, 56(%rsp) + mov 96+16(%rsp), %rax + mov %rax, 48(%rsp) + mov 96+8(%rsp), %rax + mov %rax, 40(%rsp) + mov %r9, 32(%rsp) + mov %r8, %r9 + mov %rcx, %r8 + mov %rsi, %rcx + call *%rdi + addq $96, %rsp + ret diff --git a/grub-core/kern/x86_64/efi/startup.S b/grub-core/kern/x86_64/efi/startup.S new file mode 100644 index 0000000..fb4fc7b --- /dev/null +++ b/grub-core/kern/x86_64/efi/startup.S @@ -0,0 +1,63 @@ +/* startup.S - bootstrap GRUB itself */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,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 <config.h> +#include <grub/symbol.h> +#include <grub/boot.h> + + .file "startup.S" + .text + .globl start, _start + .code64 + +start: +_start: + jmp codestart + + /* + * Compatibility version number + * + * These MUST be at byte offset 6 and 7 of the executable + * DO NOT MOVE !!! + */ + . = _start + 0x6 + .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR + + /* + * This is a special data area 8 bytes from the beginning. + */ + + . = _start + 0x8 + +VARIABLE(grub_prefix) + /* to be filled by grub-mkimage */ + + /* + * Leave some breathing room for the prefix. + */ + + . = _start + 0x50 + +codestart: + movq %rcx, EXT_C(grub_efi_image_handle)(%rip) + movq %rdx, EXT_C(grub_efi_system_table)(%rip) + + call EXT_C(grub_main) + ret + |