[SerialICE] New patch to review for serialice: d1e3d39 Add PCI config register filters
Kyösti Mälkki (kyosti.malkki@gmail.com)
gerrit at coreboot.org
Sun Oct 28 21:09:07 CET 2012
Kyösti Mälkki (kyosti.malkki at gmail.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/1645
-gerrit
commit d1e3d39e9d63adbf51f897e198775f02a8875af8
Author: Kyösti Mälkki <kyosti.malkki at 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 at 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()
More information about the SerialICE
mailing list