news 2026/9/7 8:26:28

Linux 内核 PCI 主机桥的 ACPI 设计规则:_CRS、ECAM 与地址空间保留机制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux 内核 PCI 主机桥的 ACPI 设计规则:_CRS、ECAM 与地址空间保留机制

Linux 内核 PCI 主机桥的 ACPI 设计规则:_CRS、ECAM 与地址空间保留机制

【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux

本文基于 Linux 内核仓库中的 Documentation/PCI/acpi-info.rst 展开,围绕"ACPI 命名空间应当如何描述 PCI 主机桥"这一主题,讲清 _CRS 为何是正确的地址空间保留机制、PNP0A03/PNP0A08 设备应声明哪些资源、ECAM 空间如何通过 MCFG 表或 _CBA 方法报告,并结合 drivers/acpi/pci_root.c 与 drivers/acpi/pci_mcfg.c 的源码解析验证这些规则在内核中的落地方式。读完之后,读者应能判断一份 ACPI DSDT 中的 PCI 主机桥描述是否符合规范,并理解内核启动时解析这些对象的实际逻辑。

一、总则:除非有别的发现途径,ACPI 命名空间必须描述一切

原文档开宗明义给出了一条通用规则:ACPI 命名空间应当描述操作系统(OS)可能用到的所有硬件,除非存在其他机制让 OS 发现它们。这条规则的规范依据来自:

  • ACPI 6.2 第 6.1 节:对于位于不可枚举总线(如 ISA 总线)上的设备,OSPM 枚举它们的标识符,而 ACPI 系统固件必须为每个设备提供 _HID 对象,使 OSPM 得以完成枚举;
  • ACPI 6.2 第 3.7 节:OS 枚举主板设备的方式,就是遍历 ACPI 命名空间、查找带有硬件 ID 的设备。每个经 ACPI 枚举的设备,都包含 ACPI 定义的对象来报告硬件资源:[_PRS] 报告设备可能占用的资源,[_CRS] 报告当前正在使用的资源,[_SRS] 用于配置这些资源。信息由即插即用操作系统(OSPM)用于配置设备。

这条规则的直接推论就是 PCI 主机桥的处境:PCI 主机桥不存在标准的硬件枚举机制。没有任何像 PCI 枚举那样的"标准硬件通路"能让 OS 自己找到主机桥,因此 ACPI 命名空间必须逐个描述每个主机桥,并且要描述三件事:

  1. 主机桥本身的描述(设备对象及其 _HID);
  2. 访问其下方 PCI 配置空间的方法;
  3. 主机桥转发到 PCI 总线的地址空间窗口(用 _CRS 声明);
  4. 遗留 INTx 中断的路由方式(用 _PRT 声明)。

而主机桥之下的 PCI 设备一般不需要通过 ACPI 描述——OS 可以借助标准 PCI 枚举机制发现它们:通过配置访问发现和识别设备、读取并尺寸化其 BAR。ACPI 只在三种情况下才描述 PCI 设备:

  • 固件为它们提供电源管理功能;
  • 固件为它们提供热插拔功能;
  • 设备的 INTx 中断经由平台中断控制器连接,需要 _PRT 来描述这些连接关系。

二、_CRS:一个"泛化的 PCI BAR"

ACPI 的资源描述通过 ACPI 命名空间中设备的 _CRS 对象完成(ACPI 6.2 第 3.7 节)。原文档给出了一个关键类比:

_CRS 就像一个泛化的 PCI BAR:即使 OS 没有对应设备的驱动程序,它读取 _CRS 就能弄清楚设备正在消耗什么资源。

这一点为什么重要?因为它保证了向后兼容:一个老 OS 在面对包含它尚不认识的新设备的系统时,仍然可以正确工作。新设备可能什么都不做,但老 OS 至少能保证没有任何资源与它们冲突。ACPI 6.2 第 6.2 节对此有对应说明:OSPM 使用设备配置对象为经 ACPI 枚举的硬件配置资源;枚举设备时调用 _PRS 确定资源需求,也可调用 _CRS 查询当前资源配置;设备可以消费资源(如遗留键盘)、提供资源(如专有 PCI 桥),或两者兼具;除非另有说明,设备资源被假定取自设备层次中最近的匹配上层资源。

由此引出第二条重要原则:MCFG、HPET、ECDT 等静态表不是地址空间保留机制。静态表的存在目的是让 OS 在引导早期、尚不能解析 ACPI 命名空间之前就必须知道的信息。而一旦定义了新的静态表,老 OS 需要即使完全忽略该表也能正确运行——_CRS 之所以能做到这一点,是因为它是通用的、被老 OS 所理解的;静态表则做不到。因此,凡是需要"保留一块地址空间不让 OS 分配出去"的场景,正确答案都是 ACPI 命名空间中的 _CRS,而不是某个静态表。

对于 OS 预期要管理的不可发现设备(non-discoverable device):它会被赋予特定的 _HID/_CID,告诉 OS 应绑定哪个驱动;_CRS 则告诉 OS 和驱动设备寄存器在哪里。

三、PCI 主机桥设备模型:PNP0A03 / PNP0A08

PCI 主机桥是 _HID 为PNP0A03(PCI 主机桥)或PNP0A08(PCIe 主机桥)的 ACPI 设备。原文档要求:其 _CRS 必须描述它们消耗的全部地址空间,具体包括两大类:

_CRS 应包含的内容说明
转发到 PCI 总线的全部窗口桥下方 PCI 设备使用的 MMIO/IO 空间窗口
主机桥自身的、不转发到 PCI 的寄存器例如决定桥下方总线范围的 secondary/subordinate bus 寄存器、描述窗口的窗口寄存器
ECAM 空间ECAM 由主机桥消耗,因此也要包含在内

后两类寄存器都是设备相关、非架构化的(non-architected)内容,所以通用的 PNP0A03/PNP0A08 驱动只能经由 _PRS/_CRS/_SRS 来管理它们,因为这些对象恰好承载了设备特有的细节。

源码印证:内核如何识别并解析主机桥

在 drivers/acpi/pci_root.c 中,ACPI 驱动 ID 表精确对应文档所述的两个 HID(外加 CXL 主机桥 ACPI0016):

static const struct acpi_device_id pci_root_ids[] = { {"PNP0A03", 0}, {"PNP0A08", 0}, {"ACPI0016", 0}, { } };

(见 drivers/acpi/pci_root.c#L44-L46。)

在 acpi_pci_root_add() 中,内核对该设备的解析顺序体现了文档中"_CRS 承载总线范围"的要求:

  1. 评估 _SEG 确定 PCI 域号(drivers/acpi/pci_root.c#L653-L660):acpi_evaluate_integer(handle, METHOD_NAME__SEG, ...),失败(且不是 AE_NOT_FOUND)则报 "can't evaluate _SEG" 并返回 -ENODEV——这印证了 PCI Firmware 规范"含 _CBA 的命名空间对象必须同时含 _SEG"的约束在代码层面的体现;
  2. 优先从 _CRS 取 secondary 总线范围,取不到再退回 _BBN(drivers/acpi/pci_root.c#L662-L686):代码注释明确写道"解释 _CBA(MMCONFIG 基地址)需要下游总线范围的起止值,所以它确实应该写在 _CRS 里";若 _CRS 中没有,只能假定 [_BBN-0xFF] 或 [0-0xFF],并打出FW_BUG "no secondary bus range in _CRS"的固件缺陷警告。这与原文档"bus 0 对应 MCFG/_CBA 基地址,即使 _CRS 报告的总线范围不从 0 开始"的要求严丝合缝;
  3. 按 HID 标记桥类型(drivers/acpi/pci_root.c#L702-L708):PNP0A08ACPI_BRIDGE_TYPE_PCIEACPI0016ACPI_BRIDGE_TYPE_CXL,其余假设非 PCIe 主机桥;
  4. 获取 MCFG 地址root->mcfg_addr = acpi_pci_root_get_mcfg_addr(handle);(drivers/acpi/pci_root.c#L700),随后通过 _OSC 协商 PCIe 特性控制权,再调用pci_acpi_scan_root()扫描根桥、创建 PCI 命名空间。

四、Consumer/Producer 位:一段兼容性历史

ACPI 定义了 Consumer/Producer 位来区分"桥寄存器"(Consumer,设备自身消费)与"桥窗口"(Producer,转发给下游)。但早期 BIOS 没有正确使用该位,其后果被 ACPI 规范固化为:

  • QWord/DWord/Word 地址空间描述符:General Flags 的 Bit [0] 被忽略(ACPI 6.2 第 6.4.3.5 节);
  • 扩展地址空间描述符(ECRS):Bit [0] 为 Consumer/Producer,1 表示设备消费该资源,0 表示设备产生并消费该资源;ACPI 6.2 第 19.6.43 节亦说明 ResourceConsumer/ResourceProducer 语义,未指定时假定 ResourceConsumer。

由此产生的直接规则是:操作系统必须假定所有 QWord/DWord/Word 描述符都是窗口(window)

在扩展地址空间描述符出现之前,Consumer/Producer 机制的失效意味着根本无法在 PNP0A03/PNP0A08 设备本体内描述桥寄存器。当时的变通方案是:把桥寄存器(包括 ECAM 空间)放进 PNP0C02 "catch-all" 设备中描述。由于除 ECAM 外桥寄存器空间本来就是设备相关的,通用 PNP0A03/PNP0A08 驱动(即内核中的drivers/acpi/pci_root.c)并不需要知道它们。

新架构的建议是:应当可以在 PNP0A03 设备中用 "Consumer" 扩展地址空间描述符来描述桥寄存器(包括 ECAM),尽管 PCI Firmware 3.2 第 4.1.2 节的严格解读可能不允许这么做。但要特别注意:老 x86 和 ia64 内核会把所有地址空间描述符(包括 "Consumer" 的扩展地址空间描述符)都当作窗口,因此在那两种架构上采用这种描述方式是不安全的。

PNP0C02 "主板资源"设备的规则

PNP0C02 "motherboard" 设备本质上是一个 catch-all,除了"别把这些资源挪作他用"之外没有编程模型。因此,一个 PNP0C02 的 _CRS 应当声明满足以下两个条件的地址空间:

  1. 未被 ACPI 命名空间中任何其他设备对象的 _CRS 声明;
  2. 不应被 OS 分配给别的东西。

PCI Firmware 3.2 第 4.1.2 节进一步要求:如果 OS 原生不理解 MMCFG 区域的保留,固件必须保留它;MCFG 表或 _CBA 方法报告的地址范围,必须通过声明"主板资源"来保留——在大多数系统上,它出现在 ACPI 命名空间根部(\_SB之下)一个 _HID 为 PNP0C02 的节点中,且这些资源不应同时出现在根 PCI 总线的 _CRS 中。这些资源可选地以 reserved memory 形式出现在 Int15 E820 或 EFIGetMemoryMap 中,但必须始终通过 ACPI 作为主板资源报告

内核对 PNP0C02 的识别可参见 drivers/acpi/scan.c#L2247 中的"PNP0C02", /* Motherboard resource */驱动匹配项。

五、ECAM:MCFG 与 _CBA 的分工

PCI Express 规范(PCIe 4.0 第 7.2.2 节)要求:除非存在标准的固件配置访问接口(例如 ia64 SAL 接口),否则必须实现增强型配置访问方法(ECAM)。主机桥消耗 ECAM 内存地址空间,并把内存访问转换为 PCI 配置访问。规范定义了 ECAM 地址空间的布局与功能;只有地址空间的基地址是设备相关的

ACPI OS 通过两条途径学习该基地址:

机制适用对象依据
MCFG 静态表非热插拔主机桥(MCFG 是静态表,热插拔无法更新它)PCI Firmware 3.2 第 4.1.2 节:MCFG 用于在引导时向 OS 通报非热移除 PCI Segment Group 的基地址,PC 兼容系统必须提供
_CBA 控制方法(位于 PNP0A03 设备内)可热插拔主机桥PCI Firmware 3.2 第 4.1.3 节:_CBA 返回 64 位内存映射配置基地址(处理器相对地址),求值结果为 Integer;出现 _CBA 的主机桥对象必须同时含对应的 _SEG 方法

两条途径共有的语义:基地址始终对应 bus 0,即使桥下方(经 _CRS 报告的)总线范围并不从 0 开始

源码印证:_CBA 优先于 MCFG

在 drivers/acpi/pci_mcfg.c 中,内核解析 ECAM 基地址的顺序与上述分工完全一致——第 254 行的注释即:/* Use address from _CBA if present, otherwise lookup MCFG */(drivers/acpi/pci_mcfg.c#L254):先尝试在主机桥 ACPI 设备上求值 _CBA 方法,方法不存在时才回退到 MCFG 表查找;而acpi_mcfg_allocation结构则用于承载从表中解析出的各段分配。调用入口正是 acpi_pci_root_add() 中的acpi_pci_root_get_mcfg_addr()

六、规范依据索引

原文档的全部论述均可追溯到以下规范条目,便于读者继续深入核对:

  • ACPI 6.2 第 6.1 节:不可枚举总线上的设备必须由固件提供 _HID 供 OSPM 枚举;
  • ACPI 6.2 第 3.7 节:OS 通过遍历命名空间枚举主板设备;每设备含 _PRS/_CRS/_SRS 对象;
  • ACPI 6.2 第 6.2 节:OSPM 调用 _PRS 确定资源需求、调用 _CRS 查询当前配置、调用 _SRS 设置资源;设备可消费/提供/兼具资源;
  • ACPI 6.2 第 6.4.3.5 节:QWord/DWord/Word 描述符 General Flags Bit [0] 忽略;扩展描述符 Bit [0] 为 Consumer/Producer;
  • ACPI 6.2 第 19.6.43 节:ResourceConsumer/ResourceProducer 语义;
  • PCI Firmware 3.2 第 4.1.2 节:MMCFG 区域必须由固件经 PNP0C02 主板资源保留;MCFG 表用于引导时通报非热移除 Segment Group 基地址;
  • PCI Firmware 3.2 第 4.1.3 节:_CBA 为可热插拔主机桥返回 64 位 MMCFG 基地址,且必须伴随 _SEG;
  • PCI Express 4.0 第 7.2.2 节:PC 兼容系统或无架构特定固件配置访问接口的系统必须实现 ECAM。

七、小结:面向固件与驱动开发者的检查清单

结合原文档与内核源码,一份合规的 PCI 主机桥 ACPI 描述应满足:

  1. 每个主机桥都是命名空间中的 PNP0A03/PNP0A08 设备,并声明访问配置空间的方法与 _PRT 中断路由;
  2. 其 _CRS 完整覆盖转发到 PCI 的全部窗口、桥自身寄存器以及 ECAM 空间;
  3. 桥寄存器在旧架构上应放入 PNP0C02 主板资源设备,且 ECAM 范围不得同时出现在根 PCI 总线 _CRS 中;
  4. 非热插拔桥的 ECAM 基地址写入 MCFG 表,可热插拔桥在设备内提供 _CBA(与 _SEG 并存);
  5. _CRS 中必须可解析出 secondary 总线范围,否则内核只会降级假定 [_BBN-0xFF]/[0-0xFF] 并上报 FW_BUG;
  6. 所有需要"保留"的地址空间都通过 _CRS(主板资源)表达,而不是发明新的静态表。

相关延伸阅读可参考同目录下的 PCI 子系统总览、PCI sysfs 接口 与 PCI 文档索引,它们与本文共同构成了 Linux 内核 PCI 与固件交互的文档体系。

【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 8:26:10

gerbera配置文件EDN格式解析与分行显示工具实现

简介:面向PCB设计与MFC桌面开发人员,这份源码工程演示了在Visual Studio中利用MFC读取Gerber文件并按行显示的方法,可帮助解决PCB制造文件(如铜迹、丝印、钻孔等图层)快速查看与逐行校验的实际问题。资源为rar压缩包&a…

作者头像 李华
网站建设 2026/9/7 8:26:08

从抄板到进阶:PCB设计底层逻辑与嵌入式硬件学习路线

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 8:24:11

Spring Cloud微服务实战:网约车项目核心链路与高并发方案

简介:OnlineTaxi 是基于 Spring Cloud 的网约车全流程实战项目,面向具备一定 Java 基础、希望学习微服务架构的开发者或相关专业学生。项目按乘客端、司机端与能力层拆分为订单、派单、乘客用户、短信、计价、验证码、钱包、支付、地图等多个服务&#x…

作者头像 李华
网站建设 2026/9/7 8:23:58

4K视频处理技术解析:从本地部署到影视内容分析实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华