
Linuxkernel中,PSCI其实是一个容易被误认成内核模块的接口规范 ------它既不是硬件模块,也不是内核里的某个 .ko,而是 ARM 官方定义的电源管理接口标准(Power State Coordination Interface) ,本质上是一份"合同":规定非安全世界(Linux 内核跑在 EL1)如何通过 SMC 指令去调用运行在 EL3 安全监控模式下的固件(典型就是 ARM Trusted Firmware,ATF),由固件代理执行真正触碰硬件寄存器的电源操作。
一、PSCI 到底是个什么东西
ARM 官方文档 DEN0022 对它的定位是:为多监督系统(OS、Hypervisor、Trusted OS 并存)之间协调电源控制提供标准接口。它要解决的核心痛点是:
-
多核 SoC 里,谁来负责把某个核真正断电?OS 不能直接写电源控制寄存器(那些寄存器在 EL3 安全世界)
-
不同 SoC 厂商各自实现一套 CPU 启停逻辑,导致 OS 移植困难
-
系统级关机/复位需要协调所有核进入已知状态
PSCI 给出的答案是:统一函数 ID + SMC 指令。OS 只需要调用标准函数,不用关心底层是 ATF 直接操作硬件,还是通过 SCP(System Control Processor)间接操作。
规范定义的主要函数:
| 函数 | 功能 |
|---|---|
PSCI_CPU_ON |
启动一个从核(secondary boot / hotplug 上线) |
PSCI_CPU_OFF |
关闭调用者所在核(hotplug 下线) |
PSCI_CPU_SUSPEND |
把核放入深睡/retention 状态(cpuidle 用) |
PSCI_SYSTEM_OFF |
系统关机 (对应 poweroff) |
PSCI_SYSTEM_RESET |
系统复位 (对应 reboot) |
PSCI_MIGRATE |
迁移 Trusted OS 上下文 |
💡 关键点:PSCI 不负责 DVFS(调频调压)和外设电源管理,那些归 SCMI 或其他框架管。
二、它是怎么被调用的:SMC 指令跨异常级
PSCI 调用本质上是一次跨异常级别的上下文切换:
Linux 内核 (EL1)
│ 执行 smc #0 指令
▼
触发同步异常,CPU 切换到 EL3
│
▼
Secure Monitor (EL3, 常驻固件 ATF BL31)
│ 解析 x0 中的 Function ID
│ 路由到 PSCI 服务处理
▼
执行平台特定的断电/复位操作
│
▼
返回到调用者(PSCI_SYSTEM_OFF 不返回)
调用约定(SMCCC):
-
x0 :Function ID,比如
PSCI_0_2_FN_SYSTEM_OFF = 0x84000008 -
x1~x3:参数
-
x0(返回):状态码
内核里发起调用的代码非常直白(drivers/firmware/psci/psci.c):
#define PSCI_0_2_FN_SYSTEM_OFF PSCI_0_2_FN(8)
static void psci_sys_poweroff(void)
{
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
}
invoke_psci_fn 根据设备树里 "method" 属性决定是用 smc #0 还是 hvc #0 陷入 EL3。
三、ZynqMP:完整链路
Xilinx 官方 wiki 明确说明:ZynqMP 的 ATF 实现了 PSCI 1.0 标准 ,并且所有 PSCI 电源管理操作最终都通过 **IPI(Inter-Processor Interrupt)转发给 PMU Firmware(PMUFW)** 执行。
具体到 SYSTEM_OFF,ATF 这边的实现在 plat/xilinx/zynqmp/plat_psci.c:
zynqmp_system_off() // ATF 里的 PSCI 平台回调
│
▼
pm_system_shutdown(PMF_SHUTDOWN_TYPE_SHUTDOWN,
pm_get_shutdown_scope()) // 通过 IPI 发到 PMU
│
▼
PMU Firmware // 运行在 ZynqMP 内置的 PMU 上
│
▼
实际操作硬件:拉低 PMIC 使能脚 / 切断 PS 域电源
所以当用户敲下命令: shutdown -h now时,在 ZynqMP 上的精确表述应该是:
shutdown -h now
↓
reboot(LINUX_REBOOT_CMD_POWER_OFF) [kernel/reboot.c]
↓
kernel_power_off()
↓
machine_power_off() [arch/arm64/kernel/reboot.c]
↓
psci_sys_poweroff() [drivers/firmware/psci/psci.c]
↓ smc #0
↓
ATF BL31 的 PSCI 服务 (EL3) [arm-trusted-firmware]
↓ zynqmp_system_off()
↓ 通过 IPI 发送 PMU 命令
↓
PMU Firmware [ZynqMP 内置 PMU 上运行]
↓
操作 PMIC / 电源域 → 整机断电
五、实际意义
理解了 PSCI 是"接口"而非"模块",对我们开发有几个直接指导:
-
你想在关机时保存配置到 EEPROM :仍然应该挂
reboot_notifier或驱动的.shutdown回调(上一轮讲的),不要试图在 PSCI 层做------PSCI 已经陷入 EL3,回到 Linux 上下文时系统马上就断电了,没有机会写 I2C -
ZynqMP 上真正的"断电动作"在 PMUFW 里 :如果你的设备关机后没有完全断电(比如只是 PS 域下了但 PL 还在跑),要去看 PMUFW 的配置和
zynqmp_system_off()的实现,确认 shutdown scope 是否设对了。Xilinx 在 2018 年的提交里允许通过pm_system_shutdown()API 动态设置 shutdown scope(默认是 system 级) -
调试 PSCI 调用 :可以在 ATF 里开启 PSCI 的 log,或者在 Linux 侧
cat /sys/firmware/devicetree/base/psci/查看 PSCI 版本和方法(smc/hvc) -
ATF 源码位置 :Xilinx 的 ATF 在 GitHub - Xilinx/arm-trusted-firmware: ARM Trusted Firmware · GitHub ,ZynqMP 平台 PSCI 实现集中在
plat/xilinx/zynqmp/plat_psci.c和plat/xilinx/zynqmp/pm_service/目录下
简单收一句:PSCI 是 ARM 定的"电源操作合同",Linux 是客户端,ATF 是服务端,PMUFW 是 ZynqMP 上的最终执行者。你做关机流程定制时,写配置保存逻辑在内核侧(reboot notifier),真正的断电动作是 PMUFW 通过 IPI 触发的------这两层不要搞混。
