图片无法显示,请右键点击新窗口打开图片

CXL.mem 协议可以支持连接在 CXL 链路上的 PMEM 设备,使得 CPU 可以高效地访问这些持久性内存, 换句话说 CXL TYPE 3 设备的存储介质可是持久内存Persistent Memory(PMEM). 通过 CXL.mem,系统可以将 PMEM 作为扩展内存的一部分使用,从而提供更大的内存容量和更高的可靠性. 同时,对于 PMEM 来说,SYSRAM 是持久内存的一种访问模式,它可以将 PMEM 映射到系统物理地址空间形成物理内存,并受系统内存管理进行管理,系统可以像访问普通内存一样访问 PMEM, 因此可以将 PMEM 的 CXL TYPE 3 设备通过 SYSRAM 方式访问.

图片无法显示,请右键点击新窗口打开图片

CXL Persistent Memory Device 可以直接插到 CXL Root Complex 的 RootPort 上,也可以插到 CXL SWITCH 的 DownStream Port 上. 对于 CXL Persisten Memory Device命令接口(Command Interface)由系统固件、UEFI 和操作系统驱动程序使用,用于暴露额外的持久内存功能, 其由以下几部分组成:

  • LSA(Label Storage Area): CXL 内存设备负责提供一个持久的标签存储区,UEFI 和操作系统驱动程序利用该区域读取和写入区域(交错集)配置信息和命名空间配置信息。这对于正确重组持久内存区域配置是必要的.
  • 区域标签(Region Label): 持久配置信息,向 UEFI 和操作系统驱动程序描述持久内存区域,包括所有相关设备的 UUID、每个设备对区域贡献的持久容量以及每个设备在区域中的位置。在持久内存中,设备在区域中的顺序必须始终保持,以便正确重组区域中的数据.
  • 命名空间标签(Namespace Label): 持久配置信息,向 UEFI 和操作系统驱动程序描述每个持久内存区域如何被细分为命名空间。命名空间有几种类型,包括基于 BTT(Block Translation Table)的块存储仿真
  • Poison List: 设备需要维护一个持久的损坏列表,以便 UEFI 和操作系统驱动程序可以快速确定介质的哪些区域包含无效数据并且必须避免或纠正

图片无法显示,请右键点击新窗口打开图片

上图展示了 CXL 内存设备在系统中的集成和操作流程, 图中主要涉及 CXL 持久内存设备(Type 3)与相关软件和硬件组件之间的关系:

  • 固定 ACPI 描述表(FADT): 一个现有的 ACPI 表,用于在平台启动时报告平台的固定属性。对于 CXL,新添加的 PERSISTENT_CPU_CACHES 属性被平台用于报告 CPU 缓存是否被视为持久性缓存,并由操作系统用来设置应用程序的刷新策略.
  • 持久区域(Persistent Region): 每个持久区域代表一个 HPA(主机物理地址)范围,该范围使用一组以特定顺序配置的 CXL 内存设备的持久容量. 每个区域的配置在存储于标签存储区(LSA)中的区域标签中进行描述,这些标签通过命令接口公开.
  • PMEM/SCM 区域驱动程序: 每个区域(交错集 Interleave Set)的实例将由 PMEM/SCM(存储类内存)驱动程序的单独实例使用. 这可能是对现有操作系统内核 NVDIMM 组件的显著重用.
  • 命名空间(Namespaces): 每个区域可以细分为称为命名空间的卷。每个命名空间的配置在存储于标签存储区(LSA)中的命名空间标签中进行描述,这些标签通过命令接口公开.
  • 分区(Partitions): 每个命名空间通常由操作系统细分为分区
  • 文件系统(File Systems): 现有的文件系统驱动程序将每个分区细分为一个或多个文件,并为用户提供标准的文件 API 和文件保护.
  • 内存映射文件(Memory Mapped Files): 区域被细分为命名空间,命名空间被细分为分区,最后由文件系统细分为内存映射文件. 这是应用程序在具有文件安全性和便捷性的情况下直接访问持久内存的一种标准机制.
  • 设备 DAX(Device DAX): 一种简化的直接通道,在应用程序和持久内存命名空间之间,不经过文件系统和内存映射文件使用.
  • Libraries(PMDK): 大多数支持持久内存的应用程序使用如 PMDK 这样的 Ring3 库来简化持久内存编程模型。这些库通常使用内存映射文件或直接设备 DAX 来访问持久内存。这些库将增加新功能以支持新的 CXL 特性.

图片无法显示,请右键点击新窗口打开图片 图片无法显示,请右键点击新窗口打开图片

Intel 推出的傲腾 Persistent Memory 通过插入 DIMM 插槽被系统识别(上上图),而 CXL Type3 PMEM 则通过插入 PCIe 插槽被系统识别,虽然在硬件上访问两种 PMEM 设备的方式已经改变,但在系统协议栈上还是基于 NVDIMM 子系统,其提供了 FSDAX、DEVDAX 和 SYSTEM RAM 三种方式对 PMEM 进行访问. 对于 PMEM 来说,SYSRAM 是持久内存的一种访问模式,它可以将 PMEM 映射到系统物理地址空间形成物理内存,并受系统内存管理进行管理,系统可以像访问普通内存一样访问 PMEM, 因此可以将 PMEM 的 CXL TYPE 3 设备通过 SYSRAM 方式访问, 从而实现低延迟和高吞吐量的数据访问. 接下来基于 BiscuitOS 介绍如何通过 SYSRAM 方式访问 CXL Type3 PMEM 设备.

CXL TOPOLOGY ON BiscuitOS

图片无法显示,请右键点击新窗口打开图片

  • CXL TOPOLOGY A: BiscuitOS 支持的第一种 CXL Type3 PMEM 设备拓扑结构,其并没有带任何的 CXL Switch,而是将 CXL Type3 PMEM 设备直接介绍了 CXL Root Complex 的 RootPort(RP) 上, 基于该拓扑 BiscuitOS 提供了一个容量为 512MiB 的 CXL Type3 PMEM 设备.
  • CXL TOPOLOGY B: BiscuitOS 支持的第二种 CXL Type3 PMEM 设备拓扑结构,其包含了一个 CXL Switch,并且该 Switch 直接连接到 CXL Root Complex 的 RootPort(RP) 上,而 CXLType3 PMEM 设备则连接到 CXL Switch 的下游端口上,基于该拓扑 BiscuitOS 提供了一个容量为 512MiB 的 CXL Type3 PMEM 设备.
  • CXL TOPOLOGY C: BiscuitOS 支持的第三种 CXL Type3 PMEM 设备拓扑结构,其包含了三个 CXL Switch,其中一个 CXL Switch 直接连接到 CXL Root Complex 的 RootPort(RP) 上,另外两个 CXL Switch 分别连接到顶层 CXL Switch 的下游端口. 二级 CXL Switch 的下游端口各连接了 4 个 CXL Type3 Device,因此该拓扑一共 8 个 CXL Type3 Device. 基于该拓扑结构 BiscuitOS 提供了 8 个容量为 512MiB 的 CXL Type3 PMEM 设备,总容量达到 4GiB.

BiscuitOS 已经支持多种拓扑结构的 CXL Type3 PMEM Device,接下来通过对 CXL TOPOLOGY B 方式进行实践,以此研究 Linux 如何通过 SYSRAM 对 CXL Type3 Device 进行使用,开发者参考如下命令进行实践:

# 切换到 BiscuitOS 项目目录
cd BiscuitOS
# 选择开发环境,如果已经选择过可以跳过,这里与 linux 6.9 X86 为例
make linux-6.9-x86_64_defconfig
# 通过 Kbuild 选择需要部署的应用程序
make menuconfig

  [*] DIY BiscuitOS/Broiler Hardware  --->
      [*] Intel Q35
      [*] CXL: Compute Express Link
            CXL Hardware Topology (CXL Switch With TYPE3: x1 Persistent Memory(PMEM))  --->
  [*] Package  --->
      [*] HETEROGENEOUS MEMORY MANAGEMENT
          [*] CXL: CXL.mem AS SYSTEM RAM  --->

# 配置完毕保存,然后进行部署
make

# 切换到实践案例所在目录
cd output/linux-6.9-x86_64/package/BiscuitOS-CXL-MEMORY-default
# 准备依赖工具
make prepare
# 编译实践案例
make download
make build

图片无法显示,请右键点击新窗口打开图片

BiscuitOS 系统已经集成了 CXL 实践的全部工具链,默认提供 cxl、ndctl、daxctl、numactl 和 pci-utlis 工具链。当 BiscuitOS 运行之后,使用 ‘cxl list -v’ 命令可以看到 CXL Bus 的拓扑结构,如上图所示.

图片无法显示,请右键点击新窗口打开图片 图片无法显示,请右键点击新窗口打开图片

该字段描述了 CXL BUS 和 CXL Host Bridge 信息,BiscuitOS 提供了一个 CXL BUS,名为 ‘root0’, CXL BUS 包含了一个下游端口,该下游端口连接 CXL Host Bridge, CXL Host Bridge 的别名为 ‘ACPI0016:00’, CXL Host Bridge 包含一个下游端口,该下游端口连接 CXL Root Complex,可以看到 CXL Root Complex 的 BDF 为 ‘0000:0c’.

图片无法显示,请右键点击新窗口打开图片 图片无法显示,请右键点击新窗口打开图片

该字段描述了 CXL Root Complex 和 CXL Switch 信息,BiscuitOS 提供了一个 Root Complex,名为 ‘port1’, 其对应的 BDF 为 ‘0000:0c’,其包含一个 RootPort(RP),RootPort 的 BDF 是 ‘0000:0c:00.0’, 该端口连接 CXL Swtich. CXL Switch 名为 ‘port2’, 其对应的 BDF 为 ‘0000:0d:00.0’,可以看到 CXL Swith 的上游端口连接到 ‘0000:0c:00.0’, 即连接到 CXL Root Complex 的 RootPort, CXL Swtich 包含了一个下游端口,下游端口的 BDF 为 ‘0000:0e:00.0’.

图片无法显示,请右键点击新窗口打开图片 图片无法显示,请右键点击新窗口打开图片

该字段描述了 CXL Type3 Device 信息,BiscuitOS 提供了一个 CXL Type3 PMEM 设备,其名为 ‘endpoint3’, 设备映射到 ‘/dev/cxl/mem0’, 通过 ‘parent_dport’ 可以知道其连接到了 CXL Switch 的下游端口 ‘0000:0e:00.0’. 从 memdev 字段可以获得 PMEM 设备相关的信息,其中包含 PMEM 的容量为 512MiB, 并且设备的 BDF 号为 ‘0000:0f:00.0’


CXL PCIe TOPOLOGY

图片无法显示,请右键点击新窗口打开图片

当 BiscuitOS 启动之后,使用 ‘lspci-common -vt’ 命令可以看到 CXL 在 PCIe BUS 上的拓扑结构. 从上图可以看到 CXL Root Complex 的 BDF 为 ‘0000:0c’, 由此可以知道 CXL BUS 和 CXL Host Bridge 并不以 PCIe 设备的形式呈现,其在 ACPI Tree 上呈现. CXL Root Complex 包含一个 RootProt,其 BDF 为 ‘0000:0c:00.0’, RootPort 直接连接到 CXL Switch 的上游端口,CXL Switch 的 BDF 为 ‘0000:0d:00.0’, 其包含一个下游端口,其 BDF 为 ‘0000:0e:00.0’, 并连接到 CXL Type3 PMEM Device. CXL Type3 PMEM Device 的 BDF 为 ‘0000:0f:00.0’

图片无法显示,请右键点击新窗口打开图片

CXL ROOT Complex BDF.

图片无法显示,请右键点击新窗口打开图片

CXL SWITCH BDF.

图片无法显示,请右键点击新窗口打开图片

CXL SWITCH BDF.

图片无法显示,请右键点击新窗口打开图片

CXL Type3 PMEM Device BDF.


SYSRAM FOR CXL

图片无法显示,请右键点击新窗口打开图片

当 BiscuitOS 已经部署好 CXL 硬件拓扑之后,进入 BiscuitOS 系统,使用 ‘cxl list’ 命令可以看到 CXL Type3 Device 的信息,从信息可以看到 CXL Type3 Device 是一个 PMEM 设备,其容量为 512MiB,对应的 PCIe BDF 为 ‘0000:0f:00.0’. 并在 ‘/dev/cxl’ 目录下看到 mem0 设备,并在 ‘/sys/bus/cxl/device/’ 目录下看到 CXL Type3 Device mem0 和其他设备的信息. 接下来使用 cxl 和 ndctl 工具将 CXL Type3 PMEM Device 设置为 SYSRAM 模式,然后使用应用程序对 CXL Type3 PMEM Device 进行访问.

图片无法显示,请右键点击新窗口打开图片

  • cxl destroy-region -f all: 命令用于将 CXL BUS 所有的 Region 移除,使 CXL Bus 处于一个初始状态.
  • cxl create-region -d decoder0.0 -m mem0 -s 512M -t pmem -w 1 -g 4096 -u: 用于创建一个 CXL Region,该 Region 的大小为 512MiB,大小必须与 PMEM 的大小一致,并且 Region 的类型需要使用 -t 选项指定为 pmem, 该 CXL Region 的 HDM Decorder 通过 -d 选项进行指定,这里使用 decoder0.0. 其余选项可选,用于设置 interleaving 相关的配置. 命令成功执行之后输出 CXL Region 的信息,可以看到 CXL Region 的名字、MMIO 地址和类型.
  • cxl enable-region region0: 命令将 CXL Region 使能,以供 ndctl 工具使用.

图片无法显示,请右键点击新窗口打开图片

  • ndctl destroy-namespace –force all: 该命令用于强制删除系统的所有持久内存的 Namespace,这样所有持久内存上分配的逻辑区域都将被移除,所有存储在这些 Namespace 中>的数据将被删除, 以此将 PMEM 设置为一个初始状态.
  • ndctl enable-region region0: 该命令用于启用指定持久内存区域 ,这是对之前已经配置但未激活的区域进行激活,使其可以被系统正常使用.
  • ndctl create-namespace –mode=dax -f: 该命令用于创建一个新的持久内存命名空间(Namespace), 并将其配置成 DEVDAX(Direct Access) 模式. 命令执行成功之后将输出新创建 Namespace 的信息,例如上图里新创建的 Namespace 名字为 ‘namespace0.0’, 模式为 DEVDAX,以及长度为 512MiB.

图片无法显示,请右键点击新窗口打开图片

  • free -m: 在模式由 DEVDAX 切换到 SYSRAM 前后,通过该命令查看系统可用物理内存的数量,可以看到 CXL Type3 PMEM Device 切换到 SYSRAM 模式之后,系统物理内存有增加,新增加的物理内存被系统内存管理机制进行管理.
  • cat /proc/buddyinfo: 该命令可以查看 DEVDAX 模式切换到 SYSRAM 模式前后,NUMA NODE 和 ZONE 的变化情况,可以看到 CXL Type3 PMEM Device 热插到一个独立的 NUMA NODE 上,并且 ZONE 属于 MOVABLE,那么意味着热插热拔.
  • daxctl reconfigure-device -N –mode=system-ram dax0.0 –force: 该命令用于将 PMEM 的 DEVDAX 模式切换成 SYSRAM 模式,但切换成功之后,CXL Type3 PMEM Device 会热插到系统,并安置在一个独立的 NUMA NODE 上,并集中到一个 MOVABLE ZONE 上,以便支持动态热插和热拔操作.

当以上的命令执行完毕之后,可以看到系统可用物理内存变多,并且多了一个 NUMA NODE,通过查看系统物理地址总线,可以看到 CXL Type3 PMEM Device 占用的区域被标记为 “System RAM (kmem)”. 应用程序或者内核线程可以 NUMA NODE 绑定到 CXL Type3 PMEM Device 所在的 NUMA NODE 上,那么将透明无感的从 CXL Type3 PMEM Device 上分配和使用内存. 接下来将对 SYSRAM 模式下的 CXL Type3 PMEM Device 进行访问:

图片无法显示,请右键点击新窗口打开图片

实践案例提供了如图的逻辑,对于 CXL Type3 Device 的访问,程序并没有特殊处理,只是像普通程序一样逻辑,或者无需修改程序就可以实现从 CXL Type3 PMEM Device 上分配内存。在本案例里,程序在 21 行调用 mmap 函数分配一段虚拟内存,由于采用惰性分配,因此 mmap 函数分配完成之后,mem 指向的只是虚拟内存。程序接着在 32 行对虚拟内存执行写操作,由于页表不存在,那么 MMU 触发缺页异常,在缺页异常处理函数为虚拟内存建立页表映射到 CXL Type3 PMEM Device 所在的 NUMA NODE 上,待缺页异常返回之后,应用程序重试指令,此时可以将数据写入到 CXL Type3 PMEM Device 上,接着执行读操作,可以从 PMEM 上读到数据。程序最后在 43 行对资源进行回收. 以上便是实践案例的处理逻辑,>接下来可以参考下面命令进行实践:

# 切换到实践案例所在目录
cd output/linux-6.9-x86_64/package/BiscuitOS-CXL-MEMORY-default
# 第一次部署采用运行准备依赖工具
make prepare
make download
# 编译实践案例
make build

图片无法显示,请右键点击新窗口打开图片

BiscuitOS 运行之后,直接运行 RunBiscuitOS.sh 脚本,该脚本里包含了实践所需的所有命令,可以看到最后应用程序运行之后,从 CXL Type3 Device 里读到了刚写入的数据,这里需要注意,需要使用 “numactl –membind=1 Application” 方式将应用程序绑定在 CXL Type3 PMEM Device 所在的 NUMA NODE 上. 以上实践便是 CXL Type3 PMEM Device 通过 FSDAX 访问的全部逻辑.

图片无法显示,请右键点击新窗口打开图片