CPU 热插拔与 ACPI

在 arm64 领域中,CPU 热插拔通常用于描述内核使用 PSCI 将 CPU 上线/下线。本文讨论的是 ACPI 固件允许在启动时不可用的 CPU 稍后被添加进系统中。

possiblepresent 指的是 Linux 眼中的 CPU 状态。

物理系统上的 CPU 热插拔 - 启动时不存在的 CPU

物理系统需要将一个 possible 但不 present 的 CPU 标记为 present。一个例子是双路机器,其中一个插槽中的芯片封装可以在系统运行时被替换。

这是不支持的。

在 arm64 领域中,CPU 不是单一设备,而是系统的一个切片。没有任何系统支持在系统运行时物理添加(或移除)CPU,并且 ACPI 无法充分描述它们。

例如:新 CPU 带有新的缓存,但平台的缓存拓扑结构是在静态表 PPTT 中描述的。缓存如何在 CPU 之间共享是无法自动发现的,必须由固件来描述。

例如:驱动程序必须在启动期间访问每个 CPU 的 GIC 重分发器,以发现全系统支持的功能。ACPI 的 MADT GICC 结构可以描述与禁用 CPU 关联的重分发器,但无法描述该重分发器是否可访问,只能描述它不是“始终开启(always on)”的。

arm64 的 ACPI 表假定所描述的一切都是 present 的。

虚拟系统上的 CPU 热插拔 - 启动时未启用的 CPU

虚拟系统具有一个优势:系统将拥有的所有属性都可以在启动时描述。由于此类设备是模拟的,因此无需考虑电源域问题。

虚拟系统上的 CPU 热插拔是受支持的。它与物理 CPU 热插拔不同,因为所有 vCPU 资源都在固件配置表(例如 MADT)中静态描述,这意味着它们的最大可能数量在启动时是已知的。然而,在启动时未启用的 vCPU 在热插拔之前不会被内核标记为 present。例如,虚拟机以单个 CPU 启动,一旦云编排器部署了工作负载,就会添加额外的 CPU。

对于虚拟机,VMM(例如 Qemu)扮演了固件的角色。

虚拟热插拔作为一项固件策略实现,影响哪些 CPU 可以被带上线。固件可以通过 PSCI 的返回码(例如 DENIED)来强制执行其策略。

ACPI 表必须描述虚拟机的全部资源。可热插拔的 CPU 必须在 MADT GICC 结构中设置 online capable 位并清除 enabled 位,以表明它们可以稍后启用。启动 CPU 必须被标记为 enabled 并且其 online capable 位被清除。必须使用“始终开启(always on)”的 GICR 结构来描述重分发器。

被描述为 online capable 但未 enabled 的 CPU 可以通过 DSDT 的 Processor 对象的 _STA 方法设置为启用。在虚拟系统上,_STA 方法必须始终设置 ACPI_STA_DEVICE_PRESENT 位,同时切换 ACPI_STA_DEVICE_ENABLED 位以反映其插拔状态。当热添加期间 ACPI_STA_DEVICE_ENABLED 位置位时,内核随后将在操作系统内动态将该 vCPU 标记为 present。固件策略的更改可以通过 device-check 或 eject-request 通知操作系统。

在静态表中描述为 enabled 的 CPU,其 _STA 不应由固件动态修改。诸如 kexec 之类的软重启功能将从这些静态表中重新读取系统的静态属性,如果这些属性不再描述正在运行的系统,则可能会发生故障。Linux 稍后将在启动期间从 _STA 方法中重新发现系统的动态属性。