内容总结自 B 站 Up【蛋饼嵌入式】我提着鞋带拎自己?嵌入式芯片启动过程全解析,彻底理解 bootloader
当你按下电源开关的那一瞬间,第一行代码如何在芯片上运行起来的呢?嵌入式软件代码需要一定的方式烧录到芯片中才能运行,除了物理刻蚀,无论是通讯端口的传输或者调试端口的烧录,都需要驱动程序的支持。所以说是程序烧录了程序,软件启动了软件。
这就像自己提着自己的鞋带,把自己拎起来。靴子(Boot),鞋带(Strap),提鞋带(Loader)。这就是Boot Strap Loader
的命名来源。通常称BootLoader
,中文翻译为自举。
BootLoader
是芯片最初运行的代码吗?当然不是,其实每一块芯片在出厂时都在其内部的ROM
中,烧录了它最基础的软件。CPU 搬运并运行的第一条代码的默认位置,就在ROM
的地址空间。所以一切的起始都在硬件上。
以 X86 架构的鼻祖 8086 芯片为例,按下开关的一瞬间,芯片 Reset 引脚接收到了电平跳变,在一连串电路的作用下,代码段寄存器CS
恢复成0XFFFF
,指令指针寄存器IP
恢复成0X0000
,他们组合成 20 位的地址正好等于 ROM 中存放第一条代码的位置。之后取出这里的指令在跳转到别处。
ARM 架构的芯片也是类似的过程,对于 32 位的芯片,通电后,PC
指针寄存器复位至零地址,随后从中断向量表表头的 reset 向量处获取下一个跳转的地址。这时候的代码已经以二进制形式存储,处理器可以直接搬到自身缓存中运行。有了这部分代码,就能跳转到存放有更多更复杂的代码的地址。执行硬件自检,基本的初始化操作,提供基础的输入输出支持。之后可以将操作系统从外部的存储空间加载到内部。代码就这样接力式的流转起来。
所以我们把出厂就写在ROM
里,负责启动后续用户软件的软件,称为Boot ROM
或者ROM Code
。现在不一定是用只读存储器(Read Only Memory),但是至少是一块掉电不易失的存储器,现在主要用EEPROM
,NOR Flash
。我们一般没有权限修改它,但是它也不完全是黑盒,大部分芯片都会有外部启动配置引脚,通常是以拨码快关的形式。对于 PC 机来说,Boot ROM
就是我们常说的BIOS
,它也有启动配置途径。而且提供了交互界面,用于配置部分功能和选择后续的引导设备。
除了芯片自带的Boot ROM
,还需要再给自己实际的应用程序,写一个二次引导代码或者 N 次引导代码,用作操作系统,文件系统加载等等。我们所说的Bootloader
时,其实大多数就是这样的二次引导代码。
这些事其实Boot ROM
它也能做,但是Boot ROM
实现的功能和配置方法不灵活,但是Bootloader
是开发人员可以而完全控制的引导代码。
在设计Bootloader
时,MCU
的引导步骤就开始和嵌入式 Linux 或者 PC 有所不同。这一定程度与芯片架构所采用的的存储方案有关。
先来说MCU
,与SOC
相比MCU
的主要特征是单核和或多核同构的微处理器,单核或多核同构,主频 < 1GHz,没有MMU
内存管理单元,只能运行实时操作系统。常见MCU
内核:
程序的主要运行介质为NOR Flash
,因为和RAM
一样有分离的地址线和数据线。并且可以以字节长度精确寻址,所以程序不需要拷贝到RAM
中运行的。
以英飞凌家的 TC27x 系列 MCU 为例,上电后的默认取址位置是0x8FFF 8000
,这就是他的Boot ROM
在NorFlash
中的地址。并且这块Boot Rom
分为SSW
,BSL
,TF
。
SSW 每次上电必须运行,他会根据写在program flash
,PFO
地址的前 32byte 中的配置字,来决定SSW
执行完的跳转地址。我们可以选择一个合适的跳转地址,比如0x80000020
,放上自己写的Bootloader
。也可以选择不跳转,运行厂家提供的Bootloader
(BSL)。
MCU
下的Bootloader
主要完成的事情有以下:
- 关闭看门狗,初始化中断和 trap 向量表,进行时钟和外设初始化,让芯片正常运行起来。
- 提供
CAN
,UART
,ETH
等用于通讯功能的驱动,能够接收外部数据传输请求。 - 提供
FLASH
的读写与擦除驱动,设计服务来对通讯端口接收到的更新代码进行校验、存储,以及跳转操作系统或后续应用程序代码。 - 如有必要,还会开发一些基础诊断服务,串口交互程序等等。
那么运行 Linux 的SOC
和 PC 的这一过程有何不同呢。还是先看存储方案,运行嵌入式 Linux 的 SoC。一般将它的操作系统,文件系统和他的应用程序放在nand flash
中。运行代码前,现将代码搬运到SRAM
中,相比MCU
多了一道步骤。
对于SOC
的Boot ROM
和 PC 的BIOS
而言,他们结束运行前的最终任务,是将某些代码从nand flash
搬运到SRAM
中,其中最重要的内容就是Boot Loader
。
而一般SOC
的Bootloader
,又分为SPL
(Secondary Program Loader)和uBOOT
两个阶段。SPL
的 Secondary 就是相对于BootROM
而言,他就像是接力赛中的第二棒选手。SPL
会初始化更大空间的外部DRAM
,再把uBoot
搬运到外部DRAM
中去运行。uBoot
作为第三棒选手,开始运行它的初始化程序。之后再根据系统环境变量,将 OS 内核搬运到外部DRAM
中去运行。OS 再完成根文件系统的加载等等等等。