diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2016-04-01 15:45:29 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2016-04-06 09:53:55 -0400 |
commit | d449a117a501ecf95e36a11526140ffc91073f56 (patch) | |
tree | 4f563f35d187a854bacc89414be50cfb184bb2bc /src/fw/shadow.c | |
parent | 9d691acee08bf6c5ef7ffc99ad6010f6ec1a0adc (diff) | |
download | seabios-d449a117a501ecf95e36a11526140ffc91073f56.tar.gz |
shadow: Batch PCI config writes
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>
Diffstat (limited to 'src/fw/shadow.c')
-rw-r--r-- | src/fw/shadow.c | 55 |
1 files changed, 38 insertions, 17 deletions
diff --git a/src/fw/shadow.c b/src/fw/shadow.c index f766bb59..cd02d3ab 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; |