Author: stepan Date: 2009-12-02 15:29:32 +0100 (Wed, 02 Dec 2009) New Revision: 82
Modified: trunk/SerialICE/scripts/serialice.lua Log: LUA update:
* Fix IOAPIC and Local APIC handling by always sending the APIC writes to the CPU. Attention: This means that multi CPU/core startup commands (IPI) to be filtered (or CPUID needs to be filtered to tell the BIOS that there is only a single CPU/core) * Don't log ROM accesses per default (makes logs easier to read) * Catch the end of RAM initialization (mainboard AND BIOS specific) and let RAM accesses go to Qemu instead of the target once the RAM is initialized. Right now this is only tested on one board with i945 and Phoenix BIOS. This patch incredibly speeds up SerialICE once memory is there. Within a few hours I was able to produce a 5.5GB log file whereas before a 10MB log file took two full days. * Don't log RAM accesses once RAM is there... Fills up your hard drive far too quickly. * Remove a number of semicolons as they're not needed by LUA * return 0xff instead of 0x00 on fake serial accesses * don't write to Qemu anymore per default, as there's nothing there per default anymore.
Modified: trunk/SerialICE/scripts/serialice.lua =================================================================== --- trunk/SerialICE/scripts/serialice.lua 2009-12-02 11:40:32 UTC (rev 81) +++ trunk/SerialICE/scripts/serialice.lua 2009-12-02 14:29:32 UTC (rev 82) @@ -32,6 +32,21 @@ return io.write(s:format(...)) end
+ +-- In the beginning, during RAM initialization, it is essential that +-- all DRAM accesses are handled by the target, or RAM will not work +-- correctly. After RAM initialization, RAM access has no "special" +-- meaning anymore, so we can just use Qemu's memory (and thus get +-- an incredible speed-up) + +ram_is_initialized = false + +-- Whether to log read access (code fetches) to 0xe0000 to 0xfffff + +log_rom_access = false + +-- Remember the PCI device selected via IO CF8 + SerialICE_pci_device = 0
-- SerialICE_io_read_filter is the filter function for IO reads. @@ -61,8 +76,8 @@ -- Serial Port handling
if port >= 0x3f8 and port <= 0x3ff then - printf("serial I/O (filtered)\n") - data = 0x00 + printf("Serial I/O read (filtered)\n") + data = 0xff caught = true end
@@ -110,9 +125,9 @@
-- Catch PCIe base address if SerialICE_pci_device == 0x80000048 then - PCIe_bar = bit.band(0xfc000000,data); - PCIe_size = 64 * 1024; -- hard coded for now. - printf("PCIe BAR set up: 0x%08x\n", PCIe_bar); + PCIe_bar = bit.band(0xfc000000,data) + PCIe_size = 64 * 1024 -- hard coded for now. + printf("PCIe BAR set up: 0x%08x\n", PCIe_bar) end
return false, data @@ -198,6 +213,29 @@ return true, data end
+ -- ********************************************************** + -- + -- Intel 82945 (reference BIOS) RAM switch + -- + + -- The RAM initialization code for the i945 used by AMI and + -- Phoenix uses the same POST codes. We use this to determine + -- when RAM init is done on that chipset. + -- Not catching the end of RAM init is not problematic, except + -- that it makes decompression of the BIOS core to RAM incredibly + -- slow as the decompressor inner loop has to be fetched + -- permanently from the target (several reads/writes per + -- decompressed byte). + + if port == 0x80 and data == 0xff37 then + ram_is_initialized = true + -- Register low RAM 0x00000000 - 0x000dffff + SerialICE_register_physical(0x00000000, 0xa0000) + -- SMI/VGA memory should go to the target... + SerialICE_register_physical(0x000c0000, 0x20000) + printf("\nLow RAM accesses are now directed to Qemu.\n") + end + return false, data end
@@ -245,26 +283,40 @@ -- Local APIC.. Hm, not sure what to do here. -- We should avoid that someone wakes up cores -- on the target system that go wild. - return false, true, 0 -- Handle by Qemu for now + return true, false, 0 -- XXX Handled by target elseif addr >= 0xfec00000 and addr <= 0xfecfffff then -- IO APIC.. Hm, not sure what to do here. - return false, true, 0 -- Handle by Qemu for now + return true, false, 0 -- XXX Handled by target elseif addr >= 0xfed40000 and addr <= 0xfed45000 then -- ICH7 TPM -- Phoenix "Secure" Core bails out if we don't pass this on ;-) return true, false, 0 - elseif addr >= 0x000c0000 and addr <= 0x000fffff then + elseif addr >= 0x000e0000 and addr <= 0x000fffff then -- Low ROM accesses go to Qemu memory return false, true, 0 - elseif addr >= 0x00000000 and addr <= 0x000bffff then + elseif addr >= 0x000a0000 and addr <= 0x000affff then + -- SMI/VGA go to target + return true, false, 0 + elseif addr >= 0x00000000 and addr <= 0x000dffff then -- RAM access. This is handled by SerialICE -- but *NOT* exclusively. Writes should end -- up in Qemu memory, too - return true, false, 0 + if not ram_is_initialized then + -- RAM init has not not been marked done yet. + -- so send reads to the target only. + return true, false, 0 + end + -- RAM init is done. Send all RAM accesses + -- to Qemu. Using the target as storage would + -- only slow execution down. + -- TODO handle VGA / SMI memory correctly + return false, true, 0 elseif addr >= 0x00100000 and addr <= 0xcfffffff then - -- 3.25GB RAM. This is handled by SerialICE - -- but *NOT* exclusively. Writes should end - -- up in Qemu memory, too + -- 3.25GB RAM. This is handled by SerialICE. + -- We refrain from backing up this memory in Qemu + -- because Qemu would need 3.25G RAM on the host + -- and firmware usually does not intensively use + -- high memory anyways. return true, false, 0 else printf("\nWARNING: undefined load operation @%08x\n", addr) @@ -286,7 +338,7 @@
function SerialICE_memory_write_filter(addr, size, data) if addr >= 0xfff00000 and addr <= 0xffffffff then - io.write("\nWARNING: write access to ROM?\n") + printf("\nWARNING: write access to ROM?\n") -- ROM accesses go to Qemu only return false, true, data elseif addr >= 0xf0000000 and addr <= 0xf3ffffff then @@ -310,28 +362,36 @@ -- Local APIC.. Hm, not sure what to do here. -- We should avoid that someone wakes up cores -- on the target system that go wild. - return false, true, data + return true, false, data elseif addr >= 0xfec00000 and addr <= 0xfecfffff then -- IO APIC.. Hm, not sure what to do here. - return false, true, data + return true, false, data elseif addr >= 0xfed40000 and addr <= 0xfed45000 then -- ICH7 TPM return true, false, data - elseif addr >= 0x000c0000 and addr <= 0x000fffff then + elseif addr >= 0x000e0000 and addr <= 0x000fffff then -- Low ROM accesses go to Qemu memory return false, true, data - elseif addr >= 0x00000000 and addr <= 0x000bffff then - -- RAM access. This is handled by SerialICE - return true, false, data + elseif addr >= 0x000a0000 and addr <= 0x000affff then + -- SMI/VGA go to target + return true, true, data + elseif addr >= 0x00000000 and addr <= 0x000dffff then + -- RAM access. This is handled by SerialICE during + -- RAM initialization and by Qemu later on. + if not ram_is_initialized then + return true, true, data + end + -- Don't send writes to the target for speed reasons. + return false, true, data elseif addr >= 0x00100000 and addr <= 0xcfffffff then -- 3.25 GB RAM ... This is handled by SerialICE return true, false, data else printf("\nWARNING: undefined store operation @%08x\n", addr) - -- Fall through, send to both Qemu and SerialICE + -- Fall through, send to SerialICE end
- return true, true, data + return true, false, data end
function SerialICE_msr_read_filter(addr, hi, lo) @@ -359,14 +419,21 @@ -- logging functions
function SerialICE_memory_write_log(addr, size, data, target) + if addr >= 0x00000000 and addr <= 0x0009ffff and ram_is_initialized then + return + end + if addr >= 0x000c0000 and addr <= 0x000dffff and ram_is_initialized then + return + end + if size == 1 then printf("MEM: writeb %08x <= %02x", addr, data) elseif size == 2 then printf("MEM: writew %08x <= %04x", addr, data) elseif size == 4 then printf("MEM: writel %08x <= %08x", addr, data) end if target then - printf(" *"); + printf(" *") end - printf("\n"); + printf("\n")
-- ********************************************************** -- @@ -381,14 +448,27 @@ end
function SerialICE_memory_read_log(addr, size, data, target) + if addr >= 0x00000000 and addr <= 0x0009ffff and ram_is_initialized then + return + end + if addr >= 0x000c0000 and addr <= 0x000dffff and ram_is_initialized then + return + end + if addr >= 0xe0000 and addr <= 0xfffff and not log_rom_access then + return + end + if addr >= 0xfff00000 and addr <= 0xffffffff and not log_rom_access then + return + end + if size == 1 then printf("MEM: readb %08x => %02x", addr, data) elseif size == 2 then printf("MEM: readw %08x => %04x", addr, data) elseif size == 4 then printf("MEM: readl %08x => %08x", addr, data) end if target then - printf(" *"); + printf(" *") end - printf("\n"); + printf("\n")
-- ********************************************************** --