目录
1. 硬件上电
2. ATF运行
3. Linux启动
3.1 内核启动start_kernel
3.2 平台启动setup_arch
3.4 DTS初始化psci_dt_init
3.5 系统rest创建kernel_init线程
3.6 SMP初始化smp_init
3.7 PSCI接口psci_cpu_on
3.8 SMC返回secondary_entry
系统开机牵扯到:“我是谁,我从哪里来,要到哪里去”的问题。在冰冷的硬件电路板上死气沉沉,突然一声霹雳,电源键被按下了,从此世界开始有了生机。首先就是硬件上电过程,之后就是固件软件的运行,最后就是操作系统例如Linux的运行。这其中需要涉及一系列的技术,本篇文章尽可能的去介绍。
1. 硬件上电
如上图的一个电路板,连接好12V电源后,手动拨动开关到供电的位置,这个时候会发生什么?
首先就是供电芯片例如PMIC,会对电源轨(按照功能和电压值区分的group)按照设计的顺序(Logical)进行供电,这时候各个硬件器件就来电了。具体可以查看芯片手册里面有说明,需要硬件工程师根据电路板的需求和器件用电量进行设计。
然后时钟模块这时候也开始工作了,为什么需要时钟?这就像心跳,要想CPU工作一次,就需要给一次电压电流,然后拿到计算结果,进行下一次的计算就需要再给一次电压电流。时钟就周期的提供电压电流,然后CPU就有了频率,当然主频越高干活越快。给SoC上的核心通过PLL给各个硬件子系统提供了clock后,这时候就需要一个开关核心(CPU/MCU),然后这个核心就开始工作了,这个开关就是复位信号。
某一个CPU或者MCU核会作为天选之子先硬件直接启动,启动后运行其上的软件,在软件里面控制其他核的复位,从而拉起来其他核心运行。这个天选之子一般在没有M核(SCP)的系统里面就是A核。
有此可见让一个核心工作起来的核心供应就是电压和时钟。除了天选之子,其他核心的启动都是由软件来控制的了。
2. ATF运行
提到ATF就有一个SecureBoot的概念,为了防止黑客篡改程序,什么样的程序最安全?答案就是存放在ROM里面的,不可改变,除非你把这个ROM芯片从板子上拆下来,换上自己的越狱。对于现代SoC,这个ROM做到芯片内部了,没法拆了,只能认命,防刷机神器啊。
这里扯一个话题:水货。什么是水货,首先从水路来的,水路就是海外来的,由于世界各国的消费水平,关税,地方保护等差异比较大,导致在世界上各国销售的电子产品价格差异很大,我们常说的日版iPhone,港版iPhone等价格比国内的低很多,还有各国的运营商的网络制式也不一样,一般销往某个国家的电子产品的版本都需要进行软件定制,然后售价不一样。这里面有个巨大的商机,就是明明硬件一模一样,为啥有点地方卖的贵,可以把便宜的地方的货拿来贵的地方卖,当倒爷啊。能直接用还好,但是大多面临软件版本不一样的问题,这也难不倒,我可以刷机啊,这就是水货了吧。往小了说比如一个芯片供应商,给客户A和B供货,价钱也会不一样,例如A企业风口行业效益好暴利就卖贵一点,B企业传统行业效益不一般贵了买不起,那也得养着啊,蚊子少但是多了也是肉。这里面肯定要防着企业A通过B拿货,或者企业B拿货后转卖了。SecureBoot就是这么现实的需求下诞生的,别扯什么黑客,就是分钱分的不对,这个糟老头,坏的很。
之前的文章:ARM ATF入门-安全固件软件介绍和代码运行里面有固件启动的流程图和开源代码。关于SecureBoot就是BL1 ROM固件里面存的有BL2的秘钥,BL2如果被篡改就不加载,那就不能开机了。同样这样一级一级的
BL1-->BL2-->BL31-->BL32-->BL33-->Linux,任何一个固件和操作系统都改变不了,一环出错就启动不起来,彻底把软件绑定死,不能刷机了。
BL1阶段
-
最初ROM中的BL1开始运行,主要初始化并读取启动pin引脚,启动介质为UFS,继续初始化UFS pad后,从UFS加载BL2程序到RAM,并验签启动(BL2的验签是通过软件验签实现)
BL2阶段
-
BL2开始运行,加载并软件验签HSM后启动HSM。(提前设置好HSM时钟or 默认时钟);
-
等待HSM启动完成后,就可以使用HSM验签。
-
加载验签其他fimware,例如SoC里面集成的AI模块,NPU、ISP等
-
BL2通过访问CRU设置DDR时钟,执行DDR初始化,并运行DDR training后,DDR可被正常访问;
-
BL2加载BL31、BL32、BL33并运行BL31
BL31阶段
-
等待PMU初始化完成,PMU接管对时钟复位的操作;
-
BL31其他初始化
-
BL31作为EL3最后的安全堡垒,它不像BL1和BL2是一次性运行的。如它的runtime名字暗示的那样,它通过SMC指令为Non-Secure持续提供设计安全的服务,在Secure World和Non-Secure World之间进行切换。它的主要任务是找到BL32,验签,并运行BL32。
BL32
BL32是安全OS,是运行时,运行时可以独享系统所有的资源。BL32和Linux同一时刻只能一个运行,是两个操作系统,可以进行切换。为什么BL31也是运行时,但是BL31不是OS,因为BL31虽然在某一时刻独占系统资源,也是运行时,但是其没有调度等OS的特点,只是一个运行时服务。
一般在BL32会运行OPTee OS + 安全app,它是一个可信安全的OS运行在EL1并在EL0启动可信任APP(如指纹信息,移动支付的密码等),并在Trust OS运行完成后通过SMC指令返回BL31,BL31切换到Non-Seucre World继续执行BL33。一个开源代码:https://github.com/OP-TEE
BL33也就是Uboot阶段
Uboot不是运行时,也就是完成它自己的使命就再也不工作了。U-Boot可以提供引导、配置硬件、加载内核、初始化设备等功能,使得嵌入式系统能够正常启动并运行。
Linux阶段
-
PMU及CLock、Power Domain初始化;
-
NPU等固件交互驱动初始化
-
其他设备初始化
-
根文件系统加载
-
上层服务加载运行
下面介绍两个经典的方案,一个是NXP的一个是ARM SCP的
-
NXP SCU与SCFW固件方案
以imx8qm平台为例,imx8qm引入了操纵资源分配、电源、时钟以及 IO 配置和复用的新概念。由于这种新芯片的架构复杂性,系统中添加了一个系统控制器单元 (SCU)。SCU 是 Arm Cortex-M4 内核,是 imx8qm设计中第一个启动的处理器。
为了控制 SCU 的所有功能,NXP创建了SCFW。SCFW 在移植套件中分发。SCFW 的第一个主要步骤是配置 DDR 并启动系统中的所有其他内核。引导流程如下图所示:
imx8qm启动顺序涉及 SCU ROM、SCFW、安全控制器 (SECO) ROM 和 SECO FW:
•复位时,SCU ROM 和 SECO ROM 都开始执行
•SCU ROM 读取启动模式引脚
•SCU ROM 从引导介质加载第一个容器;这个容器总是有SECO FW,使用 NXP 密钥签名
•SECO FW 加载到 SECO 紧耦合存储器 (TCM)
•SCU通过专用 MU 向 SECO ROM 发送消息以验证和运行 SECO FW
•SCU ROM 从引导介质加载第二个容器;此容器始终具有SCFW,并且可以使用客户密钥进行签名
•SCFW加载到 SCU TCM
•然后 SCU ROM 将配置 DDR
•SCU ROM 将启动 SCFW
从这一点开始,SCFW 接管并将任何image加载到 Arm Cortex-M 或 Cortex-A 内核。
-
ARM SCP固件方案
系统控制处理器(system control processor,简称SCP)一般是一个硬件模块,例如cortex-M0微处理器再加上一些外围逻辑电路做成的功耗控制单元。SCP能够配合操作系统的功耗管理软件或驱动,来完成顶层的功耗控制。
SCP固件是通过ATF中BL2过程加载的,启动过程如下:
ATF的代码这里就不分析了,可以参考下面资料里面的分析:
关于ATF启动的文章(知乎lgjjeff,写的很好):
https://zhuanlan.zhihu.com/p/520039243
关于BL32 OPTEE的文章:
https://zhuanlan.zhihu.com/p/553490159
3. Linux启动
估计大多读者还是对Linux有兴趣,这里对代码进行一下详细的分析。