UEFI开发探索14 – 访问PCI/PCI-E设备2

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

(关于PCI访问,其中一些内容来自网上,找不到出处了)

PCI规范使用从0CF8H~0CFFH 这8个I/O地址来访问所有设备的PCI配置空间。这8个字节实际上构成了两个32位寄存器:0CF8H寄存器叫做“配置地址寄存器”;0CFCH叫做“配置数据寄存器”。

当要访问配置空间的寄存器时,先向地址寄存器写上目标地址,然后就可以从数据寄存器中读写数据了。

PCI配置空间对应于一个PCI逻辑设备,所以要访问一个配置空间的某个寄存器,必须要指定:PCI总线号、PCI设备号、PCI设备功能号和寄存器号。配置地址寄存器的格式如下:

图1 配置地址寄存器CF8H

bit0、1位上的“0”是用来要求你只能按双字(4字节)来读写配置空间寄存器。第31位“使能位”用来决定是否允许访问配置空间:为“1”时表示可以访问;为“0”时表示不可以访问。

以前为了访问PCI设备,写了一个类似int 1ah的通用代码,可以看出使用方法:

图2 访问PCI设备(摘自robin’s 915 oprom /code library)

总线号从0~255、设备号从0~31、功能号从0~7。根据配置空间的第0个寄存器是否返回0FFFFH值来判断是否存在该PCI设备。下面是PCI配置空间遍历的流程图:

图5 遍历PCI设备配置空间

PCI设备中,除了配置空间外,还有两个物理空间:内存空间和I/O空间。为了访问这两个地址空间,就必须使用基址寄存器。类型0中涉及3种基址寄存器:内存空间基址寄存器、I/O空间基址寄存器和扩展ROM基址寄存器。

PCI设备可以在地址空间中浮动是PCI局部总线中最重要的功能之一。它能够简化设备的配置过程。在系统上电时,与设备无关的系统软件必须确定有哪些设备存在,同时建立一个统一的地址映射关系,并确定一个设备是否有扩展ROM。

以我现在使用的测试板卡为例,我比较关心的:

  1. 是I/O访问还是Memory访问?
  2. 访问的基地址是什么?
  3. 我的设备当然支持扩展ROM,而且必须让BIOS加载起来。

从程序员的角度,最终需要实现如何读写设备,前面所有的知识都是为了实现读写。上一篇博客所写的代码,主要是以PCI Root Bridge I/O Protocol对PCI设备进行访问。我整理了一下代码,在百度云上06 ListPCIMessage-02中,主要用函数将所需要的功能进行了简单的封装。

对测试用的板卡,PID和VID分别为0x9999和0x8000,我写了一个小工具对其进行读写访问。可以访问板卡上的寄存器,代码存在07 PCIIoRw-01中。

以上的代码都是使用PCI Root Bridge I/O Protocol来对设备进行访问的,我添加了使用PCI I/O Protocol的函数,在08 PciIO Protocol-01中。Protocol的使用方法可以参考uefi spec,具体就不贴出来了。

UEFI开发探索12中所编写的Option ROM代码,使用的是PCI Root Bridge I/O Protocol构建的函数。

百度云链接:https://pan.baidu.com/s/1gccSosw8_UAGTI5gZPnLCA
提取码:dx23
代码在 06 ListPCIMessage-02、07 PCIIoRw-01、08 PciIO Protocol-01下。

2,866 total views, 1 views today

发表评论

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