diff --git a/commands/efi/fixvideo.c b/commands/efi/fixvideo.c new file mode 100644 index 0000000..61f8d7b --- /dev/null +++ b/commands/efi/fixvideo.c @@ -0,0 +1,106 @@ +/* fixvideo.c - fix video problem in efi */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include + +static struct grub_video_patch +{ + const char *name; + grub_uint32_t pci_id; + grub_uint32_t mmio_bar; + grub_uint32_t mmio_dispa; + grub_uint32_t mmio_dispb; +} video_patches[] = + { + {"Intel 965GM", 0x2a028086, 0, 0x7019C, 0x7119C}, /* DSPBSURF */ + {0, 0, 0, 0, 0} + }; + +static int NESTED_FUNC_ATTR +scan_card (int bus, int dev, int func, grub_pci_id_t pciid) +{ + grub_pci_address_t addr; + + addr = grub_pci_make_address (bus, dev, func, 2); + if (grub_pci_read_byte (addr + 3) == 0x3) + { + struct grub_video_patch *p = video_patches; + + while (p->name) + { + if (p->pci_id == pciid) + { + grub_target_addr_t base; + + grub_printf ("Found graphic card: %s\n", p->name); + addr += 8 + p->mmio_bar * 4; + base = grub_pci_read (addr); + if ((! base) || (base & GRUB_PCI_ADDR_SPACE_IO) || + (base & GRUB_PCI_ADDR_MEM_PREFETCH)) + grub_printf ("Invalid MMIO bar %d\n", p->mmio_bar); + else + { + grub_uint32_t v; + + base &= GRUB_PCI_ADDR_MEM_MASK; + v = *((volatile grub_uint32_t *) (base + p->mmio_dispa)); + *((volatile grub_uint32_t *) (base + p->mmio_dispb)) = v; + if (*((volatile grub_uint32_t *) (base + p->mmio_dispb)) + != v) + grub_printf ("Set MMIO fails\n"); + } + + return 1; + } + p++; + } + + grub_printf ("Unknown graphic card: %x\n", pciid); + } + + return 0; +} + +static grub_err_t +grub_cmd_fixvideo (grub_command_t cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char *argv[] __attribute__ ((unused))) +{ + grub_pci_iterate (scan_card); + return 0; +} + +static grub_command_t cmd_fixvideo; + +GRUB_MOD_INIT(fixvideo) +{ + (void) mod; /* To stop warning. */ + cmd_fixvideo = grub_register_command ("fix_video", grub_cmd_fixvideo, + 0, "Fix video problem."); + +} + +GRUB_MOD_FINI(fixvideo) +{ + grub_unregister_command (cmd_fixvideo); +} diff --git a/commands/efi/loadbios.c b/commands/efi/loadbios.c new file mode 100644 index 0000000..d0a5a69 --- /dev/null +++ b/commands/efi/loadbios.c @@ -0,0 +1,211 @@ +/* loadbios.c - command to load a bios dump */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +static grub_efi_guid_t acpi_guid = GRUB_EFI_ACPI_TABLE_GUID; +static grub_efi_guid_t acpi2_guid = GRUB_EFI_ACPI_20_TABLE_GUID; +static grub_efi_guid_t smbios_guid = GRUB_EFI_SMBIOS_TABLE_GUID; + +#define EBDA_SEG_ADDR 0x40e +#define LOW_MEM_ADDR 0x413 +#define FAKE_EBDA_SEG 0x9fc0 + +#define BLANK_MEM 0xffffffff +#define VBIOS_ADDR 0xc0000 +#define SBIOS_ADDR 0xf0000 + +static int +enable_rom_area (void) +{ + grub_pci_address_t addr; + grub_uint32_t *rom_ptr; + + rom_ptr = (grub_uint32_t *) VBIOS_ADDR; + if (*rom_ptr != BLANK_MEM) + { + grub_printf ("ROM image present.\n"); + return 0; + } + + addr = grub_pci_make_address (0, 0, 0, 36); + grub_pci_write_byte (addr++, 0x30); + grub_pci_write_byte (addr++, 0x33); + grub_pci_write_byte (addr++, 0x33); + grub_pci_write_byte (addr++, 0x33); + grub_pci_write_byte (addr++, 0x33); + grub_pci_write_byte (addr++, 0x33); + grub_pci_write_byte (addr++, 0x33); + grub_pci_write_byte (addr, 0); + + *rom_ptr = 0; + if (*rom_ptr != 0) + { + grub_printf ("Can\'t enable rom area.\n"); + return 0; + } + + return 1; +} + +static void +lock_rom_area (void) +{ + grub_pci_address_t addr; + + addr = grub_pci_make_address (0, 0, 0, 36); + grub_pci_write_byte (addr++, 0x10); + grub_pci_write_byte (addr++, 0x11); + grub_pci_write_byte (addr++, 0x11); + grub_pci_write_byte (addr++, 0x11); + grub_pci_write_byte (addr, 0x11); +} + +static void +fake_bios_data (int use_rom) +{ + unsigned i; + void *acpi, *smbios; + grub_uint16_t *ebda_seg_ptr, *low_mem_ptr; + + ebda_seg_ptr = (grub_uint16_t *) EBDA_SEG_ADDR; + low_mem_ptr = (grub_uint16_t *) LOW_MEM_ADDR; + if ((*ebda_seg_ptr) || (*low_mem_ptr)) + return; + + acpi = 0; + smbios = 0; + for (i = 0; i < grub_efi_system_table->num_table_entries; i++) + { + grub_efi_guid_t *guid = + &grub_efi_system_table->configuration_table[i].vendor_guid; + + if (! grub_memcmp (guid, &acpi2_guid, sizeof (grub_efi_guid_t))) + { + acpi = grub_efi_system_table->configuration_table[i].vendor_table; + grub_printf ("ACPI2: %p\n", acpi); + } + else if (! grub_memcmp (guid, &acpi_guid, sizeof (grub_efi_guid_t))) + { + void *t; + + t = grub_efi_system_table->configuration_table[i].vendor_table; + if (! acpi) + acpi = t; + grub_printf ("ACPI: %p\n", t); + } + else if (! grub_memcmp (guid, &smbios_guid, sizeof (grub_efi_guid_t))) + { + smbios = grub_efi_system_table->configuration_table[i].vendor_table; + grub_printf ("SMBIOS: %p\n", smbios); + } + } + + + *ebda_seg_ptr = FAKE_EBDA_SEG; + *low_mem_ptr = (FAKE_EBDA_SEG >> 6); + + if (acpi) + grub_memcpy ((char *) (FAKE_EBDA_SEG << 4), acpi, 1024); + + if ((use_rom) && (smbios)) + grub_memcpy ((char *) SBIOS_ADDR, (char *) smbios + 16, 16); +} + +static grub_err_t +grub_cmd_fakebios (struct grub_command *cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), + char *argv[] __attribute__ ((unused))) +{ + if (enable_rom_area ()) + { + fake_bios_data (1); + lock_rom_area (); + } + else + fake_bios_data (0); +} + +static grub_err_t +grub_cmd_loadbios (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t file; + int size; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "No rom image specified"); + + if (argc > 1) + { + file = grub_file_open (argv[1]); + if (! file) + return grub_errno; + + if (file->size != 4) + grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid int10 dump size"); + else + grub_file_read (file, (char *) 0x40, 4); + + grub_file_close (file); + if (grub_errno) + return grub_errno; + } + + file = grub_file_open (argv[0]); + if (! file) + return grub_errno; + + size = file->size; + if ((size < 0x10000) || (size > 0x40000)) + grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid bios dump size"); + else if (enable_rom_area ()) + { + grub_file_read (file, (char *) VBIOS_ADDR, size); + fake_bios_data (size <= 0x40000); + lock_rom_area (); + } + + grub_file_close (file); + return grub_errno; +} + +static grub_command_t cmd_fakebios, cmd_loadbios; + +GRUB_MOD_INIT(loadbios) +{ + (void) mod; /* To stop warning. */ + cmd_fakebios = grub_register_command ("fakebios", grub_cmd_fakebios, + 0, "fake bios."); + + cmd_loadbios = grub_register_command ("loadbios", grub_cmd_loadbios, + "loadbios BIOS_DUMP [INT10_DUMP]", + "Load bios dump."); +} + +GRUB_MOD_FINI(loadbios) +{ + grub_unregister_command (cmd_fakebios); + grub_unregister_command (cmd_loadbios); +} diff --git a/commands/memrw.c b/commands/memrw.c new file mode 100644 index 0000000..fa04c76 --- /dev/null +++ b/commands/memrw.c @@ -0,0 +1,101 @@ +/* memrw.c - command to read / write physical memory */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include +#include + +static grub_command_t cmd_read_byte, cmd_read_word, cmd_read_dword; +static grub_command_t cmd_write_byte, cmd_write_word, cmd_write_dword; + +static grub_err_t +grub_cmd_read (grub_command_t cmd, int argc, char **argv) +{ + grub_target_addr_t addr; + grub_uint32_t value; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of arguments"); + + addr = grub_strtoul (argv[0], 0, 0); + if (cmd->name[5] == 'd') + value = *((grub_uint32_t *) addr); + else if (cmd->name[5] == 'w') + value = *((grub_uint16_t *) addr); + else + value = *((grub_uint8_t *) addr); + + grub_printf ("0x%x\n", value); + + return 0; +} + +static grub_err_t +grub_cmd_write (grub_command_t cmd, int argc, char **argv) +{ + grub_target_addr_t addr; + grub_uint32_t value; + + if (argc != 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid number of arguments"); + + addr = grub_strtoul (argv[0], 0, 0); + value = grub_strtoul (argv[1], 0, 0); + if (cmd->name[6] == 'd') + *((grub_uint32_t *) addr) = value; + else if (cmd->name[6] == 'w') + *((grub_uint16_t *) addr) = (grub_uint16_t) value; + else + *((grub_uint8_t *) addr) = (grub_uint8_t) value; + + return 0; +} + +GRUB_MOD_INIT(memrw) +{ + (void) mod; /* To stop warning. */ + cmd_read_byte = + grub_register_command ("read_byte", grub_cmd_read, + "read_byte ADDR", "read byte."); + cmd_read_word = + grub_register_command ("read_word", grub_cmd_read, + "read_word ADDR", "read word."); + cmd_read_dword = + grub_register_command ("read_dword", grub_cmd_read, + "read_dword ADDR", "read dword."); + cmd_write_byte = + grub_register_command ("write_byte", grub_cmd_write, + "write_byte ADDR VALUE", "write byte."); + cmd_write_word = + grub_register_command ("write_word", grub_cmd_write, + "write_word ADDR VALUE", "write word."); + cmd_write_dword = + grub_register_command ("write_dword", grub_cmd_write, + "write_dword ADDR VALUE", "write dword."); +} + +GRUB_MOD_FINI(memrw) +{ + grub_unregister_command (cmd_read_byte); + grub_unregister_command (cmd_read_word); + grub_unregister_command (cmd_read_dword); + grub_unregister_command (cmd_write_byte); + grub_unregister_command (cmd_write_word); + grub_unregister_command (cmd_write_dword); +} diff --git a/conf/common.rmk b/conf/common.rmk index 43bc683..ffe4ea2 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -155,6 +155,12 @@ CLEANFILES += $(grub-mkconfig_SCRIPTS) grub-mkconfig_DATA += util/grub.d/README +# For grub-dumpbios +grub-dumpbios: util/grub-dumpbios.in config.status + ./config.status --file=$@:$< + chmod +x $@ +sbin_SCRIPTS += grub-dumpbios +CLEANFILES += grub-dumpbios # Filing systems. pkglib_MODULES += fshelp.mod fat.mod ufs.mod ext2.mod ntfs.mod \ @@ -335,7 +341,7 @@ pkglib_MODULES += minicmd.mod extcmd.mod hello.mod handler.mod \ ls.mod cmp.mod cat.mod help.mod search.mod \ loopback.mod fs_uuid.mod configfile.mod echo.mod \ terminfo.mod test.mod blocklist.mod hexdump.mod \ - read.mod sleep.mod loadenv.mod crc.mod + read.mod sleep.mod loadenv.mod crc.mod memrw.mod # For minicmd.mod. minicmd_mod_SOURCES = commands/minicmd.c @@ -442,6 +448,11 @@ crc_mod_SOURCES = commands/crc.c lib/crc.c crc_mod_CFLAGS = $(COMMON_CFLAGS) crc_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For memrw.mod. +memrw_mod_SOURCES = commands/memrw.c +memrw_mod_CFLAGS = $(COMMON_CFLAGS) +memrw_mod_LDFLAGS = $(COMMON_LDFLAGS) + # Common Video Subsystem specific modules. pkglib_MODULES += video.mod videotest.mod bitmap.mod tga.mod jpeg.mod \ png.mod font.mod gfxterm.mod diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk index 18a99df..e250304 100644 --- a/conf/i386-efi.rmk +++ b/conf/i386-efi.rmk @@ -79,7 +79,7 @@ grub_install_SOURCES = util/i386/efi/grub-install.in # Modules. pkglib_MODULES = kernel.mod normal.mod chain.mod appleldr.mod \ linux.mod halt.mod reboot.mod pci.mod lspci.mod \ - datetime.mod date.mod datehook.mod + datetime.mod date.mod datehook.mod loadbios.mod fixvideo.mod # For kernel.mod. kernel_mod_EXPORTS = no @@ -182,5 +182,15 @@ datehook_mod_SOURCES = hook/datehook.c datehook_mod_CFLAGS = $(COMMON_CFLAGS) datehook_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For loadbios.mod +loadbios_mod_SOURCES = commands/efi/loadbios.c +loadbios_mod_CFLAGS = $(COMMON_CFLAGS) +loadbios_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For fixvideo.mod +fixvideo_mod_SOURCES = commands/efi/fixvideo.c +fixvideo_mod_CFLAGS = $(COMMON_CFLAGS) +fixvideo_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/i386.mk include $(srcdir)/conf/common.mk diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk index faa59fb..ec246ed 100644 --- a/conf/x86_64-efi.rmk +++ b/conf/x86_64-efi.rmk @@ -81,7 +81,7 @@ grub_install_SOURCES = util/i386/efi/grub-install.in # Modules. pkglib_MODULES = kernel.mod normal.mod chain.mod appleldr.mod \ halt.mod reboot.mod linux.mod pci.mod lspci.mod \ - datetime.mod date.mod datehook.mod + datetime.mod date.mod datehook.mod loadbios.mod fixvideo.mod # For kernel.mod. kernel_mod_EXPORTS = no @@ -185,5 +185,15 @@ datehook_mod_SOURCES = hook/datehook.c datehook_mod_CFLAGS = $(COMMON_CFLAGS) datehook_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For loadbios.mod +loadbios_mod_SOURCES = commands/efi/loadbios.c +loadbios_mod_CFLAGS = $(COMMON_CFLAGS) +loadbios_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For fixvideo.mod +fixvideo_mod_SOURCES = commands/efi/fixvideo.c +fixvideo_mod_CFLAGS = $(COMMON_CFLAGS) +fixvideo_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/i386.mk include $(srcdir)/conf/common.mk diff --git a/include/grub/i386/pci.h b/include/grub/i386/pci.h index f4f08ab..996f642 100644 --- a/include/grub/i386/pci.h +++ b/include/grub/i386/pci.h @@ -32,4 +32,39 @@ grub_pci_read (grub_pci_address_t addr) return grub_inl (GRUB_PCI_DATA_REG); } +static inline grub_uint16_t +grub_pci_read_word (grub_pci_address_t addr) +{ + grub_outl (addr & ~3, GRUB_PCI_ADDR_REG); + return grub_inw (GRUB_PCI_DATA_REG + (addr & 3)); +} + +static inline grub_uint8_t +grub_pci_read_byte (grub_pci_address_t addr) +{ + grub_outl (addr & ~3, GRUB_PCI_ADDR_REG); + return grub_inb (GRUB_PCI_DATA_REG + (addr & 3)); +} + +static inline void +grub_pci_write (grub_pci_address_t addr, grub_uint32_t data) +{ + grub_outl (addr, GRUB_PCI_ADDR_REG); + grub_outl (data, GRUB_PCI_DATA_REG); +} + +static inline void +grub_pci_write_word (grub_pci_address_t addr, grub_uint16_t data) +{ + grub_outl (addr & ~3, GRUB_PCI_ADDR_REG); + grub_outw (data, GRUB_PCI_DATA_REG + (addr & 3)); +} + +static inline void +grub_pci_write_byte (grub_pci_address_t addr, grub_uint8_t data) +{ + grub_outl (addr & ~3, GRUB_PCI_ADDR_REG); + grub_outb (data, GRUB_PCI_DATA_REG + (addr & 3)); +} + #endif /* GRUB_CPU_PCI_H */ diff --git a/include/grub/pci.h b/include/grub/pci.h index aceee49..7c8b505 100644 --- a/include/grub/pci.h +++ b/include/grub/pci.h @@ -36,8 +36,8 @@ #define GRUB_PCI_ADDR_IO_MASK ~0x03 typedef grub_uint32_t grub_pci_id_t; -typedef int (*grub_pci_iteratefunc_t) (int bus, int device, int func, - grub_pci_id_t pciid); +typedef int NESTED_FUNC_ATTR (*grub_pci_iteratefunc_t) + (int bus, int device, int func, grub_pci_id_t pciid); typedef grub_uint32_t grub_pci_address_t; grub_pci_address_t EXPORT_FUNC(grub_pci_make_address) (int bus, int device, diff --git a/loader/i386/efi/linux.c b/loader/i386/efi/linux.c index c62198a..fa83cac 100644 --- a/loader/i386/efi/linux.c +++ b/loader/i386/efi/linux.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #define GRUB_LINUX_CL_OFFSET 0x1000 @@ -248,9 +249,9 @@ allocate_pages (grub_size_t prot_size) } grub_dprintf ("linux", "real_mode_mem = %lx, real_mode_pages = %x, " - "prot_mode_mem = %lx, prot_mode_pages = %x\n", - (unsigned long) real_mode_mem, (unsigned) real_mode_pages, - (unsigned long) prot_mode_mem, (unsigned) prot_mode_pages); + "prot_mode_mem = %lx, prot_mode_pages = %x\n", + (unsigned long) real_mode_mem, (unsigned) real_mode_pages, + (unsigned long) prot_mode_mem, (unsigned) prot_mode_pages); grub_free (mmap); return 1; @@ -263,8 +264,8 @@ allocate_pages (grub_size_t prot_size) 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) + grub_uint64_t start, grub_uint64_t size, + grub_uint32_t type) { int n = *e820_num; @@ -283,57 +284,6 @@ grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num, } } -static grub_efi_guid_t acpi_guid = GRUB_EFI_ACPI_TABLE_GUID; -static grub_efi_guid_t acpi2_guid = GRUB_EFI_ACPI_20_TABLE_GUID; - -#define EBDA_SEG_ADDR 0x40e -#define LOW_MEM_ADDR 0x413 -#define FAKE_EBDA_SEG 0x9fc0 - -static void -fake_bios_data (void) -{ - unsigned i; - void *acpi; - grub_uint16_t *ebda_seg_ptr, *low_mem_ptr; - - acpi = 0; - for (i = 0; i < grub_efi_system_table->num_table_entries; i++) - { - grub_efi_guid_t *guid = - &grub_efi_system_table->configuration_table[i].vendor_guid; - - if (! grub_memcmp (guid, &acpi2_guid, sizeof (grub_efi_guid_t))) - { - acpi = grub_efi_system_table->configuration_table[i].vendor_table; - grub_printf ("ACPI2: %p\n", acpi); - } - else if (! grub_memcmp (guid, &acpi_guid, sizeof (grub_efi_guid_t))) - { - void *t; - - t = grub_efi_system_table->configuration_table[i].vendor_table; - if (! acpi) - acpi = t; - grub_printf ("ACPI: %p\n", t); - } - } - - if (acpi == 0) - return; - - ebda_seg_ptr = (grub_uint16_t *) EBDA_SEG_ADDR; - low_mem_ptr = (grub_uint16_t *) LOW_MEM_ADDR; - - if ((*ebda_seg_ptr) || (*low_mem_ptr)) - return; - - *ebda_seg_ptr = FAKE_EBDA_SEG; - *low_mem_ptr = FAKE_EBDA_SEG >> 6; - - grub_memcpy ((char *) (FAKE_EBDA_SEG << 4), acpi, 1024); -} - #ifdef __x86_64__ struct { @@ -353,13 +303,11 @@ grub_linux_boot (void) grub_efi_memory_descriptor_t *desc; int e820_num; - fake_bios_data (); - params = real_mode_mem; grub_dprintf ("linux", "code32_start = %x, idt_desc = %lx, gdt_desc = %lx\n", (unsigned) params->code32_start, - (unsigned long) &(idt_desc.limit), + (unsigned long) &(idt_desc.limit), (unsigned long) &(gdt_desc.limit)); grub_dprintf ("linux", "idt = %x:%lx, gdt = %x:%lx\n", (unsigned) idt_desc.limit, (unsigned long) idt_desc.base, @@ -376,69 +324,69 @@ grub_linux_boot (void) 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); - } + { + 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; @@ -520,41 +468,105 @@ static grub_efi_guid_t uga_draw_guid = GRUB_EFI_UGA_DRAW_GUID; #define FBTEST_STEP (0x10000 >> 2) #define FBTEST_COUNT 8 -static grub_uint32_t fb_list[]= - {0x40000000, 0x80000000, 0xc0000000, 0}; +static int +find_line_len (grub_uint32_t *fb_base, grub_uint32_t *line_len) +{ + grub_uint32_t *base = (grub_uint32_t *) (grub_target_addr_t) *fb_base; + int i; + + for (i = 0; i < FBTEST_COUNT; i++, base += FBTEST_STEP) + { + if ((*base & RGB_MASK) == RGB_MAGIC) + { + int j; + + for (j = LINE_MIN; j <= LINE_MAX; j++) + { + if ((base[j] & RGB_MASK) == RGB_MAGIC) + { + *fb_base = (grub_uint32_t) (grub_target_addr_t) base; + *line_len = j << 2; + + return 1; + } + } + + break; + } + } + + return 0; +} static int find_framebuf (grub_uint32_t *fb_base, grub_uint32_t *line_len) { - grub_uint32_t *fb; + int found = 0; + + auto int NESTED_FUNC_ATTR find_card (int bus, int dev, int func, + grub_pci_id_t pciid); - for (fb = fb_list; *fb; fb++) + int NESTED_FUNC_ATTR find_card (int bus, int dev, int func, + grub_pci_id_t pciid __attribute__ ((unused))) { - grub_uint32_t *base = (grub_uint32_t *) (grub_target_addr_t) *fb; - int i; + grub_pci_address_t addr; - for (i = 0; i < FBTEST_COUNT; i++, base += FBTEST_STEP) - { - if ((*base & RGB_MASK) == RGB_MAGIC) + addr = grub_pci_make_address (bus, dev, func, 2); + if (grub_pci_read (addr) >> 24 == 0x3) + { + int i; + + grub_printf ("Display controller: %d:%d.%d\n", bus, dev, func); + addr += 8; + for (i = 0; i < 6; i++, addr += 4) { - int j; - - for (j = LINE_MIN; j <= LINE_MAX; j++) - { - if ((base[j] & RGB_MASK) == RGB_MAGIC) - { - *fb_base = (grub_uint32_t) (grub_target_addr_t) base; - *line_len = j << 2; - - return 0; - } - } - - break; - } - } + grub_uint32_t old_bar1, old_bar2, type; + grub_uint64_t base64; + + old_bar1 = grub_pci_read (addr); + if ((! old_bar1) || (old_bar1 & GRUB_PCI_ADDR_SPACE_IO)) + continue; + + type = old_bar1 & GRUB_PCI_ADDR_MEM_TYPE_MASK; + if (type == GRUB_PCI_ADDR_MEM_TYPE_64) + { + if (i == 5) + break; + + old_bar2 = grub_pci_read (addr + 4); + } + else + old_bar2 = 0; + + base64 = old_bar2; + base64 <<= 32; + base64 |= (old_bar1 & GRUB_PCI_ADDR_MEM_MASK); + + grub_printf ("%s(%d): 0x%llx\n", + ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) ? + "VMEM" : "MMIO"), i, + (unsigned long long) base64); + + if ((old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH) && (! found)) + { + *fb_base = base64; + if (find_line_len (fb_base, line_len)) + found++; + } + + if (type == GRUB_PCI_ADDR_MEM_TYPE_64) + { + i++; + addr += 4; + } + } + } + + return found; } - return 1; + + grub_pci_iterate (find_card); + return found; } static int @@ -580,13 +592,13 @@ grub_linux_setup_video (struct linux_kernel_params *params) ret = find_framebuf (&fb_base, &line_len); grub_efi_set_text_mode (1); - if (ret) + if (! ret) { grub_printf ("Can\'t find frame buffer address\n"); return 1; } - grub_printf ("Video frame buffer: 0x%x\n", fb_base); + grub_printf ("Frame buffer base: 0x%x\n", fb_base); grub_printf ("Video line length: %d\n", line_len); params->lfb_width = width; @@ -606,6 +618,9 @@ grub_linux_setup_video (struct linux_kernel_params *params) params->reserved_mask_size = 8; params->reserved_field_pos = 24; + params->have_vga = GRUB_VIDEO_TYPE_VLFB; + params->vid_mode = 0x338; /* 1024x768x32 */ + return 0; } @@ -621,7 +636,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_ssize_t len; int i; char *dest; - int video_type; grub_dl_ref (my_mod); @@ -808,9 +822,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), grub_printf (" [Linux-bzImage, setup=0x%x, size=0x%x]\n", (unsigned) real_size, (unsigned) prot_size); + grub_linux_setup_video (params); + /* Detect explicitly specified memory size, if any. */ linux_mem_size = 0; - video_type = 0; for (i = 1; i < argc; i++) if (grub_memcmp (argv[i], "mem=", 4) == 0) { @@ -846,20 +861,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), linux_mem_size <<= shift; } } - else if (grub_memcmp (argv[i], "video=", 6) == 0) + else if (grub_memcmp (argv[i], "video=efifb", 11) == 0) { - if (grub_memcmp (&argv[i][6], "vesafb", 6) == 0) - video_type = GRUB_VIDEO_TYPE_VLFB; - else if (grub_memcmp (&argv[i][6], "efifb", 5) == 0) - video_type = GRUB_VIDEO_TYPE_EFI; + if (params->have_vga) + params->have_vga = GRUB_VIDEO_TYPE_EFI; } - if (video_type) - { - if (! grub_linux_setup_video (params)) - params->have_vga = video_type; - } - /* Specify the boot file. */ dest = grub_stpcpy ((char *) real_mode_mem + GRUB_LINUX_CL_OFFSET, "BOOT_IMAGE="); @@ -946,7 +953,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), /* Usually, the compression ratio is about 50%. */ addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12) - + page_align (size); + + page_align (size); /* Find the highest address to put the initrd. */ mmap_size = find_mmap_size (); @@ -968,7 +975,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), physical_end = addr_max; if (physical_end < page_align (size)) - continue; + continue; physical_end -= page_align (size); diff --git a/util/grub-dumpbios.in b/util/grub-dumpbios.in new file mode 100644 index 0000000..3965039 --- /dev/null +++ b/util/grub-dumpbios.in @@ -0,0 +1,58 @@ +#! /bin/sh +# +# Copyright (C) 2009 Free Software Foundation, Inc. +# +# GRUB is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# GRUB is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GRUB. If not, see . + +# Usage: usage +# Print the usage. +usage () { + cat <. +EOF +} + +# Check the arguments. +for option in "$@"; do + case "$option" in + -h | --help) + usage + exit 0 ;; + -v | --version) + echo "$0 (GNU GRUB @PACKAGE_VERSION@)" + exit 0 ;; + -o) + shift + output_dir=$1 + ;; + --output=) + output_dir=`echo "$option" | sed 's/--output=//'` + ;; + -*) + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 + ;; + esac +done + +dd if=/dev/mem of=${output_dir}vbios.bin bs=65536 skip=12 count=1 +dd if=/dev/mem of=${output_dir}int10.bin bs=4 skip=16 count=1