(请保留-> 作者: 罗冰 luobing4365的博客_CSDN博客-UEFI开发,汇编语言探索,嵌入式开发领域博主)
(关于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配置空间遍历的流程图:
图3 遍历PCI设备配置空间
PCI设备中,除了配置空间外,还有两个物理空间:内存空间和I/O空间。为了访问这两个地址空间,就必须使用基址寄存器。类型0中涉及3种基址寄存器:内存空间基址寄存器、I/O空间基址寄存器和扩展ROM基址寄存器。
PCI设备可以在地址空间中浮动是PCI局部总线中最重要的功能之一。它能够简化设备的配置过程。在系统上电时,与设备无关的系统软件必须确定有哪些设备存在,同时建立一个统一的地址映射关系,并确定一个设备是否有扩展ROM。
以我现在使用的测试板卡为例,我比较关心的:
- 是I/O访问还是Memory访问?
- 访问的基地址是什么?
- 我的设备当然支持扩展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构建的函数。
Gitee地址:https://gitee.com/luobing4365/uefi-explorer
项目代码位于:/06 ListPCIMessage-02、07 PCIIoRw-01、08 PciIO Protocol-01下。