(请保留->发布地址: http://yiiyee.cn/blog/author/luobing/ )
我所用的测试卡是PCI-E设备,公司商用的产品也是PCI-E设备。所以,我很早就“被迫”去读那些PCI spec。
从软件工程师的角度,我觉得只要解决几个问题就行了,其余的细节不妨碍编程。
1) PCI/PCI-E设备是如何定位的,也即程序如何找到设备;
2) 系统把它认作什么设备;
3) 如何访问设备的内部寄存器(一般要去读所使用的PCI-E芯片的资料);
4) 商用化的产品,需要考虑设备对ACPI的各种电源事件的处理。
前三个问题需要仔细研究下PCI设备配置空间:
除了主PCI桥之外,其他PCI设备都应该实现PCI设备配置空间。配置空间包括一系列的PCI配置寄存器,其实现位置可以在PCI配置空间中,或者IO空间,也可以直接在申请的memory空间中实现。
一般情况下,操作系统使用这些配置寄存器的内容来决定为PCI设备加载什么驱动程序:供应商ID、设备ID、版本号、类别代码、子系统供应商、子系统ID。具体的含义可以参考PCI/PCI-E的Spec手册。
隔离卡/还原卡的开发中,最让人印象深刻的就是类别代码寄存器了。它规定了你的设备是大容量存储设备还是网络设备,或者其他设备。主板有时候会找不到你的设备,无法加载Option ROM代码,改一种类型就可以了。
这个章节主要实现列举PCI设备的代码。
实际上,uefi shell下已经有了类似功能的命令。之前开发的时候我并不清楚,是在写博客的时候慢慢了解到的,可见写博客真是种学习的好方法。
Shell下pci内置在运行环境中,是\ShellPkg\Library\UefiShellDebug1CommandsLib下pci.*编译出来的,在模拟环境中执行:
很遗憾,无法执行。这也意味着我们编写的pci列举程序无法在nt32下执行,最好还是以x64方式编译,在实际环境中执行。
UEFI Spec中有两个protocol可以访问PCI设备,PCI Root Bridge I/O Protocol和PCI I/O Protocol。这两个Protocol有什么区别,到现在我理解得还是不深刻。
从实践中知道,PCI I/O Protocol可以访问改在在主板上的所有PCI设备,而PCI Root Bridge I/O Protocol不能访问PCI to PCI桥设备。两种Protocol都可以访问上一篇博客描述的测试板卡。
这次用PCI Root Bridge I/O Protocol来获取找到的PCI 设备的信息。
参照UEFI spec 2.8 page 649,了解PCI Root Bridege I/O Protocol的用法。描述太长了,就不贴图出来了。
代码仍旧放在了百度云上。核心函数为:
EFI_STATUS PciDevicePresent (
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
OUT PCI_TYPE00 *Pci,
IN UINT8 Bus,
IN UINT8 Device,
IN UINT8 Func
)
代码中以此函数,获取所有能找到的PCI设备。不过Nt32中无法演示,旁边也没有机器可以测试,运行结果就不演示了。
百度云链接:https://pan.baidu.com/s/1gccSosw8_UAGTI5gZPnLCA
提取码:dx23
代码在 05 ListPCIMessage-01下。
5,889 total views, 1 views today