非对称 32 位 SoC¶
作者:Will Deacon <will@kernel.org>
本文档描述了非对称 32 位 SoC 对执行 32 位 (AArch32
) 应用程序的影响。
日期:2021-05-17
简介¶
一些 Armv9 SoC 存在 big.LITTLE 的缺陷,其中只有一部分 CPU 能够执行 32 位用户应用程序。在这种系统上,Linux 默认将这种不对称性视为“不匹配”,并禁用对 PER_LINUX32
个性和 32 位 ELF 二进制文件的 execve(2)
的支持,后者返回 -ENOEXEC
。如果在稍后上线仅支持 64 位的 CPU 时检测到不匹配,则上线操作将失败,并且新的 CPU 将不可用于调度。
令人惊讶的是,这些 SoC 的生产目的是运行传统的 32 位二进制文件。毫不奇怪,这与 Linux 的默认行为不太相符。
未来的 SoC 似乎不可避免地会完全放弃 32 位支持,因此,如果您不幸需要在这些过渡平台上运行 32 位代码,那么您应该明智地考虑其他替代方案,例如重新编译、模拟或淘汰。如果这些选项都不切实际,请继续阅读。
启用内核支持¶
由于内核支持对用户空间并非完全透明,因此允许 32 位任务在非对称 32 位系统上运行需要显式的“选择加入”,可以通过在内核命令行上传递 allow_mismatched_32bit_el0
参数来启用。
对于本文档的其余部分,我们将把非对称系统称为运行 Linux 并启用了此内核命令行选项的非对称 32 位 SoC。
用户空间影响¶
在非对称系统上运行的 32 位任务的行为与在同构系统上的行为基本相同,只有少数与 CPU 亲和性相关的关键差异。
sysfs¶
能够运行 32 位任务的 CPU 子集在 /sys/devices/system/cpu/aarch32_el0
中描述,并在 Documentation/ABI/testing/sysfs-devices-system-cpu
中进一步记录。
注意: CPU 在被检测到时会通过此文件进行通告,因此稍后上线能够支持 32 位的 CPU 可能会导致内核在运行时修改文件内容。一旦通告,CPU 将永远不会从文件中删除。
execve(2)
¶
在同构系统上,任务的 CPU 亲和性在 execve(2)
期间保持不变。这在非对称系统上并非总是可能,特别是在要执行的新程序是 32 位,但亲和性掩码包含仅支持 64 位的 CPU 时。在这种情况下,内核确定新的亲和性掩码,如下所示
如果亲和性掩码的 32 位能力子集不为空,则亲和性将限制为该子集,并保存旧的亲和性掩码。此保存的掩码通过
fork(2)
继承,并在 32 位程序的execve(2)
中保留。注意:此步骤不适用于
SCHED_DEADLINE
任务。请参阅 SCHED_DEADLINE。否则,将遍历任务的 cpuset 层次结构,直到找到至少包含一个具有 32 位能力的 CPU 的祖先。然后,将任务的亲和性更改为与遍历确定的 cpuset 的 32 位能力子集相匹配。
如果失败(即内存不足),则亲和性将更改为内核知道的所有具有 32 位能力的 CPU 的集合。
32 位任务随后对 64 位程序执行的 execve(2)
将使在 (1) 中保存的亲和性掩码失效,并尝试使用先前有效的已保存掩码来恢复任务的 CPU 亲和性。由于截止期限策略或 cpuset 层次结构的介入更改,此恢复可能会失败,在这种情况下,execve(2)
将继续执行,并且亲和性不变。
对 32 位任务调用 sched_setaffinity(2)
将仅考虑请求的亲和性掩码中具有 32 位能力的 CPU。成功后,任务的亲和性将更新,并且来自先前 execve(2)
的任何已保存掩码都将失效。
SCHED_DEADLINE
¶
除非通过将 -1 写入 /proc/sys/kernel/sched_rt_runtime_us
来禁用准入控制,否则在非对称 32 位系统上会拒绝将 32 位截止期限任务显式准入到默认根域(例如,通过调用 sched_setattr(2)
)。
如果任务的根域包含任何仅支持 64 位的 CPU 并且启用了准入控制,则 64 位截止期限任务执行 32 位程序时的 execve(2)
将返回 -ENOEXEC
。并发关闭具有 32 位能力的 CPU 可能仍然需要执行 execve(2) 中描述的过程,在这种情况下,将跳过步骤 (1),并在控制台上发出警告。
注意:建议如果要在非对称系统上将 SCHED_DEADLINE
与 32 位任务一起使用,则将一组具有 32 位能力的 CPU 放置在单独的根域中。否则可能会导致错过截止期限。
Cpusets¶
非对称系统上 32 位任务的亲和性可能包括其所附加的 cpuset 未明确允许的 CPU。这可能由于以下两种情况而发生
附加到仅允许 64 位 CPU 的 cpuset 的 64 位任务执行 32 位程序。
关闭了包含 32 位任务的 cpuset 允许的所有具有 32 位能力的 CPU。
在这两种情况下,都将根据 execve(2) 中描述的过程的步骤 (2) 计算新的亲和性,并且无论 cgroup 版本如何,cpuset 层次结构都保持不变。
CPU 热插拔¶
在非对称系统上,第一个检测到的具有 32 位能力的 CPU 会被阻止被用户空间关闭,并且任何此类尝试都将返回 -EPERM
。请注意,即使主 CPU(即 CPU 0)仅支持 64 位,也仍然允许挂起。
KVM¶
尽管 KVM 不会在非对称系统上向任何 vCPU 通告 32 位 EL0 支持,但 EL1 中损坏的客户机仍然可能尝试在 EL0 中执行 32 位代码。在这种情况下,从 32 位模式下的 vCPU 线程退出将返回到主机用户空间,并带有 exit_reason
KVM_EXIT_FAIL_ENTRY
,并且在后续 KVM_ARM_VCPU_INIT
操作成功重新初始化之前,它将保持不可运行状态。