Enabling and disabling shadow ram on QEMU is slow. Batch the PCI writes to reduce the number of memory changes QEMU must implement.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/fw/shadow.c | 55 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 17 deletions(-)
diff --git a/src/fw/shadow.c b/src/fw/shadow.c index f766bb5..cd02d3a 100644 --- a/src/fw/shadow.c +++ b/src/fw/shadow.c @@ -21,27 +21,39 @@ // On the emulators, the bios at 0xf0000 is also at 0xffff0000 #define BIOS_SRC_OFFSET 0xfff00000
+union pamdata_u { + u8 data8[8]; + u32 data32[2]; +}; + // Enable shadowing and copy bios. static void __make_bios_writable_intel(u16 bdf, u32 pam0) { + // Read in current PAM settings from pci config space + union pamdata_u pamdata; + pamdata.data32[0] = pci_config_readl(bdf, ALIGN_DOWN(pam0, 4)); + pamdata.data32[1] = pci_config_readl(bdf, ALIGN_DOWN(pam0, 4) + 4); + u8 *pam = &pamdata.data8[pam0 & 0x03]; + // Make ram from 0xc0000-0xf0000 writable int i; - for (i=0; i<6; i++) { - u32 pam = pam0 + 1 + i; - pci_config_writeb(bdf, pam, 0x33); - } + for (i=0; i<6; i++) + pam[i + 1] = 0x33;
// Make ram from 0xf0000-0x100000 writable - int reg = pci_config_readb(bdf, pam0); - pci_config_writeb(bdf, pam0, 0x30); - if (reg & 0x10) - // Ram already present. - return; - - // Copy bios. - memcpy(VSYMBOL(code32flat_start), VSYMBOL(code32flat_start) + BIOS_SRC_OFFSET - , SYMBOL(code32flat_end) - SYMBOL(code32flat_start)); + int ram_present = pam[0] & 0x10; + pam[0] = 0x30; + + // Write PAM settings back to pci config space + pci_config_writel(bdf, ALIGN_DOWN(pam0, 4), pamdata.data32[0]); + pci_config_writel(bdf, ALIGN_DOWN(pam0, 4) + 4, pamdata.data32[1]); + + if (!ram_present) + // Copy bios. + memcpy(VSYMBOL(code32flat_start) + , VSYMBOL(code32flat_start) + BIOS_SRC_OFFSET + , SYMBOL(code32flat_end) - SYMBOL(code32flat_start)); }
static void @@ -68,6 +80,12 @@ make_bios_readonly_intel(u16 bdf, u32 pam0) // Flush any pending writes before locking memory. wbinvd();
+ // Read in current PAM settings from pci config space + union pamdata_u pamdata; + pamdata.data32[0] = pci_config_readl(bdf, ALIGN_DOWN(pam0, 4)); + pamdata.data32[1] = pci_config_readl(bdf, ALIGN_DOWN(pam0, 4) + 4); + u8 *pam = &pamdata.data8[pam0 & 0x03]; + // Write protect roms from 0xc0000-0xf0000 u32 romlast = BUILD_BIOS_ADDR, rommax = BUILD_BIOS_ADDR; if (CONFIG_WRITABLE_UPPERMEMORY) @@ -77,17 +95,20 @@ make_bios_readonly_intel(u16 bdf, u32 pam0) int i; for (i=0; i<6; i++) { u32 mem = BUILD_ROM_START + i * 32*1024; - u32 pam = pam0 + 1 + i; if (romlast < mem + 16*1024 || rommax < mem + 32*1024) { if (romlast >= mem && rommax >= mem + 16*1024) - pci_config_writeb(bdf, pam, 0x31); + pam[i + 1] = 0x31; break; } - pci_config_writeb(bdf, pam, 0x11); + pam[i + 1] = 0x11; }
// Write protect 0xf0000-0x100000 - pci_config_writeb(bdf, pam0, 0x10); + pam[0] = 0x10; + + // Write PAM settings back to pci config space + pci_config_writel(bdf, ALIGN_DOWN(pam0, 4), pamdata.data32[0]); + pci_config_writel(bdf, ALIGN_DOWN(pam0, 4) + 4, pamdata.data32[1]); }
static int ShadowBDF = -1;