[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