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 的亲和性层级。
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 内核拓扑构建流程
- 启动阶段: 主核读取自身 MPIDR,记录为 boot_cpu_mpidr。
- 设备树解析: 遍历
cpu-map节点,匹配 MPIDR 值,建立核心与簇的对应关系。 - 拓扑注册: 调用
store_cpu_topology()填充cpu_topology结构体。 - 调度使用: 调度器根据拓扑信息进行负载均衡,优先在同一簇内迁移任务。
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 调用流程
- 主核准备: 设置从核的入口地址(通常是
secondary_entry)和上下文(栈指针、页表)。 - 发起调用: 通过
smc指令进入 EL3(安全监控模式),传递 PSCI 功能码和参数。 - 固件处理: ATF(ARM Trusted Firmware)接收请求,执行电源序列,释放从核复位信号。
- 从核启动: 从核从复位向量执行,跳转到主核指定的入口地址,进入内核初始化流程。
// 内核中 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。
4.4 三者的协同关系
在 ARM64 SMP 启动中,GIC、MPIDR 和 PSCI 形成完整的硬件基础栈:
- MPIDR 提供 CPU 的全局唯一标识和拓扑位置。
- PSCI 提供电源管理接口,实现 CPU 的唤醒和关闭。
- GIC 提供中断路由和核间通信,确保多核协同工作。
启动链路: 主核读取 MPIDR 确认身份 → 通过 PSCI CPU_ON 唤醒从核 → 从核初始化 GIC 接口 → 注册到内核调度器 → 通过 IPI 进行核间同步。