4. ARM64 架构 SMP 硬件基础

多核(SMP)启动是 Linux 内核启动流程中最复杂的硬件协同环节。在 ARM64 架构下,启动过程依赖三大硬件基础:通用中断控制器(GIC)、MPIDR 寄存器 与 PSCI 协议。理解这三者,才能掌握内核如何唤醒、同步和管理多个 CPU 核心。

核心认知: ARM64 的 SMP 启动不是“所有核同时跑”,而是由主核(Primary CPU)通过 PSCI 协议逐次唤醒从核(Secondary CPU),GIC 负责中断路由,MPIDR 提供拓扑标识。

4.1 GIC(通用中断控制器)体系结构

GIC 是 ARM 架构的标准中断控制器,负责接收、分发和优先级管理硬件中断。Linux 内核通过 GIC 驱动实现中断路由、亲和性设置和核间中断(IPI)。

4.1.1 GICv2 与 GICv3 架构对比

特性 GICv2 GICv3
CPU 接口 内存映射寄存器(每个核独立) 系统寄存器(ICC_*_EL1),减少内存访问延迟
中断路由 固定路由到指定 CPU 支持亲和性路由(Affinity Routing),灵活分发
LPI(局部中断) 不支持 支持,通过 ITS(中断翻译服务)实现消息中断
虚拟化支持 基础虚拟中断 硬件虚拟化中断(vLPI、vSGI)
最大 CPU 数 最多 8 个 PE(处理单元) 可扩展至数千个 PE
内核适配: Linux 内核通过 CONFIG_ARM_GIC_V2 和 CONFIG_ARM_GIC_V3 分别支持两代 GIC。启动时根据设备树或 ACPI 表自动检测 GIC 版本。

4.1.2 GICv3 中断类型与路由机制

  • SGI(软件生成中断): 核间中断(IPI),用于 CPU 间通信,如 TLB 刷新、调度。
  • PPI(私有外设中断): 每个 CPU 私有,如本地定时器。
  • SPI(共享外设中断): 全局外设中断,可路由到任意 CPU。
  • LPI(局部中断): 基于消息的中断,通过 ITS 配置路由。

GICv3 通过 亲和性路由 将中断分发到指定 CPU 簇或核心,路由决策基于 MPIDR 的亲和性层级。

GICv3 中断分发架构 SGI(核间中断) PPI(私有中断) SPI(共享中断) LPI(消息中断) GIC 分发器 中断优先级 亲和性路由 中断屏蔽 CPU 接口(核 0) CPU 接口(核 1) CPU 接口(核 2) CPU 接口(核 3) GICv3 通过系统寄存器(ICC_*_EL1)访问 CPU 接口,减少内存映射开销,提升中断响应速度

4.2 MPIDR 寄存器与 CPU 拓扑

MPIDR(Multiprocessor Affinity Register) 是 ARM64 架构中每个 CPU 核心的硬件标识寄存器,用于描述核心在 SoC 中的拓扑位置。内核通过读取 MPIDR 构建 CPU 拓扑树,实现负载均衡和中断亲和性。

4.2.1 MPIDR 寄存器格式

位域       描述
[31:24]    Affinity 3(簇间层级,多芯片系统)
[23:16]    Affinity 2(簇层级)
[15:8]     Affinity 1(核心组层级)
[7:0]      Affinity 0(核心编号)

MPIDR 的亲和性层级形成树形拓扑:Aff3 → Aff2 → Aff1 → Aff0,对应芯片 → 簇 → 组 → 核心。

4.2.2 内核拓扑构建流程

  1. 启动阶段: 主核读取自身 MPIDR,记录为 boot_cpu_mpidr。
  2. 设备树解析: 遍历 cpu-map 节点,匹配 MPIDR 值,建立核心与簇的对应关系。
  3. 拓扑注册: 调用 store_cpu_topology() 填充 cpu_topology 结构体。
  4. 调度使用: 调度器根据拓扑信息进行负载均衡,优先在同一簇内迁移任务。
基于 MPIDR 的 CPU 拓扑树 SoC(Aff3=0) Cluster 0(Aff2=0) Cluster 1(Aff2=1) Core 0(Aff1=0) Core 1(Aff1=1) Core 2(Aff1=0) Core 3(Aff1=1) MPIDR 值示例:Core 0 = 0x00000000,Core 1 = 0x00000100,Core 2 = 0x00000101 内核通过 cpu_topology[].core_id 和 cluster_id 记录层级关系

4.3 PSCI(电源状态协调接口)协议

PSCI 是 ARM 定义的电源管理标准接口,Linux 内核通过 PSCI 实现 CPU 的开启、关闭、挂起和唤醒。在 SMP 启动中,主核调用 PSCI 的 CPU_ON 接口唤醒从核。

4.3.1 PSCI 核心功能

PSCI 功能 功能码 描述
CPU_ON 0xC4000003 唤醒指定 CPU 核心,设置入口地址和上下文
CPU_OFF 0xC4000002 关闭当前 CPU 核心
CPU_SUSPEND 0xC4000001 挂起 CPU,支持浅睡和深度睡眠
SYSTEM_SUSPEND 0xC400000E 系统级挂起
AFFINITY_INFO 0xC4000004 查询 CPU 拓扑节点的电源状态

4.3.2 PSCI CPU_ON 调用流程

  1. 主核准备: 设置从核的入口地址(通常是 secondary_entry)和上下文(栈指针、页表)。
  2. 发起调用: 通过 smc 指令进入 EL3(安全监控模式),传递 PSCI 功能码和参数。
  3. 固件处理: ATF(ARM Trusted Firmware)接收请求,执行电源序列,释放从核复位信号。
  4. 从核启动: 从核从复位向量执行,跳转到主核指定的入口地址,进入内核初始化流程。
// 内核中 PSCI CPU_ON 调用示例(arch/arm64/kernel/psci.c)
static int psci_cpu_on(unsigned long cpuid, unsigned long entry_point)
{
    struct psci_0_1_function *invoke_fn;
    int err;

    invoke_fn = psci_function_id[PSCI_FN_CPU_ON];
    err = invoke_fn(cpuid, entry_point, 0);
    return psci_to_linux_errno(err);
}
关键约束: PSCI CPU_ON 调用必须在 安全世界(EL3) 执行,普通世界(EL1/EL2)无法直接操作 CPU 电源控制器。内核通过 smc 指令陷入 EL3,由 ATF 完成实际电源操作。

4.3.3 PSCI 版本协商

内核在启动初期通过 psci_check_mode() 检测 PSCI 版本:

  • PSCI 0.1: 遗留版本,通过设备树 psci-compatible 识别。
  • PSCI 0.2: 标准化版本,支持功能码查询和版本协商。
  • PSCI 1.0/1.1: 扩展版本,新增 SYSTEM_SUSPEND 和 MEM_PROTECT。
PSCI CPU_ON 唤醒从核流程 主核(Primary CPU) EL1 内核 ① 设置入口地址 ② smc 指令陷入 EL3 ATF(EL3) PSCI 处理程序 电源状态机 复位控制 从核(Secondary CPU) 复位状态 ③ 释放复位信号 ④ 跳转到入口地址 PSCI CPU_ON 参数:target_cpu(MPIDR)、entry_point(物理地址)、context_id(可选) 从核启动后首先执行 secondary_startup,初始化 MMU、中断和调度器 整个唤醒过程在微秒级完成,内核通过 cpu_online_mask 跟踪在线核心

4.4 三者的协同关系

在 ARM64 SMP 启动中,GIC、MPIDR 和 PSCI 形成完整的硬件基础栈:

  • MPIDR 提供 CPU 的全局唯一标识和拓扑位置。
  • PSCI 提供电源管理接口,实现 CPU 的唤醒和关闭。
  • GIC 提供中断路由和核间通信,确保多核协同工作。
启动链路: 主核读取 MPIDR 确认身份 → 通过 PSCI CPU_ON 唤醒从核 → 从核初始化 GIC 接口 → 注册到内核调度器 → 通过 IPI 进行核间同步。