[SeaBIOS] [PATCH 7/8] SeaVGABios/cbvga:: Add Intel VBT support

Patrick Rudolph siro at das-labor.org
Fri Mar 24 17:27:26 CET 2017


Add support for providing Intel VBT OpRegion.

Intel's legacy VGA driver expect the VBT (Video BIOS Table)
to be present in the VGA option ROM.
As of now the VBT is not present and you will (not) see a BSOD
as the legacy driver doesn't check the ASLS register,
as newer versions of the driver do.

Parse Intel's OpRegion and copy the VBT to the end of VGA option
rom, if present, to prevent a BSOD. In case the ASLS register is
not set or the OpRegion is invalid no VBT will be installed.

Tested on GM45 (Lenovo T500) using the VBT extracted from Intel
VBIOS, as the faked VBT, generated by coreboot, doesn't work.

Signed-off-by: Patrick Rudolph <siro at das-labor.org>

diff --git a/vgasrc/cbvga.c b/vgasrc/cbvga.c
index 42a50f7..bc5b79e 100644
--- a/vgasrc/cbvga.c
+++ b/vgasrc/cbvga.c
@@ -13,6 +13,9 @@
 #include "vgabios.h" // SET_VGA
 #include "vgafb.h" // handle_gfx_op
 #include "vgautil.h" // VBE_total_memory
+#include "hw/pci.h" // pci_config_readw
+#include "hw/pci_regs.h" // PCI_VENDOR_ID
+#include "hw/pci_ids.h" // PCI_VENDOR_ID_INTEL
 
 static int CBmode VAR16;
 static struct vgamode_s CBmodeinfo VAR16;
@@ -225,6 +228,117 @@ cbvga_get_linesize(struct vgamode_s *vmode_g)
     return GET_GLOBAL(CBlinelength);
 }
 
+struct optionrom_vbt {
+    u32 hdr_signature;
+    u8  reserved[16];
+    u16 hdr_version;
+    u16 hdr_size;
+    u16 hdr_vbt_size;
+};
+
+struct opregion_header {
+    u8    signature[16];
+    u32    size;
+    u32    version;
+};
+
+static const u8 igd_opregion_signature[] VAR16 = {
+    'I', 'n', 't', 'e', 'l', 'G', 'r', 'a', 'p', 'h','i','c','s','M','e','m'
+};
+
+#define VBT_SIGNATURE 0x54425624
+#define ASLS 0xfc
+#define IGD_OPREGION_VBT_OFFSET 0x400
+
+/* Compares to memory regions */
+static int
+cbvga_memcpm(u8 *src1, u8 *src2, u8 len)
+{
+    while (len --) {
+        if (GET_FARVAR(0, *src1) != GET_GLOBAL(*src2))
+            return 1;
+        src1 ++;
+        src2 ++;
+    }
+
+    return 0;
+}
+
+/* Fetch and install Intel VBT OpRegion */
+static void
+cbvga_setup_intel_vbt(void)
+{
+    struct optionrom_vbt *vbt;
+    struct opregion_header *oph;
+    u16 offset;
+    u8 size;
+
+    /* Verify OpRegion Base address */
+    if ((pci_config_readl(pci_to_bdf(0, 2, 0), ASLS) == 0x00000000)
+        || (pci_config_readl(pci_to_bdf(0, 2, 0), ASLS) == 0xffffffff))
+        return;
+
+    dprintf(3, "found valid ASLS.\n");
+
+    /* Get OpRegion Base address */
+    oph = (void *)pci_config_readl(pci_to_bdf(0, 2, 0), ASLS);
+
+    /* Verify OpRegion */
+    if (cbvga_memcpm(oph->signature, (u8 *)igd_opregion_signature
+        , sizeof(oph->signature)) != 0)
+        return;
+
+    dprintf(3, "found valid Intel OpRegion version %d.\n"
+            , GET_FARVAR(0, oph->version));
+
+    /* Get VBT */
+    vbt = ((void *)oph) + IGD_OPREGION_VBT_OFFSET;
+
+    /* Verify VBT */
+    if ((GET_FARVAR(0, vbt->hdr_signature) != VBT_SIGNATURE)
+        || (GET_FARVAR(0, vbt->hdr_vbt_size) == 0))
+        return;
+
+    dprintf(3, "Found valid VBT with size %d.\n", GET_FARVAR(0, vbt->hdr_vbt_size));
+
+    /* Verify Option Rom free space */
+    extern u8 _rom_header_size;
+    size = GET_GLOBAL(_rom_header_size);
+    offset = size * 512;
+    if ((GET_FARVAR(0, vbt->hdr_vbt_size) + offset) > 0xffff)
+        return;
+
+    dprintf(3, "Enough space in rom to place VBT.\n");
+
+    /* Copy VBT */
+    memcpy_high((void *)(offset + BUILD_ROM_START), vbt
+                , GET_FARVAR(0, vbt->hdr_vbt_size));
+
+    dprintf(3, "Copied VBT.\n");
+
+    /* Increment rom header size */
+    size += (GET_FARVAR(0, vbt->hdr_vbt_size) + 512 - 1) >> 9;
+    SET_VGA(_rom_header_size, size);
+
+    dprintf(3, "Incremented rom size from %d to %d bytes.\n"
+            , offset, size * 512);
+
+    /* Set VBT offset */
+    extern u16 _rom_header_pnpdata;
+    SET_VGA(_rom_header_pnpdata, offset);
+
+    dprintf(3, "Wrote VBT pointer.\n");
+
+    /* Verify */
+    vbt = (void *)(offset + BUILD_ROM_START);
+    if ((GET_FARVAR(0, vbt->hdr_signature) != VBT_SIGNATURE)
+        || (GET_FARVAR(0, vbt->hdr_vbt_size) == 0))
+        return;
+
+    dprintf(1, "Successfully installed Intel VBT.\n");
+}
+
+
 #define CB_TAG_FRAMEBUFFER      0x0012
 struct cb_framebuffer {
     u32 tag;
@@ -254,6 +368,13 @@ cbvga_setup(void)
     if (GET_GLOBAL(HaveRunInit))
         return 0;
 
+    if (pci_config_readw(pci_to_bdf(0, 2, 0), PCI_VENDOR_ID)
+        == PCI_VENDOR_ID_INTEL) {
+        dprintf(1, "Found Intel GPU, trying to install VBT.\n");
+
+        cbvga_setup_intel_vbt();
+    }
+
     struct cb_header *cbh = find_cb_table();
     if (!cbh) {
         dprintf(1, "Unable to find coreboot table\n");
diff --git a/vgasrc/vgaentry.S b/vgasrc/vgaentry.S
index 53be2b3..10b1b80 100644
--- a/vgasrc/vgaentry.S
+++ b/vgasrc/vgaentry.S
@@ -16,7 +16,7 @@
 
         .section .rom.header
         .code16
-        .global _rom_header, _rom_header_size, _rom_header_checksum
+        .global _rom_header, _rom_header_size, _rom_header_checksum, _rom_header_pnpdata
 _rom_header:
         .word 0xaa55
 _rom_header_size:
-- 
2.9.3




More information about the SeaBIOS mailing list