ARM64 Linux 6.10内核启动流程6-psci.c和ATF/U-Boot 的电源接口

§1.1 arch/arm64/kernel/psci.c:和固件的 CPU 电源接口

平台:QEMU virt + ARM64,-kernel Image。没有真 ATF,也没有 U-Boot。


0. 这条要明白什么

ARM64 上 CPU 的上电、下电、改 PC,不是内核去写 SoC 复位寄存器。内核只发 PSCI 请求;真正动电源的是更高异常级的固件。

本文件是客户这一侧的适配层:把 struct cpu_operations(SMP/热插拔用的虚表)翻成 PSCI 的 CPU_ON / CPU_OFF / AFFINITY_INFO

清单写成「ATF/U-Boot」,是 BSP 口头习惯。virt 上对端是 QEMU。真板最常见是 ATF(BL31)。U-Boot 首先是加载 Image 的 bootloader,只有少数没 ATF 的板子才会顺带实现 PSCI。


1. 三个「psci」不要并成一份

文件 角色 管什么
本文件 arch/arm64/kernel/psci.c ARM64 的 cpu_ops 某一颗 CPU 的上电/下电
drivers/firmware/psci/psci.c 通用 PSCI 驱动 hvc/smc;还挂整机 SYSTEM_OFF / SYSTEM_RESET
arch/arm64/kernel/smp.c 启动/热插拔流程 何时调用上面这张表

调用方向永远是:

复制代码
smp.c  (时机)
  → 本文件 cpu_psci_ops.cpu_boot / cpu_die / cpu_kill
    → psci_ops.*     (drivers/firmware/psci/psci.c 填好的函数指针)
      → invoke_psci_fn → hvc/smc
        → 固件(virt = QEMU;真板 = ATF)

本文件 没有 hvc 指令,也 没有 poweroff。它只决定「这次要调 PSCI 的哪一个功能」。


2. 对端到底是谁

复制代码
真板典型:
  U-Boot / 厂商 bootloader     加载 Image,x0 = DTB     ← 启动协议
  ATF (BL31, EL3)              实现 PSCI,接 smc        ← 电源接口 ★ 本条
  Linux                        本文件 + firmware/psci.c  ← 客户

你现在的 virt:
  QEMU -kernel                 兼当 bootloader(填 x0)
  QEMU 自己模拟 PSCI            兼当 ATF(接 hvc)
  Linux                        客户侧完全一样

两件不同的事:

  1. 谁把内核加载进来 ------ bootloader(现在是 QEMU,以后可以是 U-Boot)。
  2. 谁给 CPU 上电/改入口 ------ PSCI 实现者(现在是 QEMU,真板是 ATF)。

加 U-Boot 只换第 1 件;加 ATF 才换第 2 件。本条关心第 2 件。

DT 里和本文件对上的是 cpu 节点的 enable-method = "psci"cpu_ops.c 用这个名字找到 cpu_psci_ops)。psci { method = "hvc"; } 则是 firmware 那份驱动选 hvc 还是 smc,不是本文件读的。


3. 文件本体:一张表

全文就是给 cpu_psci_ops 填回调。.name = "psci" 必须和 DT enable-method 字符串一致。

复制代码
const struct cpu_operations cpu_psci_ops = {
    .name            = "psci",
    .cpu_init        = cpu_psci_cpu_init,      // 空实现,返回 0
    .cpu_prepare     = cpu_psci_cpu_prepare,   // 启动前确认固件有 cpu_on
    .cpu_boot        = cpu_psci_cpu_boot,      // ★ 上电:CPU_ON
    .cpu_can_disable = ...,                    // 这颗核能不能热拔
    .cpu_disable     = ...,                    // 拔之前再检查一次
    .cpu_die         = cpu_psci_cpu_die,       // ★ 本核请求下电:CPU_OFF
    .cpu_kill        = cpu_psci_cpu_kill,      // ★ 另一核确认已经关掉
};

没有 .cpu_postboot:从核起来后不必在本文件做额外同步。

谁在什么时候调这些指针(smp.c):

回调 谁调 何时
cpu_init smp_cpu_setup() setup_archsmp_init_cpus,登记阶段
cpu_prepare smp_prepare_cpus() kernel_init_freeable,拉核之前
cpu_boot boot_secondary()__cpu_up smp_init,真正点亮从核
cpu_disable 热插拔下线路径 目标核还在跑,允许失败并中止
cpu_die 目标核自己 cpu_die() 点了不归路,必须成功
cpu_kill 另一颗核 arch_cpuhp_cleanup_dead_cpu 轮询固件:那颗核是不是真关了

4. 上电:cpu_psci_cpu_boot

这是第 1 个月必精读的一个函数。

复制代码
cpu_psci_cpu_boot(cpu)
  pa = __pa_symbol(secondary_entry)     物理地址:从核 MMU 关着
  psci_ops.cpu_on(cpu_logical_map(cpu), pa)

两个参数就是 PSCI CPU_ON 契约的全部:

  1. MPIDRcpu_logical_map(cpu),来自 DT cpu 节点 reg),不是 Linux 逻辑 CPU 号。
  2. 入口物理地址secondary_entry)。固件把目标核的 PC 设到这里。

psci_ops.cpu_onsetup_archpsci_dt_init() 里已经填好(virt 上是 psci_0_2_cpu_on)。本文件不关心 hvc 还是 smc

返回 0 只表示固件接单。从核是否 online,仍由 smp.c__cpu_upcpu_running。细节见拉核笔记第 3~5 节。

cpu_prepare 只做一件事:没有 psci_ops.cpu_on 就拒绝拉这颗核(-ENODEV)。cpu_init 为空:PSCI 不需要按 CPU 再读一份私有数据(对比 spin-table 还要读 cpu-release-addr)。


5. 下电:看函数名,不深挖热插拔

第 1 个月知道「对称的下电也走固件」即可,不必顺着 cpuhp 状态机走。

三步,故意拆开:

复制代码
1. cpu_can_disable / cpu_disable   还在内核里,可以拒绝
     - 固件没实现 CPU_OFF → -EOPNOTSUPP
     - Trusted OS 驻留在这颗核上 → -EPERM(psci_tos_resident_on)
2. cpu_die                         目标核自己调,发 CPU_OFF,不再返回
3. cpu_kill                        另一颗核轮询 AFFINITY_INFO,确认 OFF

cpu_die 里的 power_state 字段,注释写明现有实现基本不用,填一个 POWER_DOWN 即可。

cpu_kill 最多等约 100ms,是因为 cpu_diecpu_kill 并发:杀得太早会误判「还活着」。查不到 affinity_info 就当成功(没有手段确认,只能假设)。

virt 学习阶段很少做 echo 0 > /sys/devices/system/cpu/cpu1/online。知道下电同样是 PSCI、同样不写复位寄存器,这条就够。


6. 整机电源不在本文件

poweroff / reboot 挂在 drivers/firmware/psci/psci.cpsci_0_2_set_functions()

  • pm_power_off = psci_sys_poweroffSYSTEM_OFF
  • restart handler → SYSTEM_RESET

和本文件的 CPU_ON/CPU_OFF 是同一份契约、同一次 hvc 通道,但是:

本文件 firmware/psci.c
粒度 一颗 CPU 整台机器
调用者 smp.ccpu_ops kernel_power_off / reboot
第 1 个月 要知道「不在这里」 第 3.1 再顺着走

7. 重点(合上文件能用的)

  1. 客户 vs 管家 :Linux 发请求;ATF(virt 上是 QEMU)管 CPU 电源。从核起不来,先查 enable-method、PSCI 节点、固件,不是某个外设 probe
  2. 本文件只做翻译cpu_bootCPU_ONcpu_dieCPU_OFFcpu_killAFFINITY_INFO。发指令的是另一份 psci.c
  3. ATF ≠ U-Boot:U-Boot 管加载;ATF 管 PSCI。virt 上两件都由 QEMU 做。
  4. 核级 ≠ 整机 :开关某一颗核走本文件;关机/重启走 firmware 的 SYSTEM_*
  5. MPIDR + 物理入口CPU_ON 只认硬件编号和 secondary_entry 的物理地址。

相关推荐
是隼人1 小时前
buuctf-pwn PWN2(整数溢出)题解(学习过程持续更新)
c语言·学习·安全·pwn入门·ctf入门
ch3nyuyu2 小时前
驱动第三阶段
linux
LuminousCPP2 小时前
数据结构 - 排序(二):快速排序从错误初版到优化版|双指针划分 + 三数取中 + 小区间插入优化
c语言·数据结构·笔记·算法·排序算法
云飞云共享云桌面2 小时前
钣金制造研发优化:不采购传统工作站,实现 SolidWorks 团队共用服务器开展三维建模
运维·服务器·网络·数据库·3d·制造
竞赛考级题库2 小时前
202606 青少年等级考试C/C++真题一级 建议答题时长:60min
java·c语言·c++
2601_967019512 小时前
服务器SSL配置要点,规避HTTPS访问异常风险
服务器·https·ssl
迷茫、Peanut2 小时前
C语言混合链接
c语言
YUJIANYUE2 小时前
AspFox-类NetBox的ASP+Access迷你单文件服务器V202609
运维·服务器
佳&弥2 小时前
后渗透痕迹清理
服务器·windows·web安全·网络安全