Linux kernel PSCI驱动10分钟讲清楚

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 是"接口"而非"模块",对我们开发有几个直接指导:

  1. 你想在关机时保存配置到 EEPROM :仍然应该挂 reboot_notifier 或驱动的 .shutdown 回调(上一轮讲的),不要试图在 PSCI 层做------PSCI 已经陷入 EL3,回到 Linux 上下文时系统马上就断电了,没有机会写 I2C

  2. ZynqMP 上真正的"断电动作"在 PMUFW 里 :如果你的设备关机后没有完全断电(比如只是 PS 域下了但 PL 还在跑),要去看 PMUFW 的配置和 zynqmp_system_off() 的实现,确认 shutdown scope 是否设对了。Xilinx 在 2018 年的提交里允许通过 pm_system_shutdown() API 动态设置 shutdown scope(默认是 system 级)

  3. 调试 PSCI 调用 :可以在 ATF 里开启 PSCI 的 log,或者在 Linux 侧 cat /sys/firmware/devicetree/base/psci/ 查看 PSCI 版本和方法(smc/hvc)

  4. 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 触发的------这两层不要搞混。

相关推荐
未济3 天前
linux 配置环境变量
linux
傲世仙尊3 天前
目录即文件-Ext文件系统收尾篇
linux·c语言
_艾伦 耶格尔.3 天前
进程间通信
linux
Liuqy-053 天前
Linux IO编程——静态库、动态库
linux
彧azz3 天前
Linux 环境下 Redis 学习总结:数据类型、持久化、锁、事务、主从与缓存问题
linux·redis·笔记·学习·面试
-梅3 天前
linux(8) 软硬链接
linux·运维·服务器
AIgorithmGEEK3 天前
[Linux]线程三部曲(上):一个执行流的诞生——从操作系统一路拆到 pthread_create
linux·线程·pid
琥珀色糖3 天前
SimlpeHttp
linux·服务器
qeen873 天前
【Linux】操作系统之进程介绍(二)
linux·笔记·学习·进程
Zenova EdgeOS3 天前
Linux ss 工业边缘网络分析实战
linux·python·边缘计算·工业网关