[SerialICE] New patch to review for serialice: c587257 Modularized SerialICE scripting
Kyösti Mälkki (kyosti.malkki@gmail.com)
gerrit at coreboot.org
Wed Apr 4 16:37:51 CEST 2012
Kyösti Mälkki (kyosti.malkki at gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/860
-gerrit
commit c5872570b7bad3a74a201cd1e5cae5b0bc6ea08a
Author: Kyösti Mälkki <kyosti.malkki at gmail.com>
Date: Wed Apr 4 17:26:04 2012 +0300
Modularized SerialICE scripting
This is script/serialice.lua split into separate files.
It expects to find a match for the *mb command response and load
a correct .lua file for that particular mainboard.
There is a bit improved filter for PCI configuration registers,
even when written in multiple parts. Good for catching BARs.
Some filters for which I did not yet find proper location are in
the file leftover.lua, some of these were vendor bios binary specific.
As for the name simba/, it stands for simulated bus access. Plan is
to modify these further and divert some SMBus traffic to qemu
and not the real hw. One could then read SPD data from a local file.
Change-Id: Idba1c3dc7e80ebf169ff277ab7918a1564822bfe
Signed-off-by: Kyösti Mälkki <kyosti.malkki at gmail.com>
---
SerialICE/simba/aopen_dxpl_plus.lua | 94 ++++++++++++
SerialICE/simba/core_io.lua | 283 +++++++++++++++++++++++++++++++++++
SerialICE/simba/cpu.lua | 94 ++++++++++++
SerialICE/simba/i82801dx.lua | 108 +++++++++++++
SerialICE/simba/leftover.lua | 135 +++++++++++++++++
SerialICE/simba/memory.lua | 239 +++++++++++++++++++++++++++++
SerialICE/simba/misc.lua | 79 ++++++++++
SerialICE/simba/serialice.lua | 155 +++++++++++++++++++
SerialICE/simba/superio.lua | 172 +++++++++++++++++++++
9 files changed, 1359 insertions(+), 0 deletions(-)
diff --git a/SerialICE/simba/aopen_dxpl_plus.lua b/SerialICE/simba/aopen_dxpl_plus.lua
new file mode 100644
index 0000000..db528e5
--- /dev/null
+++ b/SerialICE/simba/aopen_dxpl_plus.lua
@@ -0,0 +1,94 @@
+
+
+dofile("i82801dx.lua")
+
+-- **********************************************************
+--
+
+function mainboard_io_read(port, size, data, filter)
+
+ -- KBD controller is stuck, clear 0x02
+ if ( port == 0x64 and size == 1 ) then
+ filter.filter = true
+ filter.data = 0x80
+ return true
+ end
+
+ -- Timer loop
+ if ( port == 0x61 ) then
+ -- if ( regs.cs == 0x1000 and regs.eip == 0x1634 ) then
+ if ( regs.eip == 0x1634 ) then
+ printf("Skipping delay at %04x:%04x\n", regs.cs, regs.eip);
+ regs.ecx = 0x01
+ return true, 0x20
+ end
+ -- if ( regs.cs == 0x1000 and regs.eip == 0x163a ) then
+ if ( regs.eip == 0x163a ) then
+ printf("Skipping delay at %04x:%04x\n", regs.cs, regs.eip);
+ regs.ecx = 0x01
+ return true, 0x30
+ end
+ end
+
+end
+
+
+function mainboard_io_write(port, size, data, filter)
+
+ -- **********************************************************
+ -- 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 == 0x2c and ram_is_initialized == false 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")
+
+ return false, data
+ end
+
+ if ( port == 0xed ) then
+ -- if ( regs.cs == 0x1000 and regs.eip == 0x1792 and regs.ecx == 0x0000fff0 ) then
+ if ( regs.eip == 0x1792 ) then
+ printf("Skipping IO delay... #2 \n")
+ regs.ecx = 0x01
+ end
+
+ -- SIPI delay
+ -- if ( regs.cs == 0xe000 and regs.eip == 0xb3bc and regs.ecx == 0x200) then
+ if ( regs.eip == 0xb3bc or regs.eip == 0xb3bf ) then
+ printf("Skipping IO delay... IPI #0\n")
+ regs.ecx = 0x01
+ end
+ -- if ( regs.cs == 0xe000 and regs.eip == 0xb4af and regs.ecx == 0x200) then
+ if ( regs.eip == 0xb4ad or regs.eip == 0xb4af ) then
+ printf("Skipping IO delay... IPI #1\n")
+ regs.ecx = 0x01
+ end
+
+ return false, data
+ end
+
+end
+
+function mainboard_io_write_log(port, size, data, target)
+ if port == 0xed then
+ return true -- Ignore
+ end
+ if port == 0xcfb then
+ return true -- Ignore
+ end
+end
+
+
+prepend_to_list(io_read_hooks, mainboard_io_read)
+prepend_to_list(io_write_hooks, mainboard_io_write)
+prepend_to_list(io_write_log_hooks, mainboard_io_write_log)
+
+
diff --git a/SerialICE/simba/core_io.lua b/SerialICE/simba/core_io.lua
new file mode 100644
index 0000000..1cdc2a0
--- /dev/null
+++ b/SerialICE/simba/core_io.lua
@@ -0,0 +1,283 @@
+
+-- **********************************************************
+--
+-- IO access
+
+
+io_read_hooks = new_list()
+io_write_hooks = new_list()
+io_read_log_hooks = new_list()
+io_write_log_hooks = new_list()
+
+
+-- SerialICE_io_read_filter is the filter function for IO reads.
+--
+-- Parameters:
+-- port IO port to be read
+-- data_size Size of the IO read
+-- Return values:
+-- caught True if the filter intercepted the read
+-- data Value returned if the read was intercepted
+
+function SerialICE_io_read_filter(port, size)
+ local data = 0
+ filter = { filter = false, data = data }
+ if walk_list(io_read_hooks, port, size, data, filter) then
+ return filter.filter, filter.data
+ end
+
+ return false, data
+end
+
+-- SerialICE_io_write_filter is the filter function for IO writes.
+--
+-- Parameters:
+-- port IO port to be written to
+-- size Size of the IO write
+-- data Data to be written to
+-- Return values:
+-- caught True if the filter intercepted the write
+-- data Value returned if the write was *not* intercepted
+
+function SerialICE_io_write_filter(port, size, data)
+ filter = { filter = false, data = data }
+ if walk_list(io_write_hooks, port, size, data, filter) then
+ return filter.filter, filter.data
+ end
+
+ return false, data
+end
+
+
+function SerialICE_io_write_log(port, size, data, target)
+ log_cs_ip()
+ if walk_list(io_write_log_hooks, port, size, data, target) then
+ return
+ end
+
+ printf("IO: out%s %04x <= %s\n", size_suffix(size), port, size_data(size, data))
+end
+
+function SerialICE_io_read_log(port, size, data, target)
+ log_cs_ip()
+ if walk_list(io_read_log_hooks, port, size, data, target) then
+ return
+ end
+
+ printf("IO: in%s %04x => %s\n", size_suffix(size), port, size_data(size, data))
+end
+
+
+
+-- **********************************************************
+--
+-- PCI IO config access
+
+
+pci_cfg_hooks = new_list()
+
+function add_pci_cfg_hook(bdf, size, func)
+ value = { bdf = bdf, size = size, func = func }
+ prepend_to_list(pci_cfg_hooks, value)
+end
+
+function is_pci_cfg_hooked(bdf)
+ local l = pci_cfg_hooks.list
+ while l do
+ if bdf == bit.band(l.value.bdf, bit.bnot(0x03)) then
+ return true
+ end
+ l = l.next
+ end
+ return false
+end
+
+function call_pci_cfg_hook(bdf, size, data)
+ local l = pci_cfg_hooks.list
+ while l do
+ if l.value.bdf == bdf and l.value.size == size then
+ l.value.func(bdf, size, data)
+ end
+ l = l.next
+ end
+ return false
+end
+
+function pci_bdf(bus, dev, func, reg)
+ return 0x80000000 + bus*65536 + dev*2048 + func*256 + reg
+end
+
+-- Remember the PCI device selected via IO CF8
+SerialICE_pci_device = 0
+
+
+-- Catch partial PCI configuration register writes.
+-- This synthesizes 32/16 bit wide access from separate
+-- 16/8 bit accesses for pci_cfg_hooks.
+
+port_0cf8 = 0
+port_0cfc = 0
+bv = {}
+
+function port_0cf8_reset(data)
+ local port_0cf8_new = bit.band(data,bit.bnot(0x3))
+ if not (port_0cf8 == port_0cf8_new) then
+ port_0cf8 = 0
+ if (is_pci_cfg_hooked(port_0cf8_new)) then
+ port_0cf8 = port_0cf8_new
+ end
+ for i = 0, 3, 1 do bv[i] = false end
+ end
+end
+
+function port_0cfc_access(port, size, data)
+
+ local av = {}
+
+ for i = 0, 3, 1 do av[i] = false end
+
+ ll = 8 * (port%4)
+ if (size == 1) then
+ av[port%4] = true
+ bv[port%4] = true
+ amask = bit.lshift(0xff, ll)
+ omask = bit.lshift(data, ll)
+ port_0cfc = bit.band(port_0cfc, bit.bnot(amask))
+ port_0cfc = bit.bor(port_0cfc, omask)
+ elseif (size == 2) then
+ av[port%4] = true
+ bv[port%4] = true
+ av[port%4+1] = true
+ bv[port%4+1] = true
+ amask = bit.lshift(0xffff, ll)
+ omask = bit.lshift(data, ll)
+ port_0cfc = bit.band(port_0cfc, bit.bnot(amask))
+ port_0cfc = bit.bor(port_0cfc, omask)
+ elseif (size == 4) then
+ port_0cfc = data
+ for i = 0, 3, 1 do av[i] = true end
+ for i = 0, 3, 1 do bv[i] = true end
+ end
+
+ for i = 0, 3, 1 do
+ if (bv[i] and av[i]) then
+ call_pci_cfg_hook(port_0cf8 + i, 1,
+ bit.band(0xff, bit.rshift(port_0cfc, i*8)))
+ end
+ end
+ if ((bv[0] and bv[1]) and (av[0] or av[1])) then
+ call_pci_cfg_hook(port_0cf8 + 0x00, 2,
+ bit.band(0xffff, bit.rshift(port_0cfc, 0)))
+ end
+ if (bv[2] and bv[3] and (av[2] or av[3])) then
+ call_pci_cfg_hook(port_0cf8 + 0x02, 2,
+ bit.band(0xffff, bit.rshift(port_0cfc, 16)))
+ end
+ if (bv[0] and bv[1] and bv[2] and bv[3]) then
+ call_pci_cfg_hook(port_0cf8, 4, port_0cfc)
+ end
+end
+
+
+function pci_io_cfg_write(port, size, data, filter)
+ if port == 0xcf8 then
+ port_0cf8_reset(data)
+ SerialICE_pci_device = data
+ return false
+ end
+ if port_0cf8 ~= 0 and port >= 0xcfc and port <= 0xcff then
+ port_0cfc_access(port, size, data)
+ end
+ return false
+end
+
+-- not enabled
+function pci_io_cfg_read(port, size, data, filter)
+ if port_0cf8 ~= 0 and port >= 0xcfc and port <= 0xcff then
+ port_0cfc_access(port, size, data)
+ end
+ return false
+end
+
+function pci_io_cfg_write_log(port, size, data, target)
+ if port == 0xcf8 then
+ return not log_pci_io_cfg
+ end
+ if port >= 0xcfc and port <= 0xcff then
+ printf("PCI %x:%02x.%x R.%02x <= %s\n",
+ bit.band(0xff,bit.rshift(SerialICE_pci_device, 16)),
+ bit.band(0x1f,bit.rshift(SerialICE_pci_device, 11)),
+ bit.band(0x7,bit.rshift(SerialICE_pci_device, 8)),
+ bit.band(0xff,SerialICE_pci_device + (port - 0xcfc)),
+ size_data(size, data))
+ return not log_pci_io_cfg
+ end
+end
+
+function pci_io_cfg_read_log(port, size, data, target)
+ if port == 0xcf8 then
+ return not log_pci_io_cfg
+ end
+ if port >= 0xcfc and port <= 0xcff then
+ printf("PCI %x:%02x.%x R.%02x => %s\n",
+ bit.band(0xff,bit.rshift(SerialICE_pci_device, 16)),
+ bit.band(0x1f,bit.rshift(SerialICE_pci_device, 11)),
+ bit.band(0x7,bit.rshift(SerialICE_pci_device, 8)),
+ bit.band(0xff,SerialICE_pci_device + (port - 0xcfc)),
+ size_data(size, data))
+ return not log_pci_io_cfg
+ end
+end
+
+if decode_pci_io_cfg then
+ prepend_to_list(io_write_hooks, pci_io_cfg_write)
+-- prepend_to_list(io_read_hooks, pci_io_cfg_read)
+ prepend_to_list(io_write_log_hooks, pci_io_cfg_write_log)
+ prepend_to_list(io_read_log_hooks, pci_io_cfg_read_log)
+end
+
+-- **********************************************************
+--
+-- PCIe MM config access
+
+PCIe_bar = 0
+PCIe_size = 0
+
+function pci_mm_cfg_read_log(addr, size, data, target)
+ if addr >= PCIe_bar and addr < (PCIe_bar + PCIe_size) then
+ printf("PCIe %x:%02x.%x R.%02x => %s\n",
+ bit.band(0xff,bit.rshift(addr, 20)),
+ bit.band(0x1f,bit.rshift(addr, 15)),
+ bit.band(0x7,bit.rshift(addr, 12)),
+ bit.band(0xfff,addr),
+ size_data(size, data))
+ return not log_pci_mm_cfg
+ end
+end
+
+function pci_mm_cfg_write_log(addr, size, data, target)
+ if addr >= PCIe_bar and addr < (PCIe_bar + PCIe_size) then
+ printf("PCIe %x:%02x.%x R.%02x <= %s\n",
+ bit.band(0xff,bit.rshift(addr, 20)),
+ bit.band(0x1f,bit.rshift(addr, 15)),
+ bit.band(0x7,bit.rshift(addr, 12)),
+ bit.band(0xfff,addr),
+ size_data(size, data))
+ return not log_pci_mm_cfg
+ end
+end
+
+function pcie_mm_cfg_bar(base, size)
+
+ PCIe_bar = base
+ PCIe_size = size
+ printf("PCIe MM config BAR: 0x%08x\n", PCIe_bar)
+
+ if decode_pci_mm_cfg then
+ --prepend_to_list(mem_write_hooks, pci_mm_cfg_write)
+ --prepend_to_list(mem_read_hooks, pci_mm_cfg_read)
+ prepend_to_list(mem_write_log_hooks, pci_mm_cfg_write_log)
+ prepend_to_list(mem_read_log_hooks, pci_mm_cfg_read_log)
+ end
+end
+
diff --git a/SerialICE/simba/cpu.lua b/SerialICE/simba/cpu.lua
new file mode 100644
index 0000000..f7d2dbd
--- /dev/null
+++ b/SerialICE/simba/cpu.lua
@@ -0,0 +1,94 @@
+
+
+msr_read_log_hooks = new_list()
+msr_write_log_hooks = new_list()
+
+
+function var_mtrr_log_write(addr, hi, lo, filtered)
+ if addr >= 0x200 and addr < 0x210 then
+ if addr % 2 == 0 then
+ mt = lo % 0x100
+ if mt == 0 then memtype = "Uncacheable"
+ elseif mt == 1 then memtype = "Write-Combine"
+ elseif mt == 4 then memtype = "Write-Through"
+ elseif mt == 5 then memtype = "Write-Protect"
+ elseif mt == 6 then memtype = "Write-Back"
+ else memtype = "Unknown"
+ end
+ printf("CPU: Set MTRR %x base to %08x.%08x (%s)\n", (addr - 0x200) / 2, hi, bit.band(lo, 0xffffff00), memtype)
+ else
+ if bit.band(lo, 0x800) == 0x800 then
+ valid = "valid"
+ else
+ valid = "disabled"
+ end
+ printf("CPU: Set MTRR %x mask to %08x.%08x (%s)\n", (addr - 0x200) / 2, hi, bit.band(lo, 0xfffff000), valid)
+ end
+ return true
+ end
+ return false
+end
+
+
+
+function SerialICE_msr_read_filter(addr, hi, lo)
+ -- Intel CPU microcode revision check.
+ if addr == 0x8b then
+ -- fake microcode revision of my 0x6f6 Core 2 Duo Mobile
+ return true, 0xc7, 0x00
+ end
+
+ return false, hi, lo
+end
+
+function SerialICE_msr_write_filter(addr, hi, lo)
+ -- Intel CPU microcode update
+ if addr == 0x79 then
+ return true, 0, 0xffff0000
+ end
+
+ return false, hi, lo
+end
+
+function SerialICE_msr_write_log(addr, hi, lo, filtered)
+ log_cs_ip()
+ if not walk_list(msr_write_log_hooks, addr, hi, lo, filtered) then
+ printf("CPU: wrmsr %08x <= %08x.%08x\n", addr, hi, lo)
+ end
+end
+
+function SerialICE_msr_read_log(addr, hi, lo, filtered)
+ log_cs_ip()
+ if not walk_list(msr_read_log_hooks, addr, hi, lo, filtered) then
+ printf("CPU: rdmsr %08x => %08x.%08x\n", addr, hi, lo)
+ end
+end
+
+
+prepend_to_list(msr_write_log_hooks, var_mtrr_log_write)
+
+
+-- **********************************************************
+--
+-- CPUID instruction
+
+function SerialICE_cpuid_filter(in_eax, in_ecx, eax, ebx, ecx, edx)
+ -- Set number of cores to 1 on Core Duo and Atom to trick the
+ -- firmware into not trying to wake up non-BSP nodes.
+ if in_eax == 1 then
+ ebx = bit.band(0xff00ffff, ebx);
+ ebx = bit.bor(0x00010000, ebx);
+ return true, eax, ebx, ecx, edx
+ end
+
+ -- return false, so the result is not filtered.
+ return false, eax, ebx, ecx, edx
+end
+
+
+function SerialICE_cpuid_log(in_eax, in_ecx, out_eax, out_ebx, out_ecx, out_edx, filtered)
+ log_cs_ip()
+ printf("CPU: CPUID eax: %08x; ecx: %08x => %08x.%08x.%08x.%08x\n",
+ in_eax, in_ecx, out_eax, out_ebx, out_ecx, out_edx)
+end
+
diff --git a/SerialICE/simba/i82801dx.lua b/SerialICE/simba/i82801dx.lua
new file mode 100644
index 0000000..712be69
--- /dev/null
+++ b/SerialICE/simba/i82801dx.lua
@@ -0,0 +1,108 @@
+-- **********************************************************
+--
+-- LPC decode ranges
+
+
+function lpc_decode_write(port, size, data, filter)
+ -- LPC decode registers
+ if SerialICE_pci_device == pci_bdfr(0x0,0x1f,0x3,0xe6) then
+ printf("LPC (filtered)\n")
+ filter.filter = true
+ filter.data = data
+ return true
+ end
+end
+
+function lpc_decode_hook(bdfr, size, data)
+ printf("got LPC %08x %d %08x\n", bdfr, size, data);
+end
+
+add_pci_cfg_hook(pci_bdf(0x0,0x1f,0x0,0xe4), 4, lpc_decode_hook)
+add_pci_cfg_hook(pci_bdf(0x0,0x1f,0x0,0xe6), 2, lpc_decode_hook)
+
+
+-- **********************************************************
+--
+-- SMBus controller handling
+
+smbus_host_base = 0
+smbus_host_size = 0
+
+function smbus_io_write_log(port, size, data, target)
+ if port >= smbus_host_base and port < smbus_host_base+smbus_host_size then
+ return not log_smbus_io
+ end
+end
+
+function smbus_io_read_log(port, size, data, target)
+ if port >= smbus_host_base and port < smbus_host_base+smbus_host_size then
+ return not log_smbus_io
+ end
+end
+
+
+function smbus_bar_setup(base, size)
+
+ smbus_host_base = base
+ smbus_host_size = size
+
+ printf("SMBus BAR set up: 0x%08x\n", smbus_host_base)
+ if decode_smbus then
+ prepend_to_list(io_write_log_hooks, smbus_io_write_log)
+ prepend_to_list(io_read_log_hooks, smbus_io_read_log)
+ end
+end
+
+function smbus_bar_hook(bdfr, size, data)
+ smbus_bar_setup(bit.band(data, 0x10000-0x20), 0x20)
+end
+
+add_pci_cfg_hook(pci_bdf(0x0,0x1f,0x3,0x20), 2, smbus_bar_hook)
+
+
+-- **********************************************************
+--
+
+function acpi_bar_hook(bdfr, size, data)
+ printf("ACPI BAR set up: 0x%08x\n", data)
+ printf("TCO BAR set up: 0x%08x\n", data + 0x60)
+ --acpi_bar_setup(bit.band(data, 0x10000-0x80), 0x80)
+end
+
+
+function gpio_bar_hook(bdfr, size, data)
+ printf("GPIO BAR set up: 0x%08x\n", data)
+ --gpio_bar_setup(bit.band(data, 0x10000-0x40), 0x40)
+end
+
+add_pci_cfg_hook(pci_bdf(0x0,0x1f,0x0,0x40), 2, acpi_bar_hook)
+add_pci_cfg_hook(pci_bdf(0x0,0x1f,0x0,0x58), 2, gpio_bar_hook)
+
+
+-- **********************************************************
+--
+-- AC '97 controller handling
+
+function audio_nambar_hook(bdfr, size, data)
+ printf("AUDIO NAMBAR set up: 0x%08x\n", data)
+end
+function audio_nabmbar_hook(bdfr, size, data)
+ printf("AUDIO NABMBAR set up: 0x%08x\n", data)
+end
+function audio_mmbar_hook(bdfr, size, data)
+ printf("AUDIO MMBAR set up: 0x%08x\n", data)
+end
+function audio_mbbar_hook(bdfr, size, data)
+ printf("AUDIO MBBAR set up: 0x%08x\n", data)
+end
+
+add_pci_cfg_hook(pci_bdf(0x0,0x1f,0x5,0x10), 2, audio_nambar_hook)
+add_pci_cfg_hook(pci_bdf(0x0,0x1f,0x5,0x14), 2, audio_nabmbar_hook)
+add_pci_cfg_hook(pci_bdf(0x0,0x1f,0x5,0x18), 4, audio_mmbar_hook)
+add_pci_cfg_hook(pci_bdf(0x0,0x1f,0x5,0x1c), 4, audio_mbbar_hook)
+
+
+
+
+
+
diff --git a/SerialICE/simba/leftover.lua b/SerialICE/simba/leftover.lua
new file mode 100644
index 0000000..8839248
--- /dev/null
+++ b/SerialICE/simba/leftover.lua
@@ -0,0 +1,135 @@
+
+
+ -- **********************************************************
+ --
+ -- Dell 1850 BMC filter
+
+ if port == 0xe8 then
+ -- lua lacks a switch statement
+ if data == 0x44656c6c then printf("BMC: Dell\n")
+ elseif data == 0x50726f74 then printf("BMC: Prot\n")
+ elseif data == 0x496e6974 then
+ printf("BMC: Init (filtered)\n")
+ return true, data
+ else
+ printf("BMC: unknown %08x\n", data)
+ end
+ return false, data
+ end
+
+ -- **********************************************************
+ --
+ -- Phoenix BIOS reconfigures 0:1f.0 reg 0x80/0x82.
+ -- This effectively wipes out our communication channel
+ -- so we mut not allow it.
+
+ if port == 0xcfc then
+ if SerialICE_pci_device == 0x8000f880 then
+ printf("LPC (filtered)\n")
+ return true, data
+ end
+
+ return false, 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.
+
+
+ if port == 0x80 and data == 0xff37 and ram_is_initialized == false 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")
+
+ return false, data
+ end
+
+
+ -- **********************************************************
+ --
+ -- unknown io_write delay hooks
+ --
+
+ if ( port == 0xed and data == 0x40 ) then
+ if ( regs.eip == 0x3ed and regs.ecx == 0x00000290 ) then
+ printf("Skipping IO delay...\n")
+ -- f100:03ed
+ regs.ecx = 0x05
+ end
+ end
+
+ if ( port == 0xed and data == 0x83 )
+ then
+ if ( regs.eip == 0x1bb and regs.ecx == 0x0000fff0 ) then
+ printf("Skipping IO delay...\n")
+ -- e002:01bb
+ regs.ecx = 0x10
+ regs.ebx = 0x01
+ end
+ end
+
+
+
+
+ -- **********************************************************
+ --
+ -- io_read hooks, unknown vendor
+
+ -- if port == 0x42 then
+ -- printf("WARNING: Hijacking timer port 0x42\n")
+ -- data = 0x80
+ -- caught = true
+ -- end
+
+ --
+ --
+
+ if ( port == 0x60 and data_size == 1 ) then
+ if ( regs.eip == 0xbd6d and regs.eax == 0x8aa and regs.ecx == 0x00fffff0 ) then
+ -- f000:bd6d
+ printf("Skipping keyboard timeout...\n")
+ regs.eax = 0x01aa
+ regs.ecx = 0x0010
+ end
+ end
+
+
+-- **********************************************************
+-- Intel 82945 PCIe BAR
+
+function pcie_bar_hook(bdfr, size, data)
+ -- size is hard coded 64k for now.
+ pcie_mm_cfg_bar(bit.band(0xfc000000,data) % 0x100000000, 64 * 1024)
+end
+
+if northbridge == "intel-i945" then
+ add_pci_cfg_hook(pci_bdf(0,0,0,0x48), 4, pcie_bar_hook)
+end
+
+-- **********************************************************
+--
+-- Vendor specific Cache-As-Ram regions
+
+printf("SerialICE: Registering physical memory areas for Cache-As-Ram:\n")
+
+-- Register Phoenix BIOS Cache as RAM area as normal RAM
+-- 0xffd80000 - 0xffdfffff
+new_car_region(0xffd80000, 0x80000)
+
+-- Register AMI BIOS Cache as RAM area as normal RAM
+-- 0xffbc0000 - 0xffbfffff
+new_car_region(0xffbc0000, 0x40000)
+
+-- current Phoenix BIOS
+new_car_region(0xde000, 0x2000)
+
diff --git a/SerialICE/simba/memory.lua b/SerialICE/simba/memory.lua
new file mode 100644
index 0000000..4c1dbc5
--- /dev/null
+++ b/SerialICE/simba/memory.lua
@@ -0,0 +1,239 @@
+
+
+mem_read_log_hooks = new_list()
+mem_write_log_hooks = new_list()
+
+
+car_regions = { list = nil }
+
+function new_car_region(start, size)
+ car_regions.list = { next = car_regions.list, start = start, size = size }
+ SerialICE_register_physical(start, size)
+end
+
+function is_car(addr)
+ if car_regions.list == nil then
+ return false
+ end
+ local l = car_regions.list
+ while l do
+ if addr >= l.start and addr < l.start + l.size then
+ return true
+ end
+ l = l.next
+ end
+ return false
+end
+
+
+-- SerialICE_memory_read_filter is the filter function for memory reads
+--
+-- Parameters:
+-- addr memory address to be read
+-- size Size of the memory read
+-- Return values:
+-- to_hw True if the read should be directed to the target
+-- to_qemu True if the read should be directed to Qemu
+-- result Read result if both to_hw and to_qemu are false
+
+function SerialICE_memory_read_filter(addr, size)
+
+ -- Example: catch memory read and return a value
+ -- defined in this script:
+ --
+ -- if addr == 0xfec14004 and size == 4 then
+ -- return false, false, 0x23232323
+ -- end
+
+ -- Cache-As-RAM is exclusively
+ -- handled by Qemu (RAM backed)
+ if is_car(addr) then
+ return false, true, 0
+ end
+
+ if addr >= rom_base and addr <= 0xffffffff then
+ -- ROM accesses go to Qemu only
+ return false, true, 0
+ elseif addr >= PCIe_bar and addr <= (PCIe_bar + PCIe_size) then
+ -- PCIe MMIO config space accesses are
+ -- exclusively handled by the SerialICE
+ -- target
+ return true, false, 0
+ elseif addr >= 0xfed10000 and addr <= 0xfed1ffff then
+ -- Intel chipset BARs are exclusively
+ -- handled by the SerialICE target
+ return true, false, 0
+ elseif addr >= 0xfee00000 and addr <= 0xfeefffff then
+ -- 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 true, false, 0 -- XXX Handled by target
+ elseif addr >= 0xfec00000 and addr <= 0xfecfffff then
+ -- IO APIC.. Hm, not sure what to do here.
+ 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 >= 0x000e0000 and addr <= 0x000fffff then
+ -- Low ROM accesses go to Qemu memory
+ return false, true, 0
+ 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
+ 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.
+ -- 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)
+ -- Fall through and handle by Qemu
+ end
+ return false, true, 0
+end
+
+-- SerialICE_memory_write_filter is the filter function for memory writes
+--
+-- Parameters:
+-- addr memory address to write to
+-- size Size of the memory write
+-- data Data to be written
+-- Return values:
+-- to_hw True if the write should be directed to the target
+-- to_qemu True if the write should be directed to Qemu
+-- result Data to be written (may be changed in filter)
+
+function SerialICE_memory_write_filter(addr, size, data)
+ -- Cache-As-RAM is exclusively
+ -- handled by Qemu (RAM backed)
+ if is_car(addr) then
+ return false, true, data
+ end
+
+ if addr >= rom_base and addr <= 0xffffffff then
+ printf("\nWARNING: write access to ROM?\n")
+ -- ROM accesses go to Qemu only
+ return false, true, data
+ elseif addr >= PCIe_bar and addr <= (PCIe_bar + PCIe_size) then
+ -- PCIe MMIO config space accesses are
+ -- exclusively handled by the SerialICE
+ -- target
+ return true, false, data
+ elseif addr >= 0xfed10000 and addr <= 0xfed1ffff then
+ -- Intel chipset BARs are exclusively
+ -- handled by the SerialICE target
+ return true, false, data
+ elseif addr >= 0xfee00000 and addr <= 0xfeefffff then
+ -- 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 true, false, data
+ elseif addr >= 0xfec00000 and addr <= 0xfecfffff then
+ -- IO APIC.. Hm, not sure what to do here.
+ return true, false, data
+ elseif addr >= 0xfed40000 and addr <= 0xfed45000 then
+ -- ICH7 TPM
+ return true, false, data
+ elseif addr >= 0x000e0000 and addr <= 0x000fffff then
+ -- Low ROM accesses go to Qemu memory
+ return false, true, 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
+ if addr == 0x00100000 then
+ if regs.cs == 0xe002 and regs.eip == 0x07fb then
+ -- skip high memory wipe
+ regs.ecx = 0x10
+ end
+ if regs.cs == 0xe002 and regs.eip == 0x076c and regs.edi == 0x3f then
+ -- skip high memory test
+ regs.edi=1;
+ end
+ end
+
+ -- 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 SerialICE
+ end
+
+ return true, false, data
+end
+
+
+
+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
+
+ log_cs_ip()
+
+ if walk_list(mem_write_log_hooks, addr, size, data, target) then
+ return
+ end
+
+ printf("MEM: write%s %08x <= %s", size_suffix(size), addr, size_data(size, data))
+ if target then
+ printf(" *")
+ end
+ printf("\n")
+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 >= rom_base and addr <= 0xffffffff and not log_rom_access then
+ return
+ end
+
+ log_cs_ip()
+
+ if walk_list(mem_read_log_hooks, addr, size, data, target) then
+ return
+ end
+
+ printf("MEM: read%s %08x => %s", size_suffix(size), addr, size_data(size, data))
+ if target then
+ printf(" *")
+ end
+ printf("\n")
+end
+
diff --git a/SerialICE/simba/misc.lua b/SerialICE/simba/misc.lua
new file mode 100644
index 0000000..dc8f00e
--- /dev/null
+++ b/SerialICE/simba/misc.lua
@@ -0,0 +1,79 @@
+-- **********************************************************
+--
+-- CMOS nvram
+
+port_70_reg = 0x0
+port_72_reg = 0x0
+
+function nvram_write(port, size, data, filter)
+ if port == 0x70 then
+ port_70_reg = bit.band(0x7f, data)
+ return false, data
+ end
+ if port == 0x72 then
+ port_72_reg = bit.band(0x7f, data)
+ return false, data
+ end
+
+end
+
+function nvram_write_log(port, size, data, target)
+ if port == 0x71 then
+ printf("NVram: [%02x] <= %02x\n", port_70_reg, data)
+ return not log_nvram_cfg
+ end
+ if port == 0x73 then
+ printf("NVram: [%02x] <= %02x\n", 0x80 + port_72_reg, data)
+ return not log_nvram_cfg
+ end
+ if port >= 0x70 and port < 0x74 then
+ return not log_nvram_cfg
+ end
+ return false
+end
+
+function nvram_read_log(port, size, data, target)
+ if port == 0x71 then
+ printf("NVram: [%02x] => %02x\n", port_70_reg, data)
+ return not log_nvram_cfg
+ end
+ if port == 0x73 then
+ printf("NVram: [%02x] => %02x\n", 0x80 + port_72_reg, data)
+ return not log_nvram_cfg
+ end
+ if port >= 0x70 and port < 0x74 then
+ return not log_nvram_cfg
+ end
+ return false
+end
+
+
+if decode_nvram then
+ prepend_to_list(io_write_hooks, nvram_write)
+ prepend_to_list(io_write_log_hooks, nvram_write_log)
+ prepend_to_list(io_read_log_hooks, nvram_read_log)
+end
+
+-- **********************************************************
+--
+-- System reset
+
+function sys_rst(port, size, data, filter)
+ if port == 0xcf9 and data == 0x06 then
+ SerialICE_system_reset()
+ return false, data
+ end
+end
+
+function sys_rst_log(port, size, data, target)
+ if port == 0xcf9 then
+ printf("Reset triggered at %04x:%04x\n", regs.cs, regs.eip);
+ return true
+ end
+end
+
+if decode_sys_rst then
+ prepend_to_list(io_write_hooks, sys_rst)
+ prepend_to_list(io_write_log_hooks, sys_rst_log)
+end
+
diff --git a/SerialICE/simba/serialice.lua b/SerialICE/simba/serialice.lua
new file mode 100644
index 0000000..a5535bb
--- /dev/null
+++ b/SerialICE/simba/serialice.lua
@@ -0,0 +1,155 @@
+-- SerialICE
+--
+-- Copyright (c) 2009 coresystems GmbH
+--
+-- Permission is hereby granted, free of charge, to any person obtaining a copy
+-- of this software and associated documentation files (the "Software"), to deal
+-- in the Software without restriction, including without limitation the rights
+-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+-- copies of the Software, and to permit persons to whom the Software is
+-- furnished to do so, subject to the following conditions:
+--
+-- The above copyright notice and this permission notice shall be included in
+-- all copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+-- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+-- THE SOFTWARE.
+--
+
+io.write("SerialICE: Starting LUA script\n")
+
+-- If you get an error here, install bitlib
+-- (ie. http://luaforge.net/projects/bitlib/)
+require("bit")
+
+
+-- -------------------------------------------------------------------
+-- logging functions
+
+function log_cs_ip()
+ if (ip_logging) then printf("[%04x:%04x] -- ", regs.cs, regs.eip) end
+end
+
+function printf(s,...)
+ return io.write(s:format(...))
+end
+
+function trim (s)
+ return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
+end
+
+function size_suffix(size)
+ if size == 1 then return "b"
+ elseif size == 2 then return "w"
+ elseif size == 4 then return "l"
+ elseif size == 8 then return "ll"
+ else return string.format("invalid size: %d", size)
+ end
+end
+
+function size_data(size, data)
+ if size == 1 then return string.format("%02x", data)
+ elseif size == 2 then return string.format("%04x", data)
+ elseif size == 4 then return string.format("%08x", data)
+ elseif size == 8 then return string.format("%16x", data)
+ else return string.format("Error: size=%x", size)
+ end
+end
+
+
+
+function new_list()
+ return { list = nil }
+end
+
+function prepend_to_list(list, value)
+ list.list = { next = list.list, value = value }
+end
+
+function walk_list(list, ...)
+ if list == nil or list.list == nil then
+ return false
+ end
+ local l = list.list
+ while l do
+ if l.value(...) then
+ return true
+ end
+ l = l.next
+ end
+ return false
+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)
+
+-- 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).
+
+ram_is_initialized = false
+
+
+-- Set to "true" to log read access (code fetches) to 0xe0000 to 0xfffff
+
+log_rom_access = false
+
+-- Set to "true" to log CS:IP for each access
+
+ip_logging = false
+
+
+rom_size = 4 * 1024 * 1024
+rom_base = 0x100000000 - rom_size
+
+
+decode_pci_io_cfg = true
+decode_pci_mm_cfg = true
+decode_nvram = true
+decode_sys_rst = true
+decode_smbus = true
+decode_superio = true
+
+-- Log hooks only apply when decode above is enabled
+log_pci_io_cfg = false
+log_pci_mm_cfg = false
+log_superio_cfg = false
+log_nvram_cfg = false
+log_smbus_io = false
+
+
+-- This initialization is executed right after target communication
+-- has been established
+
+dofile("core_io.lua")
+dofile("superio.lua")
+dofile("memory.lua")
+dofile("cpu.lua")
+dofile("misc.lua")
+
+printf("SerialICE: LUA script initialized.\n")
+
+mainboard_file = string.format("%s.lua", string.lower(string.gsub(SerialICE_mainboard, " ", "_")))
+
+local mainboard_lua = loadfile(mainboard_file)
+if (mainboard_lua) then
+ mainboard_lua()
+ printf("SerialICE: Mainboard script %s initialized.\n", mainboard_file)
+else
+ printf("SerialICE: Mainboard script %s not found.\n", mainboard_file)
+end
+
+return true
+
diff --git a/SerialICE/simba/superio.lua b/SerialICE/simba/superio.lua
new file mode 100644
index 0000000..eba5de4
--- /dev/null
+++ b/SerialICE/simba/superio.lua
@@ -0,0 +1,172 @@
+-- **********************************************************
+--
+-- SuperIO config handling
+
+port_2e_reg = 0x0
+port_2e_ldn = 0x0
+port_2f_reg = 0x0
+
+port_4e_reg = 0x0
+port_4e_ldn = 0x0
+port_4f_reg = 0x0
+
+if 1 then
+ -- SMSC?
+ port_2e_ldn_register = 0x07
+ port_4e_ldn_register = 0x07
+else
+ -- Winbond
+ port_2e_ldn_register = 0x06
+ port_4e_ldn_register = 0x06
+end
+
+
+function superio_write(port, size, data, filter)
+
+ if port == 0x2e then
+ -- We start requiring a decent state machine
+ port_2e_reg = data
+ filter.filter = false
+ filter.data = data
+ return false
+ end
+
+ if port == 0x2f then
+ if port_2e_reg == port_2e_ldn_register then
+ port_2e_ldn = data
+ filter.filter = false
+ filter.data = data
+ return false
+ end
+
+ -- Don't allow that our SIO power gets disabled.
+ if port_2e_reg == 0x02 then
+ printf("SuperIO (filtered)\n")
+ filter.filter = true
+ filter.data = data
+ return true
+ end
+
+ -- Don't mess with oscillator setup.
+ if port_2e_reg == 0x24 then
+ printf("SuperIO (filtered)\n")
+ filter.filter = true
+ filter.data = data
+ return true
+ end
+ end
+
+ if port == 0x4e then
+ port_4e_reg = data
+ filter.filter = false
+ filter.data = data
+ return false
+ end
+
+ if port == 0x4f then
+ if port_4e_reg == port_4e_ldn_register then
+ port_4e_ldn = data
+ filter.filter = false
+ filter.data = data
+ return false
+ end
+ -- Don't allow that our Serial power gets disabled.
+ if port_4e_reg == 0x02 then
+ printf("SuperIO (filtered)\n")
+ return true, data
+ end
+ -- Don't mess with oscillator setup.
+ if port_4e_reg == 0x24 then
+ printf("SuperIO (filtered)\n")
+ filter.filter = true
+ filter.data = data
+ return true
+ end
+
+ end
+
+ return false
+end
+
+
+
+function superio_write_log(port, size, data, target)
+
+ if port == 0x2e or port == 0x4e then
+ return not log_superio_cfg
+ end
+ if port == 0x2f then
+ if not (port_2e_reg == port_2e_ldn_register) then
+ printf("PnP %02x:%02x R.%02x <= %02x\n", 0x2e, port_2e_ldn, port_2e_reg, data)
+ end
+ return not log_superio_cfg
+ end
+ if port == 0x4f then
+ if not (port_4e_reg == port_4e_ldn_register) then
+ printf("PnP %02x:%02x R.%02x <= %02x\n", 0x4e, port_4e_ldn, port_4e_reg, data)
+ end
+ return not log_superio_cfg
+ end
+ return false
+end
+
+function superio_read_log(port, size, data, target)
+
+ if port == 0x2e or port == 0x4e then
+ return not log_superio_cfg
+ end
+ if port == 0x2f then
+ printf("PnP %02x:%02x R.%02x => %02x\n", 0x2e, port_2e_ldn, port_2e_reg, data)
+ return not log_superio_cfg
+ end
+ if port == 0x4f then
+ printf("PnP %02x:%02x R.%02x => %02x\n", 0x4e, port_4e_ldn, port_4e_reg, data)
+ return not log_superio_cfg
+ end
+ return false
+end
+
+if decode_superio then
+ prepend_to_list(io_write_hooks, superio_write)
+ prepend_to_list(io_write_log_hooks, superio_write_log)
+ prepend_to_list(io_read_log_hooks, superio_read_log)
+end
+
+
+
+-- **********************************************************
+--
+-- Serial Port handling
+
+com1_base = 0x3f8
+com1_size = 0x8
+
+
+function uart_write(port, size, data, filter)
+ if port > com1_base and port < com1_base + com1_size then
+ printf("serial I/O (filtered)\n")
+ filter.filter = true
+ filter.data = data
+ return true
+ end
+
+ if port == com1_base then
+ printf("COM1: %c\n", data)
+ filter.filter = true
+ filter.data = data
+ return true
+ end
+end
+
+function uart_read(port, size, data, filter)
+ if port >= com1_base and port < com1_base + com1_size then
+ printf("Serial I/O read (filtered)\n")
+ filter.filter = true
+ filter.data = 0xff
+ return true
+ end
+end
+
+prepend_to_list(io_write_hooks, uart_write)
+prepend_to_list(io_read_hooks, uart_read)
+
More information about the SerialICE
mailing list