本文为看雪论坛优秀文章
看雪论坛作者ID:hyjxiaobia
序
年毕业那会,我首次接触到51单片机,当时发现51单片机如此简单却功能完备:尽管它没有搭载OS,却能接收GPIOPort上的硬件事件;同时能将控制逻辑反馈给设备。反观基于x86体系的PC,虽然功能强大,但终端用户因为下列限制,很难在Ring层控制简单如按钮开关这样的外设:a.主板厂商本着节省原料的原则,未必会在主板上引出空闲的GPIOPort;退一步,即使厂商出于某种原因,引出了空闲的GPIOPort,终端用户没有主板回路图,无法找到这些GPIOPort;b.即使用户侥幸找到了GPIOPort,但是GPIOPort的作用是由主板厂商在Bios中设定的,普通用户无法修改这些设定;另外,Intel仅向IBV/OEM等它的合作厂商提供PCHspec,除非发生了类似00年7月Intel泄露了0G相关资料的事件,否则终端用户无法对外设进行准确的设定;c.OS足够强大,以至于抽象了底层硬件实现(OS的透明性),这是积极的一面。但是反过来,正是因为OS的透明性,位于Ring层的App很难访问硬件。以上种种,像是PC行业给初学者添加的重重壁垒。我由于机缘巧合,有机会在这些壁垒上自底向上的(Bios--Acpi.sys/OS--驱动--App)打了一串小孔,从而能在Ring层接受来自硬件层的GPIO中断。本文基于IntelWhiskeyLake平台,总结了这种自上而下的(非标准)访问方式,也算是我对毕业这么多年的一个回顾~0.神秘的PSB接口
IntelPCHEDSVol中规定,IntelPCH通过PSB(PrimarytoSidebandBridge)接口,以下列公式访问GPIOPad:图1.PSB访问GPIOCommunity图.PSB的PCIeLocationPSB接口是PCH上的PCIe设备,在WhiskyLake平台上,它位于B:0/D:1/F:1。看到这,你的第一反应一定是计算PSB的配置空间地址,然后通过MMIO方式获得SBREG_BAR,这就有了上述公式里1/的原料。但是PSB和PMCController(B:0/D:1/F:)一样神秘:即使已知Bus\Device\FunctionNumber,也无法访问该PCIe设备的配置空间。我们可以用RW分别访问RootBridge/PSB/PowerManagmentController个PCIe设备的配置空间:图.MMIO方式读取种PCIe设备的配置空间的结果根据图结果,我制作了下表,方便读者阅读:根据图表可知:RW无法获得PSB的配置空间,进而无法获得SBREG_BAR(PSBBaseAddressB:0/D:1/F:1/Reg0x10),所以本文结束!?当然这不是结束,我开玩笑的。RW关上一扇门,但是Intel开了一个烟囱:我们可以从Intel提供给IBV\OEM的Intel\KabyLakeSiliconPkg目录下找到SBREG_BAR和通过PSB接口访问各类寄存器的宏定义:/**DefinitionforPCRaddressThePCRaddressisusedtothePCRMMIOprogramming**/#definePCH_PCR_ADDRESS(Pid,Offset)(PCH_PCR_BASE_ADDRESS
((UINT8)(Pid)16)
(UINT16)(Offset))#definePCH_PCR_BASE_ADDRESS0xFD///SBREGMMIObaseaddress这个宏定义可以视为对图1中红线部分的补充说明。PortID不同于51单片机访问GPIOPort,IntelPCH视GPIO为GPIOPad。读者可以将GPIOPad理解为主板上的焊点(当然Pad本身也有焊盘的意思)。而焊点GPIOPad到真正的GPIOPort之间还有不为人知的回路。同时,IntelPCH将若干物理内存上相近的GPIOPad划到同一个GPIOCommunity(GPIO社区?GPIO组?),以便于访问,并赋予各个GPIOCommunity平台唯一的PortID。各个平台定义的PortID不同,需要查询EDSVol1,下图为KabyLake定义的PortID:图4.本文用到的是GPIO