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/1645
-gerrit
commit d1e3d39e9d63adbf51f897e198775f02a8875af8 Author: Kyösti Mälkki kyosti.malkki@gmail.com Date: Sun Oct 28 11:02:01 2012 +0200
Add PCI config register filters
Config register decoding is enabled by default for IO 0xcf8-0xcff access only. To enable decode of MMIO style access, it is necessary to add chipset-specific hook to set base of PCI MMIO config space.
At the moment modifying transactions is limited to conditionally dropping a write before it reaches target.
Change-Id: Ib4241701dcbd5d617749f1223141171eb8093000 Signed-off-by: Kyösti Mälkki kyosti.malkki@gmail.com --- SerialICE/simba/pci_cfg.lua | 329 ++++++++++++++++++++++++++++++++++++++++++ SerialICE/simba/serialice.lua | 4 + 2 files changed, 333 insertions(+)
diff --git a/SerialICE/simba/pci_cfg.lua b/SerialICE/simba/pci_cfg.lua new file mode 100644 index 0000000..88ea266 --- /dev/null +++ b/SerialICE/simba/pci_cfg.lua @@ -0,0 +1,329 @@ + +-- ********************************************************** +-- +-- PCI IO config access + +pci_cfg_action = {} + +PCI_CFG_READ = false +PCI_CFG_WRITE = true + +pci_cfg_hooks = new_list() + +function add_pci_cfg_hook(dev, reg, size, func) + local bdfr = bit32.bor(dev.pci_dev, reg) + local name = string.format("PCI %x:%02x.%x [%04x]", + bit32.band(0xff,bit32.rshift(bdfr, 20)), bit32.band(0x1f,bit32.rshift(bdfr, 15)), + bit32.band(0x7,bit32.rshift(bdfr, 12)), bit32.band(0xfff,bdfr)) + local filter = { + id = -1, + base = bdfr, + dev = dev, + reg = reg, + size = size, + pre = func, + name = name, + enable = true + } + enable_hook(pci_cfg_hooks, filter) +end + +function is_pci_cfg_hooked(bdf) + local l = pci_cfg_hooks.list + while l do + if bdf == bit32.band(l.hook.base, bit32.bnot(0x03)) then + return true + end + l = l.next + end + return false +end + +function walk_pci_pre_hooks(list, action) + if list == nil or list.list == nil then + return false + end + local l = list.list + local f = nil + + while l do + f = l.hook + if action.addr == f.base and action.size == f.size then + if f.enable and f.pre then + f.pre(f, action) + end + end + l = l.next + end +end + +function call_pci_cfg_hook(action, bdf, size, data) + + if action.stage == PRE_HOOK then + if action.write then + pre_action(pci_cfg_action, PCI_CFG_WRITE, bdf, size, data) + else + --pre_action(pci_cfg_action, PCI_CFG_READ, bdf, size, 0) + end + walk_pci_pre_hooks(pci_cfg_hooks, pci_cfg_action) + + if pci_cfg_action.dropped then + action.dropped = true + end + elseif action.stage == POST_HOOK then + + end +end + +function pci_cfg8_hook(dev, reg, name, hook) + add_bar(dev, reg, name, 0) + add_pci_cfg_hook(dev, reg, 1, hook) +end + +function pci_cfg16_hook(dev, reg, name, hook) + add_bar(dev, reg, name, 0) + add_pci_cfg_hook(dev, reg, 2, hook) +end + +function pci_cfg32_hook(dev, reg, name, hook) + add_bar(dev, reg, name, 0) + add_pci_cfg_hook(dev, reg, 4, hook) +end + +function io_bar_hook(f, action) + f.dev.bar[f.reg].val = action.data + generic_io_bar(f.dev.bar[f.reg]) +end + +function mem_bar_hook(f, action) + f.dev.bar[f.reg].val = action.data + generic_mmio_bar(f.dev.bar[f.reg]) +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] = {} + dev.bar[reg].f = nil + end + dev.bar[reg].name = name + dev.bar[reg].val = 0x0 + dev.bar[reg].size = size +end + +function add_io_bar(dev, reg, name, size) + add_bar(dev, reg, name, size) + add_pci_cfg_hook(dev, reg, 2, io_bar_hook) +end + +function add_mem_bar(dev, reg, name, size) + add_bar(dev, reg, name, size) + add_pci_cfg_hook(dev, reg, 4, mem_bar_hook) +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 pci_cfg_select(f, bdfr) + f.reg.bdfr = bdfr + + if f.reg.bdfr_hook ~= bdfr then + f.reg.bdfr_hook = 0 + if (is_pci_cfg_hooked(bdfr)) then + f.reg.bdfr_hook = bdfr + end + for i = 0, 3, 1 do bv[i] = false end + end +end + +function pci_cfg_print(f, action, bdfr) + local dir_str = "=>" + if (action.write) then + dir_str = "<=" + end + + printk(f, action, "%x:%02x.%x [%02x] %s %s\n", + bit32.band(0xff,bit32.rshift(bdfr, 20)), bit32.band(0x1f,bit32.rshift(bdfr, 15)), + bit32.band(0x7,bit32.rshift(bdfr, 12)), bit32.band(0xfff,bdfr), + dir_str, size_data(action.size, action.data)) +end + +function pci_cfg_access(f, action) + + if f.reg.bdfr_hook == 0 then + return false + end + + if not action.write then + return false + end + + local bdfr = f.reg.bdfr_hook + local addr = action.addr + local size = action.size + local data = action.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 + + 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 = bit32.lshift(0xff, ll) + omask = bit32.lshift(data, ll) + f.reg.data = bit32.band(f.reg.data, bit32.bnot(amask)) + f.reg.data = bit32.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 = bit32.lshift(0xffff, ll) + omask = bit32.lshift(data, ll) + f.reg.data = bit32.band(f.reg.data, bit32.bnot(amask)) + f.reg.data = bit32.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 + + local val = 0 + val = f.reg.data + for i = 0, 3, 1 do + if (bv[i] and av[i]) then + call_pci_cfg_hook(action, bdfr + i, 1, val) + end + val = bit32.rshift(val, 8) + end + val = f.reg.data + for i = 0, 2, 1 do + if ((bv[i] and bv[i+1]) and (av[i] or av[i+1])) then + call_pci_cfg_hook(action, bdfr + i, 2, val) + end + val = bit32.rshift(val, 8) + end + val = f.reg.data + if (bv[0] and bv[1] and bv[2] and bv[3]) then + call_pci_cfg_hook(action, bdfr, 4, val) + end +end + +-- ********************************************************** +-- +-- PCI IO config access + +function pci_io_cfg_pre(f, action) + if action.addr == 0xcf8 and action.size == 4 then + if action.write then + if bit32.band(0x80000000, action.data) ~= 0 then + f.reg.reset = true + new_parent_action() + end + local bdfr = 0 + bdfr = bit32.lshift(action.data, 4) + bdfr = bit32.band(bdfr, 0xfffff000) + bdfr = bit32.bor(bdfr, bit32.band(action.data, 0xfc)) + pci_cfg_select(f, bdfr) + end + return handle_action(f, action) + end + if action.addr >= 0xcfc and action.addr <= 0xcff then + pci_cfg_access(f, action) + 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 + local byte_offset = action.addr - 0xcfc + pci_cfg_print(f, action, f.reg.bdfr + byte_offset) + 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) + local bdfr = 0 + bdfr = bit32.band(action.addr, bit32.bnot(f.base)) + bdfr = bit32.band(bdfr, bit32.bnot(0x3)) + + pci_cfg_select(f, bdfr) + pci_cfg_access(f, action) + + return handle_action(f, action) +end + +function pci_mm_cfg_post(f, action) + local bdfr = bit32.band(action.addr, bit32.bnot(f.base)) + pci_cfg_print(f, action, bdfr) + 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) + local bar = dev.bar[reg] + bar.val = base + bar.size = size + + if not bar.f then + bar.f = filter_pci_mm_cfg + end + + bar.f.name = bar.name + bar.f.base = bar.val + 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/serialice.lua b/SerialICE/simba/serialice.lua index c179f8c..5529068 100644 --- a/SerialICE/simba/serialice.lua +++ b/SerialICE/simba/serialice.lua @@ -27,6 +27,8 @@ io.write("SerialICE: Starting LUA script\n")
-- Set to "false" to show undecoded access for the specified class hide_rom_access = true +hide_pci_io_cfg = true +hide_pci_mm_cfg = true
-- Set to "true" to log every memory and IO access log_everything = false @@ -46,6 +48,7 @@ dofile("hooks.lua") dofile("core_io.lua") dofile("memory.lua") dofile("cpu.lua") +dofile("pci_cfg.lua")
function do_minimal_setup() enable_hook(io_hooks, filter_io_fallback) @@ -58,6 +61,7 @@ end
function do_default_setup() enable_ram() + enable_hook(io_hooks, filter_pci_io_cfg) end
do_minimal_setup()