PCI配置空间

PCI配置空间
最后编辑:2010-5-26(修改错别字)
一.概括
任何计算机系统都会有输入/输出,所以对外部设备的访问是CPU设计中的一个重要问题。外设上一般会有很多寄存器,像状态寄存器、控制寄存器、数据寄存器等等。对这些寄存器的访问,一般会有两种不同的形式:

一种叫内存映射方式。这种方式下,外设寄存器和系统内存统一编址,于是对外设寄存器的访问和内存访问一样,不需要额外的指令。

另一种叫I/O映射方式。这种方式下,外设和系统内存分属不同的体系,所以访问外设需要另外的指令。X86体系的CPU就是用的I/O映射方式,外设寄存器访问指令为IN和OUT。和内存访问地址空间不同的是:I/O访问指令的地址空间只有从0~65535。在计算机发展早期,这些地址还算富裕,但是随着外设的发展,各种功能的寄存器越来越多,更有甚者,一些外设上竟另外配置了RAM和扩展ROM,这时区区65536的I/O地址就显得有点“捉襟见肘”了。

为了解决这个问题,PCI规范设计时就为每个设备定义了一个256字节的PCI配置空间。将PCI设备中需要用到的一些基本寄存器都集中存放在该区域。而所有的PCI设备中配置空间的访问只使用I/O地址0CF8H~0CFFH来访问。

二.PCI配置空间
256字节的PCI配置空间分为64字节的头标区和192字节的设备相关区两部分。头标区的各个寄存器用来唯一地识别设备;设备相关区则保存一些与设备相关的数据。

配置空间的头标区又分为两部分:前16个字节的定义在各种类型的PCI设备中都是一样的;剩余的字节随设备类型不同而有所不同。位于偏移地址0EH处的头标类型字段规定了头标区的布局结构。目前,规范定义了三种头标类型。

头标类型
设备
2
【PCI配置空间】PCI-CardBus桥
1
PCI-PCI桥
0
除上述桥外的所有设备

因为PCI网卡的头标类型是0,所以下面我们就来详细说说其布局结构,至于其他类型的头标请读者自行阅读。图3就是头标类型0的头标区的布局。头标区中的寄存器根据功能可分成下面几组:

1. 设备的识别
(1)供应商代码:该寄存器用于识别PCI设备的制造商,具体代码由PCI SIG(http://www.pcisig.com)分配。0FFFFH是无效的供应商代码。
(2)设备代码。该寄存器用来标识某供应商生产的具体设备,代码由各供应商定义。供应商代码和设备代码,读者可以到网站http://www.pcidatabase.com/查阅。



图3 头标类型0的头标区的布局

(3)版本号。该寄存器用来定义指定设备的版本信息。
(4)头标类型。该字段的第7位为“1”表示该设备是多功能设备,为“0”表示为单功能设备;该字段的0~6位就是上文表中所述的头标类型。
(5)设备分类代码。用来标识设备的总体功能和特定的寄存器级编程接口。
上面5个字段均为只读类型,所有的PCI设备都必须实现其功能。

2. 控制命令和设备状态
(1)命令寄存器为一个设备发出和响应PCI总线命令提供粗略的控制。图4就是命令寄存器格式。



图4 命令寄存器格式

我们比较感兴趣的位有:
a.位0(I/O空间控制):控制对I/O空间访问的响应。该位为0时,禁止设备响应对I/O空间的访问;该位为1时,允许设备响应I/O空间的访问。缺省设置为0。
b.位1(存储器空间控制):控制一个设备对存储器空间访问的响应。该位为0时,禁止响应;该位为1时,允许设备响应对存储器空间的访问。缺省设置为0。
至于其他位的功能,读者若有兴趣可以自行查阅。

(2)状态寄存器用来记录PCI总线有关的状态信息。

3. 基址寄存器
PCI设备中,除了配置空间外,还有两个物理空间:内存空间和I/O空间。为了访问这两个地址空间,就必须使用基址寄存器。头标类型0中涉及3种基址寄存器:内存空间基址寄存器、I/O空间基址寄存器和扩展ROM基址寄存器。关于基址寄存器,我们下一章重点讲述。

4. 其他寄存器
其他寄存器包括一些本文不涉及到的寄存器,如中断引脚、中断线等等。有兴趣的读者可以自行阅读。

三.PCI逻辑设备
每条PCI总线都有个总线号,主总线的总线号固定为0。每条PCI总线上都有各种各样的PCI设备。这里的设备其实指的是PCI设备接口卡(更确切地说是PCI总线接口芯片),通常取决于插槽的位置。每块PCI接口卡上可以有若干个功能模块,这些功能模块共用同一个PCI总线接口芯片,包括其中用于地址映射的电子线路,以降低陈本。从逻辑的角度说,每个“功能”实际上就是一项设备,所以设备号和功能号合在一起又可以称作“逻辑设备号”,而每块卡上最多可以容纳8个逻辑设备。显然,这些字段结合在一起就唯一地确定了系统中的一项PCI逻辑设备。

而一个PCI配置空间是对应于一个PCI逻辑设备的,所以上面说的PCI设备其实严格意义上来说应该是“PCI逻辑设备”。

四.PCI配置空间的访问
上面说过,PCI规范使用从0CF8H~0CFFH 这8个I/O地址来访问所有设备的PCI配置空间。这8个字节实际上构成了两个32位寄存器:0CF8H寄存器叫做“配置地址寄存器”;0CFCH叫做“配置数据寄存器”。当要访问配置空间的寄存器时,先向地址寄存器写上目标地址,然后就可以从数据寄存器中读写数据了。

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

31
3024
2316
1511
108
72
1
0
使能位
保留
总线号
设备号
功能号
寄存器号
0
0

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

例如,为了读总线号0、设备号17H、功能号0的30H寄存器,你可以使用下面的代码:


MOVEAX, 8000B830H
MOVDX, 0CF8H
OUTDX, EAX

MOV DX, 0CFCH
INEAX, DA


五.PCI配置空间的遍历
从上面的配置地址寄存器的格式我们可以看出:总线号从0~255、设备号从0~31、功能号从0~7。根据配置空间的第0个寄存器是否返回0FFFFH值来判断是否存在该PCI设备(没有代码为0FFFFH的供应商)。下面是PCI配置空间遍历的流程图:



图5遍历PCI配置空间流程图

根据该流程用MASM6.11编制的程序源代码pci.asm。该程序经编译,可以在DOS下运行。

    推荐阅读