首页 理论教育 普通PCI设备枚举教程

普通PCI设备枚举教程

时间:2023-10-21 理论教育 版权反馈
【摘要】:一旦探测到PCI总线的存在,就需要对PCI设备进行枚举,以收集连接到该总线的PCI设备信息。目前情况下,对PCI设备的枚举采用下列算法。探测完毕,再对该总线上的PCI-PCI桥设备进行初步配置,然后对桥设备的下级总线完成同样的探测。为了对PCI设备进行更进一步的描述,定义下列对象。在对PCI设备进行枚举时,每当发现一个设备,就创建这样一个对象,并连接在__PHYSICAL_DEVICE对象中。

普通PCI设备枚举教程

一旦探测到PCI总线的存在,就需要对PCI设备进行枚举,以收集连接到该总线的PCI设备信息。目前情况下,对PCI设备的枚举采用下列算法。

(1)从DeviceManager的SystemBus数组中找到一个空闲的(尚未被占用的)总线对象(__SYSTEM_BUS),设置该总线对象的总线类型为BUS_TYPE_PCI。

(2)从当前总线上第0号设备、第0号功能开始,依次探测对应的设备(或功能)是否存在。

(3)如果设备存在,则创建一个__PHYSICAL_DEVICE对象,把设备相关的信息(所占用的资源、中断向量号、设备类型等)填写到__PHYSICAL_DEVICE对象中,然后把该物理设备对象插入设备列表(由总线对象维护)。

(4)探测完毕,再对该总线上的PCI-PCI桥设备进行初步配置,然后对桥设备的下级总线完成同样的探测。

上述过程的实现方式如下。

978-7-111-41444-5-Chapter09-34.jpg

978-7-111-41444-5-Chapter09-35.jpg

上述过程是一个递归过程(黑色字体标出的代码)。总体思路是:首先对当前总线上的PCI设备进行搜索(PciScanDevices函数完成),并针对每个存在的PCI设备创建一个物理设备对象(__PHYSICAL_DEVICE),添加到当前总线的设备列表中。然后再次遍历当前总线的所有PCI设备,如果发现一个PCI设备是一个PCI-PCI桥,则进一步扫描该桥接设备的二级(Secondary)总线。

如果当前总线上没有任何PCI-PCI桥设备,则该函数返回当前总线号,如果有PCI-PCI桥设备,则该函数返回的数值就是该桥设备下所有总线中的最大的总线号,因此,该函数的返回值就可以作为上级总线的Subordinate值。

为了对PCI设备进行更进一步的描述,定义下列对象。

978-7-111-41444-5-Chapter09-36.jpg

978-7-111-41444-5-Chapter09-37.jpg

其中,dwDeviceType字段给出了该对象的类型。目前情况下,定义了下列四个取值。

978-7-111-41444-5-Chapter09-38.jpg

_DEVICE_TYPE_

这个字段的设置是根据HdrType字段(PCI设备配置空间)进行的。在对PCI设备进行枚举时,每当发现一个设备,就创建这样一个对象,并连接在__PHYSICAL_DEVICE对象中(__PHYSICAL_DEVICE的lpPrivateInfo字段,保存了这个对象的指针)。(www.xing528.com)

978-7-111-41444-5-Chapter09-39.jpg

这个函数从功能0、设备0开始,依次检测所有PCI总线上可能出现的设备(或功能),一旦检测到一个存在的设备或功能,就调用PciAddDevice函数,该函数创建一个物理设备对象(__PHYSICAL_DEVICE),初始化之后插入到系统总线的设备列表中。需要注意的是,该函数(PciAddDevice)会根据头部类型的不同,分别处理普通的PCI设备和PCI-PCI桥设备,如果定义了PCI_CONFIG,则该函数会重新配置物理设备(重新分配IO端口范围、内存映射空间等),对于PCI-PCI桥,该函数仅仅完成Primary和Secondary字段的配置工作,Subordinate字段则一直留到PciScanBus函数中配置。该函数的实现如下。

978-7-111-41444-5-Chapter09-40.jpg

978-7-111-41444-5-Chapter09-41.jpg

可以看出,上述函数(PciAddDevice)首先创建一个物理设备对象(__PHYSICAL_DEVICE)和一个PCI设备信息对象(__PCI_DEVICE_INFO),然后把PCI设备信息对象连接到物理对象中,并根据传递过来的参数初始化设备信息对象的部分成员。

接下来,该函数读取设备的配置空间,根据读取的结果初始化设备的ID、头部类型等字段,然后根据头部类型进一步判断是1型头部还是0型头部,对于0型头部(普通的PCI设备),调用PciFillDevResource函数完成设备所需资源的填充,对于1型头部(PCI-PCI桥设备头部),则调用PciFillBridgeResource函数完成PCI-PCI桥设备的资源填充。

首先看PciFillDevResource函数,该函数实现如下。

978-7-111-41444-5-Chapter09-42.jpg

978-7-111-41444-5-Chapter09-43.jpg

上述函数十分简单,仅仅是一个循环,把设备所有的Base Address Register读取一遍(按照本章概述中介绍的方法),然后把设备的资源信息存储到物理设备对象的Resource数组中。需要注意的是,在计算IO端口区间范围或内存映射区域大小的时候,调用了GetRange函数。最后,该函数读取设备的中断向量信息,并填充到资源数组中。

对于PCI-PCI桥设备,其资源设置方式与普通的PCI设备大致相同,在此不作赘述,读者可通过阅读代码做深入了解。

对PCI总线上的设备枚举完毕,系统就建立了一棵设备树,所有PCI总线上的普通设备(非总线桥设备)都是这棵树的叶子节点,总线桥设备(比如PCI-PCI桥等)则是这棵树的分支。Hello China提供了一个系统诊断程序sysdiag,里面实现了一个pcilist命令,可以查看系统设备树(目前仅显示PCI总线和PCI设备,包含PCI-PCI桥设备)。图9-9是pcilist命令在Virtual PC上的运行截图。

978-7-111-41444-5-Chapter09-44.jpg

图9-9 pcilist命令在Virtual PC上的运行截图

可见,Virtual PC模拟的计算机,只有一条PCI总线(Bus Number为0),连接了以太网卡、VGA控制器、IDE控制器等设备。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈