PCIE扫描过程

1. PCIE扫描过程

从按下PC的电源按钮开始,BIOS就接管系统控制权开始工作,它会先进行一些内存和设备的初始化工作(当然,也包括PCI设备),由于商业上的原因,Phoenix等厂商的BIOS代码需要授权协议,下面以另外一款开源BIOS(openbios)为例,来剖析BIOS中,PCIe设备是如何被找到以及初始化的。

PCI设备的扫描是基于深度优先搜索算法(DFS:Depth First Search),也就是说,下级分支最多的PCI桥将最先完成其子设备的扫描。下面以图片来具体说明,BIOS是如何一步步完成PCI 设备扫描的。

第一步:PCI Host 主桥扫描Bus 0上的设备(在一个处理器系统中,一般将与HOST主桥直接相连的PCI总线被命名为PCI Bus 0),系统首先会忽略Bus 0上的D1,D2等不会挂接PCI桥的设备,主桥发现Bridge 1后,将Bridge1下面的PCI Bus定为 Bus 1,系统将初始化Bridge 1的配置空间,并将该桥的Primary Bus Number 和 Secondary Bus Number寄存器分别设置成0和1,以表明Bridge1的上游总线是0,下游总线是1,由于还无法确定Bridge1下挂载设备的具体情况,系统先暂时将Subordinate Bus Number设为0xFF。如图 1.1所示:

图 1.1  PCIE扫描第一步

第二步:系统开始扫描Bus 1,将会发现Bridge 2。系统将Bridge 2下面的PCI Bus定为Bus 2,并将该桥的Primary Bus Number 和 Secondary Bus Number寄存器分别设置成1和2,和上一步一样暂时把Bridge 2的Subordinate Bus Number设为0xFF。如图 1.2所示:

图 1.2 PCIE扫描第二步

第三步:

系统继续扫描Bus 2,将会发现Bridge 4。系统将Bridge 4下面的PCI Bus定为Bus 3,并将该桥的Primary Bus Number 和 Secondary Bus Number寄存器分别设置成2和3,此后

系统继续扫描后发现Bus 3下面已经没有任何Bridge了,意味着该PCI总线下已经没有任何挂载下游总线了,因此Bridge 4的Subordinate Bus Number的值已经可以确定为3了。

如图 1.3所示:

图 1.3 PCIE扫描第三步

第四步:

完成Bus 3的扫描后,系统返回到Bus 2继续扫描,发现Bus 2下面已经没有其他Bridge了。此时Bridge 2的Subordinate Bus Number的值也已经可以确定为3了。如图 1.4所示:

图 1.4 PCIE扫描第四步

第五步:

完成Bus 2的扫描后,系统返回到Bus1继续扫描,会发现Bridge 3,系统将Bridge 3下面的PCI Bus定为Bus 4。并将Bridge 4的Primary Bus Number 和 Secondary Bus Number寄存器分别设置成1和4,此后系统继续扫描后发现Bus 4下面已经没有任何Bridge了,意味着该PCI总线下已经没有挂载任何下游总线了,因此Bridge 3的Subordinate Bus Number的值已经可以确定为4了。如图 1.5所示:

图 1.5 PCIE扫描第五步

第六步:

完成Bus 4的扫描后,系统返回到Bus 1继续扫描, 发现Bus 1下面已经没有其他Bridge了。此时Bridge 1的Subordinate Bus Number的值已经可以确定为4,系统返回Bus 0继续扫描(Bus 0下如果有其他它Bridge,将重复上述的步骤进行扫描)。至此,本例中的整个PCI的设备扫描已经完成了。最终的设备和总线的扫描结果如图 1.6所示

图 1.6 PCIE扫描第六步

一般来说,可以通过两个寄存器来访问PCI的配置空间(寄存器CONFIG_ADDRESS与CONFIG_DATA),在x86体系下,这两个寄存器分别对应0xCF8和0xCFC端口,对配置空间的访问都是通过对这两个寄存器的读写来实现先。CONFIG_ADDRESS寄存器的具体位组成如图 1.7所示:

图 1.7 x86配置寄存器

Bus Number : 总线号(8 bit),范围0--255。

Device Number: 设备号(5 bit),范围0--31。

Function Number: 功能号(3 bit),范围0--7。

Register Number: 寄存器号(6 bit),范围0--63(配置空间一共256个字节,分割成64个4字节的寄存器,从0--63编号)。

每个PCI设备可根据上图所示的四个信息:Bus Number, Device Number, Function Number,Register Number来进行具体设备的定位并对其配置空间访问。当访问PCI设备的配置空间时,先根据以上格式设置CONFIG_ADDRESS寄存器,然后再读取CONFIG_DATA寄存器即可得到相应的配置空间寄存器的值。通过以上这些步骤,BIOS就完成了所有PCI设备的扫描,并且为每个设备分配好了系统资源。

<think>好的,用户想了解PCIe扫描的详细流程。根据提供的引用内容,我需要结合引用[1]和引用[2]的信息来组织回答。首先,需要明确PCIe扫描的入口和主要步骤。 首先,引用[1]提到acpi_scan_init()是PCI初始化的入口,其中调用了acpi_pci_root_init()等函数。这说明ACPI在PCIe初始化中的重要性。接下来,引用[2]描述了递归遍历BDF(Bus, Device, Function)的过程,特别是从bus 1开始扫描桥设备,并分配新的bus号。需要将这些步骤分解成清晰的流程。 用户可能希望了解从系统启动到PCIe设备识别的整个过程,包括ACPI的作用、总线枚举、资源配置等。另外,可能需要解释BDF结构和桥设备的作用,因为它们在扫描流程中很关键。 需要确保回答符合格式要求,使用中文,行内公式用$...$,独立公式用$$...$$,但在这个问题中可能涉及较少的数学表达式,更多是流程步骤。需要生成相关问题,并在引用处添加标识。 最后,检查是否有遗漏的步骤,例如资源分配(如I/O端口、内存地址)、中断配置等,这些也是PCIe扫描的一部分。可能还需要提到操作系统如何加载驱动程序,但根据引用内容,可能主要集中在扫描和总线分配阶段。</think>### PCIe扫描流程详解 PCIe扫描是操作系统初始化阶段的关键步骤,用于识别和配置PCI/PCIe设备。其核心流程如下: #### 1. ACPI初始化入口 系统通过ACPI表定位PCI根节点,启动扫描流程。引用[1]指出: ```c int __init acpi_scan_init(void) { acpi_pci_root_init(); // 初始化PCI根总线 acpi_pci_link_init(); // 配置PCI中断链接 ... } ``` 这是PCIe扫描的入口点[^1]。 #### 2. 总线枚举(Bus Enumeration) 采用**深度优先搜索**递归遍历总线: 1. 从BDF(总线号、设备号、功能号)`{0,0,0}`开始 2. 读取设备配置空间头类型: - 类型`0x01`:检测到桥设备 - 类型`0x00`:普通端点设备 3. 为桥设备分配新总线号,建立层次结构: $$ \text{bus}_{new} = \text{bus}_{current} + \delta $$ 其中$\delta$根据系统拓扑动态确定[^2] #### 3. 资源分配 | 资源类型 | 分配方式 | |----------------|---------------------------| | I/O端口空间 | 通过BAR(Base Address Register)协商 | | 内存空间 | 地址窗口对齐分配 | | 中断号 | 使用MSI/MSI-X或传统INTx | #### 4. 设备初始化 ```c for (bus = 0; bus < max_bus; bus++) { for (device = 0; device < 32; device++) { read_header_type(); if (is_bridge) { assign_new_bus(); recurse_scan(); // 递归扫描子总线 } } } ``` 该伪代码展示了递归扫描逻辑[^2] #### 5. 中断配置 通过`acpi_pci_link_init()`建立中断路由表,将设备中断映射到全局中断控制器(如APIC)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值