ARM64 的多核启动流程分析
工作中遇到的多核 ARM CPU 越来越多,总结分享一些多核启动的知识,希望能帮助更多小伙伴。
在 ARM64 架构下如果想要启动多核,有 spin-table 和 psci 两种方式,下面针对这两种启动流程进行分析。
代码版本
boot-wrapper-aarch64 version : 28932c41e14d730b8b9a7310071384178611fb32
linux v5.14
多核 CPU 的启动方式
嵌入式系统的启动的基本流程是先运行 ,然后由 引导启动 kernel,这里无论启动的是 rt-thread 或者是 linux 原理都是一样的。bootloaderbootloader
上电后所有的 都会从 里面开始执行代码,为了防止并发造成的一些问题,需要将除了 以外的 拦截下来,这样才能保证启动的顺序是可控的。CPUbootromprimary cpucpu
【文章福利】小编推荐自己的Linux内核技术交流群:【891587639】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!(含视频教程、电子书、实战项目及代码)


spin-table 启动方法
在启动的过程中, 中有一道栅栏,它拦住了除了 外的其他 。 直接往下运行,进行设备初始化以及运行 。其他 则在栅栏外进入睡眠状态。bootloadercpu0cpucpu0Kernelcpu0
cpu0 在初始化 的时候,会在 里面填入一个地址并唤醒其他 。这时睡眠的 接受到信号,醒来的时候会先检查 这个地址里面的数据是不是有效。如果该地址是有效的(非 0 ),意味着自己需要真正开始启动了,接下来他会跳转到。smpcpu-release-addrcpucpucpu-release-addr
下面我们看看 里面的实现,在 中有如下描述:arm64arch/arm64/boot/dts/xxx.dts
在 中处理了向其他 cpu 发送信号的方法:arch/arm64/kernel/smp_spin_table.c
1、先是获取 release_addr 的虚拟地址
2、向该地址写入从 cpu 的入口地址
3、通过 sev() 指令唤醒其他 cpu
Bootloader 部分以 中的代码做示例,非主 CPU 会轮询检查 mbox(其地址等同cpu-release-addr)中的值,当其值为 0 的时候继续睡眠,否则就跳转到内核执行,代码如下所示:boot-wrapper-aarch64
PSCI 启动方法
另外一种 enable-method 就是 PSCI,依旧先从 kernel 开始分析。先看 文件,里面 节点选择了PSCI 的方法:arch/arm64/boot/dts/mediatek/mt8173.dtsicpu
并且有一个 PSCI 的节点:
在 PSCI 中的节点详细说明请参考文档:kernel/Documentation/devicetree/bindings/arm/psci.txt。在此仅说一下方法 字段。该字段有两个可选值:smc 和 hvc。表示调用 PSCI 功能使用什么指令。smc、hvc、svc 这些指令都是由低运行级别向更高级别请求服务的指令。
和系统调用一样。调用了该指令,cpu 会进入异常切入更高的权限。异常处理程序根据下面传上来的参数决定给予什么服务,smc 陷入 EL3,hvc 陷入 EL2,svc 陷入EL1。在 ARMv8 里面,EL3 总是是安全 状态,EL2 是虚拟机管态,EL1 是普通的系统态。
接下来可以看看 里面的代码,psci_ops.cpu_on 最终调用 smc call:arch/arm64/kernel/psci.c
Bootloader 以 作分析,看 psci.c 里的 psci_call 实现函数,通过 fid 与 PSCI_CPU_OFF 和 PSCI_CPU_ON 相比,找出需要执行的动作:boot-wrapper-aarch64
当然 里也需要同样的定义:
总结
目前比较主流的多核启动方式是 PSCI,一般正式的产品都有 ATF,通过 PSCI 可以实现 CPU 的开启关闭以及挂起等操作。在实际的移植工作过程中,如果有带有 ATF 的 bootloader 那多核移植就相对容易很多,如果没有的话,也可以采用 spin_table 的方式来启动多核。
