Hi, This patch contains several important update for x86_64 efi:
1, Support memory larger than 2G. 2, Fix a bug in efi_call_6 that could cause chainloadering osx to fail. 3, Improve the method to detect frame buffer address and line length in linux loader. 2009-02-19 Bean <bean12...@gmail.com> * configure.ac: Check for -mcmodel=large in x86_64 target. * include/grub/efi/api.h (efi_call_10): New macro. (efi_wrap_10): New function. * include/grub/efi/pe32.h (GRUB_PE32_REL_BASE_HIGH): New macro. (GRUB_PE32_REL_BASED_HIGH): Likewise. (GRUB_PE32_REL_BASED_LOW): Likewise. (GRUB_PE32_REL_BASED_HIGHLOW): Likewise. (GRUB_PE32_REL_BASED_HIGHADJ): Likewise. (GRUB_PE32_REL_BASED_MIPS_JMPADDR): Likewise. (GRUB_PE32_REL_BASED_SECTION): Likewise. (GRUB_PE32_REL_BASED_REL): Likewise. (GRUB_PE32_REL_BASED_IA64_IMM64): Likewise. (GRUB_PE32_REL_BASED_DIR64): Likewise. (GRUB_PE32_REL_BASED_HIGH3ADJ): Likewise. * kern/x86_64/dl.c (grub_arch_dl_relocate_symbols): Fixed relocation issue. * kern/x86_64/efi/callwrap.S (efi_wrap_6): Bug fix. (efi_wrap_10): New function. * kern/x86_64/efi/startup.S (codestart): Use relative addressing. * loader/efi/appleloader.c (devpath_5): Add support for late 2008 MB/MBP model (NV chipset). (devdata_devs): Add devpath_5 to the list. * load/i386/efi/linux.c (video_base): Remove variable. (RGB_MASK): New macro. (RGB_MAGIC): Likewise. (LINE_MIN): Likewise. (LINE_MAX): Likewise. (FBTEST_STEP): Likewise. (FBTEST_COUNT): Likewise. (fb_list): New variable. (grub_find_video_card): Remove function. (find_framebuf): New function. (grub_linux_setup_video): Use find_framebuf to get frame buffer and line length. * util/i386/efi/grub-mkimage.c (grub_reloc_section): Fix relocation problem for x86_64. -- Bean
diff --git a/configure.ac b/configure.ac index 7658c7a..fd89d30 100644 --- a/configure.ac +++ b/configure.ac @@ -299,7 +299,16 @@ fi if test "x$target_m64" = x1; then # Force 64-bit mode. - TARGET_CFLAGS="$TARGET_CFLAGS -m64" + AC_CACHE_CHECK([whether option -mcmodel=large works], grub_cv_cc_mcmodel, [ + CFLAGS="-m64 -mcmodel=large" + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], + [grub_cv_cc_mcmodel=yes], + [grub_cv_cc_mcmodel=no]) + ]) + if test "x$grub_cv_cc_mcmodel" = xno; then + AC_MSG_ERROR([-mcmodel=large not supported, upgrade your gcc]) + fi + TARGET_CFLAGS="$TARGET_CFLAGS -m64 -mcmodel=large" TARGET_LDFLAGS="$TARGET_LDFLAGS -m64" fi diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h index 44b7d27..8c38fc9 100644 --- a/include/grub/efi/api.h +++ b/include/grub/efi/api.h @@ -1104,16 +1104,31 @@ typedef struct grub_efi_block_io grub_efi_block_io_t; #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) +#define efi_call_10(func, a, b, c, d, e, f, g, h, i, j) func(a, b, c, d, e, f, g, h, i, j) #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) +#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) +#define efi_call_10(func, a, b, c, d, e, f, g, h, i, j) \ + efi_wrap_10(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) g, \ + (grub_uint64_t) h, (grub_uint64_t) i, (grub_uint64_t) j) grub_uint64_t EXPORT_FUNC(efi_wrap_0) (void *func); grub_uint64_t EXPORT_FUNC(efi_wrap_1) (void *func, grub_uint64_t arg1); @@ -1131,6 +1146,12 @@ 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); +grub_uint64_t EXPORT_FUNC(efi_wrap_10) (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, grub_uint64_t arg7, + grub_uint64_t arg8, grub_uint64_t arg9, + grub_uint64_t arg10); #endif #endif /* ! GRUB_EFI_API_HEADER */ diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h index 50b4102..4fb8d09 100644 --- a/include/grub/efi/pe32.h +++ b/include/grub/efi/pe32.h @@ -231,7 +231,16 @@ struct grub_pe32_fixup_block #define GRUB_PE32_FIXUP_ENTRY(type, offset) (((type) << 12) | (offset)) #define GRUB_PE32_REL_BASED_ABSOLUTE 0 +#define GRUB_PE32_REL_BASED_HIGH 1 +#define GRUB_PE32_REL_BASED_LOW 2 #define GRUB_PE32_REL_BASED_HIGHLOW 3 +#define GRUB_PE32_REL_BASED_HIGHADJ 4 +#define GRUB_PE32_REL_BASED_MIPS_JMPADDR 5 +#define GRUB_PE32_REL_BASED_SECTION 6 +#define GRUB_PE32_REL_BASED_REL 7 +#define GRUB_PE32_REL_BASED_IA64_IMM64 9 +#define GRUB_PE32_REL_BASED_DIR64 10 +#define GRUB_PE32_REL_BASED_HIGH3ADJ 11 struct grub_pe32_symbol { diff --git a/kern/x86_64/dl.c b/kern/x86_64/dl.c index bef3270..a84ac44 100644 --- a/kern/x86_64/dl.c +++ b/kern/x86_64/dl.c @@ -97,17 +97,17 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) switch (ELF64_R_TYPE (rel->r_info)) { case R_X86_64_64: - *addr64 = rel->r_addend + sym->st_value; + *addr64 += rel->r_addend + sym->st_value; break; case R_X86_64_PC32: - *addr32 = rel->r_addend + sym->st_value - + *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; + *addr32 += rel->r_addend + sym->st_value; break; default: diff --git a/kern/x86_64/efi/callwrap.S b/kern/x86_64/efi/callwrap.S index 6c390ec..558d280 100644 --- a/kern/x86_64/efi/callwrap.S +++ b/kern/x86_64/efi/callwrap.S @@ -1,7 +1,7 @@ /* callwrap.S - wrapper for x86_64 efi calls */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2009 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -87,10 +87,30 @@ FUNCTION(efi_wrap_6) subq $56, %rsp mov 56+8(%rsp), %rax mov %rax, 40(%rsp) - mov %r9, (%rsp) + mov %r9, 32(%rsp) mov %r8, %r9 mov %rcx, %r8 mov %rsi, %rcx call *%rdi addq $56, %rsp ret + +FUNCTION(efi_wrap_10) + subq $88, %rsp + mov 88+40(%rsp), %rax + mov %rax, 72(%rsp) + mov 88+32(%rsp), %rax + mov %rax, 64(%rsp) + mov 88+24(%rsp), %rax + mov %rax, 56(%rsp) + mov 88+16(%rsp), %rax + mov %rax, 48(%rsp) + mov 88+8(%rsp), %rax + mov %rax, 40(%rsp) + mov %r9, 32(%rsp) + mov %r8, %r9 + mov %rcx, %r8 + mov %rsi, %rcx + call *%rdi + addq $88, %rsp + ret \ No newline at end of file diff --git a/kern/x86_64/efi/startup.S b/kern/x86_64/efi/startup.S index 2fa6766..835c4fb 100644 --- a/kern/x86_64/efi/startup.S +++ b/kern/x86_64/efi/startup.S @@ -1,7 +1,7 @@ /* startup.S - bootstrap GRUB itself */ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2009 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -55,9 +55,8 @@ VARIABLE(grub_prefix) . = EXT_C(start) + 0x50 codestart: - - movq %rcx, EXT_C(grub_efi_image_handle) - movq %rdx, EXT_C(grub_efi_system_table) + movq %rcx, EXT_C(grub_efi_image_handle)(%rip) + movq %rdx, EXT_C(grub_efi_system_table)(%rip) call EXT_C(grub_main) ret diff --git a/loader/efi/appleloader.c b/loader/efi/appleloader.c index 910a13d..5e9936c 100644 --- a/loader/efi/appleloader.c +++ b/loader/efi/appleloader.c @@ -103,6 +103,16 @@ static grub_uint8_t devpath_4[] = 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, }; +/* late-2008 MB/MBP (NVidia chipset) */ +static grub_uint8_t devpath_5[] = { + 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x40, 0xCB, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xBF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, + 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00, +}; + struct devdata { char *model; @@ -115,6 +125,7 @@ struct devdata devs[] = {"Mac Pro", (grub_efi_device_path_t *) devpath_2}, {"MBP", (grub_efi_device_path_t *) devpath_3}, {"MBA", (grub_efi_device_path_t *) devpath_4}, + {"MB NV", (grub_efi_device_path_t *) devpath_5}, {NULL, NULL}, }; diff --git a/loader/i386/efi/linux.c b/loader/i386/efi/linux.c index 50e1ff1..af1821e 100644 --- a/loader/i386/efi/linux.c +++ b/loader/i386/efi/linux.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2006,2007,2008,2009 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,7 +31,6 @@ #include <grub/efi/api.h> #include <grub/efi/efi.h> #include <grub/efi/uga_draw.h> -#include <grub/pci.h> #define GRUB_LINUX_CL_OFFSET 0x1000 #define GRUB_LINUX_CL_END_OFFSET 0x2000 @@ -458,68 +457,59 @@ grub_linux_unload (void) return GRUB_ERR_NONE; } -grub_uint64_t video_base; +static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID; + + +#define RGB_MASK 0xffffff +#define RGB_MAGIC 0x121314 +#define LINE_MIN 800 +#define LINE_MAX 4096 +#define FBTEST_STEP (0x10000 >> 2) +#define FBTEST_COUNT 8 + +static grub_uint32_t fb_list[]= + {0x40000000, 0x80000000, 0xc0000000, 0}; static int -grub_find_video_card (int bus, int dev, int func, - grub_pci_id_t pciid __attribute__ ((unused))) +find_framebuf (grub_uint32_t *fb_base, grub_uint32_t *line_len) { - grub_pci_address_t addr; - - addr = grub_pci_make_address (bus, dev, func, 2); + grub_uint32_t *fb; - if (grub_pci_read (addr) >> 24 == 0x3) + for (fb = fb_list; *fb; fb++) { + grub_uint32_t *base = (grub_uint32_t *) (grub_target_addr_t) *fb; int i; - addr = grub_pci_make_address (bus, dev, func, 4); - for (i = 0; i < 6; i++, addr += 4) + for (i = 0; i < FBTEST_COUNT; i++, base += FBTEST_STEP) { - grub_uint32_t base, type; - - base = grub_pci_read (addr); - - if ((base == 0) || (base == 0xffffffff) || - (base & GRUB_PCI_ADDR_SPACE_IO)) - continue; + if ((*base & RGB_MASK) == RGB_MAGIC) + { + int j; - type = base & GRUB_PCI_ADDR_MEM_TYPE_MASK; - if (! (addr & GRUB_PCI_ADDR_MEM_PREFETCH)) + for (j = LINE_MIN; j <= LINE_MAX; j++) { - if (type == GRUB_PCI_ADDR_MEM_TYPE_64) + if ((base[j] & RGB_MASK) == RGB_MAGIC) { - i++; - addr +=4 ; + *fb_base = (grub_uint32_t) (grub_target_addr_t) base; + *line_len = j << 2; + + return 0; } - continue; } - base &= GRUB_PCI_ADDR_MEM_MASK; - if (type == GRUB_PCI_ADDR_MEM_TYPE_64) - { - if (i == 5) break; - - video_base = grub_pci_read (addr + 4); - video_base <<= 32; } - - video_base |= base; - - return 1; } } - - return 0; + return 1; } -static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID; - static int grub_linux_setup_video (struct linux_kernel_params *params) { grub_efi_uga_draw_protocol_t *c; - grub_uint32_t width, height, depth, rate; + grub_uint32_t width, height, depth, rate, pixel, fb_base, line_len; + int ret; c = grub_efi_locate_protocol (&uga_draw_guid, 0); if (! c) @@ -530,26 +520,29 @@ grub_linux_setup_video (struct linux_kernel_params *params) grub_printf ("Video mode: %ux%u...@%u\n", width, height, depth, rate); - video_base = 0; - grub_pci_iterate (grub_find_video_card); + grub_efi_set_text_mode (0); + pixel = RGB_MAGIC; + efi_call_10 (c->blt, c, &pixel, GRUB_EFI_UGA_VIDEO_FILL, + 0, 0, 0, 0, 1, height, 0); + ret = find_framebuf (&fb_base, &line_len); + grub_efi_set_text_mode (1); - if (! video_base) + if (ret) { grub_printf ("Can\'t find frame buffer address\n"); return 1; } - grub_printf ("Video frame buffer: %llx\n", (unsigned long long) video_base); + grub_printf ("Video frame buffer: 0x%x\n", fb_base); + grub_printf ("Video line length: %d\n", line_len); params->lfb_width = width; params->lfb_height = height; params->lfb_depth = depth; + params->lfb_line_len = line_len; - /* FIXME: shouldn't use fixed value. */ - params->lfb_line_len = 8192; - - params->lfb_base = video_base; - params->lfb_size = (params->lfb_line_len * params->lfb_height + 65535) >> 16; + params->lfb_base = fb_base; + params->lfb_size = (line_len * params->lfb_height + 65535) >> 16; params->red_mask_size = 8; params->red_field_pos = 16; diff --git a/util/i386/efi/grub-mkimage.c b/util/i386/efi/grub-mkimage.c index 36ea31f..52a37b9 100644 --- a/util/i386/efi/grub-mkimage.c +++ b/util/i386/efi/grub-mkimage.c @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2004,2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -807,17 +807,21 @@ make_reloc_section (FILE *out, Elf_Addr current_address, Elf_Ehdr *e, out); } #else - if ((ELF_R_TYPE (info) == R_X86_64_64) || - (ELF_R_TYPE (info) == R_X86_64_32) || + if ((ELF_R_TYPE (info) == R_X86_64_32) || (ELF_R_TYPE (info) == R_X86_64_32S)) { + grub_util_error ("Can\'t add fixup entry for R_X86_64_32(S)"); + } + else if (ELF_R_TYPE (info) == R_X86_64_64) + { 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, + GRUB_PE32_REL_BASED_DIR64, + addr, + 0, current_address, out); } #endif
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel