Linux 初始化 (早期启动)¶
Linux 配置分为两个主要步骤:早期启动和其余部分。
在早期启动期间,Linux 设置不可变的资源(例如 numa 节点),而后续操作包括驱动程序探测和内存热插拔等。 Linux 可能会在此过程中读取 EFI 和 ACPI 信息,以配置设备的逻辑表示。
在 Linux 早期启动阶段(内核中带有 __init 修饰符的函数),系统会获取 EFI/BIOS 创建的资源 (ACPI 表格) 并将其转换为内核可以使用的资源。
BIOS、构建和启动选项¶
在内核构建期间需要考虑 4 个预启动选项,这些选项决定了 Linux 在早期启动期间如何管理内存。
EFI_MEMORY_SP
BIOS/EFI 选项,用于指示内存是 SystemRAM 还是特定用途。 特定用途内存将被推迟到驱动程序管理,而不是立即作为系统 RAM 公开。
CONFIG_EFI_SOFT_RESERVE
Linux 构建配置选项,用于指示内核是否支持特定用途内存。
CONFIG_MHP_DEFAULT_ONLINE_TYPE
Linux 构建配置,用于指示应如何管理转换为 dax 设备的特定用途内存(保留为 DAX,还是作为 SystemRAM 在 ZONE_NORMAL 或 ZONE_MOVABLE 中联机)。
nosoftreserve
Linux 内核启动选项,用于指示是否应支持软保留。 类似于 CONFIG_EFI_SOFT_RESERVE。
内存映射创建¶
当内核解析 EFI 内存映射时,如果支持并检测到 Specific Purpose
内存,它将把此区域设置为 SOFT_RESERVED
。
如果 EFI_MEMORY_SP=0
、CONFIG_EFI_SOFT_RESERVE=n
或 nosoftreserve=y
- Linux 会将 CXL 设备内存区域默认设置为 SystemRAM。 这会将内存公开给 ZONE_NORMAL
中的内核页面分配器,使其可用于大多数分配(包括 struct page
和页表)。
如果设置并支持了 特定用途,则 CONFIG_MHP_DEFAULT_ONLINE_TYPE_*
指示默认情况下是否联机内存 (_OFFLINE
或 _ONLINE_*
),以及如果联机,默认情况下将该内存联机到哪个区域 (_NORMAL
或 _MOVABLE
)。
如果放置在 ZONE_MOVABLE
中,则该内存将不可用于大多数内核分配(例如 struct page
或页表)。 这可能会严重影响性能,具体取决于系统的内存容量。
NUMA 节点保留¶
Linux 引用 SRAT 中定义的邻近域 (PXM
) 以在 acpi_numa_init
中创建 NUMA 节点。 通常,PXM
和 NUMA 节点 ID 之间存在 1:1 关系。
SRAT 是 ACPI 定义的定义邻近域的唯一方法。 Linux 选择最多将这些域与 NUMA 节点 1:1 映射。 CEDT 添加了 SPA 范围的描述,Linux 可以将这些范围映射到一个或多个 NUMA 节点。
如果 CFMWS 中存在 CXL 范围,但 SRAT 中不存在,则会创建一个伪 PXM
(截至 v6.15)。 将来,由于邻近域关联的模糊性,Linux 可能会拒绝 SRAT 未描述的 CFMWS。
重要的是要注意,NUMA 节点创建不能在运行时完成。 所有可能的 NUMA 节点都在 __init
时识别,更具体地说是 mm_init
期间。 CEDT 和 SRAT 必须包含足够的 PXM
数据,以便 Linux 识别 NUMA 节点及其关联的内存区域。
相关代码存在于: linux/drivers/acpi/numa/srat.c
中。
有关更多信息,请参见 示例平台配置。
内存层创建¶
内存层是按性能特征分组的 NUMA 节点的集合。 在 __init
期间,Linux 使用包含所有标记为 N_MEMORY
的节点的默认内存层初始化系统。
memory_tier_init
在启动时为默认联机的所有内存节点调用。 memory_tier_late_init
在 late-init 期间为驱动程序配置期间设置的节点调用。
只有当节点具有在线内存时,才会标记为 N_MEMORY
。
层成员资格可以在
/sys/devices/virtual/memory_tiering/memory_tierN/nodelist
0-1
中检查如果分组的节点在性能上有明显的差异,请检查 CXL 节点的 HMAT 和 CDAT 信息。 除非通过 access_coordinates 将 HMAT/CDAT 信息报告给 memory_tier 组件,否则所有节点都默认为 DRAM 层。
有关更多信息,请参见 CXL 访问坐标文档。
连续内存分配¶
连续内存分配器 (CMA) 允许在早期启动期间在 NUMA 节点上保留连续的内存区域。 但是,CMA 无法在早期启动期间未联机的 NUMA 节点上保留内存。
void __init hugetlb_cma_reserve(int order) {
if (!node_online(nid))
/* do not allow reservations */
}
这意味着如果用户打算将 CXL 内存的管理推迟到驱动程序,则 CMA 不能用于保证巨页分配。 如果在早期启动期间将 CXL 内存作为 ZONE_NORMAL 中的 SystemRAM 启用,则可以使用 cma_pernuma
或 numa_cma
内核命令行参数进行每个节点的 CMA 预留。