UEFI开发探索13 – 访问PCI/PCI-E设备1

(请保留->发布地址: http://yiiyee.cn/blog/author/luobing/ )

我所用的测试卡是PCI-E设备,公司商用的产品也是PCI-E设备。所以,我很早就“被迫”去读那些PCI spec。

从软件工程师的角度,我觉得只要解决几个问题就行了,其余的细节不妨碍编程。

1)      PCI/PCI-E设备是如何定位的,也即程序如何找到设备;
2)      系统把它认作什么设备;
3)      如何访问设备的内部寄存器(一般要去读所使用的PCI-E芯片的资料);
4)      商用化的产品,需要考虑设备对ACPI的各种电源事件的处理。

前三个问题需要仔细研究下PCI设备配置空间:

图1 PCI配置空间(PCI spec2.3)

除了主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.*编译出来的,在模拟环境中执行:

图2 Nt32模拟器中执行shell命令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,403 total views, 1 views today

发表评论

电子邮件地址不会被公开。