我前两周写过一些文章介绍PCIe启动过程中如何分配Bus: Device. Function值,也简单介绍了一下LTSSM和枚举的关系,也有些朋友问了一些很好的问题,我们看后面有时间的话再结合SerialTek PCIe 5.0/6.0 analyzer协议分析仪实际抓取的一些上电 power-on bootup trace文件形象地讲解一下,让大家有个更加感性的认识。
今天我们仍旧来看一个和枚举有关的问题,在主机上电开机过程中,PCIe device的枚举究竟是发生在Legacy/UEFI BIOS初始化过程中,还是发生在Linux或者windows等操作系统的驱动程序初始化过程中,还是两个阶段都存在?如果都存在的话,目的有什么不同呢?还有我们所熟知的NVMe SSD或者CXL device的初始化是否也存在BIOS阶段和操作系统OS两次初始化呢?
其实,这是一个非常“工程师级”的问题,我们上面提到的 PCIe / NVMe / CXL 背景,说明我们现在谈的不是“概念”,而是真实系统行为。
我给一句话结论,下面将分层、分阶段把PCIe / NVMe / CXL串一串。
一句话总览(先给结论)
PCIe 设备的“枚举”在 BIOS/UEFI 阶段一定存在,在 OS(Linux / Windows)阶段也一定存在,但两次“枚举”的目的、深度和职责完全不同。
同理:
NVMe SSD:BIOS 阶段 + OS 阶段两次初始化
CXL Device:BIOS 阶段 + OS 阶段两次初始化,而且分工更严格
一、PCIe 枚举到底“发生在哪个阶段”?
答案是:两个阶段都发生,但不是一回事
| 阶段 | 是否做 PCIe 枚举 | 本质 |
|---|---|---|
| BIOS / UEFI 阶段 | ✅ 必须 | “发现硬件 + 分配资源” |
| OS 启动阶段(Linux / Windows) | ✅ 必须 | “重新扫描 + 驱动绑定” |
二、BIOS / UEFI 阶段的 PCIe 枚举:在干什么?
这是“平台级、硬件级枚举”,核心目标只有一个:
让系统“知道有什么 PCIe 设备存在,并且它们能被访问”
BIOS 阶段做的事情包括:
1️⃣ Link Training(链路训练)
RC ↔ EP
LTSSM → L0
确认:
Link Width
Link Speed
Lane Mapping
❗没有 L0,就根本谈不上枚举
2️⃣ PCIe 拓扑扫描(Bus Enumeration)
从Bus 0 / Device 0 / Function 0开始
递归扫描:
Root Port
PCIe Switch
Downstream Port
Endpoint
3️⃣ 分配 PCI 资源(极其关键)
BIOS 在此阶段会:
分配Bus Number
分配BAR 空间
MMIO
Prefetchable / Non-prefetchable
配置:
Command Register(Memory Enable / Bus Master Enable)
MSI/MSI-X Capability 基本参数
🔥OS 后面是否能用这个设备,100% 依赖 BIOS 这一步
4️⃣ Option ROM(可选)
VGA / NVMe / PXE 等
UEFI 下是UEFI Driver
Legacy 下是INT 13h / INT 10h
BIOS 阶段“不会做”的事
❌ 不加载 OS 驱动
❌ 不做高层功能初始化
❌ 不理解 NVMe / CXL 语义
BIOS只关心“这是一块 PCIe 设备”
三、OS 阶段的 PCIe 枚举:在干什么?
这是“软件逻辑枚举”,本质是:
“基于 BIOS 留下的硬件状态,重新认识设备,并绑定驱动”
OS 阶段会做:
1️⃣ 重新扫描 PCI Configuration Space
OS 从 ACPI / Device Tree / UEFI Tables 得知:
Bus 范围
MMIO 窗口
读取:
Vendor ID / Device ID
Class Code
Capability List
2️⃣ 驱动匹配
Windows:
INF → Hardware ID
Linux:
pci_driver → id_table
3️⃣ 驱动级初始化
Enable DMA
MSI/MSI-X 完整配置
Power Management(ASPM / L1SS)
Error Handling(AER)
SR-IOV / ATS / PASID(如果支持)
4️⃣ OS 级热插拔 / 重新枚举
Hot Plug
Surprise Down
Rescan Bus
🔑OS 阶段的“枚举”更像“重新认账 + 开始干活”
四、为什么要“两次枚举”?目的完全不同
| 阶段 | 核心目的 |
|---|---|
| BIOS | 让硬件“存在且可访问” |
| OS | 让软件“理解并使用硬件” |
一个非常形象的类比:
BIOS 枚举 = 修路、划车位、挂牌照 OS 枚举 = 驾驶员上车、点火、开走
五、NVMe SSD:是不是也有两次初始化?
答案:是,而且非常典型
1️⃣ BIOS 阶段的 NVMe(最小化支持)
BIOS 并不“真正理解 NVMe”,它只是:
把 NVMe 当作PCIe Mass Storage
可能加载:
NVMe UEFI Driver
目的只有一个:
支持“从 NVMe 启动”
BIOS NVMe 初始化通常只做到:
Identify Controller
Identify Namespace
简单 Read
不会:
队列深度调优
多队列并行
高级电源管理
2️⃣ OS 阶段的 NVMe(完整初始化)
OS NVMe 驱动会重新做:
Reset Controller
Create Admin Queue
Create IO Queues(多队列)
Enable MSI-X
Power State Management
Namespace 管理
⚠️ 所以你在协议分析仪里看到的 NVMe 初始化流量:
BIOS 阶段一套
OS 启动后一套是完全正常的
六、CXL Device:BIOS + OS 的分工更“硬核”
CXL 比 NVMe更依赖 BIOS
1️⃣ BIOS / UEFI 阶段(极其重要)
BIOS 必须:
完成 PCIe 枚举
识别CXL Capability
解析:
CXL.cache
CXL.mem
构建:
CXL Host Bridge
CXL Fixed Memory Window
向 OS 暴露:
ACPI CEDT / SRAT / HMAT
❗如果 BIOS 不支持,OS根本无法使用 CXL
2️⃣ OS 阶段(真正使用 CXL)
OS 才会:
建立 Memory Region
NUMA 拓扑
Page Allocation
Cache Coherency
CXL Error Handling
RAS
七、总结成一张“工程师视角表”
| 技术 | BIOS 阶段 | OS 阶段 |
|---|---|---|
| PCIe | Link + 枚举 + 资源分配 | 驱动绑定 + 功能启用 |
| NVMe | 最小识别 / Boot 支持 | 完整 NVMe 协议初始化 |
| CXL | 拓扑 + 内存窗口 + ACPI | 内存/缓存语义使用 |
八、上述问题背后的“隐含工程价值”
总结一下,我们上面问的,其实是:
为什么PCIe Analyzer 里会看到两次初始化流量
为什么BIOS Bug 会导致 OS 设备不可见
为什么CXL 问题 80% 出在 BIOS 阶段
为什么“OS Rescan”救不了很多问题