All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] New frame buffer detection algorithm and loadrom command for efi platform
@ 2009-03-21 10:38 Bean
  2009-03-21 15:49 ` step21
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Bean @ 2009-03-21 10:38 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 1241 bytes --]

Hi,

This patch improves the frame buffer detection algorithm. It uses pci
to find the video memory base, then scan it for frame buffer.

It also add a loadrom command which can be used to enable accel
graphic driver. The idea is that you can grab the video bios dump, and
optionally the IVT from pc mode, then load them in efi.

To grab bios dump:
sudo dd if=/dev/mem of=bios.bin bs=65536 skip=12 count=1

You can also include the system bios by changing the count to 4.

To grab IVT dump:
sudo dd if=/dev/mem of=ivt.bin bs=1024 count=1

Then, to load them in grub-efi (ivt.bin is optionally):
loadrom /bios.bin /ivt.bin

Here are some of the findings concerning different video cards:

Old 32-bit efi model, intel card:
Works with intel driver, no need to load vbios or ivt.

New 64-bit efi model, intel card:
Works with intel driver, needs to load vbios.

New 64-bit efi model, nvidia card:
Works with nvidia driver, no needs to load vbios or ivt. However, the
backlight value is set too low so desktop is barely visible. You need
to use a small tool to adjust backlight. The nv driver doesn't work.

New 64-bit efi model, ati radeon card:
Works with fglrx driver, needs to load vbios and ivt. The radeonhd
driver doesn't work.

-- 
Bean

[-- Attachment #2: loadrom.diff --]
[-- Type: application/octet-stream, Size: 18576 bytes --]

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..6e545eb 100644
--- a/loader/i386/efi/linux.c
+++ b/loader/i386/efi/linux.c
@@ -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;
 
@@ -285,19 +286,82 @@ 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;
+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 LOW_MEM_TOP	0xa000
+
+#define BLANK_MEM	0xffffffff
+#define VBIOS_ADDR	0xc0000
+#define SBIOS_ADDR	0xf0000
+
+static int rom_enabled;
+
+static int
+enable_rom_area (void)
+{
+  grub_pci_address_t addr;
+  grub_uint32_t *rom_ptr;
+
+  if (rom_enabled)
+    return 0;
+
+  rom_enabled++;
+
+  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 (void)
 {
   unsigned i;
-  void *acpi;
+  void *acpi, *smbios;
   grub_uint16_t *ebda_seg_ptr, *low_mem_ptr;
+  char *addr;
+
+  if (*((grub_uint32_t *) SBIOS_ADDR) != BLANK_MEM)
+    return;
 
   acpi = 0;
+  smbios = 0;
   for (i = 0; i < grub_efi_system_table->num_table_entries; i++)
     {
       grub_efi_guid_t *guid =
@@ -317,21 +381,30 @@ fake_bios_data (void)
 	    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);
+	}
     }
 
-  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))
+    {
+      *ebda_seg_ptr = LOW_MEM_TOP;
+      *low_mem_ptr = (LOW_MEM_TOP >> 6);
+    }
 
-  if ((*ebda_seg_ptr) || (*low_mem_ptr))
-    return;
-
-  *ebda_seg_ptr = FAKE_EBDA_SEG;
-  *low_mem_ptr = FAKE_EBDA_SEG >> 6;
+  addr = (char *) SBIOS_ADDR;
+  if (acpi)
+    {
+      grub_memcpy (addr, acpi, 512);
+      addr += 512;
+    }
 
-  grub_memcpy ((char *) (FAKE_EBDA_SEG << 4), acpi, 1024);
+  if (smbios)
+    grub_memcpy (addr, (char *) smbios + 16, 16);
 }
 
 #ifdef __x86_64__
@@ -353,13 +426,17 @@ grub_linux_boot (void)
   grub_efi_memory_descriptor_t *desc;
   int e820_num;
   
-  fake_bios_data ();
+  if (enable_rom_area ())
+    {
+      fake_bios_data ();
+      lock_rom_area ();
+    }
 
   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 +453,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 +597,150 @@ 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;
+
+	  addr = grub_pci_make_address (bus, dev, func, 4);
+	  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 (! (old_bar1 & GRUB_PCI_ADDR_MEM_PREFETCH))
+		{
+		  if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
+		    {
+		      i++;
+		      addr += 4;
+		    }
+		  continue;
+		}
+
+	      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);
+
+	      *fb_base = base64;
+	      if (find_line_len (fb_base, line_len))
+		{
+		  grub_pci_address_t cmd_addr, rom_addr;
+		  grub_uint16_t old_cmd;
+		  grub_uint64_t limit64;
+
+		  cmd_addr = grub_pci_make_address (bus, dev, func, 1);
+		  old_cmd = grub_pci_read_word (cmd_addr);
+
+		  /* Disable mem access.  */
+		  grub_pci_write_word (cmd_addr, old_cmd & 0xfffc);
+
+		  grub_pci_write (addr, 0xffffffff);
+		  if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
+		    grub_pci_write (addr + 4, 0xffffffff);
+
+		  if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
+		    {
+		      limit64 = grub_pci_read (addr + 4);
+		      limit64 <<= 32;
+		    }
+		  else
+		    limit64 = 0;
+		  limit64 |= (grub_pci_read (addr) & GRUB_PCI_ADDR_MEM_MASK);
+		  limit64 = (~limit64) + 1;
+
+		  /* Restore old state.  */
+		  grub_pci_write (addr, old_bar1);
+		  if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
+		    grub_pci_write (addr + 4, old_bar2);
+		  grub_pci_write_word (cmd_addr, old_cmd);
+
+		  grub_printf ("Display controller: %d:%d.%d\n",
+			       bus, dev, func);
+		  grub_printf ("Video memory base: 0x%llx\n",
+			       (unsigned long long) base64);
+		  grub_printf ("Video memory size: 0x%llx\n",
+			       (unsigned long long) limit64);
+
+		  rom_addr = grub_pci_make_address (bus, dev, func, 12);
+		  grub_printf ("Expansion ROM: 0x%x\n",
+			       grub_pci_read (rom_addr));
+
+		  found++;
+		  return 1;
+		}
+
+	      if (type == GRUB_PCI_ADDR_MEM_TYPE_64)
+		{
+		  i++;
+		  addr += 4;
+		}
+	    }
+	}
+
+      return 0;
     }
-  return 1;
+
+  grub_pci_iterate (find_card);
+  return found;
 }
 
 static int
@@ -580,13 +766,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;
@@ -848,16 +1034,16 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
       }
     else if (grub_memcmp (argv[i], "video=", 6) == 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 (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 (video_type)
     {
       if (!  grub_linux_setup_video (params))
-        params->have_vga = video_type;
+	params->have_vga = video_type;
     }
 
   /* Specify the boot file.  */
@@ -946,7 +1132,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 +1154,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);
 
@@ -1009,7 +1195,64 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
   return grub_errno;
 }
 
-static grub_command_t cmd_linux, cmd_initrd;
+static grub_err_t
+grub_cmd_loadrom (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");
+
+  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 rom image size");
+      goto quit;
+    }
+
+  if (! enable_rom_area ())
+    goto quit;
+
+  do
+    {
+      grub_file_read (file, (char *) VBIOS_ADDR, size);
+      if (grub_errno)
+	break;
+
+      if (argc > 1)
+	{
+	  grub_file_close (file);
+	  file = grub_file_open (argv[1]);
+	  if (! file)
+	    break;
+
+	  size = file->size;
+	  if (size != 1024)
+	    {
+	      grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid ivt size");
+	      break;
+	    }
+
+	  grub_file_read (file, (char *) 0, size);
+	}
+    }
+  while (0);
+
+  fake_bios_data ();
+  lock_rom_area ();
+
+ quit:
+  grub_file_close (file);
+  return grub_errno;
+}
+
+static grub_command_t cmd_linux, cmd_initrd, cmd_loadrom;
 
 GRUB_MOD_INIT(linux)
 {
@@ -1017,6 +1260,10 @@ GRUB_MOD_INIT(linux)
 				     0, "load linux");
   cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
 				      0, "load initrd");
+  cmd_loadrom = grub_register_command ("loadrom", grub_cmd_loadrom,
+				       "loadrom bios_dump [ivt_dump]",
+				       "load bios rom image");
+
   my_mod = mod;
 }
 
@@ -1024,4 +1271,5 @@ GRUB_MOD_FINI(linux)
 {
   grub_unregister_command (cmd_linux);
   grub_unregister_command (cmd_initrd);
+  grub_unregister_command (cmd_loadrom);
 }

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] New frame buffer detection algorithm and loadrom command for efi platform
  2009-03-21 10:38 [PATCH] New frame buffer detection algorithm and loadrom command for efi platform Bean
@ 2009-03-21 15:49 ` step21
  2009-03-21 16:30   ` Bean
  2009-03-21 18:01 ` Robert Millan
  2009-03-24 14:16 ` Peter Cros
  2 siblings, 1 reply; 10+ messages in thread
From: step21 @ 2009-03-21 15:49 UTC (permalink / raw)
  To: The development of GRUB 2

nice ... will try to test this asap.

2009/3/21 Bean <bean123ch@gmail.com>:
> Hi,
>
> This patch improves the frame buffer detection algorithm. It uses pci
> to find the video memory base, then scan it for frame buffer.
>
> It also add a loadrom command which can be used to enable accel
> graphic driver. The idea is that you can grab the video bios dump, and
> optionally the IVT from pc mode, then load them in efi.
>
> To grab bios dump:
> sudo dd if=/dev/mem of=bios.bin bs=65536 skip=12 count=1
>
> You can also include the system bios by changing the count to 4.
>
> To grab IVT dump:
> sudo dd if=/dev/mem of=ivt.bin bs=1024 count=1
>
> Then, to load them in grub-efi (ivt.bin is optionally):
> loadrom /bios.bin /ivt.bin
>
> Here are some of the findings concerning different video cards:
>
> Old 32-bit efi model, intel card:
> Works with intel driver, no need to load vbios or ivt.
>
> New 64-bit efi model, intel card:
> Works with intel driver, needs to load vbios.
>
> New 64-bit efi model, nvidia card:
> Works with nvidia driver, no needs to load vbios or ivt. However, the
> backlight value is set too low so desktop is barely visible. You need
> to use a small tool to adjust backlight. The nv driver doesn't work.
>
> New 64-bit efi model, ati radeon card:
> Works with fglrx driver, needs to load vbios and ivt. The radeonhd
> driver doesn't work.
>
> --
> Bean
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>
>



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] New frame buffer detection algorithm and loadrom command for efi platform
  2009-03-21 15:49 ` step21
@ 2009-03-21 16:30   ` Bean
  0 siblings, 0 replies; 10+ messages in thread
From: Bean @ 2009-03-21 16:30 UTC (permalink / raw)
  To: The development of GRUB 2

On Sat, Mar 21, 2009 at 11:49 PM, step21 <flo@terrorpop.de> wrote:
> nice ... will try to test this asap.

Hi,

Oh btw, there is still problem concerning the nvidia card, intel and
ati cards should be all right.

-- 
Bean



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] New frame buffer detection algorithm and loadrom command for efi platform
  2009-03-21 10:38 [PATCH] New frame buffer detection algorithm and loadrom command for efi platform Bean
  2009-03-21 15:49 ` step21
@ 2009-03-21 18:01 ` Robert Millan
  2009-03-24 14:16 ` Peter Cros
  2 siblings, 0 replies; 10+ messages in thread
From: Robert Millan @ 2009-03-21 18:01 UTC (permalink / raw)
  To: The development of GRUB 2

On Sat, Mar 21, 2009 at 06:38:12PM +0800, Bean wrote:
> Hi,
> 
> This patch improves the frame buffer detection algorithm. It uses pci
> to find the video memory base, then scan it for frame buffer.

With this detection code getting increasingly more sophisticated, wouldn't
this be a good time to make it a video backend?  (i.e. video/efi.c)

Even if it won't be complete enough for gfxterm yet, it's much better than
doing it in i386/efi/linux.c IMHO.

The code to obtain framebuffer address from video backends is pretty simple.
It's already in i386/linux.c and could be easily integrated into
i386/efi/linux.c.

-- 
Robert Millan

  The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and
  how) you may access your data; but nobody's threatening your freedom: we
  still allow you to remove your data and not access it at all."



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] New frame buffer detection algorithm and loadrom command for efi platform
  2009-03-21 10:38 [PATCH] New frame buffer detection algorithm and loadrom command for efi platform Bean
  2009-03-21 15:49 ` step21
  2009-03-21 18:01 ` Robert Millan
@ 2009-03-24 14:16 ` Peter Cros
  2009-03-25 15:42   ` Bean
  2 siblings, 1 reply; 10+ messages in thread
From: Peter Cros @ 2009-03-24 14:16 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 2030 bytes --]

Hi,
svn rev 2043 patched loadrom.diff on imac81 with ati fglrx.

I find loadrom needs time when called in menuentry, otherwise linux load
fails or loadrom fails. So I had to use sleep.
Then it works very nicely.
----------------------
insmod sleep

menuentry "loadrom hd0,4 sda4" {
search --set /ivt.bin
loadrom /bios.bin /ivt.bin
sleep 1
root=hd0,4
linux /vmlinuz root=/dev/sda4 video=vesafb
initrd /initrd.img
}

This is not apparent from command line with manual entry pauses.
---------------------------------

2009/3/21 Bean <bean123ch@gmail.com>

> Hi,
>
> This patch improves the frame buffer detection algorithm. It uses pci
> to find the video memory base, then scan it for frame buffer.
>
> It also add a loadrom command which can be used to enable accel
> graphic driver. The idea is that you can grab the video bios dump, and
> optionally the IVT from pc mode, then load them in efi.
>
> To grab bios dump:
> sudo dd if=/dev/mem of=bios.bin bs=65536 skip=12 count=1
>
> You can also include the system bios by changing the count to 4.
>
> To grab IVT dump:
> sudo dd if=/dev/mem of=ivt.bin bs=1024 count=1
>
> Then, to load them in grub-efi (ivt.bin is optionally):
> loadrom /bios.bin /ivt.bin
>
> Here are some of the findings concerning different video cards:
>
> Old 32-bit efi model, intel card:
> Works with intel driver, no need to load vbios or ivt.
>
> New 64-bit efi model, intel card:
> Works with intel driver, needs to load vbios.
>
> New 64-bit efi model, nvidia card:
> Works with nvidia driver, no needs to load vbios or ivt. However, the
> backlight value is set too low so desktop is barely visible. You need
> to use a small tool to adjust backlight. The nv driver doesn't work.
>
> New 64-bit efi model, ati radeon card:
> Works with fglrx driver, needs to load vbios and ivt. The radeonhd
> driver doesn't work.
>
> --
> Bean
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>
>


-- 
Cros (pxw)

[-- Attachment #2: Type: text/html, Size: 3194 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] New frame buffer detection algorithm and loadrom command for efi platform
  2009-03-24 14:16 ` Peter Cros
@ 2009-03-25 15:42   ` Bean
  2009-03-26  6:56     ` Bean
  0 siblings, 1 reply; 10+ messages in thread
From: Bean @ 2009-03-25 15:42 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 664 bytes --]

Hi,

The new patch have some adjustment:

1, The loadbios code is moved out of linux.c, it's in a standalone
module loadbios.mod, you could use:

fakebios

or

loadbios /VBIOS.bin

Both will fake acpi and dmi information, loadbios loads video bios rom
from external file as well.

2, loadbios doesn't load ivt.bin anymore, you need to set INT13 with
command write_dword in module memrw. First, use hexdump to get the
INT13 vector from pc boot:

sudo hexdump /dev/mem -e '1/4 "0x%x\n"' -s 0x40 -n 4

Result is something like this:
0xc0000014

The high word should always be 0xc000.

In grub2, use write_dword to change INT13:

write_dword 0x40 0xc0000014

-- 
Bean

[-- Attachment #2: loadbios_2.diff --]
[-- Type: application/octet-stream, Size: 25183 bytes --]

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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/command.h>
+
+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..42a5708 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -335,7 +335,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 +442,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..ba3f7c1 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
 
 # For kernel.mod.
 kernel_mod_EXPORTS = no
@@ -182,5 +182,10 @@ datehook_mod_SOURCES = hook/datehook.c
 datehook_mod_CFLAGS = $(COMMON_CFLAGS)
 datehook_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For loadbios.mod
+loadbios_mod_SOURCES = loader/i386/efi/loadbios.c
+loadbios_mod_CFLAGS = $(COMMON_CFLAGS)
+loadbios_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..5adb937 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
 
 # For kernel.mod.
 kernel_mod_EXPORTS = no
@@ -185,5 +185,10 @@ datehook_mod_SOURCES = hook/datehook.c
 datehook_mod_CFLAGS = $(COMMON_CFLAGS)
 datehook_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For loadbios.mod
+loadbios_mod_SOURCES = loader/i386/efi/loadbios.c
+loadbios_mod_CFLAGS = $(COMMON_CFLAGS)
+loadbios_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..a7d7398 100644
--- a/loader/i386/efi/linux.c
+++ b/loader/i386/efi/linux.c
@@ -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_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,104 @@ 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) ?
+			    "Mem " : "MMIO"), i, 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 +591,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;
@@ -848,16 +859,16 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
       }
     else if (grub_memcmp (argv[i], "video=", 6) == 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 (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 (video_type)
     {
       if (!  grub_linux_setup_video (params))
-        params->have_vga = video_type;
+	params->have_vga = video_type;
     }
 
   /* Specify the boot file.  */
@@ -946,7 +957,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 +979,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/loader/i386/efi/loadbios.c b/loader/i386/efi/loadbios.c
new file mode 100644
index 0000000..5bb5e80
--- /dev/null
+++ b/loader/i386/efi/loadbios.c
@@ -0,0 +1,195 @@
+/* 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/file.h>
+#include <grub/efi/efi.h>
+#include <grub/pci.h>
+#include <grub/command.h>
+
+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;
+  char *addr;
+
+  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");
+
+  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 rom image 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,
+					"loadbios FILE", "Load bios dump.");
+
+  cmd_loadbios = grub_register_command ("loadbios", grub_cmd_loadbios,
+					"loadbios FILE", "Load bios dump.");
+}
+
+GRUB_MOD_FINI(loadbios)
+{
+  grub_unregister_command (cmd_fakebios);
+  grub_unregister_command (cmd_loadbios);
+}

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] New frame buffer detection algorithm and loadrom command for efi platform
  2009-03-25 15:42   ` Bean
@ 2009-03-26  6:56     ` Bean
  2009-03-26 16:09       ` step21
  0 siblings, 1 reply; 10+ messages in thread
From: Bean @ 2009-03-26  6:56 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 1312 bytes --]

Hi,

This is another update, it contains the following changes with regards
to the previous one:

1, Move loadbios command to commands/efi directory.
2, loadbios support an optional second parameter which is the int10
vector dump file.
3, The linux command enables frame buffer by default, so you don't
need video= option anymore.
4. New command fix_video to fix video register issue with efi. With
this, you can boot to console mode with agp enabled.
5, New shell script grub-dumpbios which can be used to generate the
bios dump from pc mode.

As the commands usage have changed in the previous patches, here is a
summary of what you should do with this latest patch:

1, Boot without bios dump.

This is the commands to use:

search --set /vmlinuz
fix_video
fakebios
linux /vmlinuz root=/dev/sdb1
initrd /initrd.img

2, Boot with bios dump.

First, boot to pc mode, then use script grub-dumpbios to generate the
dump files:

sudo grub-dumpbios -o /boot/

video bios dump is in vbios.bin, int10 vector is in int10.bin. /boot/
is the output directory.

Then, use the following commands in grub2:
search --set /vmlinuz
fix_video
loadbios /boot/vbios.bin /boot/int10.bin
linux /vmlinuz root=/dev/sdb1
initrd /initrd.img

Moreover, if you're booting 2.6.27-28, amd64 kernel, you need to add
noefi option.

-- 
Bean

[-- Attachment #2: loadbios_3.diff --]
[-- Type: text/x-patch, Size: 31877 bytes --]

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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/file.h>
+#include <grub/pci.h>
+#include <grub/command.h>
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/file.h>
+#include <grub/efi/efi.h>
+#include <grub/pci.h>
+#include <grub/command.h>
+
+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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/command.h>
+
+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 <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_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 <http://www.gnu.org/licenses/>.
+
+# Usage: usage
+# Print the usage.
+usage () {
+    cat <<EOF
+Usage: $0 [OPTION]
+Create vbios and int10 dump
+
+  -o, --output=DIR        set output directory
+  -h, --help              print this message and exit
+  -v, --version           print the version information and exit
+
+Report bugs to <bug-grub@gnu.org>.
+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

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] New frame buffer detection algorithm and loadrom command for efi platform
  2009-03-26  6:56     ` Bean
@ 2009-03-26 16:09       ` step21
  2009-03-26 16:21         ` Bean
  0 siblings, 1 reply; 10+ messages in thread
From: step21 @ 2009-03-26 16:09 UTC (permalink / raw)
  To: The development of GRUB 2

hi,
why did you scrap ivt.bin loading ... seems much more complicated now.
I'm not sure if I remeber right, but I think ivt.bin worked best for me ...

2009/3/26 Bean <bean123ch@gmail.com>:
> Hi,
>
> This is another update, it contains the following changes with regards
> to the previous one:
>
> 1, Move loadbios command to commands/efi directory.
> 2, loadbios support an optional second parameter which is the int10
> vector dump file.
> 3, The linux command enables frame buffer by default, so you don't
> need video= option anymore.
> 4. New command fix_video to fix video register issue with efi. With
> this, you can boot to console mode with agp enabled.
> 5, New shell script grub-dumpbios which can be used to generate the
> bios dump from pc mode.
>
> As the commands usage have changed in the previous patches, here is a
> summary of what you should do with this latest patch:
>
> 1, Boot without bios dump.
>
> This is the commands to use:
>
> search --set /vmlinuz
> fix_video
> fakebios
> linux /vmlinuz root=/dev/sdb1
> initrd /initrd.img
>
> 2, Boot with bios dump.
>
> First, boot to pc mode, then use script grub-dumpbios to generate the
> dump files:
>
> sudo grub-dumpbios -o /boot/
>
> video bios dump is in vbios.bin, int10 vector is in int10.bin. /boot/
> is the output directory.
>
> Then, use the following commands in grub2:
> search --set /vmlinuz
> fix_video
> loadbios /boot/vbios.bin /boot/int10.bin
> linux /vmlinuz root=/dev/sdb1
> initrd /initrd.img
>
> Moreover, if you're booting 2.6.27-28, amd64 kernel, you need to add
> noefi option.
>
> --
> Bean
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>
>



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] New frame buffer detection algorithm and loadrom command for efi platform
  2009-03-26 16:09       ` step21
@ 2009-03-26 16:21         ` Bean
  2009-04-04  8:08           ` Bean
  0 siblings, 1 reply; 10+ messages in thread
From: Bean @ 2009-03-26 16:21 UTC (permalink / raw)
  To: The development of GRUB 2

On Fri, Mar 27, 2009 at 12:09 AM, step21 <flo@terrorpop.de> wrote:
> hi,
> why did you scrap ivt.bin loading ... seems much more complicated now.
> I'm not sure if I remeber right, but I think ivt.bin worked best for me ...

Hi,

The latest patch support loading file again, but only int10.bin, not
the whole ivt. In fact, I add a shell script grub-dumpbios that does
the job:

sudo grub-dumpbios -o /boot/

It would then save vbios.bin and int10.bin to /boot/ directory, in grub2:

loadbios /boot/vbios.bin /boot/int10.bin

-- 
Bean



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] New frame buffer detection algorithm and loadrom command for efi platform
  2009-03-26 16:21         ` Bean
@ 2009-04-04  8:08           ` Bean
  0 siblings, 0 replies; 10+ messages in thread
From: Bean @ 2009-04-04  8:08 UTC (permalink / raw)
  To: The development of GRUB 2

On Fri, Mar 27, 2009 at 12:21 AM, Bean <bean123ch@gmail.com> wrote:
> On Fri, Mar 27, 2009 at 12:09 AM, step21 <flo@terrorpop.de> wrote:
>> hi,
>> why did you scrap ivt.bin loading ... seems much more complicated now.
>> I'm not sure if I remeber right, but I think ivt.bin worked best for me ...
>
> Hi,
>
> The latest patch support loading file again, but only int10.bin, not
> the whole ivt. In fact, I add a shell script grub-dumpbios that does
> the job:
>
> sudo grub-dumpbios -o /boot/
>
> It would then save vbios.bin and int10.bin to /boot/ directory, in grub2:
>
> loadbios /boot/vbios.bin /boot/int10.bin

Committed.

-- 
Bean



^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2009-04-04  8:08 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-03-21 10:38 [PATCH] New frame buffer detection algorithm and loadrom command for efi platform Bean
2009-03-21 15:49 ` step21
2009-03-21 16:30   ` Bean
2009-03-21 18:01 ` Robert Millan
2009-03-24 14:16 ` Peter Cros
2009-03-25 15:42   ` Bean
2009-03-26  6:56     ` Bean
2009-03-26 16:09       ` step21
2009-03-26 16:21         ` Bean
2009-04-04  8:08           ` Bean

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.