
Linux CXL 平台配置BIOS/EFI 期望、UEFI_MEMORY_SP 与解码器编程规范【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux本文基于 Linux 内核官方文档 BIOS/EFI Configuration系统讲解 CXLCompute Express Link平台在 BIOS/EFI 阶段需要完成哪些静态配置、Linux 对固件的硬性期望是什么以及内存区域对齐、内存空洞Memory Hole与 HDM 解码器HDM Decoder编程中的常见陷阱。读完本文你将掌握如何使用uefisettings检查并设置EFI_MEMORY_SP位、为什么 CXL 内存区域应做 2GB 对齐、遇到内存空洞时如何用多个解码器与多个 CFMWS 条目正确描述以及 Linux 源码中这些期望的真实落点适用于 CXL 内存设备集成工程师与平台固件开发者。启动阶段的职责划分固件完成静态配置Linux 完成运行时配置CXL 设备的配置被人为地分成两个阶段BIOS/EFI 负责静态信息的描述Linux 内核负责运行时的设备配置。在启动阶段大致的流程如下原文档给出的高层视图Bootloader 启动 BIOS/EFIBIOS/EFI 执行早期设备探测early device probe确定静态配置BIOS/EFI 生成 ACPI 表如 CEDT、SRAT、HMAT 等向操作系统描述静态配置BIOS/EFI 建立系统内存映射EFI Memory Map、x86 上的 E820 等BIOS/EFI 调用start_kernel进入 Linux 早期启动Early Boot流程。其中绝大部分工作集中在ACPI 表的生成和静态内存映射的构建上。这些表的字段级说明见仓库内的 ACPI Tables 文档 及其子文档 CEDT、SRAT。原文档特别提示平台厂商应仔细阅读该节内容因为其中包含关于物理内存区域大小与对齐、内存空洞、HDM 交织interleave的建议以及 Linux 对使用这些特性的 HDM 解码器的具体期望。Linux 对 BIOS/EFI 软件的核心期望内核文档明确列出了 Linux 对固件的边界要求必须提供BIOS/EFI 必须构建足够的 ACPI 表CEDT、SRAT、HMAT 等和平台特定配置HPA 空间、host-bridge 交织配置等使 Linux CXL 驱动能够在运行时自行配置 CXL 拓扑fabric中的设备。不要求HDM 解码器与交换端口switch port的编程不需要由固件完成可以推迟给 CXL 驱动并依据管理员策略例如 udev 规则在用户态触发配置。应避免个别平台可能因为硬件 quirk 需要预先编程并锁定 HDM 解码器典型例子即文档提到的Zen5 地址转换问题。这不是正常的、被期望的配置路径应尽可能避免。从源码看这一 quirk 在 Linux 中的对应物是 drivers/cxl/cxl.h 中的区域标志CXL_REGION_F_NORMALIZED_ADDRESSING其注释明确写道Indicate Normalized Addressing. Use it to disable SPA conversion if HPA ! SPA and an address translation callback handler does not exist.Flag is needed by AMD Zen5 platforms.即当 HPA 与 SPA 不一致且没有地址转换回调时用该标志禁用 SPA 转换。平台厂商义务如果平台希望预先配置这些资源、以便在不带 CXL 驱动支持的情况下也能把内存带起来厂商应当用现有 CXL 驱动测试自己的配置并在需要 RAS 等特性时为其自动配置提供驱动支持。副作用警告需要启动时编程和/或锁定 CXL fabric 组件的平台可能会使设备热插拔hot-plug等特性无法工作。换句话说Linux 的设计哲学是固件只描述有什么驱动决定怎么用。任何绕过这一分工的静态锁定方案都可能直接牺牲热插拔、运行时重配置等能力。使用 uefisettings 检查与配置 UEFI 设置如果平台支持 UEFI 变量读取接口可以用uefisettings命令读写 EFI 设置。两个关键前提修改在下一次重启后才生效kexec 不构成一次足够sufficient的重启kexec 后修改不会生效。EFI_MEMORY_SP 位CXL 内存归属的关键开关原文档特别指出一个重要的配置项EFI_MEMORY_SPSpecific Purpose位。当该位被置位时它告诉 Linux将该内存区域的管理权交给驱动在 CXL 场景下即 CXL 驱动而不是直接交给页分配器否则该内存会被视为普通内存并在__init阶段直接暴露给页分配器page allocator。源码印证EFI_MEMORY_SP 如何映射到 E820在 x86 内核中这一机制的实现位于 arch/x86/platform/efi/efi.c 的 EFI 内存映射导入逻辑遍历 EFI 内存描述符时若某段EFI_CONVENTIONAL_MEMORY带有EFI_MEMORY_SP属性且软保留soft reserve机制已启用则把它标记为E820_TYPE_SOFT_RESERVED而不是E820_TYPE_RAMfor_each_efi_memory_desc(md) { ... switch (md-type) { case EFI_LOADER_CODE: case EFI_LOADER_DATA: case EFI_BOOT_SERVICES_CODE: case EFI_BOOT_SERVICES_DATA: case EFI_CONVENTIONAL_MEMORY: if (efi_soft_reserve_enabled() (md-attribute EFI_MEMORY_SP)) e820_type E820_TYPE_SOFT_RESERVED; else if (md-attribute EFI_MEMORY_WB) e820_type E820_TYPE_RAM; ...其中EFI_MEMORY_SP的定义在 arch/x86/boot/compressed/efi.h0x0000000000040000注释为 soft reserved。内核源码注释同时说明了逃生开关如果平台固件错误地设置了该位可以用efinosoftreserve内核参数关闭内核对EFI_MEMORY_SP的处理让内存回到普通 RAM 路径。这是排查CXL 内存为何没被 CXL 驱动接管类问题的第一条线索。uefisettings 使用示例查看平台身份BIOS 厂商、版本、产品名称等uefisettings identify bios_vendor: xxx bios_version: xxx bios_release: xxx bios_date: xxx product_name: xxx product_family: xxx product_version: xxx在部分 AMD 平台上EFI_MEMORY_SP位是通过名为CXL Memory Attribute的固件字段设置的你的平台可能使用其他名称。查询示例uefisettings get CXL Memory Attribute selector: xxx ... question: Question { name: CXL Memory Attribute, answer: Enabled, ... }物理内存映射区域大小与对齐要求内存块必须统一大小且统一对齐截至Linux v6.14热插拔内存hotplug memory子系统要求内存区域在大小和对齐上保持统一。CXL 规范允许小至 256MB 的内存区域但热插拔内存支持的块大小与对齐是架构定义的Linux 内存块memory block可以小至128MB且按 2 的幂次增长ARM默认块大小和对齐为 128MB 或 256MBx86默认块大小为 256MB并且随着系统容量增长最高到 64GB 规模增长到2GB。文档据此给出明确的工程建议为了获得跨内核版本的最佳支持平台厂商应将 CXL 内存放置在 2GB 对齐的基地址处且区域大小也应 2GB 对齐。这同时有助于避免创建数以千计的内存设备每个 block 一个 memory device。内存空洞Memory Holes最易踩坑的布局内存映射中的空洞非常棘手。原文档用一个 4GB 设备为例设备基地址0x100000000但中间夹着一个空洞内存图如下--------------------- | 0x100000000 | | CXL | | 0x1BFFFFFFF | --------------------- | 0x1C0000000 | | MEMORY HOLE | | 0x1FFFFFFFF | --------------------- | 0x200000000 | | CXL CONT. | | 0x23FFFFFFF | ---------------------这里存在两个必须同时考虑的问题解码器编程decoder programming内存块对齐memory block alignment。如果目标架构要求 2GB 统一大小且对齐的内存块那么截至 v6.14Linux 能够映射的容量只有0x100000000-0x180000000这一段因为空洞截断了第一个 2GB 对齐窗口其余容量会成为搁浅stranded容量——因为它们不构成 2GB 对齐的长度无法被热插拔内存系统接纳。如果架构与内存配置允许1GB 内存块则该内存图是被支持的。此时正确的做法是把空洞两侧分别描述为 CEDT 中多个 CFMWS条目并配备与之匹配的解码器。原文档给出的通用规则可以用并且应该用多个解码器来管理这种内存空洞但空洞切出的每一段都应按合理的块大小对齐对齐粒度越大越好如果你打算在内存映射中保留空洞就应预期每段连续的 host 物理内存对应一个解码器截至 v6.14Linux 已经支持由单个 HDM 解码器描述、但被内存空洞分隔开的多段物理内存区域的热插拔。解码器编程翻译点、交织与多介质如果 BIOS/EFI 打算把解码器静态编程好原文档强调有几条建议并不是规范specification的强制要求但 Linux 不保证在这些建议之外提供支持。翻译点Translation Point按照 CXL 规范唯一负责把 Host Physical AddressHPA翻译成 Device Physical AddressDPA的解码器是端点解码器Endpoint Decoder。fabric 中其余所有解码器root decoder、host bridge 解码器、交换端口解码器都只负责路由访问而不翻译地址。文档引用了 CXL Specification 3.1 的 8.2.4.20 节CXL HDM Decoder Capability Structure及其两条实现说明Host Bridge/Upstream Switch Port Decoder Flow、Device Decoder Logic作为依据。基于此Linux 做一个很强的假设CPU 与端点之间的所有解码器其编程的地址范围都必须是父解码器范围的子集。历史教训由于架构、ACPI、PCI 与 CXL 规范在责任交接上存在模糊地带一些早期采纳平台曾在内存控制器或 host bridge 处做地址翻译。这种配置需要平台特定的驱动扩展虽被支持但不获官方背书。文档的措辞非常直接强烈建议不要这样做否则平台需要自行实现驱动支持。Linux 源码中对这一类平台的兼容点即上文提到的CXL_REGION_F_NORMALIZED_ADDRESSING见 drivers/cxl/cxl.h。交织Interleave与配置灵活性CEDT 中 CFMWSCXL Fixed Memory Window Structure条目的组织方式决定了用户态可用的解码器编程自由度跨 host-bridge 交织必须在 CEDT 中给出一个 CFMWS 条目并列出参与交织的目标 host bridge每个 host bridge 背后可能挂多个设备host-bridge 内部交织如果该 CFMWS 覆盖了该 host bridge 背后设备的全部容量则只需一个条目希望给用户更多自由度允许用户编程 root 以下的解码器时可以考虑在 CEDT 中提供多个 CFMWS 条目例如一个覆盖所有可交织 host bridge 的 CFMWS 条目一个覆盖单个 host bridge 上所有设备的 CFMWS 条目为每个设备各一个 CFMWS 条目。平台可以三者全加也可以根据 BIOS 设置项切换模式。对每个 CFMWS 条目Linux 期望在 SRAT 中找到对应内存区域的描述以便确定早期启动/init 阶段应预留多少NUMA node。这里有一个版本敏感的注意事项截至 v6.14即使找不到匹配的 SRAT 条目Linux 也会为每个 CEDT CFMWS 条目创建一个 NUMA node但这一行为未来不保证平台应当避免依赖这种无 SRAT 对应的配置。从源码结构看这一行为对应 drivers/cxl/acpi.c 中解析 CFMWS 时的 NUMA 关联逻辑如通过phys_to_target_node(cfmws-base_hpa)将窗口基地址映射到目标 node并打印 decode range: node: %d range ... 调试信息。解码器层面的内存空洞处理如果 CXL 内存之间夹杂空洞建议用多个解码器分别覆盖各段区域而不是让解码器覆盖整个范围、指望 Linux 来处理重叠。对上文示例单个设备直连 host bridgeLinux 期望的解码器编程方式是----------------------- ----------------------- | root-decoder-0 | | root-decoder-1 | | base: 0x100000000 | | base: 0x200000000 | | size: 0xC0000000 | | size: 0x40000000 | ----------------------- ----------------------- | | ----------------------- ----------------------- | HB-decoder-0 | | HB-decoder-1 | | base: 0x100000000 | | base: 0x200000000 | | size: 0xC0000000 | | size: 0x40000000 | ----------------------- ----------------------- | | ----------------------- ----------------------- | ep-decoder-0 | | ep-decoder-1 | | base: 0x100000000 | | base: 0x200000000 | | size: 0xC0000000 | | size: 0x40000000 | ----------------------- -----------------------即root、host bridge、endpoint 三层解码器每一层都按空洞切成两个解码器且 CEDT 中相应地用两个 CFMWS 条目描述这两个 root 解码器。文档同时声明Linux 对奇怪的内存空洞情况不提供任何支持保证。多介质设备Multi-Media DevicesCEDT 的 CFMWS 字段中有特殊的限制位restriction bits描述该内存区域允许volatile易失性或 persistent持久性内存或两者皆可。若平台意图支持以下场景之一单一设备携带多种介质或把持久内存设备当普通内存使用平台可以创建多个 CEDT CFMWS 条目描述同一段内存让用户在配置方式上保有灵活性。原文档指出Linux 目前在该领域没有强约束但这属于可以这样描述的合法模式。小结平台集成自查清单综合 bios-and-efi.rst 的全文CXL 平台固件侧的自查清单可以归纳为检查项Linux 期望ACPI 表提供 CEDT、SRAT、HMAT 等完整静态描述运行时配置交给 CXL 驱动HDM 解码器不必预编程/预锁定预锁定会牺牲热插拔等特性Zen5 类 quirk 除外且需规避EFI_MEMORY_SP需要驱动管理的 CXL 区域应置位可用uefisettings检查efinosoftreserve作为 x86 逃生开关区域对齐CXL 内存基地址与区域大小建议 2GB 对齐避免海量 memory device 与搁浅容量内存空洞每段连续 HPA 用一个解码器 一个 CFMWS 条目描述两侧空洞分别建模地址翻译只允许 Endpoint Decoder 做 HPA→DPA 翻译中间层解码器范围必须是父解码器子集交织跨 host-bridge 交织的 CFMWS 必须列出全部目标 host bridgeCFMWS 应有 SRAT 对应描述配合仓库内的 CEDT 字段文档、SRAT 文档 与 CXL 平台文档总索引以及 drivers/cxl 驱动源码acpi.c 负责 ACPI/CEDT 解析、core/ 实现区域与解码器运行时逻辑即可从固件配置一路追踪到内核侧的完整行为链路。【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考