diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk new file mode 100644 index 0000000..e8557e1 --- /dev/null +++ b/conf/x86_64-efi.rmk @@ -0,0 +1,155 @@ +# -*- makefile -*- + +COMMON_ASFLAGS = -nostdinc -fno-builtin -m64 +COMMON_CFLAGS = -fno-builtin -m64 +COMMON_LDFLAGS = -melf_x86_64 -nostdlib + +# Used by various components. These rules need to precede them. +normal/execute.c_DEPENDENCIES = grub_script.tab.h +normal/command.c_DEPENDENCIES = grub_script.tab.h +normal/function.c_DEPENDENCIES = grub_script.tab.h +normal/lexer.c_DEPENDENCIES = grub_script.tab.h + +# Utilities. +bin_UTILITIES = grub-mkimage +#sbin_UTILITIES = grub-mkdevicemap +#ifeq ($(enable_grub_emu), yes) +#sbin_UTILITIES += grub-emu +#endif + +# For grub-mkimage. +grub_mkimage_SOURCES = util/i386/efi/grub-mkimage.c util/misc.c \ + util/resolve.c + +# For grub-setup. +#grub_setup_SOURCES = util/i386/pc/grub-setup.c util/biosdisk.c \ +# util/misc.c util/getroot.c kern/device.c kern/disk.c \ +# kern/err.c kern/misc.c fs/fat.c fs/ext2.c fs/xfs.c fs/affs.c \ +# fs/sfs.c kern/parser.c kern/partition.c partmap/pc.c \ +# fs/ufs.c fs/minix.c fs/hfs.c fs/jfs.c fs/hfsplus.c kern/file.c \ +# kern/fs.c kern/env.c fs/fshelp.c + +# For grub-mkdevicemap. +grub_mkdevicemap_SOURCES = util/grub-mkdevicemap.c util/misc.c \ + util/i386/get_disk_name.c + +# For grub-emu. +util/grub-emu.c_DEPENDENCIES = grub_emu_init.h +grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ + commands/configfile.c commands/help.c \ + commands/terminal.c commands/ls.c commands/test.c \ + commands/search.c commands/hexdump.c \ + commands/halt.c commands/reboot.c \ + commands/i386/cpuid.c \ + disk/loopback.c \ + \ + fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \ + fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \ + fs/ntfs.c fs/ntfscomp.c fs/reiserfs.c fs/sfs.c \ + fs/ufs.c fs/xfs.c fs/afs.c \ + \ + io/gzio.c \ + kern/device.c kern/disk.c kern/dl.c kern/elf.c kern/env.c \ + kern/err.c \ + normal/execute.c kern/file.c kern/fs.c normal/lexer.c \ + kern/loader.c kern/main.c kern/misc.c kern/parser.c \ + grub_script.tab.c kern/partition.c kern/rescue.c kern/term.c \ + normal/arg.c normal/cmdline.c normal/command.c normal/function.c\ + normal/completion.c normal/context.c normal/main.c \ + normal/menu.c normal/menu_entry.c normal/misc.c normal/script.c \ + normal/color.c \ + partmap/amiga.c partmap/apple.c partmap/pc.c partmap/sun.c \ + partmap/acorn.c partmap/gpt.c \ + util/console.c util/hostfs.c util/grub-emu.c util/misc.c \ + util/biosdisk.c util/getroot.c \ + util/i386/pc/misc.c \ + \ + disk/raid.c disk/lvm.c \ + grub_emu_init.c + +grub_emu_LDFLAGS = $(LIBCURSES) + +# Scripts. +sbin_SCRIPTS = grub-install + +# For grub-install. +grub_install_SOURCES = util/i386/efi/grub-install.in + +# Modules. +pkglib_MODULES = kernel.mod normal.mod _chain.mod chain.mod \ + cpuid.mod halt.mod reboot.mod +# _linux.mod linux.mod + +# For kernel.mod. +kernel_mod_EXPORTS = no +kernel_mod_SOURCES = kern/x86_64/efi/startup.S kern/x86_64/efi/callwrap.S \ + kern/main.c kern/device.c \ + kern/disk.c kern/dl.c kern/file.c kern/fs.c kern/err.c \ + kern/misc.c kern/mm.c kern/loader.c kern/rescue.c kern/term.c \ + kern/x86_64/dl.c kern/i386/efi/init.c kern/parser.c kern/partition.c \ + kern/env.c symlist.c kern/efi/efi.c kern/efi/init.c kern/efi/mm.c \ + term/efi/console.c disk/efi/efidisk.c +kernel_mod_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ + env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \ + partition.h pc_partition.h rescue.h symbol.h term.h time.h types.h \ + efi/efi.h efi/time.h efi/disk.h +kernel_mod_CFLAGS = $(COMMON_CFLAGS) +kernel_mod_ASFLAGS = $(COMMON_ASFLAGS) +kernel_mod_LDFLAGS = $(COMMON_LDFLAGS) + +MOSTLYCLEANFILES += symlist.c +MOSTLYCLEANFILES += symlist.c kernel_syms.lst +DEFSYMFILES += kernel_syms.lst + +symlist.c: $(addprefix include/grub/,$(kernel_mod_HEADERS)) config.h gensymlist.sh + /bin/sh gensymlist.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) + +kernel_syms.lst: $(addprefix include/grub/,$(kernel_mod_HEADERS)) config.h genkernsyms.sh + /bin/sh genkernsyms.sh $(filter %.h,$^) > $@ || (rm -f $@; exit 1) + +# For normal.mod. +normal_mod_SOURCES = normal/arg.c normal/cmdline.c normal/command.c \ + normal/completion.c normal/execute.c \ + normal/function.c normal/lexer.c normal/main.c normal/menu.c \ + normal/menu_entry.c normal/misc.c grub_script.tab.c \ + normal/script.c normal/x86_64/setjmp.S normal/color.c +normal_mod_CFLAGS = $(COMMON_CFLAGS) +normal_mod_ASFLAGS = $(COMMON_ASFLAGS) +normal_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For _chain.mod. +_chain_mod_SOURCES = loader/efi/chainloader.c +_chain_mod_CFLAGS = $(COMMON_CFLAGS) +_chain_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For chain.mod. +chain_mod_SOURCES = loader/efi/chainloader_normal.c +chain_mod_CFLAGS = $(COMMON_CFLAGS) +chain_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For _linux.mod. +_linux_mod_SOURCES = loader/i386/efi/linux.c +_linux_mod_CFLAGS = $(COMMON_CFLAGS) +_linux_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For linux.mod. +linux_mod_SOURCES = loader/i386/efi/linux_normal.c +linux_mod_CFLAGS = $(COMMON_CFLAGS) +linux_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For cpuid.mod. +cpuid_mod_SOURCES = commands/i386/cpuid.c +cpuid_mod_CFLAGS = $(COMMON_CFLAGS) +cpuid_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For halt.mod. +halt_mod_SOURCES = commands/halt.c +halt_mod_CFLAGS = $(COMMON_CFLAGS) +halt_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For reboot.mod. +reboot_mod_SOURCES = commands/reboot.c +reboot_mod_CFLAGS = $(COMMON_CFLAGS) +reboot_mod_LDFLAGS = $(COMMON_LDFLAGS) + +include $(srcdir)/conf/common.mk diff --git a/configure.ac b/configure.ac index 5ec7a47..a5ce826 100644 --- a/configure.ac +++ b/configure.ac @@ -49,11 +49,6 @@ esac case "$target_cpu" in i[[3456]]86) target_cpu=i386 ;; - x86_64) target_cpu=i386 target_m32=1 ;; - powerpc) ;; - powerpc64) target_cpu=powerpc target_m32=1;; - sparc64) ;; - *) AC_MSG_ERROR([unsupported CPU type]) ;; esac # Specify the platform (such as firmware). @@ -74,9 +69,27 @@ else platform="$with_platform" fi +if test "x$platform" = "xefi" ; then + case "$target_cpu" in + i386) ;; + x86_64) target_m64=1 ;; + *) AC_MSG_ERROR([unsupported CPU type for EFI]) ;; + esac +else + case "$target_cpu" in + i386) ;; + x86_64) target_cpu=i386 target_m32=1 ;; + powerpc) ;; + powerpc64) target_cpu=powerpc target_m32=1;; + sparc64) ;; + *) AC_MSG_ERROR([unsupported CPU type]) ;; + esac +fi + # Sanity check. case "$target_cpu"-"$platform" in i386-efi) ;; + x86_64-efi) ;; i386-pc) ;; i386-linuxbios) ;; i386-ieee1275) ;; @@ -238,6 +251,12 @@ if test "x$target_m32" = x1; then TARGET_LDFLAGS="$TARGET_LDFLAGS -m32" fi +if test "x$target_m64" = x1; then + # Force 64-bit mode. + TARGET_CFLAGS="$TARGET_CFLAGS -m64" + TARGET_LDFLAGS="$TARGET_LDFLAGS -m64" +fi + # # Compiler features. # diff --git a/disk/efi/efidisk.c b/disk/efi/efidisk.c index e51c2ea..3c5e35f 100644 --- a/disk/efi/efidisk.c +++ b/disk/efi/efidisk.c @@ -574,7 +574,7 @@ grub_efidisk_read (struct grub_disk *disk, grub_disk_addr_t sector, "reading 0x%x sectors at the sector 0x%llx from %s\n", size, sector, disk->name); - status = dio->read (dio, bio->media->media_id, + status = efi_call_5 (dio->read, dio, bio->media->media_id, (grub_efi_uint64_t) sector << GRUB_DISK_SECTOR_BITS, (grub_efi_uintn_t) size << GRUB_DISK_SECTOR_BITS, buf); @@ -602,7 +602,7 @@ grub_efidisk_write (struct grub_disk *disk, grub_disk_addr_t sector, "writing 0x%x sectors at the sector 0x%llx to %s\n", size, sector, disk->name); - status = dio->write (dio, bio->media->media_id, + status = efi_call_5 (dio->write, dio, bio->media->media_id, (grub_efi_uint64_t) sector << GRUB_DISK_SECTOR_BITS, (grub_efi_uintn_t) size << GRUB_DISK_SECTOR_BITS, (void *) buf); diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h index 6c29753..96db9a6 100644 --- a/include/grub/efi/api.h +++ b/include/grub/efi/api.h @@ -1095,4 +1095,42 @@ struct grub_efi_block_io }; typedef struct grub_efi_block_io grub_efi_block_io_t; +#if GRUB_TARGET_SIZEOF_VOID_P == 4 + +#define efi_call_0(func) func() +#define efi_call_1(func, a) func(a) +#define efi_call_2(func, a, b) func(a, b) +#define efi_call_3(func, a, b, c) func(a, b, c) +#define efi_call_4(func, a, b, c, d) func(a, b, c, d) +#define efi_call_5(func, a, b, c, d, e) func(a, b, c, d, e) +#define efi_call_6(func, a, b, c, d, e, f) func(a, b, c, d, e, f) + +#else + +#define efi_call_0(func) efi_wrap_0(func) +#define efi_call_1(func, a) efi_wrap_1(func, (grub_uint64_t) a) +#define efi_call_2(func, a, b) efi_wrap_2(func, (grub_uint64_t) a, (grub_uint64_t) b) +#define efi_call_3(func, a, b, c) efi_wrap_3(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c) +#define efi_call_4(func, a, b, c, d) efi_wrap_4(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, (grub_uint64_t) d) +#define efi_call_5(func, a, b, c, d, e) efi_wrap_5(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, (grub_uint64_t) d, (grub_uint64_t) e) +#define efi_call_6(func, a, b, c, d, e, f) efi_wrap_6(func, (grub_uint64_t) a, (grub_uint64_t) b, (grub_uint64_t) c, (grub_uint64_t) d, (grub_uint64_t) e, (grub_uint64_t) f) + +grub_uint64_t EXPORT_FUNC(efi_wrap_0) (void *func); +grub_uint64_t EXPORT_FUNC(efi_wrap_1) (void *func, grub_uint64_t arg1); +grub_uint64_t EXPORT_FUNC(efi_wrap_2) (void *func, grub_uint64_t arg1, + grub_uint64_t arg2); +grub_uint64_t EXPORT_FUNC(efi_wrap_3) (void *func, grub_uint64_t arg1, + grub_uint64_t arg2, grub_uint64_t arg3); +grub_uint64_t EXPORT_FUNC(efi_wrap_4) (void *func, grub_uint64_t arg1, + grub_uint64_t arg2, grub_uint64_t arg3, + grub_uint64_t arg4); +grub_uint64_t EXPORT_FUNC(efi_wrap_5) (void *func, grub_uint64_t arg1, + grub_uint64_t arg2, grub_uint64_t arg3, + grub_uint64_t arg4, grub_uint64_t arg5); +grub_uint64_t EXPORT_FUNC(efi_wrap_6) (void *func, grub_uint64_t arg1, + grub_uint64_t arg2, grub_uint64_t arg3, + grub_uint64_t arg4, grub_uint64_t arg5, + grub_uint64_t arg6); +#endif + #endif /* ! GRUB_EFI_API_HEADER */ diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h index b6f01a8..f2072c5 100644 --- a/include/grub/efi/pe32.h +++ b/include/grub/efi/pe32.h @@ -64,6 +64,7 @@ struct grub_pe32_coff_header }; #define GRUB_PE32_MACHINE_I386 0x14c +#define GRUB_PE32_MACHINE_X86_64 0x8664 #define GRUB_PE32_RELOCS_STRIPPED 0x0001 #define GRUB_PE32_EXECUTABLE_IMAGE 0x0002 @@ -98,9 +99,13 @@ struct grub_pe32_optional_header grub_uint32_t entry_addr; grub_uint32_t code_base; +#if GRUB_TARGET_SIZEOF_VOID_P == 4 grub_uint32_t data_base; - grub_uint32_t image_base; +#else + grub_uint64_t image_base; +#endif + grub_uint32_t section_alignment; grub_uint32_t file_alignment; grub_uint16_t major_os_version; @@ -115,10 +120,23 @@ struct grub_pe32_optional_header grub_uint32_t checksum; grub_uint16_t subsystem; grub_uint16_t dll_characteristics; + +#if GRUB_TARGET_SIZEOF_VOID_P == 4 + grub_uint32_t stack_reserve_size; grub_uint32_t stack_commit_size; grub_uint32_t heap_reserve_size; grub_uint32_t heap_commit_size; + +#else + + grub_uint64_t stack_reserve_size; + grub_uint64_t stack_commit_size; + grub_uint64_t heap_reserve_size; + grub_uint64_t heap_commit_size; + +#endif + grub_uint32_t loader_flags; grub_uint32_t num_data_directories; @@ -141,8 +159,16 @@ struct grub_pe32_optional_header struct grub_pe32_data_directory reserved_entry; }; +#if GRUB_TARGET_SIZEOF_VOID_P == 4 + #define GRUB_PE32_PE32_MAGIC 0x10b +#else + +#define GRUB_PE32_PE32_MAGIC 0x20b + +#endif + #define GRUB_PE32_SUBSYSTEM_EFI_APPLICATION 10 #define GRUB_PE32_NUM_DATA_DIRECTORIES 16 diff --git a/include/grub/elf.h b/include/grub/elf.h index 9aec816..7b76f58 100644 --- a/include/grub/elf.h +++ b/include/grub/elf.h @@ -454,6 +454,7 @@ typedef struct the end of a chain, meaning no further symbols are found in that bucket. */ #define STN_UNDEF 0 /* End of a chain. */ +#define STN_ABS 65521 /* How to extract and insert information held in the st_other field. */ @@ -1108,8 +1109,27 @@ typedef struct /* Keep this the last entry. */ #define R_386_NUM 38 + /* SUN SPARC specific definitions. */ +/* x86_64 specific definitions. */ +#define R_X86_64_NONE 0 +#define R_X86_64_64 1 +#define R_X86_64_PC32 2 +#define R_X86_64_GOT32 3 +#define R_X86_64_PLT32 4 +#define R_X86_64_COPY 5 +#define R_X86_64_GLOB_DAT 6 +#define R_X86_64_JUMP_SLOT 7 +#define R_X86_64_RELATIVE 8 +#define R_X86_64_GOTPCREL 9 +#define R_X86_64_32 10 +#define R_X86_64_32S 11 +#define R_X86_64_16 12 +#define R_X86_64_PC16 13 +#define R_X86_64_8 14 +#define R_X86_64_PC8 15 + /* Legal values for ST_TYPE subfield of st_info (symbol type). */ #define STT_REGISTER 13 /* Global register reserved to app. */ diff --git a/include/grub/kernel.h b/include/grub/kernel.h index 4a4e2cc..9cbbdaf 100644 --- a/include/grub/kernel.h +++ b/include/grub/kernel.h @@ -38,6 +38,9 @@ struct grub_module_info { /* Magic number so we know we have modules present. */ grub_uint32_t magic; +#if GRUB_TARGET_SIZEOF_VOID_P == 8 + grub_uint32_t padding; +#endif /* The offset of the modules. */ grub_target_off_t offset; /* The size of all modules plus this header. */ diff --git a/include/grub/x86_64/efi/kernel.h b/include/grub/x86_64/efi/kernel.h new file mode 100644 index 0000000..c0549f4 --- /dev/null +++ b/include/grub/x86_64/efi/kernel.h @@ -0,0 +1,33 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2007 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 . + */ + +#ifndef GRUB_MACHINE_KERNEL_HEADER +#define GRUB_MACHINE_KERNEL_HEADER 1 + +/* The prefix which points to the directory where GRUB modules and its + configuration file are located. */ +extern char grub_prefix[]; + +/* The offset of GRUB_PREFIX. */ +#define GRUB_KERNEL_MACHINE_PREFIX 0x8 + +/* End of the data section. */ +#define GRUB_KERNEL_MACHINE_DATA_END 0x50 + +#endif /* ! GRUB_MACHINE_KERNEL_HEADER */ + diff --git a/include/grub/x86_64/efi/loader.h b/include/grub/x86_64/efi/loader.h new file mode 100755 index 0000000..3308be0 --- /dev/null +++ b/include/grub/x86_64/efi/loader.h @@ -0,0 +1,27 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2003,2004,2006,2007 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 . + */ + +#ifndef GRUB_LOADER_MACHINE_HEADER +#define GRUB_LOADER_MACHINE_HEADER 1 + +/* It is necessary to export these functions, because normal mode commands + reuse rescue mode commands. */ +void grub_rescue_cmd_linux (int argc, char *argv[]); +void grub_rescue_cmd_initrd (int argc, char *argv[]); + +#endif /* ! GRUB_LOADER_MACHINE_HEADER */ diff --git a/include/grub/x86_64/efi/machine.h b/include/grub/x86_64/efi/machine.h new file mode 100755 index 0000000..1600768 --- /dev/null +++ b/include/grub/x86_64/efi/machine.h @@ -0,0 +1,24 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2007 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 . + */ + +#ifndef GRUB_MACHINE_MACHINE_HEADER +#define GRUB_MACHINE_MACHINE_HEADER 1 + +#define GRUB_MACHINE_EFI 1 + +#endif /* ! GRUB_MACHINE_MACHINE_HEADER */ diff --git a/include/grub/x86_64/efi/time.h b/include/grub/x86_64/efi/time.h new file mode 100644 index 0000000..7a9241f --- /dev/null +++ b/include/grub/x86_64/efi/time.h @@ -0,0 +1,24 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007 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 . + */ + +#ifndef GRUB_MACHINE_TIME_HEADER +#define GRUB_MACHINE_TIME_HEADER 1 + +#include + +#endif /* ! GRUB_MACHINE_TIME_HEADER */ diff --git a/include/grub/x86_64/setjmp.h b/include/grub/x86_64/setjmp.h new file mode 100644 index 0000000..e417f65 --- /dev/null +++ b/include/grub/x86_64/setjmp.h @@ -0,0 +1,27 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2006,2007 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 . + */ + +#ifndef GRUB_SETJMP_CPU_HEADER +#define GRUB_SETJMP_CPU_HEADER 1 + +typedef unsigned long grub_jmp_buf[8]; + +int grub_setjmp (grub_jmp_buf env); +void grub_longjmp (grub_jmp_buf env, int val) __attribute__ ((noreturn)); + +#endif /* ! GRUB_SETJMP_CPU_HEADER */ diff --git a/include/grub/x86_64/time.h b/include/grub/x86_64/time.h new file mode 100644 index 0000000..842882c --- /dev/null +++ b/include/grub/x86_64/time.h @@ -0,0 +1,29 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2007 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 . + */ + +#ifndef KERNEL_CPU_TIME_HEADER +#define KERNEL_CPU_TIME_HEADER 1 + +static __inline void +grub_cpu_idle (void) +{ + /* FIXME: this can't work until we handle interrupts. */ +/* __asm__ __volatile__ ("hlt"); */ +} + +#endif /* ! KERNEL_CPU_TIME_HEADER */ diff --git a/include/grub/x86_64/types.h b/include/grub/x86_64/types.h new file mode 100644 index 0000000..bdee5a1 --- /dev/null +++ b/include/grub/x86_64/types.h @@ -0,0 +1,31 @@ +/* + * 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 . + */ + +#ifndef GRUB_TYPES_CPU_HEADER +#define GRUB_TYPES_CPU_HEADER 1 + +/* The size of void *. */ +#define GRUB_TARGET_SIZEOF_VOID_P 8 + +/* The size of long. */ +#define GRUB_TARGET_SIZEOF_LONG 8 + +/* x86_64 is little-endian. */ +#undef GRUB_TARGET_WORDS_BIGENDIAN + +#endif /* ! GRUB_TYPES_CPU_HEADER */ diff --git a/kern/dl.c b/kern/dl.c index 9e8c24a..9654c3a 100644 --- a/kern/dl.c +++ b/kern/dl.c @@ -29,7 +29,7 @@ #include #include -#if GRUB_CPU_SIZEOF_VOID_P == 4 +#if GRUB_TARGET_SIZEOF_VOID_P == 4 typedef Elf32_Word Elf_Word; typedef Elf32_Addr Elf_Addr; @@ -40,7 +40,7 @@ typedef Elf32_Sym Elf_Sym; # define ELF_ST_BIND(val) ELF32_ST_BIND (val) # define ELF_ST_TYPE(val) ELF32_ST_TYPE (val) -#elif GRUB_CPU_SIZEOF_VOID_P == 8 +#elif GRUB_TARGET_SIZEOF_VOID_P == 8 typedef Elf64_Word Elf_Word; typedef Elf64_Addr Elf_Addr; diff --git a/kern/efi/efi.c b/kern/efi/efi.c index 11dac58..d6d9c1d 100644 --- a/kern/efi/efi.c +++ b/kern/efi/efi.c @@ -43,9 +43,8 @@ grub_efi_locate_protocol (grub_efi_guid_t *protocol, void *registration) void *interface; grub_efi_status_t status; - status = grub_efi_system_table->boot_services->locate_protocol (protocol, - registration, - &interface); + status = efi_call_3 (grub_efi_system_table->boot_services->locate_protocol, + protocol, registration, &interface); if (status != GRUB_EFI_SUCCESS) return 0; @@ -71,7 +70,7 @@ grub_efi_locate_handle (grub_efi_locate_search_type_t search_type, return 0; b = grub_efi_system_table->boot_services; - status = b->locate_handle (search_type, protocol, search_key, + status = efi_call_5 (b->locate_handle, search_type, protocol, search_key, &buffer_size, buffer); if (status == GRUB_EFI_BUFFER_TOO_SMALL) { @@ -80,7 +79,7 @@ grub_efi_locate_handle (grub_efi_locate_search_type_t search_type, if (! buffer) return 0; - status = b->locate_handle (search_type, protocol, search_key, + status = efi_call_5 (b->locate_handle, search_type, protocol, search_key, &buffer_size, buffer); } @@ -104,12 +103,12 @@ grub_efi_open_protocol (grub_efi_handle_t handle, void *interface; b = grub_efi_system_table->boot_services; - status = b->open_protocol (handle, - protocol, - &interface, - grub_efi_image_handle, - 0, - attributes); + status = efi_call_6 (b->open_protocol, handle, + protocol, + &interface, + grub_efi_image_handle, + 0, + attributes); if (status != GRUB_EFI_SUCCESS) return 0; @@ -128,12 +127,12 @@ grub_efi_set_text_mode (int on) already in text mode. */ return 1; - if (c->get_mode (c, &mode, 0, 0) != GRUB_EFI_SUCCESS) + if (efi_call_4 (c->get_mode, c, &mode, 0, 0) != GRUB_EFI_SUCCESS) return 0; new_mode = on ? GRUB_EFI_SCREEN_TEXT : GRUB_EFI_SCREEN_GRAPHICS; if (mode != new_mode) - if (c->set_mode (c, new_mode) != GRUB_EFI_SUCCESS) + if (efi_call_2 (c->set_mode, c, new_mode) != GRUB_EFI_SUCCESS) return 0; return 1; @@ -142,7 +141,7 @@ grub_efi_set_text_mode (int on) void grub_efi_stall (grub_efi_uintn_t microseconds) { - grub_efi_system_table->boot_services->stall (microseconds); + efi_call_1 (grub_efi_system_table->boot_services->stall, microseconds); } grub_efi_loaded_image_t * @@ -157,25 +156,24 @@ void grub_exit (void) { grub_efi_fini (); - grub_efi_system_table->boot_services->exit (grub_efi_image_handle, - GRUB_EFI_SUCCESS, - 0, 0); + efi_call_4 (grub_efi_system_table->boot_services->exit, + grub_efi_image_handle, GRUB_EFI_SUCCESS, 0, 0); } void grub_reboot (void) { grub_efi_fini (); - grub_efi_system_table->runtime_services-> - reset_system (GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL); + efi_call_4 (grub_efi_system_table->runtime_services->reset_system, + GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL); } void grub_halt (void) { grub_efi_fini (); - grub_efi_system_table->runtime_services-> - reset_system (GRUB_EFI_RESET_SHUTDOWN, GRUB_EFI_SUCCESS, 0, NULL); + efi_call_4 (grub_efi_system_table->runtime_services->reset_system, + GRUB_EFI_RESET_SHUTDOWN, GRUB_EFI_SUCCESS, 0, NULL); } int @@ -185,7 +183,7 @@ grub_efi_exit_boot_services (grub_efi_uintn_t map_key) grub_efi_status_t status; b = grub_efi_system_table->boot_services; - status = b->exit_boot_services (grub_efi_image_handle, map_key); + status = efi_call_2 (b->exit_boot_services, grub_efi_image_handle, map_key); return status == GRUB_EFI_SUCCESS; } @@ -196,7 +194,7 @@ grub_get_rtc (void) grub_efi_runtime_services_t *r; r = grub_efi_system_table->runtime_services; - if (r->get_time (&time, 0) != GRUB_EFI_SUCCESS) + if (efi_call_2 (r->get_time, &time, 0) != GRUB_EFI_SUCCESS) /* What is possible in this case? */ return 0; diff --git a/kern/efi/mm.c b/kern/efi/mm.c index 9cd096d..94b8722 100644 --- a/kern/efi/mm.c +++ b/kern/efi/mm.c @@ -30,7 +30,7 @@ /* The size of a memory map obtained from the firmware. This must be a multiplier of 4KB. */ -#define MEMORY_MAP_SIZE 0x1000 +#define MEMORY_MAP_SIZE 0x3000 /* Maintain the list of allocated pages. */ struct allocated_page @@ -59,7 +59,7 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address, grub_efi_status_t status; grub_efi_boot_services_t *b; -#if GRUB_CPU_SIZEOF_VOID_P < 8 +#if GRUB_TARGET_SIZEOF_VOID_P < 8 /* Limit the memory access to less than 4GB for 32-bit platforms. */ if (address > 0xffffffff) return 0; @@ -79,7 +79,7 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address, #endif b = grub_efi_system_table->boot_services; - status = b->allocate_pages (type, GRUB_EFI_LOADER_DATA, pages, &address); + status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_LOADER_DATA, pages, &address); if (status != GRUB_EFI_SUCCESS) return 0; @@ -88,7 +88,7 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address, /* Uggh, the address 0 was allocated... This is too annoying, so reallocate another one. */ address = 0xffffffff; - status = b->allocate_pages (type, GRUB_EFI_LOADER_DATA, pages, &address); + status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_LOADER_DATA, pages, &address); grub_efi_free_pages (0, pages); if (status != GRUB_EFI_SUCCESS) return 0; @@ -135,7 +135,7 @@ grub_efi_free_pages (grub_efi_physical_address_t address, } b = grub_efi_system_table->boot_services; - b->free_pages (address, pages); + efi_call_2 (b->free_pages, address, pages); } /* Get the memory map as defined in the EFI spec. Return 1 if successful, @@ -159,7 +159,7 @@ grub_efi_get_memory_map (grub_efi_uintn_t *memory_map_size, descriptor_version = &version; b = grub_efi_system_table->boot_services; - status = b->get_memory_map (memory_map_size, memory_map, map_key, + status = efi_call_5 (b->get_memory_map, memory_map_size, memory_map, map_key, descriptor_size, descriptor_version); if (status == GRUB_EFI_SUCCESS) return 1; diff --git a/kern/main.c b/kern/main.c index 09de03a..776e8f3 100644 diff --git a/kern/partition.c b/kern/partition.c index b9a0457..48b8ad5 100644 diff --git a/kern/term.c b/kern/term.c index 4c45d71..07965b5 100644 --- a/kern/term.c +++ b/kern/term.c @@ -21,6 +21,7 @@ #include #include #include +#include /* The list of terminals. */ static grub_term_t grub_term_list; diff --git a/kern/x86_64/dl.c b/kern/x86_64/dl.c new file mode 100755 index 0000000..bef3270 --- /dev/null +++ b/kern/x86_64/dl.c @@ -0,0 +1,121 @@ +/* dl-x86_64.c - arch-dependent part of loadable module support */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2002,2005,2007 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 + +/* 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_Sym *symtab; + 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"); + + symtab = (Elf64_Sym *) ((char *) e + s->sh_offset); + 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 *) symtab + + entsize * ELF64_R_SYM (rel->r_info)); + + switch (ELF64_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", ELF64_R_TYPE (rel->r_info)); + } + } + } + } + + return GRUB_ERR_NONE; +} diff --git a/kern/x86_64/efi/callwrap.S b/kern/x86_64/efi/callwrap.S new file mode 100755 index 0000000..36e5509 --- /dev/null +++ b/kern/x86_64/efi/callwrap.S @@ -0,0 +1,96 @@ +/* callwrap.S - wrapper for x86_64 efi calls */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007 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 + +/* + * x86_64 uses registry to pass parameters. Unfortuanately, 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 $40, %rsp + call *%rdi + addq $40, %rsp + ret + +FUNCTION(efi_wrap_1) + subq $40, %rsp + mov %rsi, %rcx + call *%rdi + addq $40, %rsp + ret + +FUNCTION(efi_wrap_2) + subq $40, %rsp + mov %rsi, %rcx + call *%rdi + addq $40, %rsp + ret + +FUNCTION(efi_wrap_3) + subq $40, %rsp + mov %rcx, %r8 + mov %rsi, %rcx + call *%rdi + addq $40, %rsp + ret + +FUNCTION(efi_wrap_4) + subq $40, %rsp + mov %r8, %r9 + mov %rcx, %r8 + mov %rsi, %rcx + call *%rdi + addq $40, %rsp + ret + +FUNCTION(efi_wrap_5) + subq $40, %rsp + mov %r9, 32(%rsp) + mov %r8, %r9 + mov %rcx, %r8 + mov %rsi, %rcx + call *%rdi + addq $40, %rsp + ret + +FUNCTION(efi_wrap_6) + subq $56, %rsp + mov 56+8(%rsp), %rax + mov %rax, 40(%rsp) + mov %r9, (%rsp) + mov %r8, %r9 + mov %rcx, %r8 + mov %rsi, %rcx + call *%rdi + addq $56, %rsp + ret diff --git a/kern/x86_64/efi/startup.S b/kern/x86_64/efi/startup.S new file mode 100644 index 0000000..592f6a3 --- /dev/null +++ b/kern/x86_64/efi/startup.S @@ -0,0 +1,61 @@ +/* startup.S - bootstrap GRUB itself */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2006,2007 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 + + .file "startup.S" + .text + .globl start, _start +start: +_start: + jmp codestart + + /* + * Compatibility version number + * + * These MUST be at byte offset 6 and 7 of the executable + * DO NOT MOVE !!! + */ + . = EXT_C(start) + 0x6 + .byte GRUB_BOOT_VERSION_MAJOR, GRUB_BOOT_VERSION_MINOR + + /* + * This is a special data area 8 bytes from the beginning. + */ + + . = EXT_C(start) + 0x8 + +VARIABLE(grub_prefix) + /* to be filled by grub-mkimage */ + + /* + * Leave some breathing room for the prefix. + */ + + . = EXT_C(start) + 0x50 + +codestart: + + movq %rcx, EXT_C(grub_efi_image_handle) + movq %rdx, EXT_C(grub_efi_system_table) + + call EXT_C(grub_main) + ret diff --git a/loader/efi/chainloader.c b/loader/efi/chainloader.c index 19285d9..17a8c40 100644 --- a/loader/efi/chainloader.c +++ b/loader/efi/chainloader.c @@ -47,9 +47,9 @@ grub_chainloader_unload (void) grub_efi_boot_services_t *b; b = grub_efi_system_table->boot_services; - b->unload_image (image_handle); - b->free_pages (address, pages); - grub_free (file_path); + efi_call_1 (b->unload_image, image_handle); + efi_call_2 (b->free_pages, address, pages); + efi_call_1 (grub_free, file_path); grub_dl_unref (my_mod); return GRUB_ERR_NONE; @@ -64,7 +64,7 @@ grub_chainloader_boot (void) grub_efi_char16_t *exit_data; b = grub_efi_system_table->boot_services; - status = b->start_image (image_handle, &exit_data_size, &exit_data); + status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data); if (status != GRUB_EFI_SUCCESS) { if (exit_data) @@ -227,7 +227,7 @@ grub_chainloader_cmd (const char *filename) size = grub_file_size (file); pages = (((grub_efi_uintn_t) size + ((1 << 12) - 1)) >> 12); - status = b->allocate_pages (GRUB_EFI_ALLOCATE_ANY_PAGES, + status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_ANY_PAGES, GRUB_EFI_LOADER_CODE, pages, &address); if (status != GRUB_EFI_SUCCESS) @@ -244,7 +244,7 @@ grub_chainloader_cmd (const char *filename) goto fail; } - status = b->load_image (0, grub_efi_image_handle, file_path, + status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path, (void *) ((grub_addr_t) address), size, &image_handle); if (status != GRUB_EFI_SUCCESS) @@ -284,7 +284,7 @@ grub_chainloader_cmd (const char *filename) grub_free (file_path); if (address) - b->free_pages (address, pages); + efi_call_2 (b->free_pages, address, pages); grub_dl_unref (my_mod); } diff --git a/normal/x86_64/setjmp.S b/normal/x86_64/setjmp.S new file mode 100644 index 0000000..2b6622b --- /dev/null +++ b/normal/x86_64/setjmp.S @@ -0,0 +1,64 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2003,2007 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 + + .file "setjmp.S" + + .text + +/* + * jmp_buf: + * rbx rbp r12 r13 r14 r15 rsp rip + * 0 8 16 24 32 40 48 56 + */ + +/* + * int grub_setjmp (grub_jmp_buf env) + */ +FUNCTION(grub_setjmp) + movq %rbx, 0(%rdi) + movq %rbp, 8(%rdi) + movq %r12, 16(%rdi) + movq %r13, 24(%rdi) + movq %r14, 32(%rdi) + movq %r15, 40(%rdi) + leaq 8(%rsp), %rax + movq %rax, 48(%rdi) + movq (%rsp), %rax + movq %rax, 56(%rdi) + movq $0, %rax + ret + +/* + * int grub_longjmp (grub_jmp_buf env, int val) + */ +FUNCTION(grub_longjmp) + movq %rsi, %rax + + movq 8(%rdi), %rbp + + movq 48(%rdi), %rsp + pushq 56(%rdi) + movq 0(%rdi), %rbx + movq 16(%rdi), %r12 + movq 24(%rdi), %r13 + movq 32(%rdi), %r14 + movq 40(%rdi), %r15 + + ret diff --git a/term/efi/console.c b/term/efi/console.c index af198e5..3e88b28 100644 --- a/term/efi/console.c +++ b/term/efi/console.c @@ -52,10 +52,10 @@ grub_console_putchar (grub_uint32_t c) str[1] = 0; /* Should this test be cached? */ - if (c > 0x7f && o->test_string (o, str) != GRUB_EFI_SUCCESS) + if (c > 0x7f && efi_call_2 (o->test_string, o, str) != GRUB_EFI_SUCCESS) return; - o->output_string (o, str); + efi_call_2 (o->output_string, o, str); } static grub_ssize_t @@ -76,7 +76,7 @@ grub_console_checkkey (void) return 1; i = grub_efi_system_table->con_in; - status = i->read_key_stroke (i, &key); + status = efi_call_2 (i->read_key_stroke, i, &key); #if 1 switch (status) { @@ -169,7 +169,7 @@ grub_console_getkey (void) do { - status = b->wait_for_event (1, &(i->wait_for_key), &index); + status = efi_call_3 (b->wait_for_event, 1, &(i->wait_for_key), &index); if (status != GRUB_EFI_SUCCESS) return -1; @@ -189,7 +189,7 @@ grub_console_getwh (void) grub_efi_uintn_t columns, rows; o = grub_efi_system_table->con_out; - if (o->query_mode (o, o->mode->mode, &columns, &rows) != GRUB_EFI_SUCCESS) + if (efi_call_4 (o->query_mode, o, o->mode->mode, &columns, &rows) != GRUB_EFI_SUCCESS) { /* Why does this fail? */ columns = 80; @@ -214,7 +214,7 @@ grub_console_gotoxy (grub_uint8_t x, grub_uint8_t y) grub_efi_simple_text_output_interface_t *o; o = grub_efi_system_table->con_out; - o->set_cursor_position (o, x, y); + efi_call_3 (o->set_cursor_position, o, x, y); } static void @@ -225,9 +225,9 @@ grub_console_cls (void) o = grub_efi_system_table->con_out; orig_attr = o->mode->attribute; - o->set_attributes (o, GRUB_EFI_BACKGROUND_BLACK); - o->clear_screen (o); - o->set_attributes (o, orig_attr); + efi_call_2 (o->set_attributes, o, GRUB_EFI_BACKGROUND_BLACK); + efi_call_1 (o->clear_screen, o); + efi_call_2 (o->set_attributes, o, orig_attr); } static void @@ -239,13 +239,13 @@ grub_console_setcolorstate (grub_term_color_state state) switch (state) { case GRUB_TERM_COLOR_STANDARD: - o->set_attributes (o, grub_console_standard_color); + efi_call_2 (o->set_attributes, o, grub_console_standard_color); break; case GRUB_TERM_COLOR_NORMAL: - o->set_attributes (o, grub_console_normal_color); + efi_call_2 (o->set_attributes, o, grub_console_normal_color); break; case GRUB_TERM_COLOR_HIGHLIGHT: - o->set_attributes (o, grub_console_highlight_color); + efi_call_2 (o->set_attributes, o, grub_console_highlight_color); break; default: break; @@ -272,7 +272,7 @@ grub_console_setcursor (int on) grub_efi_simple_text_output_interface_t *o; o = grub_efi_system_table->con_out; - o->enable_cursor (o, on); + efi_call_2 (o->enable_cursor, o, on); } static struct grub_term grub_console_term = diff --git a/util/i386/efi/grub-mkimage.c b/util/i386/efi/grub-mkimage.c index 57c1fc8..af765d5 100644 --- a/util/i386/efi/grub-mkimage.c +++ b/util/i386/efi/grub-mkimage.c @@ -31,16 +31,56 @@ #include #include +#if GRUB_TARGET_SIZEOF_VOID_P == 4 + +typedef Elf32_Word Elf_Word; +typedef Elf32_Addr Elf_Addr; +typedef Elf32_Ehdr Elf_Ehdr; +typedef Elf32_Shdr Elf_Shdr; +typedef Elf32_Sym Elf_Sym; +typedef Elf32_Half Elf_Half; +typedef Elf32_Off Elf_Off; +typedef Elf32_Section Elf_Section; +typedef Elf32_Rel Elf_Rel; +typedef Elf32_Rela Elf_Rela; + +#define ELF_R_SYM ELF32_R_SYM +#define ELF_R_TYPE ELF32_R_TYPE +#define ELF_R_INFO ELF32_R_INFO + +#define grub_le_to_cpu grub_le_to_cpu32 + +#elif GRUB_TARGET_SIZEOF_VOID_P == 8 + +typedef Elf64_Word Elf_Word; +typedef Elf64_Addr Elf_Addr; +typedef Elf64_Ehdr Elf_Ehdr; +typedef Elf64_Shdr Elf_Shdr; +typedef Elf64_Sym Elf_Sym; +typedef Elf64_Half Elf_Half; +typedef Elf64_Off Elf_Off; +typedef Elf64_Section Elf_Section; +typedef Elf64_Rel Elf_Rel; +typedef Elf64_Rela Elf_Rela; + +#define ELF_R_SYM ELF64_R_SYM +#define ELF_R_TYPE ELF64_R_TYPE +#define ELF_R_INFO ELF64_R_INFO + +#define grub_le_to_cpu grub_le_to_cpu64 + +#endif + static const grub_uint8_t stub[] = GRUB_PE32_MSDOS_STUB; -static inline Elf32_Addr -align_address (Elf32_Addr addr, unsigned alignment) +static inline Elf_Addr +align_address (Elf_Addr addr, unsigned alignment) { return (addr + alignment - 1) & ~(alignment - 1); } -static inline Elf32_Addr -align_pe32_section (Elf32_Addr addr) +static inline Elf_Addr +align_pe32_section (Elf_Addr addr) { return align_address (addr, GRUB_PE32_SECTION_ALIGNMENT); } @@ -60,14 +100,15 @@ read_kernel_module (const char *dir, char *prefix, size_t *size) if (GRUB_KERNEL_MACHINE_PREFIX + strlen (prefix) + 1 > GRUB_KERNEL_MACHINE_DATA_END) grub_util_error ("prefix too long"); - strcpy (kernel_image + 0x34 + GRUB_KERNEL_MACHINE_PREFIX, prefix); + + //strcpy (kernel_image + 0x34 + GRUB_KERNEL_MACHINE_PREFIX, prefix); return kernel_image; } /* Return if the ELF header is valid. */ static int -check_elf_header (Elf32_Ehdr *e, size_t size) +check_elf_header (Elf_Ehdr *e, size_t size) { if (size < sizeof (*e) || e->e_ident[EI_MAG0] != ELFMAG0 @@ -76,9 +117,11 @@ check_elf_header (Elf32_Ehdr *e, size_t size) || e->e_ident[EI_MAG3] != ELFMAG3 || e->e_ident[EI_VERSION] != EV_CURRENT || e->e_version != grub_cpu_to_le32 (EV_CURRENT) - || e->e_ident[EI_CLASS] != ELFCLASS32 + || ((e->e_ident[EI_CLASS] != ELFCLASS32) && + (e->e_ident[EI_CLASS] != ELFCLASS64)) || e->e_ident[EI_DATA] != ELFDATA2LSB - || e->e_machine != grub_cpu_to_le16 (EM_386)) + || ((e->e_machine != grub_cpu_to_le16 (EM_386)) && + (e->e_machine != grub_cpu_to_le16 (EM_X86_64)))) return 0; return 1; @@ -87,7 +130,7 @@ check_elf_header (Elf32_Ehdr *e, size_t size) /* Return the starting address right after the header, aligned by the section alignment. Allocate 4 section tables for .text, .data, .reloc, and mods. */ -static Elf32_Addr +static Elf_Addr get_starting_section_address (void) { return align_pe32_section (sizeof (struct grub_pe32_header) @@ -97,7 +140,7 @@ get_starting_section_address (void) /* Determine if this section is a text section. Return false if this section is not allocated. */ static int -is_text_section (Elf32_Shdr *s) +is_text_section (Elf_Shdr *s) { return ((s->sh_flags & grub_cpu_to_le32 (SHF_EXECINSTR | SHF_ALLOC)) == grub_cpu_to_le32 (SHF_EXECINSTR | SHF_ALLOC)); @@ -107,7 +150,7 @@ is_text_section (Elf32_Shdr *s) BSS is also a data section, since the converter initializes BSS when producing PE32 to avoid a bug in EFI implementations. */ static int -is_data_section (Elf32_Shdr *s) +is_data_section (Elf_Shdr *s) { return (s->sh_flags & grub_cpu_to_le32 (SHF_ALLOC) && ! (s->sh_flags & grub_cpu_to_le32 (SHF_EXECINSTR))); @@ -116,14 +159,14 @@ is_data_section (Elf32_Shdr *s) /* Locate section addresses by merging code sections and data sections into .text and .data, respectively. Return the array of section addresses. */ -static Elf32_Addr * -locate_sections (Elf32_Shdr *sections, Elf32_Half section_entsize, - Elf32_Half num_sections, const char *strtab) +static Elf_Addr * +locate_sections (Elf_Shdr *sections, Elf_Half section_entsize, + Elf_Half num_sections, const char *strtab) { int i; - Elf32_Addr current_address; - Elf32_Addr *section_addresses; - Elf32_Shdr *s; + Elf_Addr current_address; + Elf_Addr *section_addresses; + Elf_Shdr *s; section_addresses = xmalloc (sizeof (*section_addresses) * num_sections); memset (section_addresses, 0, sizeof (*section_addresses) * num_sections); @@ -133,10 +176,10 @@ locate_sections (Elf32_Shdr *sections, Elf32_Half section_entsize, /* .text */ for (i = 0, s = sections; i < num_sections; - i++, s = (Elf32_Shdr *) ((char *) s + section_entsize)) + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if (is_text_section (s)) { - Elf32_Word align = grub_le_to_cpu32 (s->sh_addralign); + Elf_Word align = grub_le_to_cpu32 (s->sh_addralign); const char *name = strtab + grub_le_to_cpu32 (s->sh_name); if (align) @@ -153,10 +196,10 @@ locate_sections (Elf32_Shdr *sections, Elf32_Half section_entsize, /* .data */ for (i = 0, s = sections; i < num_sections; - i++, s = (Elf32_Shdr *) ((char *) s + section_entsize)) + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if (is_data_section (s)) { - Elf32_Word align = grub_le_to_cpu32 (s->sh_addralign); + Elf_Word align = grub_le_to_cpu32 (s->sh_addralign); const char *name = strtab + grub_le_to_cpu32 (s->sh_name); if (align) @@ -172,16 +215,16 @@ locate_sections (Elf32_Shdr *sections, Elf32_Half section_entsize, } /* Return the symbol table section, if any. */ -static Elf32_Shdr * -find_symtab_section (Elf32_Shdr *sections, - Elf32_Half section_entsize, Elf32_Half num_sections) +static Elf_Shdr * +find_symtab_section (Elf_Shdr *sections, + Elf_Half section_entsize, Elf_Half num_sections) { int i; - Elf32_Shdr *s; + Elf_Shdr *s; for (i = 0, s = sections; i < num_sections; - i++, s = (Elf32_Shdr *) ((char *) s + section_entsize)) + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if (s->sh_type == grub_cpu_to_le32 (SHT_SYMTAB)) return s; @@ -190,12 +233,12 @@ find_symtab_section (Elf32_Shdr *sections, /* Return the address of the string table. */ static const char * -find_strtab (Elf32_Ehdr *e, Elf32_Shdr *sections, Elf32_Half section_entsize) +find_strtab (Elf_Ehdr *e, Elf_Shdr *sections, Elf_Half section_entsize) { - Elf32_Shdr *s; + Elf_Shdr *s; char *strtab; - s = (Elf32_Shdr *) ((char *) sections + s = (Elf_Shdr *) ((char *) sections + grub_le_to_cpu16 (e->e_shstrndx) * section_entsize); strtab = (char *) e + grub_le_to_cpu32 (s->sh_offset); return strtab; @@ -203,21 +246,21 @@ find_strtab (Elf32_Ehdr *e, Elf32_Shdr *sections, Elf32_Half section_entsize) /* Relocate symbols; note that this function overwrites the symbol table. Return the address of a start symbol. */ -static Elf32_Addr -relocate_symbols (Elf32_Ehdr *e, Elf32_Shdr *sections, - Elf32_Shdr *symtab_section, Elf32_Addr *section_addresses, - Elf32_Half section_entsize, Elf32_Half num_sections) +static Elf_Addr +relocate_symbols (Elf_Ehdr *e, Elf_Shdr *sections, + Elf_Shdr *symtab_section, Elf_Addr *section_addresses, + Elf_Half section_entsize, Elf_Half num_sections) { - Elf32_Word symtab_size, sym_size, num_syms; - Elf32_Off symtab_offset; - Elf32_Addr start_address = 0; - Elf32_Sym *sym; - Elf32_Word i; - Elf32_Shdr *strtab_section; + Elf_Word symtab_size, sym_size, num_syms; + Elf_Off symtab_offset; + Elf_Addr start_address = 0; + Elf_Sym *sym; + Elf_Word i; + Elf_Shdr *strtab_section; const char *strtab; strtab_section - = (Elf32_Shdr *) ((char *) sections + = (Elf_Shdr *) ((char *) sections + (grub_le_to_cpu32 (symtab_section->sh_link) * section_entsize)); strtab = (char *) e + grub_le_to_cpu32 (strtab_section->sh_offset); @@ -227,17 +270,21 @@ relocate_symbols (Elf32_Ehdr *e, Elf32_Shdr *sections, symtab_offset = grub_le_to_cpu32 (symtab_section->sh_offset); num_syms = symtab_size / sym_size; - for (i = 0, sym = (Elf32_Sym *) ((char *) e + symtab_offset); + for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset); i < num_syms; - i++, sym = (Elf32_Sym *) ((char *) sym + sym_size)) + i++, sym = (Elf_Sym *) ((char *) sym + sym_size)) { - Elf32_Section index; + Elf_Section index; const char *name; name = strtab + grub_le_to_cpu32 (sym->st_name); index = grub_le_to_cpu16 (sym->st_shndx); - if (index == STN_UNDEF) + if (index == STN_ABS) + { + continue; + } + else if ((index == STN_UNDEF)) { if (sym->st_name) grub_util_error ("undefined symbol %s", name); @@ -260,22 +307,22 @@ relocate_symbols (Elf32_Ehdr *e, Elf32_Shdr *sections, } /* Return the address of a symbol at the index I in the section S. */ -static Elf32_Addr -get_symbol_address (Elf32_Ehdr *e, Elf32_Shdr *s, Elf32_Word i) +static Elf_Addr +get_symbol_address (Elf_Ehdr *e, Elf_Shdr *s, Elf_Word i) { - Elf32_Sym *sym; + Elf_Sym *sym; - sym = (Elf32_Sym *) ((char *) e + sym = (Elf_Sym *) ((char *) e + grub_le_to_cpu32 (s->sh_offset) + i * grub_le_to_cpu32 (s->sh_entsize)); return sym->st_value; } /* Return the address of a modified value. */ -static Elf32_Addr -get_target_address (Elf32_Ehdr *e, Elf32_Shdr *s, Elf32_Addr offset) +static Elf_Addr * +get_target_address (Elf_Ehdr *e, Elf_Shdr *s, Elf_Addr offset) { - return (Elf32_Addr) e + grub_le_to_cpu32 (s->sh_offset) + offset; + return (Elf_Addr *) ((char *) e + grub_le_to_cpu32 (s->sh_offset) + offset); } /* Deal with relocation information. This function relocates addresses @@ -283,34 +330,35 @@ get_target_address (Elf32_Ehdr *e, Elf32_Shdr *s, Elf32_Addr offset) addresses can be fully resolved. Absolute addresses must be relocated again by a PE32 relocator when loaded. */ static void -relocate_addresses (Elf32_Ehdr *e, Elf32_Shdr *sections, - Elf32_Addr *section_addresses, - Elf32_Half section_entsize, Elf32_Half num_sections, +relocate_addresses (Elf_Ehdr *e, Elf_Shdr *sections, + Elf_Addr *section_addresses, + Elf_Half section_entsize, Elf_Half num_sections, const char *strtab) { - Elf32_Half i; - Elf32_Shdr *s; + Elf_Half i; + Elf_Shdr *s; for (i = 0, s = sections; i < num_sections; - i++, s = (Elf32_Shdr *) ((char *) s + section_entsize)) - if (s->sh_type == grub_cpu_to_le32 (SHT_REL)) + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if ((s->sh_type == grub_cpu_to_le32 (SHT_REL)) || + (s->sh_type == grub_cpu_to_le32 (SHT_RELA))) { - Elf32_Rel *r; - Elf32_Word rtab_size, r_size, num_rs; - Elf32_Off rtab_offset; - Elf32_Shdr *symtab_section; - Elf32_Word target_section_index; - Elf32_Addr target_section_addr; - Elf32_Shdr *target_section; - Elf32_Word j; - - symtab_section = (Elf32_Shdr *) ((char *) sections + Elf_Rela *r; + Elf_Word rtab_size, r_size, num_rs; + Elf_Off rtab_offset; + Elf_Shdr *symtab_section; + Elf_Word target_section_index; + Elf_Addr target_section_addr; + Elf_Shdr *target_section; + Elf_Word j; + + symtab_section = (Elf_Shdr *) ((char *) sections + (grub_le_to_cpu32 (s->sh_link) * section_entsize)); target_section_index = grub_le_to_cpu32 (s->sh_info); target_section_addr = section_addresses[target_section_index]; - target_section = (Elf32_Shdr *) ((char *) sections + target_section = (Elf_Shdr *) ((char *) sections + (target_section_index * section_entsize)); @@ -323,47 +371,84 @@ relocate_addresses (Elf32_Ehdr *e, Elf32_Shdr *sections, rtab_offset = grub_le_to_cpu32 (s->sh_offset); num_rs = rtab_size / r_size; - for (j = 0, r = (Elf32_Rel *) ((char *) e + rtab_offset); + for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset); j < num_rs; - j++, r = (Elf32_Rel *) ((char *) r + r_size)) + j++, r = (Elf_Rela *) ((char *) r + r_size)) { - Elf32_Word info; - Elf32_Addr offset; - Elf32_Addr sym_addr; - Elf32_Addr *target; - - offset = grub_le_to_cpu32 (r->r_offset); - target = (Elf32_Addr *) get_target_address (e, target_section, - offset); - info = grub_le_to_cpu32 (r->r_info); + Elf_Addr info; + Elf_Addr offset; + Elf_Addr sym_addr; + Elf_Addr *target, *value; + + offset = grub_le_to_cpu (r->r_offset); + target = get_target_address (e, target_section, offset); + info = grub_le_to_cpu (r->r_info); sym_addr = get_symbol_address (e, symtab_section, - ELF32_R_SYM (info)); + ELF_R_SYM (info)); + + value = (s->sh_type == grub_cpu_to_le32 (SHT_RELA)) ? + (Elf_Addr *) &r->r_addend : target; - switch (ELF32_R_TYPE (info)) + switch (ELF_R_TYPE (info)) { +#if GRUB_TARGET_SIZEOF_VOID_P == 4 case R_386_NONE: break; case R_386_32: /* This is absolute. */ - *target = grub_cpu_to_le32 (grub_le_to_cpu32 (*target) - + sym_addr); + *target = grub_cpu_to_le32 (grub_le_to_cpu32 (*value) + + sym_addr); grub_util_info ("relocating an R_386_32 entry to 0x%x at the offset 0x%x", *target, offset); break; case R_386_PC32: /* This is relative. */ - *target = grub_cpu_to_le32 (grub_le_to_cpu32 (*target) + *target = grub_cpu_to_le32 (grub_le_to_cpu32 (*value) + sym_addr - target_section_addr - offset); grub_util_info ("relocating an R_386_PC32 entry to 0x%x at the offset 0x%x", *target, offset); break; +#else + + case R_X86_64_NONE: + break; + + case R_X86_64_64: + *target = grub_cpu_to_le64 (grub_le_to_cpu64 (*value) + sym_addr); + grub_util_info ("relocating an R_X86_64_64 entry to 0x%llx at the offset 0x%llx", + *target, offset); + break; + + case R_X86_64_PC32: + { + grub_uint32_t *t32 = (grub_uint32_t *) target; + *t32 = grub_cpu_to_le64 (grub_le_to_cpu64 (*value) + + sym_addr + - target_section_addr - offset); + grub_util_info ("relocating an R_X86_64_PC32 entry to 0x%x at the offset 0x%llx", + *t32, offset); + break; + } + + case R_X86_64_32: + case R_X86_64_32S: + { + grub_uint32_t *t32 = (grub_uint32_t *) target; + *t32 = grub_cpu_to_le64 (grub_le_to_cpu64 (*value) + + sym_addr); + grub_util_info ("relocating an R_X86_64_32(S) entry to 0x%x at the offset 0x%llx", + *t32, offset); + break; + } + +#endif default: grub_util_error ("unknown relocation type %d", - ELF32_R_TYPE (info)); + ELF_R_TYPE (info)); break; } } @@ -382,9 +467,9 @@ write_padding (FILE *out, size_t size) /* Add a PE32's fixup entry for a relocation. Return the resulting address after having written to the file OUT. */ -Elf32_Addr +Elf_Addr add_fixup_entry (struct grub_pe32_fixup_block **block, grub_uint16_t type, - Elf32_Addr addr, int flush, Elf32_Addr current_address, + Elf_Addr addr, int flush, Elf_Addr current_address, FILE *out) { struct grub_pe32_fixup_block *b = *block; @@ -400,7 +485,7 @@ add_fixup_entry (struct grub_pe32_fixup_block **block, grub_uint16_t type, { /* Add as much padding as necessary to align the address with a section boundary. */ - Elf32_Addr next_address; + Elf_Addr next_address; unsigned padding_size; size_t index; @@ -473,10 +558,10 @@ add_fixup_entry (struct grub_pe32_fixup_block **block, grub_uint16_t type, } /* Write out zeros to make space for the header. */ -static Elf32_Addr +static Elf_Addr make_header_space (FILE *out) { - Elf32_Addr addr; + Elf_Addr addr; addr = get_starting_section_address (); write_padding (out, addr); @@ -485,24 +570,24 @@ make_header_space (FILE *out) } /* Write text sections. */ -static Elf32_Addr -write_text_sections (FILE *out, Elf32_Addr current_address, - Elf32_Ehdr *e, Elf32_Shdr *sections, - Elf32_Half section_entsize, Elf32_Half num_sections, +static Elf_Addr +write_text_sections (FILE *out, Elf_Addr current_address, + Elf_Ehdr *e, Elf_Shdr *sections, + Elf_Half section_entsize, Elf_Half num_sections, const char *strtab) { - Elf32_Half i; - Elf32_Shdr *s; - Elf32_Addr addr; + Elf_Half i; + Elf_Shdr *s; + Elf_Addr addr; for (i = 0, s = sections; i < num_sections; - i++, s = (Elf32_Shdr *) ((char *) s + section_entsize)) + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if (is_text_section (s)) { - Elf32_Word align = grub_le_to_cpu32 (s->sh_addralign); - Elf32_Off offset = grub_le_to_cpu32 (s->sh_offset); - Elf32_Word size = grub_le_to_cpu32 (s->sh_size); + Elf_Word align = grub_le_to_cpu32 (s->sh_addralign); + Elf_Off offset = grub_le_to_cpu32 (s->sh_offset); + Elf_Word size = grub_le_to_cpu32 (s->sh_size); const char *name = strtab + grub_le_to_cpu32 (s->sh_name); if (align) @@ -538,24 +623,24 @@ write_text_sections (FILE *out, Elf32_Addr current_address, } /* Write data sections. */ -static Elf32_Addr -write_data_sections (FILE *out, Elf32_Addr current_address, - Elf32_Ehdr *e, Elf32_Shdr *sections, - Elf32_Half section_entsize, Elf32_Half num_sections, +static Elf_Addr +write_data_sections (FILE *out, Elf_Addr current_address, + Elf_Ehdr *e, Elf_Shdr *sections, + Elf_Half section_entsize, Elf_Half num_sections, const char *strtab) { - Elf32_Half i; - Elf32_Shdr *s; - Elf32_Addr addr; + Elf_Half i; + Elf_Shdr *s; + Elf_Addr addr; for (i = 0, s = sections; i < num_sections; - i++, s = (Elf32_Shdr *) ((char *) s + section_entsize)) + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) if (is_data_section (s)) { - Elf32_Word align = grub_le_to_cpu32 (s->sh_addralign); - Elf32_Off offset = grub_le_to_cpu32 (s->sh_offset); - Elf32_Word size = grub_le_to_cpu32 (s->sh_size); + Elf_Word align = grub_le_to_cpu32 (s->sh_addralign); + Elf_Off offset = grub_le_to_cpu32 (s->sh_offset); + Elf_Word size = grub_le_to_cpu32 (s->sh_size); const char *name = strtab + grub_le_to_cpu32 (s->sh_name); if (align) @@ -594,15 +679,15 @@ write_data_sections (FILE *out, Elf32_Addr current_address, } /* Write modules. */ -static Elf32_Addr -make_mods_section (FILE *out, Elf32_Addr current_address, +static Elf_Addr +make_mods_section (FILE *out, Elf_Addr current_address, const char *dir, char *mods[]) { struct grub_util_path_list *path_list; grub_size_t total_module_size; struct grub_util_path_list *p; struct grub_module_info modinfo; - Elf32_Addr addr; + Elf_Addr addr; path_list = grub_util_resolve_dependencies (dir, "moddep.lst", mods); @@ -666,26 +751,27 @@ make_mods_section (FILE *out, Elf32_Addr current_address, } /* Make a .reloc section. */ -static Elf32_Addr -make_reloc_section (FILE *out, Elf32_Addr current_address, Elf32_Ehdr *e, - Elf32_Addr *section_addresses, Elf32_Shdr *sections, - Elf32_Half section_entsize, Elf32_Half num_sections, +static Elf_Addr +make_reloc_section (FILE *out, Elf_Addr current_address, Elf_Ehdr *e, + Elf_Addr *section_addresses, Elf_Shdr *sections, + Elf_Half section_entsize, Elf_Half num_sections, const char *strtab) { - Elf32_Half i; - Elf32_Shdr *s; + Elf_Half i; + Elf_Shdr *s; struct grub_pe32_fixup_block *fixup_block = 0; for (i = 0, s = sections; i < num_sections; - i++, s = (Elf32_Shdr *) ((char *) s + section_entsize)) - if (s->sh_type == grub_cpu_to_le32 (SHT_REL)) + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if ((s->sh_type == grub_cpu_to_le32 (SHT_REL)) || + (s->sh_type == grub_cpu_to_le32 (SHT_RELA))) { - Elf32_Rel *r; - Elf32_Word rtab_size, r_size, num_rs; - Elf32_Off rtab_offset; - Elf32_Addr section_address; - Elf32_Word j; + Elf_Rel *r; + Elf_Word rtab_size, r_size, num_rs; + Elf_Off rtab_offset; + Elf_Addr section_address; + Elf_Word j; grub_util_info ("translating the relocation section %s", strtab + grub_le_to_cpu32 (s->sh_name)); @@ -697,20 +783,21 @@ make_reloc_section (FILE *out, Elf32_Addr current_address, Elf32_Ehdr *e, section_address = section_addresses[grub_le_to_cpu32 (s->sh_info)]; - for (j = 0, r = (Elf32_Rel *) ((char *) e + rtab_offset); + for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset); j < num_rs; - j++, r = (Elf32_Rel *) ((char *) r + r_size)) + j++, r = (Elf_Rel *) ((char *) r + r_size)) { - Elf32_Word info; - Elf32_Addr offset; + Elf_Addr info; + Elf_Addr offset; offset = grub_le_to_cpu32 (r->r_offset); info = grub_le_to_cpu32 (r->r_info); /* Necessary to relocate only absolute addresses. */ - if (ELF32_R_TYPE (info) == R_386_32) +#if GRUB_TARGET_SIZEOF_VOID_P == 4 + if (ELF_R_TYPE (info) == R_386_32) { - Elf32_Addr addr; + Elf_Addr addr; addr = section_address + offset; grub_util_info ("adding a relocation entry for 0x%x", addr); @@ -719,6 +806,21 @@ make_reloc_section (FILE *out, Elf32_Addr current_address, Elf32_Ehdr *e, addr, 0, current_address, out); } +#else + if ((ELF_R_TYPE (info) == R_X86_64_64) || + (ELF_R_TYPE (info) == R_X86_64_32) || + (ELF_R_TYPE (info) == R_X86_64_32S)) + { + Elf_Addr addr; + + addr = section_address + offset; + grub_util_info ("adding a relocation entry for 0x%llx", addr); + current_address = add_fixup_entry (&fixup_block, + GRUB_PE32_REL_BASED_HIGHLOW, + addr, 0, current_address, + out); + } +#endif } } @@ -730,9 +832,9 @@ make_reloc_section (FILE *out, Elf32_Addr current_address, Elf32_Ehdr *e, /* Create the header. */ static void -make_header (FILE *out, Elf32_Addr text_address, Elf32_Addr data_address, - Elf32_Addr mods_address, Elf32_Addr reloc_address, - Elf32_Addr end_address, Elf32_Addr start_address) +make_header (FILE *out, Elf_Addr text_address, Elf_Addr data_address, + Elf_Addr mods_address, Elf_Addr reloc_address, + Elf_Addr end_address, Elf_Addr start_address) { struct grub_pe32_header header; struct grub_pe32_coff_header *c; @@ -747,14 +849,22 @@ make_header (FILE *out, Elf32_Addr text_address, Elf32_Addr data_address, /* The COFF file header. */ c = &header.coff_header; +#if GRUB_TARGET_SIZEOF_VOID_P == 4 c->machine = grub_cpu_to_le16 (GRUB_PE32_MACHINE_I386); +#else + c->machine = grub_cpu_to_le16 (GRUB_PE32_MACHINE_X86_64); +#endif + c->num_sections = grub_cpu_to_le16 (4); c->time = grub_cpu_to_le32 (time (0)); c->optional_header_size = grub_cpu_to_le16 (sizeof (header.optional_header)); c->characteristics = grub_cpu_to_le16 (GRUB_PE32_EXECUTABLE_IMAGE | GRUB_PE32_LINE_NUMS_STRIPPED +#if GRUB_TARGET_SIZEOF_VOID_P == 4 + | GRUB_PE32_32BIT_MACHINE +#endif | GRUB_PE32_LOCAL_SYMS_STRIPPED - | GRUB_PE32_32BIT_MACHINE); + | GRUB_PE32_DEBUG_STRIPPED); /* The PE Optional header. */ o = &header.optional_header; @@ -764,7 +874,9 @@ make_header (FILE *out, Elf32_Addr text_address, Elf32_Addr data_address, o->bss_size = 0; o->entry_addr = grub_cpu_to_le32 (start_address); o->code_base = grub_cpu_to_le32 (text_address); +#if GRUB_TARGET_SIZEOF_VOID_P == 4 o->data_base = grub_cpu_to_le32 (data_address); +#endif o->image_base = 0; o->section_alignment = grub_cpu_to_le32 (GRUB_PE32_SECTION_ALIGNMENT); o->file_alignment = grub_cpu_to_le32 (GRUB_PE32_FILE_ALIGNMENT); @@ -847,30 +959,31 @@ convert_elf (const char *dir, char *prefix, FILE *out, char *mods[]) char *kernel_image; size_t kernel_size; const char *strtab; - Elf32_Ehdr *e; - Elf32_Shdr *sections; - Elf32_Off section_offset; - Elf32_Half section_entsize; - Elf32_Half num_sections; - Elf32_Addr *section_addresses; - Elf32_Shdr *symtab_section; - Elf32_Addr start_address; - Elf32_Addr text_address, data_address, reloc_address, mods_address; - Elf32_Addr end_address; + Elf_Ehdr *e; + Elf_Shdr *sections; + Elf_Off section_offset; + Elf_Half section_entsize; + Elf_Half num_sections; + Elf_Addr *section_addresses; + Elf_Shdr *symtab_section; + Elf_Addr start_address; + Elf_Addr text_address, data_address, reloc_address, mods_address; + Elf_Addr end_address; /* Get the kernel image and check the format. */ kernel_image = read_kernel_module (dir, prefix, &kernel_size); - e = (Elf32_Ehdr *) kernel_image; + e = (Elf_Ehdr *) kernel_image; if (! check_elf_header (e, kernel_size)) grub_util_error ("invalid ELF header"); section_offset = grub_cpu_to_le32 (e->e_shoff); section_entsize = grub_cpu_to_le16 (e->e_shentsize); num_sections = grub_cpu_to_le16 (e->e_shnum); + if (kernel_size < section_offset + section_entsize * num_sections) grub_util_error ("invalid ELF format"); - sections = (Elf32_Shdr *) (kernel_image + section_offset); + sections = (Elf_Shdr *) (kernel_image + section_offset); strtab = find_strtab (e, sections, section_entsize); /* Relocate sections then symbols in the virtual address space. */