diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk new file mode 100644 index 0000000..4339cf7 --- /dev/null +++ b/conf/x86_64-efi.rmk @@ -0,0 +1,154 @@ +# -*- 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 b/configure index 1f44d19..e7de78c 100755 --- a/configure +++ b/configure @@ -1927,13 +1927,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) ;; - *) { { echo "$as_me:$LINENO: error: unsupported CPU type" >&5 -echo "$as_me: error: unsupported CPU type" >&2;} - { (exit 1); exit 1; }; } ;; esac # Specify the platform (such as firmware). @@ -1959,9 +1952,31 @@ else platform="$with_platform" fi +if test "x$platform" = "xefi" ; then + case "$target_cpu" in + i386) ;; + x86_64) target_m64=1 ;; + *) { { echo "$as_me:$LINENO: error: unsupported CPU type for EFI" >&5 +echo "$as_me: error: unsupported CPU type for EFI" >&2;} + { (exit 1); exit 1; }; } ;; + esac +else + case "$target_cpu" in + i386) ;; + x86_64) target_cpu=i386 target_m32=1 ;; + powerpc) ;; + powerpc64) target_cpu=powerpc target_m32=1;; + sparc64) ;; + *) { { echo "$as_me:$LINENO: error: unsupported CPU type" >&5 +echo "$as_me: error: unsupported CPU type" >&2;} + { (exit 1); exit 1; }; } ;; + esac +fi + # Sanity check. case "$target_cpu"-"$platform" in i386-efi) ;; + x86_64-efi) ;; i386-pc) ;; i386-linuxbios) ;; i386-ieee1275) ;; @@ -6686,6 +6701,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/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/i386/linux.h b/include/grub/i386/linux.h old mode 100644 new mode 100755 index 7a8e006..cafb751 --- a/include/grub/i386/linux.h +++ b/include/grub/i386/linux.h @@ -44,14 +44,38 @@ #define GRUB_LINUX_SETUP_MOVE_SIZE 0x9100 #define GRUB_LINUX_CL_MAGIC 0xA33F +#ifdef __x86_64__ + +#define GRUB_LINUX_EFI_SIGNATURE \ + ('4' << 24 | '6' << 16 | 'L' << 8 | 'E') + +#else + #define GRUB_LINUX_EFI_SIGNATURE \ - ('E' << 24 | 'F' << 16 | 'I' << 8 | 'L') + ('2' << 24 | '3' << 16 | 'L' << 8 | 'E') + +#endif #define GRUB_LINUX_OFW_SIGNATURE \ (' ' << 24 | 'W' << 16 | 'F' << 8 | 'O') #ifndef ASM_FILE +#define GRUB_E820_RAM 1 +#define GRUB_E820_RESERVED 2 +#define GRUB_E820_ACPI 3 +#define GRUB_E820_NVS 4 +#define GRUB_E820_EXEC_CODE 5 + +#define GRUB_E820_MAX_ENTRY 128 + +struct grub_e820_mmap +{ + grub_uint64_t addr; + grub_uint64_t size; + grub_uint32_t type; +} __attribute__((packed)); + /* For the Linux/i386 boot protocol version 2.03. */ struct linux_kernel_header { @@ -173,17 +197,39 @@ struct linux_kernel_params grub_uint32_t efi_mmap; /* 1d0 */ grub_uint32_t efi_mmap_size; /* 1d4 */ - grub_uint8_t padding8[0x1e0 - 0x1d8]; + grub_uint32_t efi_system_table_hi; /* 1d8 */ + grub_uint32_t efi_mmap_hi; /* 1dc */ grub_uint32_t alt_mem; /* 1e0 */ - grub_uint8_t padding9[0x1e8 - 0x1e4]; + grub_uint8_t padding8[0x1e8 - 0x1e4]; grub_uint32_t mmap_size; /* 1e8 */ - grub_uint8_t padding10[0x1ff - 0x1ec]; + grub_uint8_t padding9[0x1ff - 0x1ec]; grub_uint8_t ps_mouse; /* 1ff */ + + grub_uint16_t jump; /* Jump instruction */ + grub_uint32_t header; /* Magic signature "HdrS" */ + grub_uint16_t version; /* Boot protocol version supported */ + grub_uint32_t realmode_swtch; /* Boot loader hook */ + grub_uint16_t start_sys; /* The load-low segment (obsolete) */ + grub_uint16_t kernel_version; /* Points to kernel version string */ + grub_uint8_t type_of_loader; /* Boot loader identifier */ + grub_uint8_t loadflags; /* Boot protocol option flags */ + grub_uint16_t setup_move_size; /* Move to high memory size */ + grub_uint32_t code32_start; /* Boot loader hook */ + grub_uint32_t ramdisk_image; /* initrd load address */ + grub_uint32_t ramdisk_size; /* initrd size */ + grub_uint32_t bootsect_kludge; /* obsolete */ + grub_uint16_t heap_end_ptr; /* Free memory after setup end */ + grub_uint16_t pad1; /* Unused */ + grub_uint32_t cmd_line_ptr; /* Points to the kernel command line */ + + grub_uint8_t pad2[164]; /* 22c */ + struct grub_e820_mmap e820_map[GRUB_E820_MAX_ENTRY]; /* 2d0 */ + } __attribute__ ((packed)); #endif /* ! ASM_FILE */ 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/linux.h b/include/grub/x86_64/linux.h new file mode 100644 index 0000000..19ea936 --- /dev/null +++ b/include/grub/x86_64/linux.h @@ -0,0 +1,19 @@ +/* + * 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 . + */ + +#include 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..d5239a5 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; @@ -218,7 +218,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) { if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY -#if GRUB_CPU_SIZEOF_VOID_P < 8 +#if GRUB_TARGET_SIZEOF_VOID_P < 8 && desc->physical_start <= 0xffffffff #endif && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000 @@ -234,7 +234,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, desc->physical_start = 0x100000; } -#if GRUB_CPU_SIZEOF_VOID_P < 8 +#if GRUB_TARGET_SIZEOF_VOID_P < 8 if (BYTES_TO_PAGES (filtered_desc->physical_start) + filtered_desc->num_pages > BYTES_TO_PAGES (0x100000000LL)) @@ -326,6 +326,7 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map, desc < memory_map_end; desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size), i++) { + if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY) grub_printf ("MD: t=%x, p=%llx, v=%llx, n=%llx, a=%llx\n", desc->type, desc->physical_start, desc->virtual_start, desc->num_pages, desc->attribute); 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..a79e772 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) @@ -86,7 +86,7 @@ grub_chainloader_boot (void) } if (exit_data) - b->free_pool (exit_data); + efi_call_1 (b->free_pool, exit_data); grub_chainloader_unload (); @@ -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/loader/i386/efi/linux.c b/loader/i386/efi/linux.c index ee3fb99..7300262 100644 --- a/loader/i386/efi/linux.c +++ b/loader/i386/efi/linux.c @@ -60,29 +60,25 @@ static grub_uint8_t gdt[] __attribute__ ((aligned(16))) = struct gdt_descriptor { - grub_uint16_t dummy; grub_uint16_t limit; - grub_uint32_t base; -} __attribute__ ((aligned(4), packed)); + void *base; +} __attribute__ ((packed)); static struct gdt_descriptor gdt_desc = { - 0, - sizeof (gdt) - 1, - (grub_addr_t) gdt + sizeof (gdt), + &gdt }; struct idt_descriptor { - grub_uint16_t dummy; grub_uint16_t limit; - grub_uint32_t base; -} __attribute__ ((aligned(4))); + void *base; +} __attribute__ ((packed)); static struct idt_descriptor idt_desc = { 0, - 0, 0 }; @@ -156,24 +152,28 @@ free_pages (void) /* Allocate pages for the real mode code and the protected mode code for linux as well as a memory map buffer. */ static int -allocate_pages (grub_size_t real_size, grub_size_t prot_size) +allocate_pages (grub_size_t prot_size) { grub_efi_uintn_t desc_size; grub_efi_memory_descriptor_t *mmap, *mmap_end; grub_efi_uintn_t mmap_size, tmp_mmap_size; grub_efi_memory_descriptor_t *desc; + grub_size_t real_size; /* Make sure that each size is aligned to a page boundary. */ - real_size = page_align (real_size + GRUB_DISK_SECTOR_SIZE); + real_size = page_align (sizeof (struct linux_kernel_params)); prot_size = page_align (prot_size); mmap_size = find_mmap_size (); + if (real_size + mmap_size > GRUB_LINUX_CL_OFFSET) + grub_fatal ("Memory map too large"); + grub_dprintf ("linux", "real_size = %x, prot_size = %x, mmap_size = %x\n", - real_size, prot_size, mmap_size); + (unsigned) real_size, (unsigned) prot_size, (unsigned) mmap_size); /* Calculate the number of pages; Combine the real mode code with the memory map buffer for simplicity. */ - real_mode_pages = ((real_size + mmap_size) >> 12); + real_mode_pages = ((GRUB_LINUX_CL_END_OFFSET + 1) >> 12); prot_mode_pages = (prot_size >> 12); /* Initialize the memory pointers with NULL for convenience. */ @@ -200,31 +200,20 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size) /* Probably it is better to put the real mode code in the traditional space for safety. */ if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY - && desc->physical_start <= 0x90000 + && desc->physical_start < 0xA0000 && desc->num_pages >= real_mode_pages) { - grub_efi_physical_address_t physical_end; - grub_efi_physical_address_t addr; + grub_efi_physical_address_t addr; - physical_end = desc->physical_start + (desc->num_pages << 12); - if (physical_end > 0x90000) - physical_end = 0x90000; - - grub_dprintf ("linux", "physical_start = %x, physical_end = %x\n", - (unsigned) desc->physical_start, - (unsigned) physical_end); - addr = physical_end - real_size - mmap_size; - if (addr < 0x10000) - continue; - - grub_dprintf ("linux", "trying to allocate %u pages at %x\n", - real_mode_pages, (unsigned) addr); - real_mode_mem = grub_efi_allocate_pages (addr, real_mode_pages); - if (! real_mode_mem) - grub_fatal ("cannot allocate pages"); - - desc->num_pages -= real_mode_pages; - break; + addr = desc->physical_start + ((desc->num_pages - real_mode_pages) << 12); + + if (addr > 0x90000) + addr = 0x90000; + + /* There could be multiple ranges that means the condition, + * use the highest one. */ + if (addr > real_mode_mem) + real_mode_mem = addr; } } @@ -233,6 +222,12 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size) grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages"); goto fail; } + else + { + real_mode_mem = grub_efi_allocate_pages (real_mode_mem, real_mode_pages); + if (! real_mode_mem) + grub_fatal ("cannot allocate pages"); + } mmap_buf = (void *) ((char *) real_mode_mem + real_size); @@ -255,56 +250,182 @@ allocate_pages (grub_size_t real_size, grub_size_t prot_size) return 0; } +static void +grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num, + grub_uint64_t start, grub_uint64_t size, + grub_uint32_t type) +{ + int n = *e820_num; + + if (n >= GRUB_E820_MAX_ENTRY) + grub_fatal ("Too many e820 memory map entries"); + + if ((n > 0) && (e820_map[n - 1].addr + e820_map[n - 1].size == start) && + (e820_map[n - 1].type == type)) + e820_map[n - 1].size += size; + else + { + e820_map[n].addr = start; + e820_map[n].size = size; + e820_map[n].type = type; + (*e820_num)++; + } +} + +#ifdef __x86_64__ +struct +{ + grub_uint32_t kernel_entry; + grub_uint32_t kernel_cs; +} jumpvector; +void *jump_start; +#endif + static grub_err_t grub_linux_boot (void) { - struct linux_kernel_header *lh; struct linux_kernel_params *params; grub_efi_uintn_t mmap_size; grub_efi_uintn_t map_key; grub_efi_uintn_t desc_size; grub_efi_uint32_t desc_version; + grub_efi_memory_descriptor_t *desc; + int e820_num; - lh = real_mode_mem; params = real_mode_mem; grub_dprintf ("linux", "code32_start = %x, idt_desc = %x, gdt_desc = %x\n", - (unsigned) lh->code32_start, (grub_addr_t) &(idt_desc.limit), + (unsigned) params->code32_start, (grub_addr_t) &(idt_desc.limit), (grub_addr_t) &(gdt_desc.limit)); grub_dprintf ("linux", "idt = %x:%x, gdt = %x:%x\n", (unsigned) idt_desc.limit, (unsigned) idt_desc.base, (unsigned) gdt_desc.limit, (unsigned) gdt_desc.base); + mmap_size = find_mmap_size (); if (grub_efi_get_memory_map (&mmap_size, mmap_buf, &map_key, &desc_size, &desc_version) <= 0) grub_fatal ("cannot get memory map"); + e820_num = 0; + for (desc = mmap_buf; + desc < NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); + desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) + { + switch (desc->type) + { + case GRUB_EFI_ACPI_RECLAIM_MEMORY: + grub_e820_add_region(params->e820_map, &e820_num, + desc->physical_start, + desc->num_pages << 12, + GRUB_E820_ACPI); + break; + + case GRUB_EFI_ACPI_MEMORY_NVS: + grub_e820_add_region(params->e820_map, &e820_num, + desc->physical_start, + desc->num_pages << 12, + GRUB_E820_NVS); + break; + + case GRUB_EFI_RUNTIME_SERVICES_CODE: + grub_e820_add_region(params->e820_map, &e820_num, + desc->physical_start, + desc->num_pages << 12, + GRUB_E820_EXEC_CODE); + break; + + case GRUB_EFI_LOADER_CODE: + case GRUB_EFI_LOADER_DATA: + case GRUB_EFI_BOOT_SERVICES_CODE: + case GRUB_EFI_BOOT_SERVICES_DATA: + case GRUB_EFI_CONVENTIONAL_MEMORY: + { + grub_uint64_t start, size, end; + + start = desc->physical_start; + size = desc->num_pages << 12; + end = start + size; + + /* Skip A0000 - 100000 region. */ + if ((start < 0x100000ULL) && (end > 0xA0000ULL)) + { + if (start < 0xA0000ULL) + { + grub_e820_add_region (params->e820_map, &e820_num, + start, + 0xA0000ULL - start, + GRUB_E820_RAM); + } + + if (end <= 0x100000ULL) + continue; + + start = 0x100000ULL; + size = end - start; + } + + grub_e820_add_region (params->e820_map, &e820_num, + start, size, GRUB_E820_RAM); + break; + } + + default: + grub_e820_add_region(params->e820_map, &e820_num, + desc->physical_start, + desc->num_pages << 12, + GRUB_E820_RESERVED); + } + } + + params->mmap_size = e820_num; + if (! grub_efi_exit_boot_services (map_key)) - grub_fatal ("cannot exit boot services"); + grub_fatal ("cannot exit boot services"); /* Note that no boot services are available from here. */ - /* Hardware interrupts are not safe any longer. */ - asm volatile ("cli" : : ); - /* Pass EFI parameters. */ params->efi_mem_desc_size = desc_size; params->efi_mem_desc_version = desc_version; - params->efi_mmap = (grub_addr_t) mmap_buf; + params->efi_mmap = (grub_uint32_t) mmap_buf; +#ifdef __x86_64__ + params->efi_mmap_hi = (grub_uint32_t) ((grub_uint64_t) mmap_buf >> 32); +#endif params->efi_mmap_size = mmap_size; + /* Hardware interrupts are not safe any longer. */ + asm volatile ("cli" : : ); + +#ifdef __x86_64__ + + jumpvector.kernel_entry = params->code32_start; + jumpvector.kernel_cs = 0x10; + jump_start = (void *) &jumpvector; + + asm volatile ("lidt %0" : : "m" (idt_desc)); + asm volatile ("lgdt %0" : : "m" (gdt_desc)); + + asm volatile ( "mov %0, %%rsi" : : "m" (real_mode_mem) ); + + asm volatile ( "mov %0, %%rcx" : : "m" (jump_start) ); + asm volatile ( "ljmp *(%%rcx)" : :); + +#else + /* Pass parameters. */ asm volatile ("movl %0, %%esi" : : "m" (real_mode_mem)); - asm volatile ("movl %0, %%ecx" : : "m" (lh->code32_start)); + asm volatile ("movl %0, %%ecx" : : "m" (params->code32_start)); asm volatile ("xorl %%ebx, %%ebx" : : ); /* Load the IDT and the GDT for the bootstrap. */ - asm volatile ("lidt %0" : : "m" (idt_desc.limit)); - asm volatile ("lgdt %0" : : "m" (gdt_desc.limit)); + asm volatile ("lidt %0" : : "m" (idt_desc)); + asm volatile ("lgdt %0" : : "m" (gdt_desc)); /* Enter Linux. */ asm volatile ("jmp *%%ecx" : : ); +#endif + /* Never reach here. */ return GRUB_ERR_NONE; } @@ -384,19 +505,22 @@ grub_rescue_cmd_linux (int argc, char *argv[]) real_size = setup_sects << GRUB_DISK_SECTOR_BITS; prot_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE; - if (! allocate_pages (real_size, prot_size)) + if (! allocate_pages (prot_size)) goto fail; - /* XXX Linux assumes that only elilo can boot Linux on EFI!!! */ - lh.type_of_loader = 0x50; + params = (struct linux_kernel_params *) real_mode_mem; + grub_memset (params, 0, sizeof (struct linux_kernel_params)); + grub_memcpy (¶ms->jump, &lh.jump, + (char *) &lh.ramdisk_image - (char *) &lh.jump); - lh.cl_magic = GRUB_LINUX_CL_MAGIC; - lh.cl_offset = GRUB_LINUX_CL_END_OFFSET; - lh.cmd_line_ptr = (char *) real_mode_mem + GRUB_LINUX_CL_OFFSET; - lh.ramdisk_image = 0; - lh.ramdisk_size = 0; + /* XXX Linux assumes that only elilo can boot Linux on EFI!!! */ + params->type_of_loader = 0x50; - params = (struct linux_kernel_params *) &lh; + params->cl_magic = GRUB_LINUX_CL_MAGIC; + params->cl_offset = GRUB_LINUX_CL_END_OFFSET; + params->cmd_line_ptr = (grub_uint32_t) real_mode_mem + GRUB_LINUX_CL_OFFSET; + params->ramdisk_image = 0; + params->ramdisk_size = 0; /* These are not needed to be precise, because Linux uses these values only to raise an error when the decompression code cannot find good @@ -414,6 +538,15 @@ grub_rescue_cmd_linux (int argc, char *argv[]) params->have_vga = 0; params->font_size = 16; /* XXX */ + params->efi_signature = GRUB_LINUX_EFI_SIGNATURE; /* XXX not used */ + params->efi_system_table = (grub_uint32_t) grub_efi_system_table; +#ifdef __x86_64__ + params->efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32); +#endif + +#if 0 + /* The structure is zeroed already. */ + /* No VBE on EFI. */ params->lfb_width = 0; params->lfb_height = 0; @@ -457,10 +590,6 @@ grub_rescue_cmd_linux (int argc, char *argv[]) /* No MCA on EFI. */ params->rom_config_len = 0; - params->efi_signature = GRUB_LINUX_EFI_SIGNATURE; /* XXX not used */ - params->efi_system_table = (grub_addr_t) grub_efi_system_table; - /* The other EFI parameters are filled when booting. */ - /* No need to fake the BIOS's memory map. */ params->mmap_size = 0; @@ -478,19 +607,15 @@ grub_rescue_cmd_linux (int argc, char *argv[]) grub_memset (params->padding8, 0, sizeof (params->padding8)); grub_memset (params->padding9, 0, sizeof (params->padding9)); - /* Put the real mode code at the real location. */ - grub_memmove (real_mode_mem, &lh, sizeof (lh)); +#endif - len = real_size + GRUB_DISK_SECTOR_SIZE - sizeof (lh); - if (grub_file_read (file, (char *) real_mode_mem + sizeof (lh), len) != len) - { - grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file"); - goto fail; - } + /* The other EFI parameters are filled when booting. */ + + grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE); /* XXX there is no way to know if the kernel really supports EFI. */ grub_printf (" [Linux-EFI, setup=0x%x, size=0x%x]\n", - real_size, prot_size); + (unsigned) real_size, (unsigned) prot_size); /* Detect explicitly specified memory size, if any. */ linux_mem_size = 0; @@ -601,7 +726,7 @@ grub_rescue_cmd_initrd (int argc, char *argv[]) lh = (struct linux_kernel_header *) real_mode_mem; - addr_max = grub_cpu_to_le32 (lh->initrd_addr_max); + addr_max = (grub_cpu_to_le32 (lh->initrd_addr_max) << 10); if (linux_mem_size != 0 && linux_mem_size < addr_max) addr_max = linux_mem_size; @@ -612,7 +737,8 @@ grub_rescue_cmd_initrd (int argc, char *argv[]) addr_max -= 0x10000; /* Usually, the compression ratio is about 50%. */ - addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12); + addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12) + + page_align (size); /* Find the highest address to put the initrd. */ mmap_size = find_mmap_size (); @@ -625,8 +751,6 @@ grub_rescue_cmd_initrd (int argc, char *argv[]) desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) { if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY - && desc->physical_start >= addr_min - && desc->physical_start + size < addr_max && desc->num_pages >= initrd_pages) { grub_efi_physical_address_t physical_end; @@ -635,6 +759,9 @@ grub_rescue_cmd_initrd (int argc, char *argv[]) if (physical_end > addr_max) physical_end = addr_max; + if (physical_end < addr_min) + continue; + if (physical_end > addr) addr = physical_end - page_align (size); } @@ -657,7 +784,7 @@ grub_rescue_cmd_initrd (int argc, char *argv[]) } grub_printf (" [Initrd, addr=0x%x, size=0x%x]\n", - addr, size); + (unsigned) addr, (unsigned) size); lh->ramdisk_image = addr; lh->ramdisk_size = size; diff --git a/normal/x86_64/setjmp.S b/normal/x86_64/setjmp.S new file mode 100644 index 0000000..4beb90c --- /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..9bd4264 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 + sizeof (Elf_Ehdr) + 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. */