Kyösti Mälkki (kyosti.malkki@gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/860
-gerrit
commit 1a439c2b46780b929e0e0a39212416e825835950 Author: Kyösti Mälkki kyosti.malkki@gmail.com Date: Sun Jul 8 15:44:07 2012 +0300
Modularized SerialICE scripting [NOTFORMERGE]
At the time there is no decision how/if this will take over the single-file serialice.lua script. Until then I've made this available for feedback and maybe even Real Use.
Using this _runtime_ requires Qemu 0.15.x with lua interface modified. The one here should be compatible: http://review.coreboot.org/#/c/1017/
Until issues with lua interface to qemu are solved, you can filter old SerialICE log files through the replayer script like this:
$ cat log | lua replay.lua
The old script/serialice.lua was 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. A few sample mainboard files are included here.
There is decoding of SMBus traffic for Intel ICH.
There is a bit improved filter for PCI configuration registers, even when written in multiple parts. Good for catching BARs.
There is some decoding of CMOS nvram and PnP cycles to SuperIO.
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.
Change-Id: Idba1c3dc7e80ebf169ff277ab7918a1564822bfe Signed-off-by: Kyösti Mälkki kyosti.malkki@gmail.com --- SerialICE/simba/aopen_dxpl_plus.lua | 143 +++++++++ SerialICE/simba/asrock_775i65g.lua | 11 + SerialICE/simba/asus_p4p800_vm.lua | 83 +++++ SerialICE/simba/conroexfire_esata2.lua | 87 +++++ SerialICE/simba/core_io.lua | 352 +++++++++++++++++++++ SerialICE/simba/cpu.lua | 126 ++++++++ SerialICE/simba/e7505.lua | 12 + SerialICE/simba/hooks.lua | 305 ++++++++++++++++++ SerialICE/simba/i82801dx.lua | 118 +++++++ SerialICE/simba/i82801gx.lua | 126 ++++++++ SerialICE/simba/intel_bars.lua | 79 +++++ SerialICE/simba/intel_d845gbv2.lua | 93 ++++++ SerialICE/simba/intel_d946gzis.lua | 79 +++++ SerialICE/simba/intel_smbus.lua | 259 +++++++++++++++ SerialICE/simba/interface.lua | 161 ++++++++++ SerialICE/simba/leftover.lua | 136 ++++++++ SerialICE/simba/memory.lua | 244 ++++++++++++++ SerialICE/simba/mmio.lua | 40 +++ SerialICE/simba/output.lua | 81 +++++ SerialICE/simba/pc80.lua | 546 ++++++++++++++++++++++++++++++++ SerialICE/simba/replay.lua | 186 +++++++++++ SerialICE/simba/serialice.lua | 122 +++++++ SerialICE/simba/smbus_host.lua | 559 +++++++++++++++++++++++++++++++++ SerialICE/simba/superio.lua | 252 +++++++++++++++ SerialICE/simba/via_bars.lua | 30 ++ SerialICE/simba/via_epia_m_850.lua | 165 ++++++++++ 26 files changed, 4395 insertions(+)
diff --git a/SerialICE/simba/aopen_dxpl_plus.lua b/SerialICE/simba/aopen_dxpl_plus.lua new file mode 100644 index 0000000..d199e27 --- /dev/null +++ b/SerialICE/simba/aopen_dxpl_plus.lua @@ -0,0 +1,143 @@ +-- SerialICE +-- +-- Copyright (c) 2012 Kyösti Mälkki kyosti.malkki@gmail.com +-- +-- 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. +-- + +dofile("i82801dx.lua") +dofile("e7505.lua") +dofile("mmio.lua") + +-- ********************************************************** +-- + +function mainboard_io_read(f, action) + -- Some timer loop + if ( action.addr == 0x61 ) then + if ( regs.eip == 0x1634 ) then + regs.ecx = 0x01 + return fake_action(f, action, 0x20) + end + if ( regs.eip == 0x163a ) then + regs.ecx = 0x01 + return fake_action(f, action, 0x30) + end + end + + -- IO slowdown + if action.addr == 0xed then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + if action.addr == 0xcfb then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + return skip_filter(f, action) +end + + +function mainboard_io_write(f, action) + + -- Catch RAM controller ready. + if action.addr == 0x80 and action.data == 0x2c and not ram_enabled() then + enable_ram() + end + + if action.addr == 0xcfb then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + if action.addr == 0xed then + if ( regs.eip == 0x1792 ) then + regs.ecx = 0x01 + end +if false then + -- SIPI delay + if ( regs.eip == 0xb3bc or regs.eip == 0xb3bf ) then + regs.ecx = 0x01 + end + if ( regs.eip == 0xb4ad or regs.eip == 0xb4af ) then + regs.ecx = 0x01 + end +end + ignore_action(f, action) + return drop_action(f, action, action.data) + end + + return skip_filter(f, action) +end + +function mainboard_io_pre(f, action) + if action.write then + return mainboard_io_write(f, action) + else + return mainboard_io_read(f, action) + end +end + +function mainboard_io_post(f, action) + if action.addr == 0xed or action.addr == 0xcfb then + return true + end + + -- If KBD controller returns status=0xff, clear 0x02. + if action.addr == 0x64 and not action.write and action.size == 1 then + if action.data == 0xff then + -- tag these but give out correct data + fake_action(f, action, action.data) + end + end +end + +filter_mainboard = { + id = -1, + name = "AOpen", + pre = mainboard_io_pre, + post = mainboard_io_post, + hide = hide_mainboard_io, + base = 0x0, + size = 0x10000 +} + + +function do_mainboard_setup() + enable_hook(io_hooks, filter_pci_io_cfg) + enable_hook(mem_hooks, filter_lapic) + enable_hook(mem_hooks, filter_ioapic) + + enable_hook(cpumsr_hooks, filter_intel_microcode) + enable_hook(cpuid_hooks, filter_multiprocessor) + + -- I have a hook to detect RAM initialisation from + -- a POST code I can skip this here + --enable_ram() + + enable_hook_pc80() + enable_hook_superio(0x2e, 0x07) + --enable_hook(io_hooks, filter_com1) + enable_hook_i82801dx() + + -- Apply mainboard hooks last, so they are the first ones to check + enable_hook(io_hooks, filter_mainboard) +end diff --git a/SerialICE/simba/asrock_775i65g.lua b/SerialICE/simba/asrock_775i65g.lua new file mode 100644 index 0000000..b98b63c --- /dev/null +++ b/SerialICE/simba/asrock_775i65g.lua @@ -0,0 +1,11 @@ + +dofile("i82801dx.lua") + +function do_mainboard_setup() + do_default_setup() + + enable_hook_i82801dx() + + -- Apply mainboard hooks last, so they are the first ones to check + --enable_hook(io_hooks, filter_mainboard) +end diff --git a/SerialICE/simba/asus_p4p800_vm.lua b/SerialICE/simba/asus_p4p800_vm.lua new file mode 100644 index 0000000..296a833 --- /dev/null +++ b/SerialICE/simba/asus_p4p800_vm.lua @@ -0,0 +1,83 @@ + + +function mainboard_io_read(f, action) + -- Some timer loop + if ( action.addr == 0x61 ) then + if ( regs.eip == 0x1634 ) then + regs.ecx = 0x01 + return fake_action(f, action, 0x20) + end + if ( regs.eip == 0x163a ) then + regs.ecx = 0x01 + return fake_action(f, action, 0x30) + end + end + + -- IO slowdown + if action.addr == 0xed then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + if action.addr == 0xcfb then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + return skip_filter(f, action) +end + + +function mainboard_io_write(f, action) + + + if action.addr == 0xcfb then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + if action.addr == 0xe1 then + ignore_action(f, action) + return drop_action(f, action, action.data) + end + + return skip_filter(f, action) +end + +function mainboard_io_pre(f, action) + if action.write then + return mainboard_io_write(f, action) + else + return mainboard_io_read(f, action) + end +end + +function mainboard_io_post(f, action) + if action.addr == 0xe1 or action.addr == 0xed or action.addr == 0xcfb then + return true + end + if action.addr == 0x80 and not action.write then + return true + end +end + +filter_mainboard = { + id = -1, + name = "test", + pre = mainboard_io_pre, + post = mainboard_io_post, + hide = hide_mainboard_io, + base = 0x0, + size = 0x10000 +} + +dofile("i82801dx.lua") + +function do_mainboard_setup() + do_default_setup() + + enable_hook_i82801dx() + + -- Apply mainboard hooks last, so they are the first ones to check + enable_hook(io_hooks, filter_mainboard) +end diff --git a/SerialICE/simba/conroexfire_esata2.lua b/SerialICE/simba/conroexfire_esata2.lua new file mode 100644 index 0000000..4471e20 --- /dev/null +++ b/SerialICE/simba/conroexfire_esata2.lua @@ -0,0 +1,87 @@ + + + +function mainboard_io_read(f, action) + -- Some timer loop + if ( action.addr == 0x61 ) then + if ( regs.eip == 0x1634 ) then + regs.ecx = 0x01 + return fake_action(f, action, 0x20) + end + if ( regs.eip == 0x163a ) then + regs.ecx = 0x01 + return fake_action(f, action, 0x30) + end + end + + -- IO slowdown + if action.addr == 0xed then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + if action.addr == 0xcfb then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + return skip_filter(f, action) +end + + +function mainboard_io_write(f, action) + + + if action.addr == 0xcfb then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + if action.addr == 0xe1 then + ignore_action(f, action) + return drop_action(f, action, action.data) + end + + return skip_filter(f, action) +end + +function mainboard_io_pre(f, action) + if action.write then + return mainboard_io_write(f, action) + else + return mainboard_io_read(f, action) + end +end + +function mainboard_io_post(f, action) + if action.addr == 0xe1 or action.addr == 0xed or action.addr == 0xcfb then + return true + end + if action.addr == 0x80 and not action.write then + return true + end +end + +filter_mainboard = { + id = -1, + name = "test", + pre = mainboard_io_pre, + post = mainboard_io_post, + hide = hide_mainboard_io, + base = 0x0, + size = 0x10000 +} + +dofile("i82801gx.lua") +dofile("intel_bars.lua") + +function do_mainboard_setup() + do_default_setup() + + enable_hook_i82801gx() + + northbridge_i945() + + -- Apply mainboard hooks last, so they are the first ones to check + enable_hook(io_hooks, filter_mainboard) +end diff --git a/SerialICE/simba/core_io.lua b/SerialICE/simba/core_io.lua new file mode 100644 index 0000000..ecf1774 --- /dev/null +++ b/SerialICE/simba/core_io.lua @@ -0,0 +1,352 @@ + +function io_undefined(f, action) + action.to_hw = true + action.to_qemu = false + action.undefined = true + return true +end + +function io_post(f, action) + if (action.write) then + printk(f, action, "out%s %04x <= %s\n", size_suffix(action.size), action.addr, size_data(action.size, action.data)) + else + printk(f, action, " in%s %04x => %s\n", size_suffix(action.size), action.addr, size_data(action.size, action.data)) + end + return true +end + +function io_base_post(f, action) + if (action.write) then + printk(f, action, "[%04x] <= %s\n", bit.band(action.addr, (f.size - 1)), size_data(action.size, action.data)) + else + printk(f, action, "[%04x] => %s\n", bit.band(action.addr, (f.size - 1)), size_data(action.size, action.data)) + end + return true +end + +filter_io_fallback = { + id = -1, + name = "IO", + pre = io_undefined, + post = io_post, + base = 0x0, + size = 0x10000, +} + + +-- ********************************************************** +-- +-- PCI IO config access + + +pci_cfg_hooks = new_list() + +function add_pci_cfg_hook(dev, reg, size, func) + value = { + bdf = bit.bor(dev.pci_dev, reg), + dev = dev, + reg = reg, + size = size, + func = func + } + prepend_to_list(pci_cfg_hooks, value) +end + + + +function hook_pci_cfg8(dev, reg, hook) + add_pci_cfg_hook(dev, reg, 1, hook) +end + +function hook_pci_cfg16(dev, reg, hook) + add_pci_cfg_hook(dev, reg, 2, hook) +end + +function hook_pci_cfg32(dev, reg, hook) + add_pci_cfg_hook(dev, reg, 4, hook) +end + + + +function io_bar_hook(dev, reg, data) + local bar = dev.bar[reg] + if bar then + bar.base = data + generic_io_bar(bar) + end +end + +function mem_bar_hook(dev, reg, data) + local bar = dev.bar[reg] + if bar then + bar.base = data + generic_mmio_bar(bar) + end +end + +function add_bar(dev, reg, name, size) + if not dev.bar then + dev.bar = {} + end + if not dev.bar[reg] then + dev.bar[reg] = {} + end + dev.bar[reg].f = nil + dev.bar[reg].name = name + dev.bar[reg].base = 0x0 + dev.bar[reg].size = size +end + +function add_io_bar(dev, reg, name, size) + add_bar(dev, reg, name, size) + hook_pci_cfg16(dev, reg, io_bar_hook) +end + +function add_mem_bar(dev, reg, name, size) + add_bar(dev, reg, name, size) + hook_pci_cfg32(dev, reg, mem_bar_hook) +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(l.value.dev, l.value.reg, data) + end + l = l.next + end + return false +end + +function pci_bdf(bus, dev, func, reg) + return bus*1048576 + dev*32768 + func*4096 + reg +end + +-- Catch partial PCI configuration register writes. +-- This synthesizes 32/16 bit wide access from separate +-- 16/8 bit accesses for pci_cfg_hooks. + +bv = {} + +function is_pci_io_cfg(bdf) + local f = filter_pci_io_cfg + return f.reg.bdfr == bdf +end + +function pci_cfg_0cf8_reset(f, data) + f.reg.bdfr = bit.lshift(data,4) + f.reg.bdfr = bit.band(f.reg.bdfr, 0xfffff000) + f.reg.bdfr = bit.bor(f.reg.bdfr, bit.band(data,0xfc)) + + if bit.band(0x80000000, data) ~= 0 then + f.reg.reset = true + new_parent_action() + end + + if not (f.reg.bdfr_hook == f.reg.bdfr) then + f.reg.bdfr_hook = 0 + if (is_pci_cfg_hooked(f.reg.bdfr)) then + f.reg.bdfr_hook = f.reg.bdfr + end + for i = 0, 3, 1 do bv[i] = false end + end +end + +function pci_cfg_0cfc_access(f, addr, size, data) + + if not f.reg.reset and ((f.reg.prev_addr ~= addr) or (f.reg.prev_size ~= size)) then + new_parent_action() + end + f.reg.reset = false + f.reg.prev_addr = addr + f.reg.prev_size = size + + if f.reg.bdfr_hook == 0 then + return + end + + local av = {} + + for i = 0, 3, 1 do av[i] = false end + + ll = 8 * (addr%4) + if (size == 1) then + av[addr%4] = true + bv[addr%4] = true + amask = bit.lshift(0xff, ll) + omask = bit.lshift(data, ll) + f.reg.data = bit.band(f.reg.data, bit.bnot(amask)) + f.reg.data = bit.bor(f.reg.data, omask) + elseif (size == 2) then + av[addr%4] = true + bv[addr%4] = true + av[addr%4+1] = true + bv[addr%4+1] = true + amask = bit.lshift(0xffff, ll) + omask = bit.lshift(data, ll) + f.reg.data = bit.band(f.reg.data, bit.bnot(amask)) + f.reg.data = bit.bor(f.reg.data, omask) + elseif (size == 4) then + f.reg.data = 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(f.reg.bdfr + i, 1, + bit.band(0xff, bit.rshift(f.reg.data, i*8))) + end + end + if ((bv[0] and bv[1]) and (av[0] or av[1])) then + call_pci_cfg_hook(f.reg.bdfr + 0x00, 2, + bit.band(0xffff, bit.rshift(f.reg.data, 0))) + end + if ((bv[1] and bv[2]) and (av[1] or av[2])) then + call_pci_cfg_hook(f.reg.bdfr + 0x01, 2, + bit.band(0xffff, bit.rshift(f.reg.data, 8))) + end + if (bv[2] and bv[3] and (av[2] or av[3])) then + call_pci_cfg_hook(f.reg.bdfr + 0x02, 2, + bit.band(0xffff, bit.rshift(f.reg.data, 16))) + end + if (bv[0] and bv[1] and bv[2] and bv[3]) then + call_pci_cfg_hook(f.reg.bdfr, 4, f.reg.data) + end +end + +function pci_io_cfg_pre(f, action) + if action.addr == 0xcf8 and action.size == 4 then + if action.write then + pci_cfg_0cf8_reset(f, action.data) + end + return handle_action(f, action) + end + if action.addr >= 0xcfc and action.addr <= 0xcff then + if action.write then + pci_cfg_0cfc_access(f, action.addr, action.size, action.data) + end + return handle_action(f, action) + end + return skip_filter(f, action) +end + +function pci_io_cfg_post(f, action) + if action.addr == 0xcf8 and action.size == 4 then + return true + end + if action.addr >= 0xcfc and action.addr <= 0xcff then + if (action.write) then + dir_str = "<=" + else + dir_str = "=>" + end + printk(f, action, "%x:%02x.%x [%02x] %s %s\n", + bit.band(0xff,bit.rshift(f.reg.bdfr, 20)), + bit.band(0x1f,bit.rshift(f.reg.bdfr, 15)), + bit.band(0x7,bit.rshift(f.reg.bdfr, 12)), + bit.band(0xff,f.reg.bdfr + (action.addr - 0xcfc)), + dir_str, size_data(action.size, action.data)) + return true + end + return false +end + +filter_pci_io_cfg = { + id = -1, + name = "PCI", + pre = pci_io_cfg_pre, + post = pci_io_cfg_post, + hide = hide_pci_io_cfg, + base = 0xcf8, + size = 0x08, + reg = { bdfr = 0, bdfr_hook = 0, data = 0, + reset = true, prev_addr = 0, prev_size = 0 } +} + +-- ********************************************************** +-- +-- PCIe MM config access + +function pci_mm_cfg_pre(f, action) + + if (action.write) then + + f.reg.bdfr = bit.band(action.addr, bit.bnot(f.base)) + f.reg.bdfr = bit.band(f.reg.bdfr, bit.bnot(0x3)) + + if not (f.reg.bdfr_hook == f.reg.bdfr) then + f.reg.bdfr_hook = 0 + if (is_pci_cfg_hooked(f.reg.bdfr)) then + f.reg.bdfr_hook = f.reg.bdfr + end + for i = 0, 3, 1 do bv[i] = false end + end + + pci_cfg_0cfc_access(f, action.addr, action.size, action.data) + + end + + return handle_action(f, action) +end + +function pci_mm_cfg_post(f, action) + local addr = bit.band(action.addr, bit.bnot(f.base)) + if (action.write) then + dir_str = "<=" + else + dir_str = "=>" + end + printk(f, action, "%x:%02x.%x [%02x] %s %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), + dir_str, size_data(action.size, action.data)) + return true +end + +filter_pci_mm_cfg = { + id = -1, + pre = pci_mm_cfg_pre, + post = pci_mm_cfg_post, + hide = hide_pci_mm_cfg, + reg = { bdfr = 0, bdfr_hook = 0, data = 0, + reset = true, prev_addr = 0, prev_size = 0 } +} + +function pcie_mm_enable(dev, reg, base, size) + + if not ( dev.bar and dev.bar[reg] ) then + add_bar(dev, reg, "PCI", size) + end + local bar = dev.bar[reg] + bar.base = base + + if not bar.f then + bar.f = filter_pci_mm_cfg + end + + bar.f.name = bar.name + bar.f.base = bar.base + bar.f.size = bar.size + enable_hook(mem_hooks, bar.f) +end + +function pcie_mm_disable(dev, reg, base, size) + if dev.bar and dev.bar[reg] and dev.bar[reg].f then + disable_hook(mem_hooks, dev.bar[reg].f) + end +end diff --git a/SerialICE/simba/cpu.lua b/SerialICE/simba/cpu.lua new file mode 100644 index 0000000..d162f62 --- /dev/null +++ b/SerialICE/simba/cpu.lua @@ -0,0 +1,126 @@ + +function var_mtrr_post(f, action) + + local addr = action.rin.ecx + local hi = action.rin.edx + local lo = action.rin.eax + + 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 + printk(f, action, "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 + printk(f, action, "Set MTRR %x mask to %08x.%08x (%s)\n", (addr - 0x200) / 2, hi, bit.band(lo, 0xfffff000), valid) + end +end + +function cpumsr_pre(f, action) + return handle_action(f, action) +end + +function cpumsr_post(f, action) + if action.write then + printk(f, action, "[%08x] <= %08x.%08x\n", + action.rin.ecx, action.rin.edx, action.rin.eax) + if action.addr >= 0x200 and action.addr < 0x210 then + var_mtrr_post(f, action) + end + else + printk(f, action, "[%08x] => %08x.%08x\n", + action.rin.ecx, action.rout.edx, action.rout.eax) + end + return true +end + + +function cpuid_pre(f, action) + return handle_action(f, action) +end + +function cpuid_post(f, action) + printk(f, action, "eax: %08x; ecx: %08x => %08x.%08x.%08x.%08x\n", + action.rin.eax, action.rin.ecx, + action.rout.eax, action.rout.ebx, action.rout.ecx, action.rout.edx) + return true +end + + + +filter_cpumsr_fallback = { + id = -1, + name = "CPU MSR", + pre = cpumsr_pre, + post = cpumsr_post, +} +filter_cpuid_fallback = { + id = -1, + name = "CPUID", + pre = cpuid_pre, + post = cpuid_post, +} + + + +function multicore_pre(f, action) + return skip_filter(f, action) +end + +function multicore_post(f, action) + local rout = action.rout + local rin = action.rin + -- 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 not action.write and rin.eax == 0x01 then + rout.ebx = bit.band(0xff00ffff, rout.ebx); + rout.ebx = bit.bor(0x00010000, rout.ebx); + fake_action(f, action, 0) + end + return skip_filter(f, action) +end + +filter_multiprocessor = { + id = -1, + name = "Multiprocessor Count", + pre = multicore_pre, + post = multicore_post, +} + +-- Intel CPU microcode update +function intel_microcode_pre(f, action) + if action.rin.ecx == 0x79 then + --action.dropped = true + --action.rout.edx = 0 + --action.rout.eax = 0xffff0000 + return drop_action(f, action) + end + return skip_filter(f, action) +end + +-- Intel CPU microcode revision check +-- Fakes microcode revision of my 0x6f6 Core 2 Duo Mobile +function intel_microcode_post(f, action) + if action.rin.ecx == 0x8b then + action.rout.edx = 0xc7 + action.rout.eax = 0 + return fake_action(f, action, 0) + end + return skip_filter(f, action) +end + +filter_intel_microcode = { + id = -1, + name = "Microcode Update", + pre = intel_microcode_pre, + post = intel_microcode_post, +} diff --git a/SerialICE/simba/e7505.lua b/SerialICE/simba/e7505.lua new file mode 100644 index 0000000..70d96ea --- /dev/null +++ b/SerialICE/simba/e7505.lua @@ -0,0 +1,12 @@ + + +dev_e7505_mch = { + pci_dev = pci_bdf(0x0,0x0,0x0,0x0), + name = "MCH", + bar = {} +} + +add_mem_bar(dev_e7505_mch, 0x14, "RCOMP", 0x1000) + + + diff --git a/SerialICE/simba/hooks.lua b/SerialICE/simba/hooks.lua new file mode 100644 index 0000000..3020515 --- /dev/null +++ b/SerialICE/simba/hooks.lua @@ -0,0 +1,305 @@ + + +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 + + + +next_filter_id = 1 +next_action_id = 1 +current_parent_id = 0 + +function action_id() + local n = next_action_id + next_action_id = next_action_id + 1 + return n +end + +function new_parent_action() + current_parent_id = action_id() +end + + +io_hooks = new_list() +mem_hooks = new_list() + +cpumsr_hooks = new_list() +cpuid_hooks = new_list() + + +function enable_hook(list, filter) + if not filter then + printks(froot, "Enable_hook called with filter==nil\n") + return + end + + local l = list.list + local found = false + while l and not found do + found = (l.hook == filter) + l = l.next + end + if not found then + if (filter.id < 0) then + filter.id = next_filter_id + next_filter_id = next_filter_id + 1 + end + list.list = { next = list.list, hook = filter } + end + if (list == io_hooks) then + printks(fresource, "[%04x] IO [%04x-%04x] = %s\n", + filter.id, filter.base, filter.base + filter.size - 1, filter.name) + elseif (list == mem_hooks) then + printks(fresource, "[%04x] MEM [%08x-%08x] = %s\n", + filter.id, filter.base, filter.base + filter.size - 1, filter.name) + else + printks(fresource, "[%04x] %s\n", filter.id, filter.name) + end + filter.enable = true +end + +function disable_hook(list, filter) + if not filter then + return + end + local l = list.list + local found = false + while l and not found do + found = (l.hook == filter) + l = l.next + end + if found then + printks(froot, "id=%04x disabled\n", filter.id) + filter.enable = false + else + printks(filter, "disabled\n", filter.id) + filter.enable = false + end +end + + + + + + +prev_filter = nil + +function walk_pre_hooks(list, action) + if list == nil or list.list == nil then + return false + end + local logged = false + local l = list.list + local f = nil + + if list == io_hooks or list == mem_hooks then + + while l and not logged do + f = l.hook + if action.addr >= f.base and action.addr < f.base + f.size then + if f.enable and f.pre then + logged = f.pre(f, action) + end + end + l = l.next + end + + else + + while l and not logged do + f = l.hook + if f.enable and f.pre then + logged = f.pre(f, action) + end + l = l.next + end + + end + + if prev_filter ~= f and not action.ignore then + prev_filter = f + new_parent_action() + end + if action.dropped then + action.to_hw = false + action.to_qemu = false + end +end + +function walk_post_hooks(list, action) + if list == nil or list.list == nil then + return false + end + local logged = false + local l = list.list + local f = nil + + if list == io_hooks or list == mem_hooks then + + while l and not logged do + f = l.hook + if action.addr >= f.base and action.addr < f.base + f.size then + if f.enable and f.post then + if f.post(f, action) then + action.f = f + logged = f.hide and not log_everything + end + end + end + l = l.next + end + + else + + while l and not logged do + f = l.hook + if f.enable and f.post then + logged = f.post(f, action) + end + l = l.next + end + + end + + +end + +function generic_io_bar(bar) + if not bar.f then + f = {} + f.id = -1 + f.pre = handle_action + f.post = io_base_post + f.hide = true + f.name = bar.name + f.size = bar.size + bar.f = f + end + bar.f.base = bit.band(bar.base, bit.bnot(bar.size-1)) + if (bar.f.base ~= 0) then + enable_hook(io_hooks, bar.f) + else + disable_hook(io_hooks, bar.f) + end +end + +function generic_mmio_bar(bar) + if not bar.f then + f = {} + f.id = -1 + f.pre = handle_action + f.post = mem_base_post + f.hide = true + f.name = bar.name + f.size = bar.size + bar.f = f + end + bar.f.base = bit.band(bar.base, bit.bnot(bar.size-1)) + if bar.f.base ~= 0 then + enable_hook(mem_hooks, bar.f) + else + disable_hook(mem_hooks, bar.f) + end +end + +PRE_HOOK = 1 +POST_HOOK = 2 + +function handle_action(f, action) + action.to_hw = true + return true +end + +function drop_action(f, action, data) + if action.stage == POST_HOOK then + printk(f, action, "ERROR: Cannot drop action in a post-hook.\n") + return true + end + action.dropped = true + action.data = data + return true +end + +function ignore_action(f, action) + action.ignore = true +end + +function fake_action(f, action, data) + if action.stage == POST_HOOK and action.write then + printk(f, action, "ERROR: Cannot fake write in a post-hook.\n") + return true + end + action.faked = true + action.data = data + return true +end + + +function skip_filter(f, action) + return false +end + +function pre_action(action, dir_wr, addr, size, data) + action.stage = PRE_HOOK + -- CS:IP logging + action.cs = regs.cs + action.eip = regs.eip + + -- no filter, not filtered + action.f = nil + action.ignore = false + action.undefined = false + action.faked = false + action.dropped = false + action.to_hw = false + action.to_qemu = false + + action.write = dir_wr + action.addr = addr + action.size = size + if action.write then + action.data = data + else + action.data = 0 + end +end + +function post_action(action, data) + action.stage = POST_HOOK + action.parent_id = current_parent_id + action.my_id = action_id() + + if not action.write then + if not action.faked and not action.dropped then + action.data = data + end + end +end + +function load_regs(regs, eax, ebx, ecx, edx) + regs.eax = eax + regs.ebx = ebx + regs.ecx = ecx + regs.edx = edx +end + + diff --git a/SerialICE/simba/i82801dx.lua b/SerialICE/simba/i82801dx.lua new file mode 100644 index 0000000..39b35f0 --- /dev/null +++ b/SerialICE/simba/i82801dx.lua @@ -0,0 +1,118 @@ +-- ********************************************************** +-- +-- LPC decode ranges + +function lpc_decode_write(f, action) + -- LPC decode registers + if action.write and is_pci_io_cfg(pci_bdf(0x0,0x1f,0x0,0xe4)) then + if action.addr == 0xcfc and action.size == 4 or action.addr == 0xcfe then + return drop_action(f, action, action.data) + end + end +end + +filter_lpc_lock = { + id = -1, + name = "LPC", + pre = lpc_decode_write, + base = 0xcfc, + size = 0x4 +} + + +-- ********************************************************** +-- +-- SMBus controller handling + + +dofile("intel_smbus.lua") + +function smbus_bar_hook(dev, reg, base) + intel_smbus_setup(base, 0x20) +end + +dev_sb_lpc = { + pci_dev = pci_bdf(0x0,0x1f,0x3,0x0), + name = "Smbus", + bar = {}, +} + +function enable_smbus_host_bar() + hook_pci_cfg16(dev_sb_lpc, 0x20, smbus_bar_hook) +end + + +-- ********************************************************** +-- + +dev_power = { + pci_dev = pci_bdf(0x0,0x1f,0x0,0x0), + name = "SYS", + bar = {}, + acpi = { f = nil }, + tco = { f = nil }, +} + +function pm_io_bar(dev, reg, base) + dev.acpi.name = "ACPI" + dev.acpi.base = base + dev.acpi.size = 0x60 + generic_io_bar(dev.acpi) + + dev.tco.name = "TCO" + dev.tco.base = base + 0x60 + dev.tco.size = 0x20 + generic_io_bar(dev.tco) +end + +function enable_power_bars() + --add_io_bar(dev_power, 0x40, "PM", 0x80) + hook_pci_cfg16(dev_power, 0x40, pm_io_bar) + add_io_bar(dev_power, 0x58, "GPIO", 0x40) +end + +function enable_lpc_bars() + add_io_bar(dev_power, 0xe4, "LPC1", 0x80) + add_io_bar(dev_power, 0xec, "LPC2", 0x10) +end + +-- ********************************************************** +-- +-- AC '97 controller handling + + +dev_audio = { + pci_dev = pci_bdf(0x0,0x1f,0x5,0x0), + name = "Audio", + bar = {} +} + +function enable_audio_bars() + add_io_bar(dev_audio, 0x10, "NAMBAR", 0x100) + add_io_bar(dev_audio, 0x14, "NABMBAR", 0x40) + add_mem_bar(dev_audio, 0x18, "MMBAR", 0x200) + add_mem_bar(dev_audio, 0x1C, "MBBAR", 0x100) +end + +dev_modem = { + pci_dev = pci_bdf(0x0,0x1f,0x6,0x0), + name = "Audio", + bar = {} +} + +function enable_modem_bars() + add_io_bar(dev_audio, 0x10, "MMBAR", 0x100) + add_io_bar(dev_audio, 0x14, "MBAR", 0x80) +end + + +function enable_hook_i82801dx() + enable_hook(io_hooks, filter_lpc_lock) + enable_smbus_host_bar() + enable_power_bars() + enable_lpc_bars() + enable_audio_bars() +end + + + diff --git a/SerialICE/simba/i82801gx.lua b/SerialICE/simba/i82801gx.lua new file mode 100644 index 0000000..091f3e8 --- /dev/null +++ b/SerialICE/simba/i82801gx.lua @@ -0,0 +1,126 @@ +-- ********************************************************** +-- +-- LPC decode ranges + +function lpc_decode_write(f, action) + -- LPC decode registers + if action.write and is_pci_io_cfg(pci_bdf(0x0,0x1f,0x0,0xe4)) then + if action.addr == 0xcfc and action.size == 4 or action.addr == 0xcfe then + return drop_action(f, action, action.data) + end + end +end + +filter_lpc_lock = { + id = -1, + name = "LPC", + pre = lpc_decode_write, + base = 0xcfc, + size = 0x4 +} + + +-- ********************************************************** +-- +-- SMBus controller handling + + +dofile("intel_smbus.lua") + +function smbus_bar_hook(dev, reg, base) + intel_smbus_setup(base, 0x20) +end + +dev_sb_lpc = { + pci_dev = pci_bdf(0x0,0x1f,0x3,0x0), + name = "Smbus", + bar = {}, +} + +function enable_smbus_host_bar() + hook_pci_cfg16(dev_sb_lpc, 0x20, smbus_bar_hook) +end + + +-- ********************************************************** +-- + +dev_power = { + pci_dev = pci_bdf(0x0,0x1f,0x0,0x0), + name = "SYS", + bar = {}, + acpi = { f = nil }, + tco = { f = nil }, +} + +function pm_io_bar(dev, reg, base) + dev.acpi.name = "ACPI" + dev.acpi.base = base + dev.acpi.size = 0x60 + generic_io_bar(dev.acpi) + + dev.tco.name = "TCO" + dev.tco.base = base + 0x60 + dev.tco.size = 0x20 + generic_io_bar(dev.tco) +end + +function lpc_io_bar(dev, reg, base) + add_bar(dev_power, reg, "LPC", 0x100) + io_bar_hook(dev, reg, base) +end + +function enable_power_bars() + --add_io_bar(dev_power, 0x40, "PM", 0x80) + hook_pci_cfg16(dev_power, 0x40, pm_io_bar) + add_io_bar(dev_power, 0x48, "GPIO", 0x40) +end + +function enable_lpc_bars() + hook_pci_cfg16(dev_power, 0x84, lpc_io_bar) + hook_pci_cfg16(dev_power, 0x88, lpc_io_bar) + hook_pci_cfg16(dev_power, 0x8c, lpc_io_bar) + hook_pci_cfg16(dev_power, 0x90, lpc_io_bar) +end + +-- ********************************************************** +-- +-- AC '97 controller handling + + +dev_audio = { + pci_dev = pci_bdf(0x0,0x1f,0x5,0x0), + name = "Audio", + bar = {} +} + +function enable_audio_bars() + add_io_bar(dev_audio, 0x10, "NAMBAR", 0x100) + add_io_bar(dev_audio, 0x14, "NABMBAR", 0x40) + add_mem_bar(dev_audio, 0x18, "MMBAR", 0x200) + add_mem_bar(dev_audio, 0x1C, "MBBAR", 0x100) +end + +dev_modem = { + pci_dev = pci_bdf(0x0,0x1f,0x6,0x0), + name = "Audio", + bar = {} +} + +function enable_modem_bars() + add_io_bar(dev_audio, 0x10, "MMBAR", 0x100) + add_io_bar(dev_audio, 0x14, "MBAR", 0x80) +end + + +function enable_hook_i82801gx() + add_mem_bar(dev_power, 0xf0, "RCBA", 0x4000) + enable_hook(io_hooks, filter_lpc_lock) + enable_smbus_host_bar() + enable_power_bars() + enable_lpc_bars() + enable_audio_bars() +end + + + diff --git a/SerialICE/simba/intel_bars.lua b/SerialICE/simba/intel_bars.lua new file mode 100644 index 0000000..952cf46 --- /dev/null +++ b/SerialICE/simba/intel_bars.lua @@ -0,0 +1,79 @@ + +-- ********************************************************** +-- Intel 82945 PCIe BAR + +function i945_pcie_bar(dev, reg, base) + local sizebits = bit.band(bit.rshift(base, 1), 0x3) + local baseaddr = 0 + local size = 0 + + if sizebits == 0 then + size = 256*1024*1024 + baseaddr = bit.band(base, 0xf0000000) + elseif sizebits == 1 then + size = 128*1024*1024 + baseaddr = bit.band(base, 0xf8000000) + elseif sizebits == 2 then + size = 64*1024*1024 + baseaddr = bit.band(base, 0xfc000000) + else + -- undefined, really + baseaddr = bit.band(base, 0xfe000000) + size = 32*1024*1024 + end + + if bit.band(base, 1) ~= 0 then + pcie_mm_enable(dev, reg, baseaddr, size) + else + pcie_mm_disable(dev, reg, baseaddr, size) + end +end + +dev_i945 = { + pci_dev = pci_bdf(0,0,0,0), + name = "i945", + bar = {}, +} + +function northbridge_i945() + add_mem_bar(dev_i945, 0x40, "EPBAR", 4*1024) + add_mem_bar(dev_i945, 0x44, "MCHBAR", 16*1024) + add_mem_bar(dev_i945, 0x4c, "DMIBAR", 4*1024) + add_mem_bar(dev_i945, 0x60, "(unknown)", 4*1024) + + hook_pci_cfg32(dev_i945, 0x48, i945_pcie_bar) +end + +function northbridge_i946() + add_mem_bar(dev_i945, 0x40, "PXPEPBAR", 4*1024) + add_mem_bar(dev_i945, 0x48, "MCHBAR", 16*1024) + add_mem_bar(dev_i945, 0x68, "DMIBAR", 4*1024) + + hook_pci_cfg32(dev_i945, 0x60, i945_pcie_bar) +end + +-- ********************************************************** +-- +-- Intel chipset BARs are exclusively handled by the +-- SerialICE target + +filter_intel_bars = { + id = -1, + name = "IntelBAR", + pre = mem_target_only, + post = mem_base_post, + base = 0xfed10000, + size = 0x00010000, +} + +-- ICH7 TPM +-- Phoenix "Secure" Core bails out if we don't pass the read on ;-) +filter_ich7_tpm = { + id = -1, + name = "ICH7 TPM", + pre = mem_target_only, + post = mem_base_post, + base = 0xfed40000, + size = 0x00005000, +} + diff --git a/SerialICE/simba/intel_d845gbv2.lua b/SerialICE/simba/intel_d845gbv2.lua new file mode 100644 index 0000000..2cb1a90 --- /dev/null +++ b/SerialICE/simba/intel_d845gbv2.lua @@ -0,0 +1,93 @@ + + +function mainboard_io_read(f, action) + -- Some timer loop + if ( action.addr == 0x61 ) then + end + + -- IO slowdown + if action.addr == 0xed then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + if action.addr == 0xcfb then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + return skip_filter(f, action) +end + + +function mainboard_io_write(f, action) + + -- Catch RAM controller ready. + if action.addr == 0x80 and action.data == 0xd5 and not ram_enabled() then + -- enable_ram() + end + + if action.addr == 0xcfb then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + if action.addr == 0xe1 then + ignore_action(f, action) + return drop_action(f, action, action.data) + end + + return skip_filter(f, action) +end + +function mainboard_io_pre(f, action) + if action.write then + return mainboard_io_write(f, action) + else + return mainboard_io_read(f, action) + end +end + +function mainboard_io_post(f, action) + if action.addr == 0xe1 or action.addr == 0xed or action.addr == 0xcfb then + return true + end + if action.addr == 0x80 and not action.write then + return true + end +end + +filter_mainboard = { + id = -1, + name = "GEBV2", + pre = mainboard_io_pre, + post = mainboard_io_post, + hide = hide_mainboard_io, + base = 0x0, + size = 0x10000 +} + +dofile("i82801dx.lua") + +function do_mainboard_setup() + new_car_region(0xfef00000, 0x800) + + enable_hook(io_hooks, filter_pci_io_cfg) + enable_hook(mem_hooks, filter_lapic) + enable_hook(mem_hooks, filter_ioapic) + + enable_hook(cpumsr_hooks, filter_intel_microcode) + enable_hook(cpuid_hooks, filter_multiprocessor) + + -- I have a hook to detect RAM initialisation from + -- a POST code I can skip this here + enable_ram() + + enable_hook_pc80() + enable_hook_superio(0x2e, 0x07) + --enable_hook(io_hooks, filter_com1) + enable_hook_i82801dx() + + -- Apply mainboard hooks last, so they are the first ones to check + enable_hook(io_hooks, filter_mainboard) +end diff --git a/SerialICE/simba/intel_d946gzis.lua b/SerialICE/simba/intel_d946gzis.lua new file mode 100644 index 0000000..2bdb0eb --- /dev/null +++ b/SerialICE/simba/intel_d946gzis.lua @@ -0,0 +1,79 @@ + + + +function mainboard_io_read(f, action) + -- IO slowdown + if action.addr == 0xed then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + if action.addr == 0xcfb then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + return skip_filter(f, action) +end + + +function mainboard_io_write(f, action) + + + if action.addr == 0xcfb then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + if action.addr == 0xe1 then + ignore_action(f, action) + return drop_action(f, action, action.data) + end + + return skip_filter(f, action) +end + +function mainboard_io_pre(f, action) + if action.write then + return mainboard_io_write(f, action) + else + return mainboard_io_read(f, action) + end +end + +function mainboard_io_post(f, action) + if action.addr == 0xe1 or action.addr == 0xed or action.addr == 0xcfb then + return true + end + if action.addr == 0x80 and not action.write then + return true + end +end + +filter_mainboard = { + id = -1, + name = "test", + pre = mainboard_io_pre, + post = mainboard_io_post, + hide = hide_mainboard_io, + base = 0x0, + size = 0x10000 +} + +dofile("i82801gx.lua") +dofile("intel_bars.lua") + +function do_mainboard_setup() + do_default_setup() + + enable_hook_i82801gx() + enable_hook(mem_hooks, filter_ich7_tpm) + enable_hook(cpumsr_hooks, filter_intel_microcode) + enable_hook(cpuid_hooks, filter_multiprocessor) + northbridge_i946() + + new_car_region(0xfef00000,0x2000) + + -- Apply mainboard hooks last, so they are the first ones to check + enable_hook(io_hooks, filter_mainboard) +end diff --git a/SerialICE/simba/intel_smbus.lua b/SerialICE/simba/intel_smbus.lua new file mode 100644 index 0000000..70ca640 --- /dev/null +++ b/SerialICE/simba/intel_smbus.lua @@ -0,0 +1,259 @@ + + +dofile("smbus_host.lua") + +-- ******************************************** +-- Intel 82801 SMBus Host controller + +I801_SMB_HSTSTS = 0 +I801_SMB_HSTCNT = 2 +I801_SMB_HSTCMD = 3 +I801_SMB_HSTADD = 4 +I801_SMB_HSTDAT0 = 5 +I801_SMB_HSTDAT1 = 6 +I801_SMB_BLKDAT = 7 +I801_SMB_PEC = 8 +I801_SMB_AUXSTS = 12 +I801_SMB_AUXCTL = 13 + +I801_QUICK = 0x00 +I801_BYTE = 0x04 +I801_BYTE_DATA = 0x08 +I801_WORD_DATA = 0x0C +I801_PROC_CALL = 0x10 +I801_BLOCK_DATA = 0x14 +I801_I2C_BLOCK_DATA = 0x18 +I801_BLOCK_PROCESS = 0x1C +I801_BLOCK_LAST = 0x34 -- 0x14 | 0x20 +I801_I2C_BLOCK_LAST = 0x38 -- 0x18 | 0x20 +I801_START = 0x40 +I801_PEC_EN = 0x80 + + +local function intel_smbus_get_protocol(f) + local proto = bit.band(f.reg.control, 0x1c) + + if proto == I801_QUICK then + return SMBUS_QUICK + + elseif proto == I801_BYTE then + return SMBUS_BYTE + + elseif proto == I801_BYTE_DATA then + return SMBUS_BYTE_DATA + + elseif proto == I801_WORD_DATA then + return SMBUS_WORD_DATA + + elseif proto == I801_PROC_CALL then + return SMBUS_PROC_CALL + + elseif proto == I801_BLOCK_DATA then + return SMBUS_BLOCK_DATA + + elseif proto == I801_I2C_BLOCK_DATA then + return SMBUS_I2C_BLOCK_DATA + + elseif proto == I801_BLOCK_PROCESS then + return SMBUS_BLOCK_PROCESS + + else + printk(f, action, "Unknown protocol\n") + return SMBUS_NOOP + end +end + +local function intel_smbus_host_status(f, action) + if not action.write then + if smbus.passive(f) then + f.reg.status = action.data; + end + + if smbus.state(f, HOST_IDLE) then + if not smbus.passive(f) then + f.reg.status = 0x0 + end + if bit.band(f.reg.status, 0x40) ~= 0 then + printk(f, action, "Host may be busy, ignoring.\n") + end + smbus.get_resource(f) + + elseif smbus.state(f, HOST_ACTIVE) then + f.reg.busy_count = 3 + + elseif smbus.state(f, HOST_STARTED) then + if not smbus.passive(f) then + f.reg.status = bit.band(f.reg.status, 0xFE) + if f.reg.busy_count > 0 then + f.reg.busy_count = f.reg.busy_count - 1 + f.reg.status = bit.bor(f.reg.status, 0x01) + end + if bit.band(f.reg.status, 0x02) == 0 then + smbus_transaction(host) + end + end + + local irq = bit.band(f.reg.status, 0x02) ~= 0 + local failures = bit.band(f.reg.status, 0x1c) ~= 0 + local host_busy = bit.band(f.reg.status, 0x01) ~= 0 + + if irq and not host_busy then + smbus.done(f) + end + if failures then + smbus.timeout(f) + end + end + + if not smbus.passive(f) then + action.data = f.reg.status; + f.reg.status = bit.bor(f.reg.status, 0x40) + end + else + + if not smbus.passive(f) then + f.reg.status = bit.band(f.reg.status, bit.bnot(action.data)) + end + + local ack_irq = bit.band(action.data, 0x02) ~= 0 + local release_host = bit.band(action.data, 0x40) ~= 0 + local failures = bit.band(action.data, 0x1c) ~= 0 + if release_host then + smbus.put_resource(f) + end + if failures then + smbus.timeout_ack(f) + end + if ack_irq then + smbus.ack(f) + end + end + +end + + +local function intel_smbus_host_control(f, action) + + if not action.write then + f.reg.block_ptr=0; + if not smbus.passive(f) then + action.data = bit.band(f.reg.control, bit.bnot(0x40)) + end + + else + + f.reg.control = action.data; + if bit.band(f.reg.control, 0x80) ~= 0 then + printk(f, action, "No PEC simulation\n") + end + + local abort = bit.band(f.reg.control, 0x02) ~= 0 + local start = bit.band(f.reg.control, 0x40) ~= 0 + if abort then + smbus.abort(f) + end + if start then + f.reg.block_ptr=0; + smbus.update_register(f, action, SMB_REG_PROTO) + smbus.start(f, intel_smbus_get_protocol(f)) + end + end +end + + + +local function intel_smbus_block_data(f, action) + if f.reg.block_ptr < MAX_BLOCK_SRAM then + smbus.block_data(f, action, f.reg.block_ptr) + end + f.reg.block_ptr = f.reg.block_ptr + 1 + smbus.update_register(f, action, SMB_REG_BLOCK) +end + +local function intel_smbus_host_access(f, action) + local reg = bit.band(action.addr, (f.size-1)) + + -- mirror hw register both ways + local data_write = 0 + + -- Store this to display CS:IP etc. + f.host.action = action + + if reg == I801_SMB_HSTSTS then + intel_smbus_host_status(f, action); + + elseif reg == I801_SMB_HSTCNT then + intel_smbus_host_control(f, action); + + elseif reg == I801_SMB_HSTCMD then + smbus.update_register(f, action, SMB_REG_CMD) + + elseif reg == I801_SMB_HSTADD then + smbus.update_register(f, action, SMB_REG_SLAVE) + + elseif reg == I801_SMB_HSTDAT0 then + smbus.update_register(f, action, SMB_REG_DATA0) + + elseif reg == I801_SMB_HSTDAT1 then + smbus.update_register(f, action, SMB_REG_DATA1) + + elseif reg == I801_SMB_BLKDAT then + intel_smbus_block_data(f, action); + + elseif reg == I801_SMB_AUXSTS then + if data_write then + f.reg.aux_sts = action.data; + else + action.data = f.reg.aux_sts; + end + + elseif reg == I801_SMB_AUXCTL then + if data_write then + f.reg.aux_ctl = action.data; + else + action.data = f.reg.aux_ctl; + end + + else + printk(f, action, "Unknown register 0x%02x\n", reg); + end +end + + +function intel_smbus_host_pre(f, action) + if action.write then + intel_smbus_host_access(f, action) + end + return handle_action(f, action) +end + +function intel_smbus_host_post(f, action) + if not action.write then + intel_smbus_host_access(f, action) + end + return true +end + + +local intel_smbus_host = { + id = -1, + name = "i801-smbus", + pre = intel_smbus_host_pre, + post = intel_smbus_host_post, + hide = hide_smbus_io, + base = 0x0, + size = 0x0, +} + +function intel_smbus_setup(base, size) + local f = intel_smbus_host + f.base = bit.band(base, bit.bnot(size-1)) + f.size = size + if not f.reg then + f.reg = { control = 0, status = 0, busy_count = 0, block_ptr = 0, aux_ctl = 0, aux_sts = 0 } + end + smbus.init(f) + + enable_hook(io_hooks, f) +end + diff --git a/SerialICE/simba/interface.lua b/SerialICE/simba/interface.lua new file mode 100644 index 0000000..48ff8de --- /dev/null +++ b/SerialICE/simba/interface.lua @@ -0,0 +1,161 @@ + +-- IO, MMIO, RAM and ROM access +io_action = {} +mem_action = {} + +IO_READ = false +IO_WRITE = true +MEM_READ = false +MEM_WRITE = true + +-- CPUID and CPU MSR +MSR_READ = false +MSR_WRITE = true +CPUID = false + +cpu_action = {} +cpu_action.rin = {} +cpu_action.rout = {} + + + +-- SerialICE_io_read_filter is the filter function for IO reads. +-- +-- Parameters: +-- addr IO port to be read +-- size Size of the IO 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 + +function SerialICE_io_read_filter(addr, size) + pre_action(io_action, IO_READ, addr, size, 0) + walk_pre_hooks(io_hooks, io_action) + return io_action.to_hw, io_action.to_qemu +end + +-- Parameters: +-- data Data from hw or Qemu +-- Return values: +-- result Data to give back to Qemu + +function SerialICE_io_read_log(data) + post_action(io_action, data) + walk_post_hooks(io_hooks, io_action) + return io_action.data +end + +-- SerialICE_io_write_filter is the filter function for IO writes. +-- +-- Parameters: +-- addr IO port to be written to +-- size Size of the IO write +-- data Data to be written to +-- 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 +-- data Data to be written (possible changed in filter) + +function SerialICE_io_write_filter(addr, size, data) + pre_action(io_action, IO_WRITE, addr, size, data) + walk_pre_hooks(io_hooks, io_action) + return io_action.to_hw, io_action.to_qemu, io_action.data +end + +function SerialICE_io_write_log() + post_action(io_action) + walk_post_hooks(io_hooks, io_action) +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 + +function SerialICE_memory_read_filter(addr, size) + pre_action(mem_action, MEM_READ, addr, size, 0) + walk_pre_hooks(mem_hooks, mem_action) + return mem_action.to_hw, mem_action.to_qemu +end + +function SerialICE_memory_read_log(data) + post_action(mem_action, data) + walk_post_hooks(mem_hooks, mem_action) + return mem_action.data +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) + pre_action(mem_action, MEM_WRITE, addr, size, data) + walk_pre_hooks(mem_hooks, mem_action) + return mem_action.to_hw, mem_action.to_qemu, mem_action.data +end + +function SerialICE_memory_write_log() + post_action(mem_action, 0) + walk_post_hooks(mem_hooks, mem_action) +end + +function SerialICE_msr_read_filter(addr) + pre_action(cpu_action, MSR_READ, 0, 0, 0) + load_regs(cpu_action.rin, 0, 0, addr, 0) + + walk_pre_hooks(cpumsr_hooks, cpu_action) + return cpu_action.to_hw, cpu_action.to_qemu +end + +function SerialICE_msr_read_log(hi, lo) + local rout = cpu_action.rout + post_action(cpu_action, 0) + load_regs(cpu_action.rout, lo, 0, 0, hi) + walk_post_hooks(cpumsr_hooks, cpu_action) + return rout.edx, rout.eax +end + +function SerialICE_msr_write_filter(addr, hi, lo) + local rin = cpu_action.rin + pre_action(cpu_action, MSR_WRITE, 0, 0, 0) + load_regs(cpu_action.rin, lo, 0, addr, hi) + walk_pre_hooks(cpumsr_hooks, cpu_action) + return cpu_action.to_hw, cpu_action.to_qemu, rin.edx, rin.eax +end + +function SerialICE_msr_write_log() + post_action(cpu_action, 0) + load_regs(cpu_action.rout, 0, 0, 0, 0) + walk_post_hooks(cpumsr_hooks, cpu_action) +end + +function SerialICE_cpuid_filter(eax, ecx) + pre_action(cpu_action, CPUID, 0, 0, 0) + load_regs(cpu_action.rin, eax, 0, ecx, 0) + walk_pre_hooks(cpuid_hooks, cpu_action) + return cpu_action.to_hw, cpu_action.to_qemu +end + +function SerialICE_cpuid_log(eax, ebx, ecx, edx) + local rout = cpu_action.rout + post_action(cpu_action, 0) + load_regs(cpu_action.rout, eax, ebx, ecx, edx) + walk_post_hooks(cpuid_hooks, cpu_action) + return rout.eax, rout.ebx, rout.ecx, rout.edx +end + diff --git a/SerialICE/simba/leftover.lua b/SerialICE/simba/leftover.lua new file mode 100644 index 0000000..05e516e --- /dev/null +++ b/SerialICE/simba/leftover.lua @@ -0,0 +1,136 @@ + + + -- ********************************************************** + -- + -- Dell 1850 BMC filter + + if action.addr == 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 action.addr == 0xcfc then + if is_pci_io_cfg(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 action.addr == 0x80 and action.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 ( action.addr == 0xed and action.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 ( action.addr == 0xed and action.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 + + -- ********************************************************** + -- high memory write + + if action.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 + + + -- ********************************************************** + -- + -- io_read hooks, unknown vendor + + -- if action.addr == 0x42 then + -- printf("WARNING: Hijacking timer action.addr 0x42\n") + -- data = 0x80 + -- caught = true + -- end + + -- + -- + + if ( action.addr == 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 + + + +-- ********************************************************** +-- +-- Vendor specific Cache-As-Ram regions + +printks(froot, "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..550df75 --- /dev/null +++ b/SerialICE/simba/memory.lua @@ -0,0 +1,244 @@ +-- ********************************************************** +-- + +function mem_undefined(f, action) + if (action.write) then + action.to_hw = true + action.to_qemu = false + else + action.to_hw = false + action.to_qemu = true + end + action.undefined = true + return true +end + +function mem_post(f, action) + if (action.write) then + printk(f, action, "write%s %08x <= %s", size_suffix(action.size), action.addr, size_data(action.size, action.data)) + else + printk(f, action, " read%s %08x => %s", size_suffix(action.size), action.addr, size_data(action.size, action.data)) + end + if action.to_hw then + printf(" *") + end + printf("\n") + return true +end + +function mem_base_post(f, action) + if (action.write) then + printk(f, action, "[%08x] <= %s\n", bit.band(action.addr, (f.size - 1)), size_data(action.size, action.data)) + else + printk(f, action, "[%08x] => %s\n", bit.band(action.addr, (f.size - 1)), size_data(action.size, action.data)) + end + return true +end + + +filter_mem_fallback = { + id = -1, + name = "MEM", + pre = mem_undefined, + post = mem_post, + base = 0x0, + size = 0x100000000 +} + +-- ********************************************************** +-- ROM access + +function mem_qemu_rom_pre(f, action) + action.to_hw = false + action.to_qemu = true + -- Reads from ROM space do not count for filter change. + if not action.write then + ignore_action(f, action) + end + return true +end + +function mem_rom_post(f, action) + if not action.write then + return true + end + -- Writes to ROM space fall-thru to the fallback filter, + -- so they get logged there. + return false +end + +filter_rom_low = { + id = -1, + name = "ROM_LO", + pre = mem_qemu_rom_pre, + post = mem_rom_post, + hide = hide_rom_access, + base = 0xE0000, + size = 0x20000 +} +filter_rom_high = { + id = -1, + name = "ROM_HI", + pre = mem_qemu_rom_pre, + post = mem_rom_post, + hide = hide_rom_access, + base = rom_base, + size = rom_size, +} + +-- ********************************************************** +-- CAR access + +function car_qemu_only(f, action) + action.to_hw = false + action.to_qemu = true + return true +end + +function car_post(f, action) + return true +end + +function new_car_region(start, size) + f = {} + f.id = -1 + f.name = "CAR" + f.base = start + f.size = size + f.pre = car_qemu_only + f.post = car_post + f.hide = true + enable_hook(mem_hooks, f) + SerialICE_register_physical(start, size) +end + + +-- ********************************************************** +-- RAM access. + +-- 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 + +-- This is handled by SerialICE but *NOT* exclusively. +-- Writes end up in Qemu memory, too +function mem_ram_low(f, action) + if ram_is_initialized then + -- RAM init is done. Send all RAM accesses + -- to Qemu. Using the target as storage would + -- only slow execution down. + action.to_hw = false + action.to_qemu = true + else + -- RAM init has not been marked done yet. + -- so send reads to the target only. + action.to_hw = true + action.to_qemu = action.write + end + return true +end + +-- SMI/VGA writes go to target and qemu +-- SMI/VGA reads come from target +function mem_smi_vga(f, action) + if action.write then + action.to_hw = true + action.to_qemu = true + else + action.to_hw = true + action.to_qemu = false + end + return true +end + + +function mem_post_pre_ram_only(f, action) + return ram_is_initialized +end + +filter_ram_low = { + id = -1, + name = "MEM", + pre = mem_ram_low, + post = mem_post_pre_ram_only, + hide = true, + base = 0x0, + size = 0xa0000 +} + +filter_smi_vga = { + id = -1, + name = "SMI_VGA", + pre = mem_smi_vga, + post = mem_post, + hide = true, + base = 0x000a0000, + size = 0x00010000, +} + +filter_ram_low_2 = { + id = -1, + name = "MEM", + pre = mem_ram_low, + post = mem_post_pre_ram_only, + hide = true, + base = 0xc0000, + size = 0x20000 +} + + +function mem_target_only(f, action) + action.to_hw = true + action.to_qemu = false + return true +end + +-- 3.25GB RAM. This is handled by SerialICE. +-- FIXME: use TOLM here + +-- We refrain from backing up this memory in Qemu because Qemu would +-- need lots of ram on the host and firmware usually does not intensively +-- use high memory anyways. +filter_ram_high = { + id = -1, + name = "MEM", + pre = mem_target_only, + post = mem_post_pre_ram_only, + hide = true, + base = 0x100000, + size = 0xd0000000 - 0x100000 +} + + +function ram_enabled() + return ram_is_initialized +end + +function enable_ram() + + enable_hook(mem_hooks, filter_ram_low) + enable_hook(mem_hooks, filter_smi_vga) + enable_hook(mem_hooks, filter_ram_low_2) + enable_hook(mem_hooks, filter_ram_high) + + -- Register low RAM 0x00000000 - 0x000dffff + SerialICE_register_physical(0x00000000, 0xa0000) + -- SMI/VGA memory should go to the target... + SerialICE_register_physical(0x000c0000, 0x20000) + --printf("Low RAM accesses are now directed to Qemu.\n") + ram_is_initialized = true +end + + + + diff --git a/SerialICE/simba/mmio.lua b/SerialICE/simba/mmio.lua new file mode 100644 index 0000000..f34d18d --- /dev/null +++ b/SerialICE/simba/mmio.lua @@ -0,0 +1,40 @@ + +-- ********************************************************** +-- +-- Vendor independent X86 memory mapped IO + +-- Local APIC +-- We should avoid that someone wakes up cores +-- on the target system that go wild. +function mem_lapic(f, action) + if bit.band(action.addr, f.size-1) == 0x300 then + -- replace Start-Up IPI with Init IPI + if action.write and bit.band(action.data, 0xf0f00) == 0xc0600 then + return fake_action(f, action, 0xc0500) + end + end + return handle_action(f, action) +end + +filter_lapic = { + id = -1, + name = "LAPIC", + pre = mem_lapic, + post = mem_base_post, + hide = true, + base = 0xfee00000, + size = 0x00010000, +} + +-- IOAPIC +filter_ioapic = { + id = -1, + name = "IOAPIC", + pre = mem_target_only, + post = mem_base_post, + hide = true, + base = 0xfec00000, + size = 0x00010000, +} + + diff --git a/SerialICE/simba/output.lua b/SerialICE/simba/output.lua new file mode 100644 index 0000000..c3bf4e4 --- /dev/null +++ b/SerialICE/simba/output.lua @@ -0,0 +1,81 @@ + + +froot = { + id = 0, + name = "SerialICE", +} + +fresource = { + id = -1, + name = "Resource", +} + +-- ------------------------------------------------------------------- +-- logging functions + +function printf(s,...) + return io.write(s:format(...)) +end + +function printk(f, action, fmt, ...) + if ip_logging then + printf("[%04x:%04x] ", action.cs, action.eip) + end + + if ip_logging then + printf("%04x.%04x ", action.parent_id, action.my_id) + end + + local str = " " + if action.dropped or action.faked then + str = "!" + end + if action.undefined then + str = "#" + end + + if action.f then + printf("%s %s,%s: ", str, f.name, action.f.name) + printf(fmt, ...) + else + printf("%s %s: ", str, f.name) + printf(fmt, ...) + end +end + +function printks(f, fmt, ...) + if ip_logging then + printf("[%04x:%04x] ", 0, 0) + end + + if ip_logging then + printf("%04x.%04x ", 0, 0) + end + printf(" %s: ", f.name) + printf(fmt, ...) +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 + + + diff --git a/SerialICE/simba/pc80.lua b/SerialICE/simba/pc80.lua new file mode 100644 index 0000000..f259628 --- /dev/null +++ b/SerialICE/simba/pc80.lua @@ -0,0 +1,546 @@ +-- ********************************************************** +-- +-- Debug POST port at IO 0x80 + +function debugport_post(f, action) + if action.write then + printk(f, action, "*** %02x ***\n", action.data) + return true + end + return false +end + +filter_debugport = { + id = -1, + name = "POST", + pre = handle_action, + post = debugport_post, + hide = true, + base = 0x80, + size = 0x1 +} + + +-- ********************************************************** +-- +-- i8259 PIC + +function i8259_pre(f, action) + local master = (bit.rshift(0x05, action.addr) == 0x1) + local slave = (bit.rshift(0x05, action.addr) == 0x5) + local reg = bit.band(0x03, action.addr) + if reg == 0 or reg == 1 then + return handle_action(f, action) + end + return skip_filter(f, action) +end + +function i8259_post(f,action) + local reg = bit.band(0x03, action.addr) + if reg == 0 or reg == 1 then + return true + end + return false +end + +function i8259_edge_pre(f, action) + return handle_action(f, action) +end + +function i8259_edge_post(f,action) + return true +end + +filter_i8259_master = { + id = -1, + name = "i8259 A", + pre = i8259_pre, + post = i8259_post, + hide = hide_i8259_io, + base = 0x20, + size = 0x20 +} + +filter_i8259_slave = { + id = -1, + name = "i8259 B", + pre = i8259_pre, + post = i8259_post, + hide = hide_i8259_io, + base = 0xa0, + size = 0x20 +} + +filter_i8259_edge = { + id = -1, + name = "i8259 C", + pre = i8259_edge_pre, + post = i8259_edge_post, + hide = hide_i8259_io, + base = 0x4d0, + size = 0x2 +} + +-- ********************************************************** +-- +-- i8237 DMA + +function i8237_pre(f, action) + if action.addr == 0x80 then + return skip_filter(f, action) + end + return handle_action(f, action) +end + +function i8237_post(f, action) + if action.addr == 0x80 then + return false + end + return true +end + + +filter_i8237_a = { + id = -1, + name = "i8237 A", + pre = i8237_pre, + post = i8237_post, + hide = hide_i8237_io, + base = 0x00, + size = 0x20 +} +filter_i8237_b = { + id = -1, + name = "i8237 B", + pre = i8237_pre, + post = i8237_post, + hide = hide_i8237_io, + base = 0x80, + size = 0x20 +} +filter_i8237_c = { + id = -1, + name = "i8237 C", + pre = i8237_pre, + post = i8237_post, + hide = hide_i8237_io, + base = 0xc0, + size = 0x20 +} + + +-- ********************************************************** +-- +-- i8254 IRQ0 and Speaker + +function i8254_pre(f, action) + + -- nothing to do on reads + if not action.write then + return handle_action(f, action) + end + + local reg = bit.band(0x03, action.addr) + if reg >= 0x0 and reg < 0x03 then + local counter_n = 0 + local counter_p = 0 + if f.counter[reg].lsb then + f.counter[reg].lsb = f.counter[reg].after_lsb + counter_n = action.data + counter_p = bit.band(0xff00, f.counter[reg].init) + else + counter_n = bit.lshift(action.data, 8) + counter_p = bit.band(0x00ff, f.counter[reg].init) + end + f.counter[reg].init = bit.bor(counter_n, counter_p) + elseif reg == 0x03 then + local reg2 = bit.rshift(action.data, 6) + local rwsel = bit.band(0x3, bit.rshift(action.data, 4)) + if reg2 == 0x3 then + if bit.band(0x10, action.data) == 0 then + f.counter[0].readback = (bit.band(0x2, action.data) ~= 0) + f.counter[1].readback = (bit.band(0x4, action.data) ~= 0) + f.counter[2].readback = (bit.band(0x8, action.data) ~= 0) + end + if bit.band(0x20, action.data) == 0 then + f.counter[0].latch = (bit.band(0x2, action.data) ~= 0) + f.counter[1].latch = (bit.band(0x4, action.data) ~= 0) + f.counter[2].latch = (bit.band(0x8, action.data) ~= 0) + end + elseif rwsel == 0x0 then + f.counter[reg2].latch = true + else + f.counter[reg2].mode = bit.band(0xf, action.data) + if rwsel == 0x1 then + f.counter[reg2].lsb = true + f.counter[reg2].after_lsb = true + elseif rwsel == 0x2 then + f.counter[reg2].lsb = false + f.counter[reg2].after_lsb = false + elseif rwsel == 03 then + f.counter[reg2].lsb = true + f.counter[reg2].after_lsb = false + end + end + end + return handle_action(f, action) +end + +function i8254_post(f, action) + local reg = bit.band(0x03, action.addr) + if reg >= 0x0 and reg < 0x03 then + if action.write then + local mode = bit.band(0x0f, f.counter[reg].mode); + local modestr = "Mode" .. mode + if mode == 0x4 then + modestr = "Square Wave" + elseif mode == 0x6 then + modestr = "Rate Generator" + end + if bit.band(0x01, mode) ~= 0 then + modestr = modestr .. " (BCD)" + end + + local period = 838 * f.counter[reg].init + if reg == 0 then + if period == 0 then + printk(f, action, "IRQ0 disabled\n") + else + printk(f, action, "IRQ0 (%s): %d ns\n", modestr, period) + end + elseif reg == 1 then + if period == 0 then + printk(f, action, "Refresh disabled\n") + else + printk(f, action, "Refresh (%s): %d ns\n", modestr, period) + end + elseif reg == 2 then + if period ~= 0 then + local spktone = 1193000 / f.counter[reg].init + printk(f, action, "Speaker Tone (%s): %d kHz\n", modestr, spktone) + end + end + else + if f.counter[reg].readback then + f.counter[reg].readback = false + f.counter[reg].status = action.data + printk(f, action, "[%d] status = %02x\n", reg, f.counter[reg].status) + end + if f.counter[reg].latch then + f.counter[reg].latch = false + f.counter[reg].current = action.data + printk(f, action, "[%d] current = %d\n", reg, f.counter[reg].current) + end + end + elseif reg == 0x03 then + end + return true +end + +i8254_counters = {} +i8254_counters[0x0] = { init=0, current=0, latch, readback, status=0 } +i8254_counters[0x1] = { init=0, current=0, latch, readback, status=0 } +i8254_counters[0x2] = { init=0, current=0, latch, readback, status=0 } + +filter_i8254_a = { + id = -1, + name = "i8254 A", + pre = i8254_pre, + post = i8254_post, + base = 0x40, + hide = hide_i8254_io, + size = 4, + counter = i8254_counters, +} +filter_i8254_b = { + id = -1, + name = "i8254 B", + pre = i8254_pre, + post = i8254_post, + base = 0x50, + hide = hide_i8254_io, + size = 4, + counter = i8254_counters, +} + + +-- ********************************************************** +-- +-- i8042 KBD, A20, Reset(?) + +function i8042_write(f, action) + if action.addr == 0x60 then + f.reg.data = action.data + f.reg.sts = bit.band(f.reg.sts, 0xf7) + if (f.reg.cmd == 0xd1) then + f.reg.A20 = (bit.band(0x02, action.data) == 0x02) + end + return handle_action(f, action) + end + if action.addr == 0x64 then + f.reg.cmd = action.data + f.reg.sts = bit.bor(f.reg.sts, 0x0a) + return handle_action(f, action) + end + return skip_filter(f, action) +end + +function i8042_read(f, action) + if action.addr == 0x60 then + f.reg.sts = bit.band(f.reg.sts, 0xfe) + return handle_action(f, action) + end + if action.addr == 0x64 then + return handle_action(f, action) + end + return skip_filter(f, action) +end + +function i8042_pre(f, action) + if (action.write) then + return i8042_write(f, action) + else + return i8042_read(f, action) + end +end + +function i8042_post(f, action) + if action.addr == 0x60 then + if action.write and f.reg.cmd == 0xd1 then + if f.reg.A20 then + printk(f, action, "A20 enabled\n") + else + printk(f, action, "A20 disabled\n") + end + end + return true + end + if action.addr == 0x64 then + return true + end + return false +end + +filter_i8042 = { + id = -1, + name = "i8042", + pre = i8042_pre, + post = i8042_post, + hide = hide_i8042_io, + base = 0x60, + size = 0x5, + reg = { data = 0, sts = 0, cmd = 0, A20 = 0 } +} + + +-- ********************************************************** +-- +-- CMOS nvram + + +function nvram_bank(addr) + if bit.band(0xfe, addr) == 0x70 then + return 1 + elseif bit.band(0xfe, addr) == 0x72 then + return 2 + elseif bit.band(0xfe, addr) == 0x74 then + return 2 + else + return 0 + end +end + +function nvram_write(f, action) + local val = action.data + local rtc = false + local is_index = (bit.band(0x01, action.addr) == 0x0) + local bank = nvram_bank(action.addr) + + if bank == 1 then + if is_index then + f.reg.p70 = bit.band(0x7f, val) + if f.reg.p70 < 0x0E then + rtc = true + end + else + f.nvram_data[f.reg.p70] = val + f.nvram_set[f.reg.p70] = true + if f.reg.p70 < 0x0E then + rtc = true + end + end + elseif bank == 2 then + if is_index then + f.reg.p72 = bit.band(0x7f, val) + else + local index = 0x80 + f.reg.p72 + f.nvram_data[index] = val + f.nvram_set[index] = true + end + end + if cache_nvram and not rtc then + return fake_action(f, action, val) + else + return handle_action(f, action) + end +end + +function nvram_read(f, action) + local val = 0 + local rtc = false + local is_index = (bit.band(0x01, action.addr) == 0x0) + local bank = nvram_bank(action.addr) + + if bank == 1 then + if is_index then + -- NMI returned as 0 + val = f.reg.p70 + if f.reg.p70 < 0x0E then + rtc = true + end + else + if f.reg.p70 < 0x0E then + rtc = true + elseif f.nvram_set[f.reg.p70] then + val = f.nvram_data[f.reg.p70] + end + end + else -- bank + if is_index then + -- NMI returned as 0 + val = f.reg.p72 + else + local index = 0x80 + f.reg.p72 + if f.nvram_set[index] then + val = f.nvram_data[index] + end + end + end + if cache_nvram and not rtc then + return fake_action(f, action, val) + else + return handle_action(f, action) + end +end + +function nvram_pre(f, action) + if (action.write) then + return nvram_write(f, action) + else + return nvram_read(f, action) + end +end + +function nvram_post(f, action) + if bit.band(0x01, action.addr) == 0x0 then + return true + end + + local bank = nvram_bank(action.addr) + if (action.write) then + if bank == 1 then + printk(f, action, "[%02x] <= %02x\n", f.reg.p70, action.data) + elseif bank == 2 then + printk(f, action, "[%02x] <= %02x\n", 0x80 + f.reg.p72, action.data) + end + else + if bank == 1 then + printk(f, action, "[%02x] => %02x\n", f.reg.p70, action.data) + elseif bank == 2 then + printk(f, action, "[%02x] => %02x\n", 0x80 + f.reg.p72, action.data) + end + end + return true +end + +filter_nvram = { + id = -1, + name = "NVram", + pre = nvram_pre, + post = nvram_post, + base = 0x70, + size = 8, + hide = hide_nvram_io, + reg = { p70 = 0, p72 = 0 }, + nvram_data = {}, + nvram_set = {}, +} + + +-- ********************************************************** +-- +-- Reset at 0xcf9 + +function sys_rst_pre(f, action) + if action.size == 1 then + if action.write and bit.band(action.data, 0x04) == 0x04 then + SerialICE_system_reset() + end + return handle_action(f, action) + end + return skip_filter(f, action) +end + +function sys_rst_post(f, action) + if action.size == 1 then + if action.write then + printk(f, action, "Control = %02x\n", action.data) + return true + end + end + return false +end + +filter_reset = { + id = -1, + name = "Reset", + pre = sys_rst_pre, + post = sys_rst_post, + hide = false, + base = 0xcf9, + size = 1 +} + +-- ********************************************************** +-- +-- VGA io + +function vga_io_pre(f, action) + return skip_filter(f, action) +end + +function vga_io_post(f, action) + return true +end + +filter_vga_io = { + id = -1, + name = "VGA", + pre = vga_io_pre, + post = vga_io_post, + hide = false, + base = 0x3c0, + size = 0x20, +} + + +-- ********************************************************** +-- +-- Enable all PC80 stuff + +function enable_hook_pc80() + enable_hook(io_hooks, filter_i8237_a) + enable_hook(io_hooks, filter_i8237_b) + enable_hook(io_hooks, filter_i8237_c) + enable_hook(io_hooks, filter_i8259_master) + enable_hook(io_hooks, filter_i8259_slave) + enable_hook(io_hooks, filter_i8259_edge) + enable_hook(io_hooks, filter_i8042) + enable_hook(io_hooks, filter_i8254_a) + enable_hook(io_hooks, filter_i8254_b) + enable_hook(io_hooks, filter_reset) + enable_hook(io_hooks, filter_nvram) + enable_hook(io_hooks, filter_vga_io) + enable_hook(io_hooks, filter_debugport) +end + diff --git a/SerialICE/simba/replay.lua b/SerialICE/simba/replay.lua new file mode 100644 index 0000000..fa2ba99 --- /dev/null +++ b/SerialICE/simba/replay.lua @@ -0,0 +1,186 @@ + + +function SerialICE_register_physical() +end + +function SerialICE_system_reset() +end + +SerialICE_mainboard = "undetected" + +regs = { eax, ebc, ecx, edx, cs=0, eip=0, ds, es, ss, gs, fs, } +ids = { parent, this, } + +function replay_io(dir_wr, addr, size, data) + pre_action(io_action, dir_wr, addr, size, data) + walk_pre_hooks(io_hooks, io_action) + io_action.data = data + post_action(io_action, data) + walk_post_hooks(io_hooks, io_action) +end + +function replay_mem(dir_wr, addr, size, data) + pre_action(mem_action, dir_wr, addr, size, data) + walk_pre_hooks(mem_hooks, mem_action) + mem_action.data = data + post_action(mem_action, data) + walk_post_hooks(mem_hooks, mem_action) +end + +function replay_unknown(str) + local dummy = {} + pre_action(dummy, false, 0, 0, 0) + post_action(dummy, 0) + io.write(string.format("[%04x:%04x] %04x.%04x %s\n", + regs.cs, regs.eip, ids.parent, ids.this, str)) +end + +function parse_cpu(line) + if string.find(line, "CPUID") then + replay_unknown(line) + return true + end + if string.find(line, "CPU MSR") then + replay_unknown(line) + return true + end + return false +end + + +function parse_io(line) + local io_op = "IO,[^:]*:?%s+%a+%s+(%x+)%s+(<?=>?)%s+(%x+)" + local found, addr, dir, data + found, _, addr, dir, data = string.find(line, io_op) + if not found then + return false + end + local naddr = tonumber(addr, 16) + local ndata = tonumber(data, 16) + local nsize = string.len(data)/2 + if string.find("<=", dir) then + replay_io(true, naddr, nsize, ndata) + else + replay_io(false, naddr, nsize, ndata) + end + return true +end + +function parse_mem(line) + local mem_op = "MEM,?[^:]*:?%s+%a+%s+(%x+)%s+(<?=>?)%s+(%x+)" + local found, addr, dir, data + found, _, addr, dir, data = string.find(line, mem_op) + if not found then + return false + end + local naddr = tonumber(addr, 16) + local ndata = tonumber(data, 16) + local nsize = string.len(data)/2 + if string.find("<=", dir) then + replay_mem(true, naddr, nsize, ndata) + else + replay_mem(false, naddr, nsize, ndata) + end + return true +end + +-- Old script already parsed PCI config, synthesize those IOs back. +function parse_pci(line) + local found, bus, dev, fn, reg, dir, data + local pci_cfg = "PCI:?%s+(%x):(%x+).(%x+)%s+R.(%x+)%s+(<?=>?)%s+(%x+)" + found, _, bus, dev, fn, reg, dir, data = string.find(line, pci_cfg) + if not found then + local pci_cfg_empty = "PCI:?%s+(%x):(%x+).(%x+)%s+R.(%x+)" + if string.find(line, pci_cfg_empty) then + return true + end + return false + end + + local nreg = bit.band(0xfc, tonumber(reg,16)) + local noff = bit.band(0x03, tonumber(reg,16)) + local ndata = tonumber(data,16) + local nsize = string.len(data)/2 + + replay_io(true, 0xcf8, 4, pci_bdf(tonumber(bus,16), tonumber(dev,16), tonumber(fn,16), nreg)) + if string.find("<=", dir) then + replay_io(true, 0xcfc + noff, nsize, ndata) + else + replay_io(false, 0xcfc + noff, nsize, ndata) + end + return true +end + +function parse_headers() + while true do + local found = false + line = io.read("*line") + if not found then + local board + found, _, board = string.find(line, "SerialICE: Mainboard...:%s+(.+)") + if found then + SerialICE_mainboard = board + end + end +-- io.write(line) +-- io.write("\n") + if string.find(line, "LUA script initialized.") then + return + end + end +end + +function parse_file() + while true do + local iplog = false + local found = false + local line, str, cs, eip, a, b + + line = io.read("*line") + if not line then + return + end + + regs.cs = 0 + regs.eip = 0 + ids.parent = 0 + ids.this = 0 + iplog, _, cs, eip, a, b, str = string.find(line, "%[(%x+):(%x+)%]%s+(%x+)[%.:](%x+)...(.*)") + if iplog then + regs.cs = tonumber(cs, 16) + regs.eip = tonumber(eip, 16) + ids.parent = tonumber(a, 16) + ids.this = tonumber(b, 16) + end + + if not iplog then + str = line + end + + if not found then + found = parse_io(str) + end + if not found then + found = parse_pci(str) + end + if not found then + found = parse_mem(str) + end + if not found then + found = parse_cpu(str) + end + if not found then + --replay_unknown(str) + end + end +end + +parse_headers() + +dofile("serialice.lua") + +parse_file() + + + + diff --git a/SerialICE/simba/serialice.lua b/SerialICE/simba/serialice.lua new file mode 100644 index 0000000..ced9cdd --- /dev/null +++ b/SerialICE/simba/serialice.lua @@ -0,0 +1,122 @@ +-- 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") + + +-- Set to "false" to show undecoded IO accesses +-- for the specified class +hide_pci_io_cfg = true +hide_pci_mm_cfg = true +hide_superio_cfg = true +hide_nvram_io = true +hide_smbus_io = true +hide_mainboard_io = true +hide_i8254_io = true +hide_i8042_io = false +hide_i8237_io = true +hide_i8259_io = true + +-- Set to "true" to log every memory and IO access +log_everything = false + + + +-- Use lua table for NVram +-- RTC registers 0x0-0xd go to HW +cache_nvram = false + +-- SMSC 0x07, Winbond 0x06 ? +DEFAULT_SUPERIO_LDN_REGISTER = 0x07 + +-- Set to "false" to log access to ROM regions + +hide_rom_access = true + +-- Set to "true" to log CS:IP for each access + +ip_logging = true + + +rom_size = 4 * 1024 * 1024 +rom_base = 0x100000000 - rom_size + + +-- -------------------------------------------------------------------- +-- This initialization is executed right after target communication +-- has been established + +dofile("interface.lua") +dofile("output.lua") +dofile("hooks.lua") +dofile("core_io.lua") +dofile("memory.lua") +dofile("cpu.lua") +dofile("superio.lua") +dofile("pc80.lua") +dofile("mmio.lua") + +function do_minimal_setup() + enable_hook(io_hooks, filter_io_fallback) + enable_hook(mem_hooks, filter_mem_fallback) + enable_hook(cpumsr_hooks, filter_cpumsr_fallback) + enable_hook(cpuid_hooks, filter_cpuid_fallback) + enable_hook(mem_hooks, filter_rom_low) + enable_hook(mem_hooks, filter_rom_high) +end + +function do_default_setup() + enable_ram() + enable_hook(mem_hooks, filter_lapic) + enable_hook(mem_hooks, filter_ioapic) + enable_hook(io_hooks, filter_pci_io_cfg) + enable_hook_pc80() + enable_hook_superio(0x2e, DEFAULT_SUPERIO_LDN_REGISTER) + enable_hook_superio(0x4e, DEFAULT_SUPERIO_LDN_REGISTER) + enable_hook(io_hooks, filter_com1) + if superio_initialization then + superio_initialization() + end +end + +mainboard_file = string.format("%s.lua", string.lower(string.gsub(SerialICE_mainboard, "[ -]", "_"))) +local mainboard_lua = loadfile(mainboard_file) +if (mainboard_lua) then + mainboard_lua() + printks(froot, "Mainboard script %s initialized.\n", mainboard_file) + do_minimal_setup() + do_mainboard_setup() +else + printks(froot, "Mainboard script %s not found.\n", mainboard_file) + do_minimal_setup() + do_default_setup() +end + +printks(froot, "LUA script initialized.\n") + +return true + diff --git a/SerialICE/simba/smbus_host.lua b/SerialICE/simba/smbus_host.lua new file mode 100644 index 0000000..90ab9ea --- /dev/null +++ b/SerialICE/simba/smbus_host.lua @@ -0,0 +1,559 @@ + + +local debug_smbus = false +smbus = {} + +smbus.host = { + state = { current = 0, jump_to = 0 }, + proto = 0, + start_proto = 0, + + passive = true, + signals = 0, + + slave = 0, + cmd = 0, + data0 = 0, + data1 = 0, + data0_valid = false, + data1_valid = false, + wr_data0 = 0, + wr_data1 = 0, + block_register = 0, + + block = {}, + max_index = 0, +} + +MAX_BLOCK_SRAM = 32 + +if true then + for i = 0, MAX_BLOCK_SRAM-1, 1 do + smbus.host.block[i] = { hw = 0, tmp = 0, hw_valid = false, tmp_valid = false } + end +end + +-- ******************* + +SIG_INUSE = 0 +SIG_RELEASE = 1 +SIG_START = 2 +SIG_ABORT = 3 +SIG_DONE = 4 +SIG_ACK = 5 +SIG_TIMEOUT = 6 +SIG_TIMEOUT_ACK = 7 +SIG_DATA_WRITE = 8 + +local function signal_reset(f) + f.host.signals = 0 +end + +local function signal_set(f, flag) + local mask = bit.lshift(1, flag) + f.host.signals = bit.bor(f.host.signals, mask) +end + +local function signal_clr(f, flag) + local mask = bit.bnot(bit.lshift(1, flag)) + f.host.signals = bit.band(f.host.signals, mask) + +end + +local function signal_in(f, flag) + local mask = bit.lshift(1, flag) + return bit.band(f.host.signals, mask) ~= 0 +end + +-- ******************* + +-- SMBus Protocol Message Types +SMBUS_NOOP = 0 +SMBUS_QUICK = 1 +SMBUS_BYTE = 2 +SMBUS_BYTE_DATA = 3 +SMBUS_WORD_DATA = 4 +SMBUS_PROC_CALL = 5 +SMBUS_BLOCK_DATA = 6 +SMBUS_I2C_BLOCK_DATA = 7 +SMBUS_BLOCK_PROCESS = 8 + +local proto_name = {} +proto_name[SMBUS_NOOP] = "(no-op)" +proto_name[SMBUS_QUICK] = "quick" +proto_name[SMBUS_BYTE] = "byte" +proto_name[SMBUS_BYTE_DATA] = "byte_data" +proto_name[SMBUS_WORD_DATA] = "word_data" +proto_name[SMBUS_PROC_CALL] = "proc_call" +proto_name[SMBUS_BLOCK_DATA] = "block" +proto_name[SMBUS_I2C_BLOCK_DATA] = "i2c_block" +proto_name[SMBUS_BLOCK_PROCESS] = "block_process" + +-- SMBus Host +SMB_REG_CMD = 1 +SMB_REG_SLAVE = 2 +SMB_REG_DATA0 = 3 +SMB_REG_DATA1 = 4 +SMB_REG_BLOCK = 5 +SMB_REG_PROTO = 6 + + +local function dump_block(f, length) + local block = "" + local max_length = math.min(length, MAX_BLOCK_SRAM) + + for i=0, max_length-1, 1 do + if f.host.block[i].hw_valid then + block = block .. string.format(" %02x", f.host.block[i].hw) + else + block = block .. " xx" + end + end + return block +end + + +-- FIXME: Probably wrong for process calls and hw-dependent. +local function host_proto(f, proto) + return f.host.proto == proto +end + +local function host_reading(f) + return bit.band(f.host.slave, 0x01) == 0x01 +end + + + +local function dump_transaction(f, action) + + local data0, data1, length, dir + local invalid_data = "xx" + local iodir = {} + iodir[0] = "<=" + iodir[1] = "=>" + + if host_reading(f) then + dir = iodir[1] + data0 = invalid_data + length = f.host.max_index + if f.host.data0_valid then + length = f.host.data0 + data0 = string.format("%02x", f.host.data0) + end + data1 = invalid_data + if f.host.data1_valid then + data1 = string.format("%02x", f.host.data1) + end + else + dir = iodir[0] + length = f.host.wr_data0 + data0 = string.format("%02x", f.host.wr_data0) + data1 = string.format("%02x", f.host.wr_data1) + end + + + local dump = string.format("%02x %s ", f.host.slave / 2, proto_name[f.host.proto]) + + if host_proto(f, SMBUS_QUICK) then + + elseif host_proto(f, SMBUS_BYTE) then + dump = dump .. string.format("%02x %s %s", f.host.cmd, dir, data0) + + elseif host_proto(f, SMBUS_BYTE_DATA) then + dump = dump .. string.format("%02x %s %s", f.host.cmd, dir, data0) + + elseif host_proto(f, SMBUS_WORD_DATA) then + dump = dump .. string.format("%02x %s %s%s", f.host.cmd, dir, data0, data1) + + elseif host_proto(f, SMBUS_PROC_CALL) then + dump = dump .. string.format("%02x %02x %02x %s %s %s", f.host.cmd, + f.host.wr_data0, f.host.wr_data1, iodir[1], data0, data1) + + elseif host_proto(f, SMBUS_BLOCK_DATA) then + dump = dump .. string.format("%02x len=%02d %s", f.host.cmd, length, dir) + dump = dump .. dump_block(f, length) .. "" + + elseif host_proto(f, SMBUS_I2C_BLOCK_DATA) then + dump = dump .. string.format("%02x %02x %02x len=%02d %s", + f.host.cmd, f.host.data0, f.host.data1, f.host.max_index, dir) + dump = dump .. dump_block(f, length) .. "" + + elseif host_proto(f, SMBUS_BLOCK_PROCESS) then + dump = dump .. string.format("%02x len=%02d %s", f.host.cmd, length, iodir[1]) + dump = dump .. dump_block(f, length) .. "" + else + dump = dump .. "Cannot parse command" + end + + if signal_in(f, SIG_TIMEOUT) then + action.undefined = true + dump = dump .. " (TIMEOUT) " + end + + printk(f, action, "%s\n", dump) +end + + +-- ******************* + +HOST_NOOP = 0 +HOST_IDLE = 1 +HOST_ACTIVE = 2 +HOST_STARTED = 3 +HOST_WAIT = 4 +HOST_COMPLETE = 5 +HOST_FAIL = 6 + +local ctrl_state = {} +ctrl_state[HOST_NOOP] = "noop" +ctrl_state[HOST_IDLE] = "idle" +ctrl_state[HOST_ACTIVE] = "active" +ctrl_state[HOST_STARTED] = "started" +ctrl_state[HOST_WAIT] = "wait" +ctrl_state[HOST_COMPLETE] = "complete" +ctrl_state[HOST_FAIL] = "failed" + +function dprintk(...) + if debug_smbus then + printk(...) + end +end + +local function host_jump(f, state) + f.host.state.jump_to = state +end + +local function host_change_state(f, prev_state, new_state) + + if new_state == HOST_NOOP then + --printk(f, f.host.action, "state switch to HOST_NOOP\n") + new_state = HOST_IDLE + end + + dprintk(f, f.host.action, "%s -> %s\n", + ctrl_state[prev_state], ctrl_state[new_state]) + + -- Jumping to current is no jump. + f.host.state.current = new_state + f.host.state.jump_to = new_state + + if smbus.state(f, HOST_IDLE) then + signal_reset(f) + + elseif smbus.state(f, HOST_ACTIVE) then + signal_reset(f) + signal_set(f, SIG_INUSE) + + elseif smbus.state(f, HOST_STARTED) then + local i + f.host.proto = f.host.start_proto + f.host.wr_data0 = f.host.data0 + f.host.wr_data1 = f.host.data1 + + -- Invalidation used with reads + f.host.data0_valid = false + f.host.data1_valid = false + + for i = 0, MAX_BLOCK_SRAM-1, 1 do + f.host.max_index = 0 + -- On block writes, previously read data in buffer is also valid. + if f.host.block[i].tmp_valid then + f.host.block[i].hw = f.host.block[i].tmp + f.host.block[i].tmp_valid = false + f.host.block[i].hw_valid = true + end + -- On block reads, no data in buffer is yet valid. + if host_reading(f) and host_proto(f, SMBUS_BLOCK_DATA) then + f.host.block[i].hw_valid = false; + end + end + + elseif smbus.state(f, HOST_COMPLETE) then + dump_transaction(f, f.host.action) + if signal_in(f, SIG_RELEASE) then + host_jump(f, HOST_IDLE) + else + host_jump(f, HOST_ACTIVE) + end + +-- elseif smbus.state(f, HOST_FAIL) then +-- dump_transaction(f, f.host.action) +-- host_jump(f, HOST_ACTIVE) + end + +end + +local function host_switch(f, new_state) + local prev_state = f.host.state.current + while prev_state ~= new_state do + host_change_state(f, prev_state, new_state) + prev_state = f.host.state.current + new_state = f.host.state.jump_to + end +end + +local function host_read_completed(f) + + if not host_reading(f) then + return true + end + + local complete = false + + if host_proto(f, SMBUS_QUICK) then + complete = true + + elseif host_proto(f, SMBUS_BYTE) then + complete = f.host.data0_valid + + elseif host_proto(f, SMBUS_BYTE_DATA) then + complete = f.host.data0_valid + + elseif host_proto(f, SMBUS_WORD_DATA) then + complete = f.host.data0_valid and f.host.data1_valid + + elseif host_proto(f, SMBUS_BLOCK_DATA) then + complete = f.host.data0_valid and f.host.max_index >= f.host.data0 + + elseif host_proto(f, SMBUS_PROC_CALL) or host_proto(f, SMBUS_I2C_BLOCK_DATA) + or host_proto(f, SMBUS_BLOCK_PROCESS) then + printk(f, f.host.action, "Unimplemented completion (proto %d)\n", f.host.proto) + end + return complete +end + + +-- Syncronize state machine according to input signals. +local function host_sync(f) + +-- if release and not smbus.state(f, HOST_ACTIVE) then +-- printk(f, f.host.action, "Premature reset of bit INUSE_STS\n") +-- end + if signal_in(f, SIG_ABORT) then + -- FIXME Killing on-going transaction. + host_switch(f, HOST_COMPLETE) + end + + if smbus.state(f, HOST_IDLE) then + if signal_in(f, SIG_INUSE) then + host_switch(f, HOST_ACTIVE) + end + if signal_in(f, SIG_START) then + host_switch(f, HOST_STARTED) + end + + elseif smbus.state(f, HOST_ACTIVE) then + if signal_in(f, SIG_START) then + host_switch(f, HOST_STARTED) + end + + elseif smbus.state(f, HOST_STARTED) then + if signal_in(f, SIG_TIMEOUT) then + host_switch(f, HOST_FAIL) + elseif signal_in(f, SIG_DONE) then + host_switch(f, HOST_WAIT) + end + + elseif smbus.state(f, HOST_WAIT) then + if signal_in(f, SIG_START) then + -- Restarting previous transaction. + host_switch(f, HOST_COMPLETE) + host_switch(f, HOST_STARTED) + elseif signal_in(f, SIG_ACK) and not host_reading(f) then + -- Complete after sw ack. + host_switch(f, HOST_COMPLETE) + elseif signal_in(f, SIG_DATA_WRITE) or host_read_completed(f) then + -- Complete after all data read or new data written + -- remain active + signal_clr(f, SIG_RELEASE) + host_switch(f, HOST_COMPLETE) + end + elseif smbus.state(f, HOST_FAIL) then + if signal_in(f, SIG_TIMEOUT_ACK) then + host_switch(f, HOST_COMPLETE) + end + end + + if signal_in(f, SIG_START) and not smbus.state(f, HOST_STARTED) then + printk(f, f.host.action, "Starting from illegal state\n"); + end + + signal_clr(f, SIG_DONE) + signal_clr(f, SIG_START) + signal_clr(f, SIG_DATA_WRITE) +end + + + +-- ******************************* + +-- Mutual exclusion. +function smbus.get_resource(f) + signal_set(f, SIG_INUSE) + host_sync(f) +end + +function smbus.put_resource(f) + signal_set(f, SIG_RELEASE) + host_sync(f) +end + +-- status +function smbus.state(f, state) + return f.host.state.current == state +end + +function smbus.passive(f) + return f.host.passive +end + +-- control +function smbus.start(f, proto) + signal_set(f, SIG_START) + f.host.start_proto = proto + host_sync(f) +end + +function smbus.timeout(f) + signal_set(f, SIG_TIMEOUT) + host_sync(f) +end + +function smbus.timeout_ack(f) + signal_set(f, SIG_TIMEOUT_ACK) + host_sync(f) +end + +function smbus.done(f) + signal_set(f, SIG_DONE) + host_sync(f) +end + +function smbus.ack(f) + signal_set(f, SIG_ACK) + host_sync(f) +end + +function smbus.abort(f) + signal_set(f, SIG_ABORT) + host_sync(f) +end + +-- A data read may complete and close an active transaction. +function smbus.data_read(f, action) + if not action.write then + signal_clr(f, SIG_DATA_WRITE) + host_sync(f) + end +end + +-- A data write will close active transaction. +function smbus.data_write(f, action) + if action.write then + signal_set(f, SIG_DATA_WRITE) + host_sync(f) + end +end + + + +function smbus.update_register(f, action, smb_reg) + + local data_write = action.write or smbus.passive(f) + + -- A write to data registers completes previous transaction. + smbus.data_write(f, action) + + if smb_reg == SMB_REG_SLAVE then + if data_write then + f.host.slave = action.data + else + action.data = f.host.slave + end + + elseif smb_reg == SMB_REG_CMD then + if data_write then + f.host.cmd = action.data + else + action.data = f.host.cmd + end + + elseif smb_reg == SMB_REG_DATA0 then + if data_write then + f.host.data0 = action.data + else + action.data = f.host.data0 + end + f.host.data0_valid = true + + elseif smb_reg == SMB_REG_DATA1 then + if data_write then + f.host.data1 = action.data + else + action.data = f.host.data1 + end + f.host.data1_valid = true + + elseif smb_reg == SMB_REG_BLOCK then + if data_write then + f.host.block_register = action.data + else + action.data = f.host.block_register + end + -- Nothing here, smbus.host_block_data updates datas. + -- This exist to check completion below for blocks. + elseif smb_reg == SMB_REG_PROTO then + -- Nothing here. Protocol updates when signalling start. + else + printk(f, f.host.action, "Undefined host register\n") + end + + -- New read data may complete a waiting transaction. + smbus.data_read(f, action) +end + +function smbus.block_data(f, action, index) + + if smbus.passive(f) then + if not action.write then + f.host.block[index].hw = action.data + f.host.block[index].hw_valid = true + end + f.host.block[index].tmp = action.data + f.host.block[index].tmp_valid = true + else + if action.write then + f.host.block[index].tmp = action.data + f.host.block[index].tmp_valid = true + else + action.data = 0xff + if f.host.block[index].tmp_valid then + action.data = f.host.block[index].tmp + elseif f.host.block[index].hw_valid then + action.data = f.host.block[index].hw + end + end + end + + -- Detect for block read completion via maximum indexed item. + if not action.write then + f.host.max_index = math.max(f.host.max_index, index+1) + end +end + +local init_action = { + name = "init", + cs = 0, + eip = 0, + my_id = 0, + parent_id = 0, +} +function smbus.init(f) + if not f.host then + f.host = smbus.host + f.host.action = init_action + end + host_switch(f, HOST_IDLE) +end + + diff --git a/SerialICE/simba/superio.lua b/SerialICE/simba/superio.lua new file mode 100644 index 0000000..5d81148 --- /dev/null +++ b/SerialICE/simba/superio.lua @@ -0,0 +1,252 @@ + + +function pnp_switch_ldn(f, data) + if not f.ldn[data] then + f.ldn[data] = { data = {}, set = {}, bar0 = {}, bar1 = {} } + end + f.pnp.active_ldn = data +end + +function pnp_select_cfg(f, data) + f.pnp.reg = data +end + +function pnp_store_cfg(f, data) + local ldn = f.pnp.active_ldn + local reg = f.pnp.reg + f.ldn[ldn].data[reg] = data; + f.ldn[ldn].set[reg] = true; +end + + +-- ********************************************************** +-- +-- SuperIO device handling + +function superio_pnpdev(f) + return string.format("%s %02x:%02x", f.name, f.base, f.pnp.active_ldn) +end + +function superio_dev_post(f, action) + if f.pnp.reg < 0x30 then + printk(f, action, "%02x: ", f.base) + else + printk(f, action, "%02x:%02x ", f.base, f.pnp.active_ldn) + end +end + +function superio_register_post(f, action) + superio_dev_post(f, action) + if action.write then + printf("[%02x] <= %02x\n", f.pnp.reg, action.data) + else + printf("[%02x] => %02x\n", f.pnp.reg, action.data) + end +end + +function superio_try_enable_io(f, idx) + + local ldn = f.ldn[f.pnp.active_ldn] + + if ldn.set[0x30] and ldn.data[0x30] ~= 0x0 then + if idx == 0 and ldn.set[0x60] and ldn.set[0x61] then + local iobase = bit.bor(bit.lshift(ldn.data[0x60], 8), ldn.data[0x61]) + if not ldn.bar0.size then + ldn.bar0.size = 1 + end + if not ldn.bar0.name then + ldn.bar0.name = superio_pnpdev(f) + end + ldn.bar0.base = iobase + generic_io_bar(ldn.bar0) + end + if idx == 1 and ldn.set[0x62] and ldn.set[0x63] then + local iobase = bit.bor(bit.lshift(ldn.data[0x62], 8), ldn.data[0x63]) + if not ldn.bar1.size then + ldn.bar1.size = 1 + end + if not ldn.bar1.name then + ldn.bar1.name = superio_pnpdev(f) + end + ldn.bar1.base = iobase + generic_io_bar(ldn.bar1) + end + end +end + +function superio_try_enable_ldn(f, action) + local ldn = f.ldn[f.pnp.active_ldn] + + if ldn.set[0x30] and ldn.data[0x30] == 0x0 then + superio_dev_post(f, action) + printf("disabled\n") + else + superio_dev_post(f, action) + printf("enabled\n") + end +end + +function superio_pre(f, action) + if not action.write then + return handle_action(f, action) + end + + if action.addr == f.base then + pnp_select_cfg(f, action.data) + return handle_action(f, action) + end + + if action.addr == f.base + 0x01 then + -- Also creates new LDN instance, if necessary. + if f.pnp.reg == f.pnp.ldn_register then + pnp_switch_ldn(f, action.data) + end + + pnp_store_cfg(f, action.data) + + -- Don't allow that our SIO power gets disabled. + if f.pnp.reg == 0x02 then + return drop_action(f, action, 0) + end + + -- Don't mess with oscillator setup. + if f.pnp.reg == 0x24 then + return drop_action(f, action, 0) + end + return handle_action(f, action) + end + + -- should not reach here + return skip_filter(f, action) +end + +function superio_post(f, action) + + -- Do not log change of register or LDN. + if action.addr == f.base or f.pnp.reg == f.pnp.ldn_register then + return true + end + + if not action.write then + superio_register_post(f, action) + return true + end + + local ldn = f.ldn[f.pnp.active_ldn] + + -- Log base address once both bytes are set. + + if ( f.pnp.reg == 0x60 or f.pnp.reg == 0x61 ) then + superio_try_enable_io(f, 0) + return true + end + + if ( f.pnp.reg == 0x62 or f.pnp.reg == 0x63 ) then + superio_try_enable_io(f, 1) + return true + end + + if f.pnp.reg == 0x30 then + superio_try_enable_io(f, 0) + superio_try_enable_io(f, 1) + superio_try_enable_ldn(f, action) + return true + end + + if f.pnp.reg == 0x70 then + superio_dev_post(f, action) + printf("irq = %d\n", ldn.data[0x70]) + return true + end + if f.pnp.reg == 0x72 then + superio_dev_post(f, action) + printf("irq2 = %d\n", ldn.data[0x72]) + return true + end + + superio_register_post(f, action) + return true +end + + +filter_superio_2e = { + id = -1, + name = "PnP", + pre = superio_pre, + post = superio_post, + base = 0x2e, + size = 0x02, + hide = hide_superio_cfg, + pnp = { reg = 0, active_ldn = -1, ldn_register = 0 }, + ldn = {}, +} +filter_superio_4e = { + id = -1, + name = "PnP", + pre = superio_pre, + post = superio_post, + base = 0x4e, + size = 0x02, + hide = hide_superio_cfg, + pnp = { reg = 0, active_ldn = -1, ldn_register = 0 }, + ldn = {}, +} + + +function superio_get_filter(cfg_base) + if cfg_base == 0x2e then + return filter_superio_2e + elseif cfg_base == 0x4e then + return filter_superio_4e + else + return nil + end +end + +function superio_set_ldn_register(f, ldn_register) + f.pnp.ldn_register = ldn_register +end + +function superio_new_ldn(f, idx) + if not f.ldn[idx] then + f.ldn[idx] = { data = {}, set = {}, bar0 = {}, bar1 = {} } + end +end + +function superio_ldn_iobase0(f, idx, name, size) + f.ldn[idx].bar0.name = name + f.ldn[idx].bar0.size = size +end + +function superio_ldn_iobase1(f, idx, name, size) + f.ldn[idx].bar1.name = name + f.ldn[idx].bar1.size = size +end + +function enable_hook_superio(base, ldn_register) + local sio = superio_get_filter(base) + superio_set_ldn_register(sio, ldn_register) + enable_hook(io_hooks, sio) +end + +-- ********************************************************** +-- +-- Serial Port handling + +function com_pre(f, action) + if (action.write) then + return drop_action(f, action, action.data) + else + return drop_action(f, action, 0xff) + end +end + +filter_com1 = { + id = -1, + name = "COM1", + pre = com_pre, + post = io_post, + base = 0x3f8, + size = 8, + hide = false, +} diff --git a/SerialICE/simba/via_bars.lua b/SerialICE/simba/via_bars.lua new file mode 100644 index 0000000..305acaf --- /dev/null +++ b/SerialICE/simba/via_bars.lua @@ -0,0 +1,30 @@ + +function sb_pcie_bar(dev, reg, base) + local baseaddr = bit.lshift(base, 16) + local size = 64*1024 + + pcie_mm_cfg_bar(baseaddr, size) +end + +dev_sb = { + pci_dev = pci_bdf(0,0x11,0,0), + name = "sb", + bar = {}, +} + +function nb_pcie_bar(dev, reg, base) + local size = 64*1024 + + pcie_mm_cfg_bar(base, size) +end + +dev_nb = { + pci_dev = pci_bdf(0,0,0,0), + name = "nb", + bar = {}, +} + +function northbridge_vx900() + hook_pci_cfg16(dev_sb, 0xbd, sb_pcie_bar) + hook_pci_cfg32(dev_nb, 0x0, nb_pcie_bar) +end diff --git a/SerialICE/simba/via_epia_m_850.lua b/SerialICE/simba/via_epia_m_850.lua new file mode 100644 index 0000000..e931905 --- /dev/null +++ b/SerialICE/simba/via_epia_m_850.lua @@ -0,0 +1,165 @@ +-- SerialICE +-- +-- Copyright (c) 2012 Kyösti Mälkki kyosti.malkki@gmail.com +-- +-- 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. +-- + + +-- ********************************************************** +-- + +function mainboard_io_read(f, action) + + -- IO slowdown + if action.addr == 0xed then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + -- IO slowdown + if action.addr == 0xeb then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + if action.addr == 0xcfb then + ignore_action(f, action) + return drop_action(f, action, 0) + end + + return skip_filter(f, action) +end + + +function mainboard_io_write(f, action) + + -- Catch RAM controller ready. + if action.addr == 0x80 and action.data == 0x2c and not ram_enabled() then + enable_ram() + end + +-- if action.addr == 0xcfb then +-- ignore_action(f, action) +-- return drop_action(f, action, 0) +-- end + + if action.addr == 0xeb then + ignore_action(f, action) + return drop_action(f, action, action.data) + end + + if action.addr == 0xed then + ignore_action(f, action) + return drop_action(f, action, action.data) + end + + return skip_filter(f, action) +end + +function mainboard_io_pre(f, action) + if action.write then + return mainboard_io_write(f, action) + else + return mainboard_io_read(f, action) + end +end + +function mainboard_io_post(f, action) + if action.addr == 0xeb or action.addr == 0xed then + return true + end + + -- If KBD controller returns status=0xff, clear 0x02. + if action.addr == 0x64 and not action.write and action.size == 1 then + if action.data == 0xff then + -- tag these but give out correct data + fake_action(f, action, action.data) + end + end +end + +filter_mainboard = { + id = -1, + name = "VIA", + pre = mainboard_io_pre, + post = mainboard_io_post, + hide = hide_mainboard_io, + base = 0x0, + size = 0x10000 +} + + + +-- MOVE THIS TO CHIPSET FILE + +dofile("intel_smbus.lua") +dofile("via_bars.lua") + +function smbus_bar_hook(dev, reg, base) + intel_smbus_setup(base, 0x20) +end + +dev_sb_lpc = { + pci_dev = pci_bdf(0x0,0x1f,0x3,0x0), + name = "Smbus", + bar = {}, +} + +dev_power = { + pci_dev = pci_bdf(0x0,0x11,0x0,0x0), + name = "SYS", + bar = {}, + acpi = { f = nil }, + tco = { f = nil }, +} + +function pm_io_bar(dev, reg, base) + dev.acpi.name = "ACPI" + dev.acpi.base = base + dev.acpi.size = 0x60 + generic_io_bar(dev.acpi) +end + + + +-- **************** + +function do_mainboard_setup() + enable_hook(io_hooks, filter_pci_io_cfg) + enable_hook(mem_hooks, filter_lapic) + enable_hook(mem_hooks, filter_ioapic) + + enable_hook(cpumsr_hooks, filter_intel_microcode) + enable_hook(cpuid_hooks, filter_multiprocessor) + + -- I have a hook to detect RAM initialisation from + -- a POST code I can skip this here + --enable_ram() + + enable_hook_pc80() + enable_hook_superio(0x4e, 0x07) + + northbridge_vx900() + hook_pci_cfg16(dev_power, 0x88, pm_io_bar) + hook_pci_cfg16(dev_power, 0xd0, smbus_bar_hook) + + -- Apply mainboard hooks last, so they are the first ones to check + enable_hook(io_hooks, filter_mainboard) +end