Add support for enabling ram in 0xc0000-0xf0000 area.
authorKevin O'Connor <kevin@koconnor.net>
Sun, 26 Jul 2009 23:16:09 +0000 (19:16 -0400)
committerKevin O'Connor <kevin@koconnor.net>
Sun, 26 Jul 2009 23:16:09 +0000 (19:16 -0400)
Enhance shadow ram support to enable read/write of option rom area.
This enables support for option roms that modify themselves.
Support copying the roms before enabling shadowing, to work around the
    qemu implementation of ram shadowing.
Rename next_rom to RomEnd and export it.
Support locking ram being used for optionroms before booting.
Don't bother and'ing/or'ing 0x59 register - it's usage is well defined.

src/config.h
src/optionroms.c
src/shadow.c
src/util.h

index 3b4b5fee669cf9eb14ab7e5606ee6ac9cf302904..6f1910701311db260b2acd547d3f23f12e0b2a8d 100644 (file)
 #define BUILD_STACK_ADDR          0x7c00
 #define BUILD_S3RESUME_STACK_ADDR 0x1000
 #define BUILD_AP_BOOT_ADDR        0x10000
+#define BUILD_ROM_START           0xc0000
 #define BUILD_BIOS_ADDR           0xf0000
 #define BUILD_BIOS_SIZE           0x10000
+// 32KB for shadow ram copying (works around emulator deficiencies)
+#define BUILD_BIOS_TMP_ADDR       0x30000
 
 #define BUILD_APIC_ADDR           0xfee00000
 #define BUILD_IOAPIC_ADDR         0xfec00000
index 93c1959303ab3a7240860ddb31ed28c3be0ec2b4..00fa85dcb5cf792cb426a6870d5a0fe3b90695d7 100644 (file)
@@ -64,15 +64,14 @@ struct pnp_data {
     u16 staticresource;
 } PACKED;
 
-#define OPTION_ROM_START 0xc0000
 #define OPTION_ROM_SIGNATURE 0xaa55
 #define OPTION_ROM_ALIGN 2048
 #define OPTION_ROM_INITVECTOR offsetof(struct rom_header, initVector[0])
 #define PCI_ROM_SIGNATURE 0x52494350 // PCIR
 #define PCIROM_CODETYPE_X86 0
 
-// Next available position for an option rom.
-static u32 next_rom;
+// The end of the last deployed rom.
+u32 RomEnd;
 
 
 /****************************************************************
@@ -171,15 +170,15 @@ static struct rom_header *
 copy_rom(struct rom_header *rom)
 {
     u32 romsize = rom->size * 512;
-    if (next_rom + romsize > BUILD_BIOS_ADDR) {
+    if (RomEnd + romsize > BUILD_BIOS_ADDR) {
         // Option rom doesn't fit.
         dprintf(1, "Option rom %p doesn't fit.\n", rom);
         return NULL;
     }
     dprintf(4, "Copying option rom (size %d) from %p to %x\n"
-            , romsize, rom, next_rom);
-    memcpy((void*)next_rom, rom, romsize);
-    return (void*)next_rom;
+            , romsize, rom, RomEnd);
+    memcpy((void*)RomEnd, rom, romsize);
+    return (void*)RomEnd;
 }
 
 // Run rom init code and note rom size.
@@ -193,7 +192,7 @@ init_optionrom(struct rom_header *rom, u16 bdf, int isvga)
         // Only init vga and PnP roms here.
         callrom(rom, bdf);
 
-    next_rom = (u32)rom + ALIGN(rom->size * 512, OPTION_ROM_ALIGN);
+    RomEnd = (u32)rom + ALIGN(rom->size * 512, OPTION_ROM_ALIGN);
 
     return 0;
 }
@@ -215,11 +214,11 @@ lookup_hardcode(u32 vendev)
         && ((OPTIONROM_VENDEV_2 >> 16)
             | ((OPTIONROM_VENDEV_2 & 0xffff)) << 16) == vendev)
         return copy_rom((void*)OPTIONROM_MEM_2);
-    int ret = cbfs_copy_optionrom((void*)next_rom, BUILD_BIOS_ADDR - next_rom
+    int ret = cbfs_copy_optionrom((void*)RomEnd, BUILD_BIOS_ADDR - RomEnd
                                   , vendev);
     if (ret < 0)
         return NULL;
-    return (void*)next_rom;
+    return (void*)RomEnd;
 }
 
 // Run all roms in a given CBFS directory.
@@ -229,10 +228,10 @@ run_cbfs_roms(const char *prefix, int isvga)
     struct cbfs_file *tmp = NULL;
     for (;;) {
         tmp = cbfs_copyfile_prefix(
-            (void*)next_rom, BUILD_BIOS_ADDR - next_rom, prefix, tmp);
+            (void*)RomEnd, BUILD_BIOS_ADDR - RomEnd, prefix, tmp);
         if (!tmp)
             break;
-        init_optionrom((void*)next_rom, 0, isvga);
+        init_optionrom((void*)RomEnd, 0, isvga);
     }
 }
 
@@ -339,17 +338,17 @@ optionrom_setup()
 
     dprintf(1, "Scan for option roms\n");
 
-    u32 post_vga = next_rom;
+    u32 post_vga = RomEnd;
 
     if (CONFIG_OPTIONROMS_DEPLOYED) {
         // Option roms are already deployed on the system.
-        u32 pos = next_rom;
+        u32 pos = RomEnd;
         while (pos < BUILD_BIOS_ADDR) {
             int ret = init_optionrom((void*)pos, 0, 0);
             if (ret)
                 pos += OPTION_ROM_ALIGN;
             else
-                pos = next_rom;
+                pos = RomEnd;
         }
     } else {
         // Find and deploy PCI roms.
@@ -369,7 +368,7 @@ optionrom_setup()
     // All option roms found and deployed - now build BEV/BCV vectors.
 
     u32 pos = post_vga;
-    while (pos < next_rom) {
+    while (pos < RomEnd) {
         struct rom_header *rom = (void*)pos;
         if (! is_valid_rom(rom)) {
             pos += OPTION_ROM_ALIGN;
@@ -404,16 +403,17 @@ optionrom_setup()
 void
 vga_setup()
 {
+    VGAbdf = -1;
+    RomEnd = BUILD_ROM_START;
+
     if (! CONFIG_OPTIONROMS)
         return;
 
     dprintf(1, "Scan for VGA option rom\n");
-    VGAbdf = -1;
-    next_rom = OPTION_ROM_START;
 
     if (CONFIG_OPTIONROMS_DEPLOYED) {
         // Option roms are already deployed on the system.
-        init_optionrom((void*)OPTION_ROM_START, 0, 1);
+        init_optionrom((void*)BUILD_ROM_START, 0, 1);
     } else {
         // Find and deploy PCI VGA rom.
         int bdf = VGAbdf = pci_find_vga();
@@ -424,9 +424,9 @@ vga_setup()
         run_cbfs_roms("vgaroms/", 1);
     }
 
-    if (next_rom == OPTION_ROM_START) {
+    if (RomEnd == BUILD_ROM_START) {
         // No VGA rom found
-        next_rom += OPTION_ROM_ALIGN;
+        RomEnd += OPTION_ROM_ALIGN;
         return;
     }
 
@@ -445,7 +445,7 @@ s3_resume_vga_init()
 {
     if (!CONFIG_S3_RESUME_VGA_INIT)
         return;
-    struct rom_header *rom = (void*)OPTION_ROM_START;
+    struct rom_header *rom = (void*)BUILD_ROM_START;
     if (! is_valid_rom(rom))
         return;
     callrom(rom, 0);
index 1c389f44a44d74b3499d453e9d58f2c8cdc76339..daa2e213f43ede8330e7a3f65f6ba00ff2b9577a 100644 (file)
@@ -1,6 +1,6 @@
 // Support for enabling/disabling BIOS ram shadowing.
 //
-// Copyright (C) 2008  Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2008,2009  Kevin O'Connor <kevin@koconnor.net>
 // Copyright (C) 2006 Fabrice Bellard
 //
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
 // Enable shadowing and copy bios.
 static void
-copy_bios(u16 bdf, int reg)
+copy_bios(u16 bdf)
 {
-    pci_config_writeb(bdf, 0x59, reg | 0x30);
+    pci_config_writeb(bdf, 0x59, 0x30);
     memcpy((void*)BUILD_BIOS_ADDR, (void*)BIOS_SRC_ADDR, BUILD_BIOS_SIZE);
 }
 
-// Make the BIOS code segment area (0xf0000) writable.
+// Make the 0xc0000-0x100000 area read/writable.
 void
 make_bios_writable()
 {
@@ -45,10 +45,33 @@ make_bios_writable()
         return;
     }
 
+    // Make ram from 0xc0000-0xf0000 writable
+    int clear = 0;
+    int i;
+    for (i=0; i<6; i++) {
+        if (CONFIG_OPTIONROMS_DEPLOYED) {
+            int reg = pci_config_readb(bdf, 0x5a + i);
+            if ((reg & 0x11) != 0x11) {
+                // Need to copy optionroms to work around qemu implementation
+                void *mem = (void*)(BUILD_ROM_START + i * 32*1024);
+                memcpy((void*)BUILD_BIOS_TMP_ADDR, mem, 32*1024);
+                pci_config_writeb(bdf, 0x5a + i, 0x33);
+                memcpy(mem, (void*)BUILD_BIOS_TMP_ADDR, 32*1024);
+                clear = 1;
+            } else {
+                pci_config_writeb(bdf, 0x5a + i, 0x33);
+            }
+        } else {
+            pci_config_writeb(bdf, 0x5a + i, 0x33);
+        }
+    }
+    if (clear)
+        memset((void*)BUILD_BIOS_TMP_ADDR, 0, 32*1024);
+
     int reg = pci_config_readb(bdf, 0x59);
-    if (reg & 0x30) {
+    if (reg & 0x10) {
         // Ram already present - just enable writes
-        pci_config_writeb(bdf, 0x59, reg | 0x30);
+        pci_config_writeb(bdf, 0x59, 0x30);
         return;
     }
 
@@ -58,10 +81,10 @@ make_bios_writable()
         // temporary storage area so that memory does not change under
         // the executing code.
         u32 pos = (u32)copy_bios - BUILD_BIOS_ADDR + BIOS_SRC_ADDR;
-        void (*func)(u16 bdf, int reg) = (void*)pos;
-        func(bdf, reg);
+        void (*func)(u16 bdf) = (void*)pos;
+        func(bdf);
     } else {
-        copy_bios(bdf, reg);
+        copy_bios(bdf);
     }
 }
 
@@ -80,8 +103,21 @@ make_bios_readonly()
         return;
     }
 
+    // Flush any pending writes before locking memory.
     wbinvd();
-    int v = pci_config_readb(bdf, 0x59);
-    v = (v & 0x0f) | (0x10);
-    pci_config_writeb(bdf, 0x59, v);
+
+    // Write protect roms from 0xc0000-0xf0000
+    int i;
+    for (i=0; i<6; i++) {
+        u32 mem = BUILD_ROM_START + i * 32*1024;
+        if (RomEnd <= mem + 16*1024) {
+            if (RomEnd > mem)
+                pci_config_writeb(bdf, 0x5a + i, 0x31);
+            break;
+        }
+        pci_config_writeb(bdf, 0x5a + i, 0x11);
+    }
+
+    // Write protect 0xf0000-0x100000
+    pci_config_writeb(bdf, 0x59, 0x10);
 }
index b566f561f5981b72ea209549c01ede52b8bbca1e..8ae54f4d70d38d7dfdd88f6926570500094edc9c 100644 (file)
@@ -220,6 +220,7 @@ void call_bcv(u16 seg, u16 ip);
 void optionrom_setup();
 void vga_setup();
 void s3_resume_vga_init();
+extern u32 RomEnd;
 
 // resume.c
 void init_dma();