序言
前面一阶段的学习,我掌握了通过ADB或者TF开烧写系统、通过拨码开关设置系统的启动介质,今天我就要来详细探究一下这里面的原理。拨码开关是怎么控制启动介质的选择的,烧写的都是些什么东西?被烧写到了什么地方?芯片内部有怎样的机制去配合这些烧写过程?这都是我们要详细探讨的问题。这些问题其实都是属于一个大问题:Booting Sequence,每一种芯片都有自己独特的Booting Sequence。boot在这里是引导的意思,sequence是连续顺序次序的意思,代表了一种过程,所以这个短语的意思也就是引导过程。今天的内容主要分为如下几个部分:
- 4412的地址映射
- iROM介绍
- BL1介绍
- BL2介绍
- iRAM布局
- bootloader镜像的整体构成
4412的地址映射
下面是4412地址空间的整体的概览,具体每个地址范围内是什么含义,可以自己去看芯片手册
开头64K是给iROM准备的,iROM也就是internal ROM,是一部分是只读存储器。这里面存储了一段程序,是固化的,不用烧写的,这段程序是芯片上电最先执行的一段程序,这段程序主要干了哪些事情呢?请看下图
iROM中的程序首先做一些芯片的初始化工作,然后根据OM引脚的状态(由拨码开关控制)来选择引导介质,从图中我们可以看到有NAND、SD卡、eMMC,OM引脚配置与启动介质的对应关系如下图所示,这些启动介质里存储了u-boot镜像。
我们可以看到,它最后跳到了BL1,BL1是什么呢?这是一段由三星提供的二进制程序,是无法更改的,但这并不意味着它是固化在芯片内部的,我们是需要把它放在启动介质中的,在实际情况中,它是u-boot镜像的一部分。
BL1介绍
前面我们知道了iROM的主要作用就是初始化芯片,根据OM引脚选择启动介质,将BL1从启动介质加载到内部RAM,然后就开始执行BL1,下面我们来看看BL1是什么。
我们肯定会猜到,既然有BL1,那么应该也有BL2,是的没错。实际上BL1的作用就是为了引导BL2,那为什么这样做呢?这其实是出于安全考虑,手册中把这种boot方式叫做:secure boot chain,安全引导链,那么这种引导方式到底安全在哪里呢,看看BL1和BL2的关系就应该明白了。
BL1是芯片相关的部分,BL2是平台相关的部分,BL1是三星提供的二进制程序,BL2是使用者自己写得平台相关的程序,使用者需要向芯片供应商提供他们公钥(由CodeSigner Client产生,同时还会产生一个私钥,由使用者保存),芯片供应商会使用CodeSigner Server为使用者提供的公钥产生secure context data,然后把secure context data 封装在BL1二进制文件中,并把这个带有公钥相关的信息的BL1提供给使用者,使用者会将这个带有公钥的BL1和他们自己的带有私钥的BL2结合在一起。
如下是BL1的二进制结构
下图是BL1的引导过程
BL2介绍
BL2会把OS镜像(其实是u-boot)拷贝到外部的DRAM中,并且会验证OS的完整性,如果我们想对芯片做一些额外的配置,我们可以通过修改BL2来实现。
如下是BL2的二进制结构
下面是BL2的引导过程
iRAM布局
前面我们知道iROM里面由固化的代码,这些代码可以在iROM中直接执行,但是BL1和BL2可不能在SD卡或者EMMC中执行,它们需要被加载到iRAM中执行,iRAM是4412内部的一小块RAM,只有256K。除了BL1和BL2需要RAM之外,iROM中的程序也需要占用一点iRAM。下图展示了iRAM在引导阶段的内存内容布局,两种4412的内存布局在BL1的大小上稍微有点区别,注意一下
bootloader镜像的整体构成
前面我们介绍了芯片的引导过程,从iROM到BL1,再到BL2、最后进入u-boot实现OS的引导,这期间的每一步都是如何精确定位的?这依赖于这些代码之间精确的二进制组织结构,下面我们就来看看这些模块之间的关系,也就是bootloader镜像的二进制结构。
先上图
我们来分析一下这个二进制文件的产生过程
- 使用者用CodeSigner产生两个文件:Exynos4412.prv和Exynos4412.spk,后者给芯片供应商,前者自己留着
- 供应商拿到public key,把它和原始的BL1结合在一起并进行加密,生成一个二进制文件,也就是上图的第一个部分,把这个加密二进制文件给使用者
-为BL2加上Checksum、Exynos4412.prv,最后加上padding形成图中的第二部分 - 用padding补全uboot.bin形成第三部分
- 156K的TrustZone作为第四部分
最终我们需要把它们放到SD卡中或者eMMC中
在SD卡中,需要偏移512B,然后再放置这个bootloader镜像
再eMMC中,具体的boot区域由CSD寄存器确定,但是有两条规则
- BL1应该在boot block得block0
- BL2应该在在BL1后面得连续位置
结束
stay foolish, stay hungry