文章目录
- 1 基础知识
- 2 BOOT配置
- 2.1 BOOT_CFG配置
- 2.2 BOOT_MODE
- 3 Bootable image
- 3.1 文件格式
- 3.2 Bootable image头的组成
- 3.3 Bootable image的生成
- 3.4 例:BootROM之non-XIP加载过程
- 3.5 例:bin文件分析
1 基础知识
(1)BootROM
BootROM(ROM Bootloader)是芯片在出厂前固化在ROM里的一段Bootloader程序。每次上电的时候都将执行里面的代码,它完成了对于特定引脚上的FlexSPI、SEMC和SDHC接口的初始化,并从这些接口连接到的Flash和RAM中引导程序启动。
当然,对于BootROM来说,它还可以通过IVT中相关字段的配置完成程序的加密和解密等操作,这个将在后续介绍。
(2)Flashloader
Flashloader是一个RT1170的工程。对于BootROM来说,它主要是完成对于程序的启动功能。而对于Flashloader来说,它实现了一些Flash的擦除和烧写函数,当然还有基于熔丝的读取和烧录、加解密等功能。这些功能之所以没有在BootROM中实现,我想大概率是基于成本考虑而决定的。
- 用户可以通过USB1或LPUART1与BootROM和Flashloaer进行通信
(3)eFuse
eFUSE是I.MXRT1170内嵌的一块OTP(One time Programmable
) memory,初始状态下所有bit均为0,仅能被烧写1次。RT1176的eFUSE有8Kbit,分为32个Bank,每个Bank有8个word(1个word为4字节),即32字节。下图0~0x8F为eFUSE的bank word索引地址(index地址)。
这里不详细对eFuse进行介绍,简单地说一下:
- eFuse中部分位的定义在参考手册
26.2 Boot Fusemap
中有介绍,对于所有位的介绍,比如加密启动的一些字段,需要参考Secure Reference Manual
,这个手册需要找FAE要,自己是下载不了的。 - eFuse除了有OTP特性外,还有Lock特性,它包含三层:写保护、覆盖保护和访问保护
- eFuse空间有两类:一类受冗余保护(牺牲一半的空间保存数据的备份以防止数据损坏),一类受ECC保护(可纠正损坏位)
- eFuse空间的读写由RT1170中的
OCOTP
控制器来实现,如果想要修改eFuse,用户可以参考SDK中OCOTP
相关代码自己来实现。也可以通过集成了eFuse烧写的工具:blhost
、sdphost
或MCUBootUtility
(通过Flashloader)来修改。
(4)从外部存储器启动
(1)NOR Flash:可以XIP执行,但也需要BootROM引导完成Nor的初始化及XIP相关配置
(2)Nand Flash:无法XIP执行,由BootROM从Nand拷贝代码到RAM中执行
(3)SDRAM与SRAM:SRAM挂在系统BUS上,无需初始化;而SDRAM挂载存SEMC控制器上,需要初始化。在BootROM中,可以通过DCD字段对SDRAM进行初始化。
2 BOOT配置
2.1 BOOT_CFG配置
前面我们知道,BootROM可以帮助我们从外部存储器中启动程序。但是BootROM需要知道一些信息:启动设备连接在从哪个FlexSPI接口,这个接口上接的是Nand还是NOR或者是EMMC等设备,还有是否需要加密启动等信息。这些信息就BOOT_CFG
引脚来告诉BootROM,这些引脚在硬件上也是固定的,如下图所示。
- 引脚的具体含义,参考手册
10.6 Boot Device
章节。对于不同的外部存储器,引脚的定义都不相同。这个章节对于BOOT_CFG
的介绍实际是eFuseBOOT_CFG
相关位的定义,但这和GPIOBOOT_CFG
的定义是相同的。这是因为eFuse中有和GPIO的BOOT_CFG
相同的定义的位,在eFuse中的BT_FUSE_SEL
位置1时,将使用eFuse中的BOOT_CFG
配置。
2.2 BOOT_MODE
对于I.MXRT1XXX系列单片机来说,上电永远是从BootROM开始启动,而用户可以通过BOOT_MODE[1:0]
决定BootROM程序的不同行为模式。这两个字段由硬件进行配置,它们所对应的引脚是固定的:
总共有四种不同的启动方式,如下图所示:
1、Boot From Fuses模式
在这个模式下,将根据Fuse里的Boot配置来决定从哪个外部存储器Boot,如下图所示。
由上图可以看出:
Internal Boot | Boot from Fuses | |
---|---|---|
BT_FUSE_SEL=0 | BOOT_CFG从GPIO相关引脚中获取 | 从USB的Serial Loader启动(通过USB传输程序) |
BT_FUSE_SEL=1 | BOOT_CFG从eFuse相关字段中获取 | BOOT_CFG从eFuse相关字段中获取 |
2、Serial Downlaoder模式
在此模式下,用户可以与参考手册中指定引脚连接的UART或USB与BootROM进行通信,从而接收程序并在SRAM中运行。该模式主要用来从SRAM中启动Flashloader,用户可以将Flashloader程序烧录,然后与Flashloader进行通信,通过Flashloader里面的函数来对Flash、eFuse等内容进行修改。
- Serial Downloader模式的通讯遵从一定的协议,NXP官方提供了几个相关的工具可用于此通信:
sdphost.exe
、mfgtool
和MCUBootUtility
3、Internal Boot模式(Serial NOR/NAND、Parallel NOR/NAND、SD/eMMC、1bit Recovery SPI NOR)
该模式支持从串行/并行的NOR/NAND Flash、SDCard、EMMC和带1位恢复位的Recovery SPI NOR中启动,这是最常使用的一种启动模式。
在这个模式下,也会参考eFuse中的BT_FUSE_SEL
位来使用不同的配置:
①BT_FUSE_SEL=0
:BootROM将使用BOOT_CFG[x:0] pins
的配置
②BT_FUSE_SEL=1
:BootROM将使用Fuse中的配置
- 我们可以在确定了启动设备后,将
BT_FUSE_SEL
烧录为1,然后将GPIO已经测试过没有问题的BOOT_CFG
位烧录到eFuse中对应的BOOT_CFG
位中,这样启动设备就不可能被硬件上更改了。 - 如果
Internal Boot
失败,比如用户的BOOT_CFG
配置有错,系统将进入Serial Downlaoder模式。
3 Bootable image
前面BootROM帮我们初始化了外部的存储器,可以从里面获取到我们写的程序。但是程序的大小是多少、需要链接到哪里运行呢?这就需要我们在生成的程序最前面加一个头来让BootROM知道这些信息,从而完成程序的拷贝和跳转。
3.1 文件格式
对于不同的IDE来说,编译后生成的程序的文件格式都不太一样,常见的有以下几种:
AXF
:用于基于ARM的微控制器。它包含可执行代码、数据和调试信息。AXF文件通常在开发和调试过程中使用HEX
:由十六进制数及其对应的内存地址组成,可以将程序解析和编程到目标设备的内存中S19
:以特定格式的ASCII字符表示二进制数据。S19文件包含数据和内存地址,常用于编程旧的微控制器和EEPROMELF
:包含可执行代码、数据和其他加载和执行程序所需的信息,可用于调试、分析和部署到目标设备SREC
:类似于S19的文件格式。它以ASCII字符表示二进制数据,但遵循不同的格式BIN
:BIN文件是直接包含可执行机器代码的二进制文件。它们通常用于以原始二进制格式存储最终编译的代码。
不管什么格式,都是为不同下载器或者调试而服务的,经过解析后下载进MCU内部FLASH的数据还是bin格式。
3.2 Bootable image头的组成
以下偏移均以NOR Flash为例,对于Nand Flash来说,有略微的不同,但大致相同。
1、FCB
(FlexSPI Configuration Block
):偏移0x400
可选,用于Serial/Parallel NOR FLASH。其数据结构随着Flash的接口的不同而不同,用来存储FLASH的特性参数。因为BootROM需要兼容不同的Flash,所以BootROM上电会使用比较通用的、低速的配置来初始化FLASH。那如果我们希望Flash能工作在更高的频率下,就可以通过此字段保存配置信息,BootROM会根据此字段重新配置Flash。
- 实际上0x0处和0x800处还有关于加密启动的相关字段,这里没有使用加密,故忽略这些字段。参考我的这篇文章:I.MX RT1170加密启动详解(1):Encrypted Boot image组成
2、IVT
(Image Vector Table
):偏移0x1000
必选的与FLASH无关的structure,IVT中记录了Application、DCD、BD、CSF的位置信息,与BootROM加载启动有关。IVT大小固定为32byte,数据结构如下:
typedef struct _ivt_
{
uint32_t hdr;
uint32_t entry;
uint32_t reserved1;
uint32_t dcd;
uint32_t boot_data;
uint32_t self;
uint32_t csf;
uint32_t reserved2;
} ivt;
具体每个字段的含义后面实例分析时会解释,有实例也更好理解。
3、BD
(Boot Data
):偏移0x1020
必选的与FLASH无关的structure,BD中记录了Bootable image的起始地址与总长度,其大小固定为16byte,数据结构如下:
typedef struct _boot_data_
{
uint32_t start; /* boot start location */
uint32_t size; /* size */
uint32_t plugin; /* plugin flag - 1 if downloaded application is plugin */
uint32_t placeholder; /* placehoder to make even 0x10 size */
} BOOT_DATA_T;
4、DCD
(Device Configuration Data
)
可选的用于初始化SEMC接口的配置信息,主要用于SDRAM的初始化,它由寄存器地址和数据对组成,有三种指令类型:写指令、检查指令和空指令。可以在MCUXPresso IDE中配置DCD字段:
- 可以看到是可以初始化任意寄存器的值的,所以还可以用来初始化HyperRAM
- Bootable image中还有一个
XMCD
字段可以用来对HyperRAM进行初始化,具体参考reference manual
5、Application Binary
:偏移0x2000
即用户编译出的程序,偏移位置固定为0x2000。
6、CSF
(Command Sequence File
)
主要用于安全启动的认证相关特性。
7、KeyBlob
主要用于安全启动的加密相关特性。
- 对于安全启动加密相关内容,将在后续博客中介绍
3.3 Bootable image的生成
(1)IDE:MCUXPresso IDE、IAR、Keil
通过在链接脚本中声明IVT
、Boot Data
和DCD
等段,然后在C文件中声明其数据结构对应的结构体,再用attribute
关键字将对应结构体变量链接到指定段中。
- 注意需要打开一些宏定义,如使用DCD,则需要声明
XIP_BOOT_HEADER_ENABLE = 1
(2)elftosb.exe
elftosb.exe
是NXP提供的一个软件,可以用来生成Bootable image,当然还有一些其它的功能,比如生成可以与Flashloader能识别的指定协议的镜像文件,可以实现修改eFuse、烧录Flash、AES固件加密等功能。
对于生成Bootable image,其命令格式固定如下:
elftosb.exe -f imx -V -c config_application.bd -o ivt_application.bin application.out
-
ivt_application.bin
:最终生成的Bootable image -
application.out
:编译链接生成的ELF文件 -
config_application.bd
:用户配置文件
.bd
指示elftosb如何在binary基础上添加IVT
、BD
等其他信息数据从而形成Bootable image,在Flashloader目录下给了很多bd文件示例,只需在某一个bd文件基础上修改即可
(3)MCUBootUtility
自动检测有没有IVT、BD头,没有的话将根据镜像文件自动填充该字段。
3.4 例:BootROM之non-XIP加载过程
假设程序保存在Nand Flash,然后要在ITCM
(0x00000000~0x20000000)运行,下图显示了BootROM加载image的四个阶段:
(1)Bootable image存储在Nand Flash中
(2)BootROM从Nand Flash读取Bootable image前4KB(包含IVT
和BD
)数据到OCRAM
(0x20240000~0x202C0000)
(3)为了避免重复读取,BootROM会把读取的4KB数据先复制到ITCM
(4)BootROM根据IVT
和BD
的字段,获得程序的偏移和大小,将剩下的image从Nand Flash中读到ITCM
中
3.5 例:bin文件分析
以NOR Flash,程序XIP执行为例,对SDK中的evkmimxrt1170_freertos_hello_cm7
编译生成的bin文件进行分析:
1、FCB
(FlexSPI Configuration Block
):偏移0x400
可选的,格式参考手册10.6.3 Serial NOR and NAND Configuration based on FlexSPI Interface
,主要是Flash一些参数的声明、时钟频率的初始化还有保存Flash读写时序的FlexSPI LUT(Look Up Table
)
2、IVT
(Image Vector Table
):偏移0x1000
其中TAG
为d1,IVT Length
为0x2000,version
为0x41,entrypoint Address
为0x300024e9(Reset_ISR
的地址),DCD的绝对地址为0x30001030,Boot Data链接地址为0x30001020,IVT链接地址为0x30001000
3、BD
(Boot Data
):偏移0x1020
其中镜像的绝对起始地址为0x30000000,程序镜像的大小为0x1000000(实际保存的是Flash的大小)。
4、DCD
:偏移0x1030
前面在IVT中指定了DCD的地址为0x30001030(绝对地址),BootROM就会从这个地址读取DCD。其中Tag
为0xd2;整个DCD的长度为0x4b8(这个大小为大端存储),即结束地址为0x14E8;版本为0x41。也就是说从0x1040~0x14E8就是DCD配置字段。
- 前面有提到,XMCD可以用来hyperRAM,实际上是将其FlexSPI配置块FCB填充到0x1040处,也就是说BootROM不能同时初始化DCD和XMCD字段。