[SerialICE] New patch to review for serialice: eb43380 Add superio filtering

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/1647

-gerrit

commit eb43380a5a24737214e43f9200630ef96fdbcc79
Author: Kyösti Mälkki <kyosti.malkki at gmail.com>
Date:   Sun Oct 28 11:32:48 2012 +0200

    Add superio filtering
    
    Decoder is able to pretty-print the config cycles to port 0x2e/0x4e
    and activate new IO regions. One should provide a map of LDN functions
    with the size of each IO region as part of the mainboard script.
    
    Change-Id: I976f43818b43a30db97b4e679de04e399f691b97
    Signed-off-by: Kyösti Mälkki <kyosti.malkki at gmail.com>
---
 SerialICE/simba/serialice.lua |  11 ++
 SerialICE/simba/superio.lua   | 259 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 270 insertions(+)

diff --git a/SerialICE/simba/serialice.lua b/SerialICE/simba/serialice.lua
index 4b63e25..3700589 100644
--- a/SerialICE/simba/serialice.lua
+++ b/SerialICE/simba/serialice.lua
@@ -34,6 +34,7 @@ hide_i8042_io = false
 hide_i8237_io = true
 hide_i8254_io = true
 hide_i8259_io = true
+hide_superio_cfg = true
 
 -- Set to "true" to log every memory and IO access
 log_everything = false
@@ -43,6 +44,9 @@ log_everything = false
 -- RTC registers 0x0-0xd go to HW
 cache_nvram = false
 
+-- SMSC 0x07, Winbond 0x06 ?
+DEFAULT_SUPERIO_LDN_REGISTER = 0x07
+
 rom_size = 4 * 1024 * 1024
 rom_base = 0x100000000 - rom_size
 
@@ -59,6 +63,7 @@ dofile("memory.lua")
 dofile("cpu.lua")
 dofile("pci_cfg.lua")
 dofile("pc80.lua")
+dofile("superio.lua")
 
 function do_minimal_setup()
 	enable_hook(io_hooks, filter_io_fallback)
@@ -73,6 +78,12 @@ function do_default_setup()
 	enable_ram()
 	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
 
 do_minimal_setup()
diff --git a/SerialICE/simba/superio.lua b/SerialICE/simba/superio.lua
new file mode 100644
index 0000000..1248af5
--- /dev/null
+++ b/SerialICE/simba/superio.lua
@@ -0,0 +1,259 @@
+
+
+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 reg = f.pnp.reg
+	if reg < 0x30 then
+		f.chip.data[reg] = data;
+		f.chip.set[reg] = true;
+	else
+		local ldn = f.pnp.active_ldn
+		f.ldn[ldn].data[reg] = data;
+		f.ldn[ldn].set[reg] = true;
+	end
+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 = bit32.bor(bit32.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.val = iobase
+			generic_io_bar(ldn.bar0)
+		end
+		if idx == 1 and ldn.set[0x62] and ldn.set[0x63] then
+			local iobase = bit32.bor(bit32.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.val = 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,
+	chip = { data = {}, set = {} },
+	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,
+	chip = { data = {}, set = {} },
+	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,
+}



More information about the SerialICE mailing list