aboutsummaryrefslogtreecommitdiffstats
path: root/src/fw/shadow.c
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2016-04-01 15:45:29 -0400
committerKevin O'Connor <kevin@koconnor.net>2016-04-06 09:53:55 -0400
commitd449a117a501ecf95e36a11526140ffc91073f56 (patch)
tree4f563f35d187a854bacc89414be50cfb184bb2bc /src/fw/shadow.c
parent9d691acee08bf6c5ef7ffc99ad6010f6ec1a0adc (diff)
downloadseabios-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.c55
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;