This patch series improves PAM emulation. PAM defines 4 memory access redirection modes. In mode 1 reads are directed to RAM and writes are directed to PCI. In mode 2 it is contrary. In mode 0 all access is directed to PCI. In mode 3 it is directed to RAM. Modes 0 and 3 are well emulated but modes 1 and 2 are not. The cause is: aliases are used while more complicated logic is required.
The idea is to use ROM device like memory regions for mode 1 and 2 emulation instead of aliases. Writes are directed to proper destination region by specified I/O callback. Read redirection depends on type of source region. In most cases source region is RAM (or ROM), so ram_addr of PAM region is set to ram_addr of source region with offset. Otherwise, when source region is an I/O region, reading is redirected to source region read callback by PAM region one. Read source and write destination regions are updated by the memory commit callback. Note that we cannot use I/O region for PAM as it will violate "trying to execute code outside RAM or ROM" assertion. Qemu distribution includes SeaBIOS which has hacks to work around incorrect modes 1 and 2 emulation. This patch series is tested using modified SeaBIOS. It is forced to use mode 2 for copying its data. BIOS reads a value from memory and immediately writes it to same address. According to PAM definition, reads are directed to PCI (i.e. to BIOS ROM) and writes are directed to RAM. The patch for SeaBIOS is listed below. Both SeaBIOS versions works with new PAM but the modified one does not work with old PAM. ====== diff --git a/src/fw/shadow.c b/src/fw/shadow.c index 4f00006..5b0e527 100644 --- a/src/fw/shadow.c +++ b/src/fw/shadow.c @@ -26,32 +26,43 @@ static void __make_bios_writable_intel(u16 bdf, u32 pam0) { // Make ram from 0xc0000-0xf0000 writable - int clear = 0; int i; + unsigned *mem, *mem_limit; for (i=0; i<6; i++) { u32 pam = pam0 + 1 + i; int reg = pci_config_readb(bdf, pam); - if (CONFIG_OPTIONROMS_DEPLOYED && (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); + if ((reg & 0x11) != 0x11) { + mem = (unsigned *)(BUILD_ROM_START + i * 32 * 1024); + pci_config_writeb(bdf, pam, 0x22); + mem_limit = mem + 32 * 1024 / sizeof(unsigned); + + while (mem < mem_limit) { + volatile unsigned tmp = *mem; + *mem = tmp; + mem++; + } pci_config_writeb(bdf, pam, 0x33); - memcpy(mem, (void*)BUILD_BIOS_TMP_ADDR, 32*1024); - clear = 1; } else { pci_config_writeb(bdf, pam, 0x33); } } - if (clear) - memset((void*)BUILD_BIOS_TMP_ADDR, 0, 32*1024); // 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; + pci_config_writeb(bdf, pam0, 0x22); + mem = (unsigned *)BUILD_BIOS_ADDR; + mem_limit = mem + 32 * 1024 / sizeof(unsigned); + while (mem < mem_limit) { + volatile unsigned tmp = *mem; + *mem = tmp; + mem++; + } + pci_config_writeb(bdf, pam0, 0x33); + // Copy bios. extern u8 code32flat_start[], code32flat_end[]; memcpy(code32flat_start, code32flat_start + BIOS_SRC_OFFSET @@ -61,17 +72,6 @@ __make_bios_writable_intel(u16 bdf, u32 pam0) static void make_bios_writable_intel(u16 bdf, u32 pam0) { - int reg = pci_config_readb(bdf, pam0); - if (!(reg & 0x10)) { - // QEMU doesn't fully implement the piix shadow capabilities - - // if ram isn't backing the bios segment when shadowing is - // disabled, the code itself wont be in memory. So, run the - // code from the high-memory flash location. - u32 pos = (u32)__make_bios_writable_intel + BIOS_SRC_OFFSET; - void (*func)(u16 bdf, u32 pam0) = (void*)pos; - func(bdf, pam0); - return; - } // Ram already present - just enable writes __make_bios_writable_intel(bdf, pam0); } Efimov Vasily (3): memory: make function invalidate_and_set_dirty public memory: make function memory_access_is_direct public PAM: make PAM emulation closer to documentation exec.c | 14 +-- hw/pci-host/pam.c | 238 ++++++++++++++++++++++++++++++++++++----- include/exec/memory-internal.h | 15 +++ include/hw/pci-host/pam.h | 10 +- 4 files changed, 239 insertions(+), 38 deletions(-) -- 1.9.1