2009-04-04 Bean <bean123ch@gnail.com>
* include/grub/efi/api.h (grub_efi_configuration_table): Add packed attribute, otherwise the size would be wrong for i386 platform. * include/grub/pci.h (grub_pci_read_word): New inline function. (grub_pci_read_byte): Likewise. (grub_pci_write): Likewise. (grub_pci_write_word): Likewise. (grub_pci_write_byte): Likewise. * include/grub/pci.h (grub_pci_iteratefunc_t): Add NESTED_FUNC_ATTR. * loader/i386/efi/linux.c (fake_bios_data): Moved to loadbios module. (find_framebuf): Scan pci to locate the frame buffer address. * commands/efi/fixvideo.c: New file. * commands/efi/loadbios.c: Likewise. * commands/memrw.c: Likewise. * util/grub-dumpbios.in: Likewise. * conf/common.rmk (grub-dumpbios): New utility. (pkglib_MODULES): New module memrw.mod. (memrw_mod_SOURCE): New macro. (memrw_mod_CFLAGS): Likewise. (memrw_mod_LDFLAGS): Likewise. * conf/i386-efi.rmk (pkglig_MODULES): New module loadbios.mod and fixvideo.mod. (loadbios_mod_SOURCE): New macro. (loadbios_mod_CFLAGS): Likewise. (loadbios_mod_LDFLAGS): Likewise. (fixvideo_mod_SOURCE): Likewise. (fixvideo_mod_CFLAGS): Likewise. (fixvideo_mod_LDFLAGS): Likewise. * conf/x86_64.rmk (pkglig_MODULES): New module loadbios.mod and fixvideo.mod. (loadbios_mod_SOURCE): New macro. (loadbios_mod_CFLAGS): Likewise. (loadbios_mod_LDFLAGS): Likewise. (fixvideo_mod_SOURCE): Likewise. (fixvideo_mod_CFLAGS): Likewise. (fixvideo_mod_LDFLAGS): Likewise.
This commit is contained in:
parent
da4c0bb629
commit
838c454296
18 changed files with 3387 additions and 3140 deletions
|
@ -30,6 +30,7 @@
|
|||
#include <grub/efi/api.h>
|
||||
#include <grub/efi/efi.h>
|
||||
#include <grub/efi/uga_draw.h>
|
||||
#include <grub/pci.h>
|
||||
#include <grub/command.h>
|
||||
|
||||
#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_dprintf ("linux", "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_dprintf ("linux", "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_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_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_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;
|
||||
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;
|
||||
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);
|
||||
}
|
||||
/* 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;
|
||||
if (end <= 0x100000ULL)
|
||||
continue;
|
||||
|
||||
start = 0x100000ULL;
|
||||
size = end - start;
|
||||
}
|
||||
start = 0x100000ULL;
|
||||
size = end - start;
|
||||
}
|
||||
|
||||
grub_e820_add_region (params->e820_map, &e820_num,
|
||||
start, size, GRUB_E820_RAM);
|
||||
break;
|
||||
}
|
||||
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);
|
||||
}
|
||||
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,106 @@ 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;
|
||||
|
||||
for (fb = fb_list; *fb; fb++)
|
||||
auto int NESTED_FUNC_ATTR find_card (int bus, int dev, int func,
|
||||
grub_pci_id_t pciid);
|
||||
|
||||
int NESTED_FUNC_ATTR find_card (int bus, int dev, int func,
|
||||
grub_pci_id_t pciid)
|
||||
{
|
||||
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\nDevice id: %x\n",
|
||||
bus, dev, func, pciid);
|
||||
addr += 8;
|
||||
for (i = 0; i < 6; i++, addr += 4)
|
||||
{
|
||||
int j;
|
||||
grub_uint32_t old_bar1, old_bar2, type;
|
||||
grub_uint64_t base64;
|
||||
|
||||
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;
|
||||
old_bar1 = grub_pci_read (addr);
|
||||
if ((! old_bar1) || (old_bar1 & GRUB_PCI_ADDR_SPACE_IO))
|
||||
continue;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
type = old_bar1 & GRUB_PCI_ADDR_MEM_TYPE_MASK;
|
||||
if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
|
||||
{
|
||||
if (i == 5)
|
||||
break;
|
||||
|
||||
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 +593,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 +619,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 +637,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 +823,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 +862,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 +954,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 +976,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);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue