《S32G3系列芯片——Boot详解》系列——Boot过程相关镜像详解:IVT、DCD、App Boot镜像到底是什么?
- 一、概述
- 二、 IVT镜像
- 2.1 IVT header的结构
- 2.2 BCW和LCW的结构
- 2.3 最后16个字节GMAC的概念
- 三、DCD镜像
- 3.1 DCD相关的基本概念
- 3.2 DCD header的结构
- 3.3 DCD指令
- 3.3.1 写数据指令(Write Data)
- 3.3.2 检查数据指令(Check Data)
- 3.3.3 空指令指令(NOP)
- 四、Self-Test镜像
- 4.1 自检的启动条件
- 4.2 自检流程
- 五、应用程序启动镜像(App Bootloader)
- 5.1 镜像结构
- 5.2 RAM start pointer和RAM entry pointer
- 5.3 μSDHC启动场景下的注意点
- 六、Serial Boot镜像
- 七、结语
学习更多Boot相关内容,获取HSE基于IVT安全启动方案?>>>>>>>>> 返回专栏总目录 《S32G3系列芯片——Boot详解》<<<<<<<<<
Tip📌:鼠标悬停双虚线关键词/句,可获得更详细的描述
一、概述
S32G3系列芯片的正常启动需要一份有效的程序镜像,主要包括以下部分:
- Image Vector Table (IVT):这是BootROM从启动设备读取的第一个镜像。IVT包含了启动过程中BootROM使用的必要数据,如各个镜像的入口点、指向设备配置数据(DCD)的指针和其他指针。
- Device Configuration Data (DCD):提供了对设备进行配置的数据。
- Self-Test DCD:用于执行自测。
- Application boot image:用于启动应用程序的镜像(BootLoader),通常芯片使用方会自行开发这个镜像,可以把它类比为linux中的uboot。
- Serial boot image:包含通过串行接口启动时需要的数据,实际上就是能跑在SRAM里面的App数据。
在详细认识每个镜像前,先简单了解主分区和备份区的概念:
在S32G3系列芯片中,镜像的存储结构设计采用了主分区(Primary Partition)和备份区(Backup Partition)的概念,旨在增强系统的可靠性和故障恢复能力。主分区包含当前运行的系统镜像,它是系统启动和运行时主要读取和执行的代码和数据区域。而备份区则存储了系统镜像的一个副本,用于在主分区损坏或更新失败时恢复系统。
这种设计允许系统在遇到软件故障或损坏时,自动或通过用户指令切换到备份区的镜像,从而快速恢复到一个已知良好的状态,减少系统的停机时间。此外,这也支持了更为安全和灵活的软件更新机制,因为更新可以首先在备份区进行,只有当新更新被验证无误后,才将其作为主要运行镜像。这大大降低了软件更新导致系统不稳定或不可用的风险。
二、 IVT镜像
IVT的位置在BootROM中是有固定要求的,BootROM启动后会直接从这个固定的特殊地址读取这个IVT镜像。对于不同类型的启动设备,IVT距离设备基地址的偏移如下所示:
BootROM在执行引导时,根据启动设备的不同(QuadSPI启动或μSDHC启动),对于指向设备配置数据(DCD)、自检DCD、应用程序镜像以及HSE_H固件镜像的指针有不同的对齐要求。对于QuadSPI启动,这些指针需要是8字节对齐的;而对于μSDHC启动,这些指针则需要是512字节块对齐的。
在S32G3系列芯片的启动过程中,IVT包含了重要的启动配置信息和指向各镜像代码入口指针。IVT镜像的结构如下所示:
地址 | 大小(字节) | 字段名称 | 备注 |
---|---|---|---|
0h | 4 | IVT header | 4字节镜像头标识,常称为镜像的Magic number |
4h | 4 | 保留未使用 | 保留未使用 |
8h | 4 | Self-Test DCD pointer(primary) | Self-Test DCD镜像的位置(主区) |
Ch | 4 | Self-Test DCD pointer (backup) | Self-Test DCD镜像的位置(备份区) |
10h | 4 | DCD pointer(primary) | DCD镜像位置(主分区) |
14h | 4 | DCD pointer (backup) | DCD镜像位置(备份区) |
18h | 4 | HSE_H firmware flash memory start pointer(primary) | HSE_H固件的位置(主分区) |
1Ch | 4 | HSE_H firmware flash memory start pointer (backup) | HSE_H固件的位置(备份区) |
20h | 4 | Application boot code flash memory start pointer(primary) | 应用程序bootloader的位置(主分区) |
24h | 4 | Application boot code flash memory start pointer (backup) | 应用程序bootloader的位置(备份区) |
28h | 4 | Boot configuration word | boot的配置信息 |
2Ch | 4 | Life cycle configuration word | LC配置信息 |
30h | 4 | 保留未使用 | 保留未使用 |
34h | 32 | Reserved for HSE_H firmware | 专门为HSE_H固件保留的字段 |
54h | 156 | 保留未使用 | 保留未使用 |
F0h | 16 | Galois Message Authentication Code (GMAC) | IVT镜像前240字节的GMAC值 |
2.1 IVT header的结构
4个字节的固定值,含义如下:
2.2 BCW和LCW的结构
除了前面提到的IVT中存在各个镜像的entry pointer外,还有两个内容需要大家关注下,分别是Boot configuration word(BCW)、Life cycle configuration word(LCW)。
——BCW的结构
4个字节BCW的32位功能划分如下:
各位域字段区间含义如下:
位域 | 描述 | 选项 |
---|---|---|
31:4 | 保留 | — |
3 | BOOT_SEQ 安全启动模式 | 0 - 非安全启动。BootROM不执行应用程序镜像认证。 1 - 安全启动。HSE_H固件在认证后执行应用程序镜像。 |
2 | SWT 启动目标看门狗 | 0 - BootROM不配置SWT_0 1 - BootROM在启动目标启用之前,用默认超时启用SWT_0 |
1:0 | BOOT_TARGET 选择启动的目标核 | 00 - Cortex-M7_0 01b - Cortex-A53_0 10 - 保留 11 - 保留 |
——LCW的结构
4个字节BCW的32位功能划分如下:
各位域字段区间含义如下:
位域 | 描述 | 选项 |
---|---|---|
31:24 | 保留 | — |
7:4 | IN_FIELD | 0101 — 将生命周期状态推进到IN_FIELD。此字段值优先于OEM_PROD字段值。其他字段值将被忽略。 |
3:0 | OEM_PROD | 1010 — 将生命周期状态推进到OEM_PROD。其他字段值将被忽略。 |
2.3 最后16个字节GMAC的概念
IVT(Image Vector Table)镜像中的GMAC(Galois Message Authentication Code)是一种基于Galois Field算法(通常是GF(2^128))的消息认证码,用于验证数据的完整性和真实性。
IVT镜像最后16字节的GMAC是在镜像创建过程中计算出的一个值,它用于在系统启动过程中验证镜像的完整性。具体来说,启动前,硬件或者引导程序会使用相同的算法和密钥对当前的镜像内容进行计算,生成一个GMAC值,并将其与镜像中存储的GMAC值进行比对。如果两个值匹配,说明镜像未被篡改,系统可以信任并执行该镜像;如果不匹配,则系统可能会拒绝启动该镜像,以防止潜在的安全风险。
这种机制提供了一种安全措施,确保了镜像在制作后至执行前,没有被未经授权的第三方修改,是系统安全启动的一个关键部分。
三、DCD镜像
3.1 DCD相关的基本概念
当设备复位后,所有模块寄存器都会被设置成默认值。这些默认设置通常不是最佳的配置,可能不会发挥出系统的最优性能。此外,有些外设在使用前必须进行配置。
DCD,即设备配置数据(Device Configuration Data),是BootROM用来配置设备上的外设的配置信息的。这些配置信息包含在DCD镜像中。BootROM通过在IVT中的指针来确定DCD镜像的位置。
DCD镜像的最大尺寸是8192字节(8k)。这意味着配置数据的总大小不能超过8192字节。BootROM在启动过程中会读取IVT中的DCD指针,然后根据这些配置信息来初始化外设,以确保外设能按照预期的方式工作,例如设置时钟、电源管理、接口模式等,从而达到系统的最佳性能。
DCD镜像结构如下所示,它主要是由一系列DCD命令组成的大端字节序的数组,也就是下表的第二行:
3.2 DCD header的结构
3.3 DCD指令
上面提到DCD镜像实际上是一个由允许的DCD命令组成的大端字节序的数组,主要包括以下三种类型的指令:写数据(Write Data)、检查数据(Check Data)、空指令(NOP)。
3.3.1 写数据指令(Write Data)
"Write Data"命令是一种用于将数据写入到目标地址的控制指令。该命令允许你将单字节、双字节或四字节值(或位掩码)写入到一系列相应的目标地址中。该命令的结构是一个大端(big-endian)字节数组,这意味着在这个数组中,数据的高位字节存储在低地址上,而数据的低位字节存储在高地址上。指令格式如下所示:
其中各字段的含义进一步解释如下:
命令字节 | 描述 |
---|---|
Length | 包括头部在内的整个写数据命令结构体的大小。 |
Parameters | 该字节被划分为若干字段,详见下文。 |
Address | 数据将被写入的目标地址。可以指定一个或多个地址和数值/掩码对。相同的字节和标志参数适用于命令中的所有位置。 |
Value/Mask | 要写入地址的数据值或位掩码。可以指定一个或多个地址和数值/掩码对。相同的字节和标志参数适用于命令中的所有位置。 |
其中Parameters字节的结构如下所示:
位域 | 描述 | 选项 |
---|---|---|
7:5 | 保留 | — |
4 | Data Set | 状态位,显示目标位是否被成功覆写。 0 - 目标地址的位未被覆写 1 - 目标地址的位被覆写 |
3 | Data Mask | 允许覆写目标地址的位。 0 - 所有位都可以被覆写 1 - 只有特定位可以被覆写 |
2:0 | Bytes | 目标位置的宽度(以字节为单位)。 001 - 1字节 010 - 2字节 100 - 4字节 |
成功执行“Write Data”命令时,该命令将根据Data Mask和Data Set值按照下表所示的方式向每个目标地址写入数据:
在使用“Write Data”命令时,BootROM将执行一系列检查,以确保数据写入操作的有效性和安全性。下面是当处理写地址/值对列表时BootROM执行的检查:
-
地址对齐性检查
BootROM会检查目标地址是否与在“参数字节”(Parameters byte)的Bytes字段中指定的数据宽度具有相同的对齐。地址对齐意味着,例如,如果你试图写入一个四字节(32位)的值,目标地址必须是4的倍数。如果地址没有正确对齐,BootROM不会写入任何值。 -
数值大小和位掩码宽度检查
BootROM还会检查写入的值是否超出了在Parameters byte的Bytes字段中指定的数据宽度所允许的大小,或者位掩码是否宽于允许的宽度。如果任何值太大或任何位掩码太宽,BootROM不会写入任何值。 -
目标地址范围检查
另外,BootROM会检查目标地址是否位于允许的范围内。不是所有的内存区域都是可以让用户程序写入的。某些区域可能是受保护的,有的可能是未映射的。如果任何地址不在允许的范围内,BootROM不会写入任何值。
关于SRAM的特别说明,SRAM在初始化之前不能使用“Write Data”命令写入数据,这是因为SRAM在某些系统中是有64位ECC(错误校正码)保护的。在SRAM初始化完成之前,如果写入数据,将会触发ECC错误。SRAM初始化过程会确保每个存储位置有正确的ECC值,以便后续的读写操作不会产生ECC错误。因此,确保SRAM已经通过适当的过程初始化并设置好ECC值是非常重要的步骤。
3.3.2 检查数据指令(Check Data)
“Check Data”命令是一种用于从源地址测试特定的1字节、2字节或4字节位掩码的指令。与写数据操作类似,这个命令的结构同样是一个大端(big-endian)字节数组。其结构如下所示:
其中各字段的含义进一步解释如下:
命令字节 | 描述 |
---|---|
Length | 整个检查数据命令结构(包括头部)的大小。用于确定可选的计数(Count)。 |
Parameters | 该字节被划分为若干字段,详见下文。 |
Address | 要测试的源地址。 |
Mask | 要测试的位掩码。 |
Count | 可选的轮询计数。如果没有指定值,此命令将无限期轮询,直到满足退出条件。对于有限的值,此命令轮询Count次。 如果Count = 0,此命令表现为NOP(无操作)命令。 |
其中Parameters字节的结构如下所示:
位域 | 描述 | 选项 |
---|---|---|
7:5 | 保留 | — |
4 | Data Set | 启用目标地址的位检查。 0 - 目标地址的位被忽略 1 - 检查目标地址的位 |
3 | Data Mask | 在Data Set字段设置为1时,使能部分/全部位的检查。 0 - 检查掩码中的所有位 1 - 在目标地址检查掩码中的任何位 |
2:0 | Bytes | 目标位置的大小(以字节为单位)。 001 - 1字节 010 - 2字节 100 - 4字节 |
此命令通过不断轮询直到满足退出条件或达到轮询计数。如果在达到轮询计数之前退出条件没有得到满足,那么这个操作会被跳过。退出条件由Data Mask和Data Set值确定。执行逻辑如下所示:
以下是“Check Data”命令无法读取字段的原因:
-
地址对齐性问题
如果地址没有与在参数字节(Parameters byte)的Bytes字段中指定的数据宽度相同的对齐,那么值不会被读取(即对于给定的数据宽度,只有当地址正确对齐时,才能保证数据的正确读取)。例如,如果你试图读取一个4字节的值,那么地址必须是4的倍数。 -
掩码宽度问题
如果掩码宽度超出了在参数字节的Bytes字段中指定的数据宽度所允许的范围,那么值也不会被读取。这意味着,掩码必须适用于指定的数据宽度内,才能正确执行测试。
这个“Check Data”命令的使用场景包括检查硬件设备的状态寄存器,确认特定的位是否已经被设置或清除,这在等待设备就绪或检测特定事件发生时特别有用。通过指定要检查的位(通过Data Mask)和期望的位值(通过Data Set),可以精确地控制和测试所需的条件。
3.3.3 空指令指令(NOP)
该指令是个4字节的大端序的数组,没什么实际作用,其结构如下所示:
四、Self-Test镜像
BootROM提供的自检功能是在设备经历电源开启复位(POR)后,用来确保设备正确运行的一种机制。这一功能对于验证系统完整性至关重要,并且能够在早期检测到故障,从而使系统采取纠正措施或阻止其启动进入故障状态。
4.1 自检的启动条件
- 设备必须刚完成电源开启复位(POR)。
- 自检完成状态(ST_DONE)在管理控制寄存器组(MC_RGM)中未被设置。这个标志用来指示自检是否已经运行过,以避免在非POR的后续复位中不必要地重新运行。
4.2 自检流程
- 验证自检DCD镜像头:BootROM首先验证自检镜像的头部,确保它是有效的。
- 将自检DCD镜像复制到内部内存:如果头部有效,BootROM将镜像复制到内部内存中执行。
- 认证镜像:如果生命周期(LC)状态是OEM_PROD或IN_FIELD,且IVT_AUTH设置为1,并且未启用外部控制,则BootROM会认证镜像,确保其来源可信。(这个步骤是安全启动中的功能)
- 执行自检命令:执行自检镜像中的命令。最后一个命令应该通过设置自检控制单元2(STCU2)中的RUNSW[RUNSW]为1来触发开始自检。
Tip📌:
STCU2中的看门狗超时也会导致ST_DONE assert,并且破坏性复位事件不会清除ST_DONE标志。因此,这两种事件都不会导致BootROM重新运行STCU2自检。
自检DCD镜像的结构与标准DCD镜像的结构相同,用于设备配置。BootROM使用IVT中提供的指针定位自检DCD镜像。自检DCD镜像的最大大小也是限制为8192字节,镜像头结构如下所示:
这一自检过程是BootROM执行的一系列自动化操作,用于验证设备的硬件和配置。它对于维护系统的可靠性和安全性至关重要,确保设备仅使用经过验证和确认的硬件设置启动。
五、应用程序启动镜像(App Bootloader)
5.1 镜像结构
在进行非安全启动(IVT镜像的BCW中的BOOT_SEQ == 0)时,应用程序启动代码(Application Boot Code)镜像必须符合如下结构。
偏移地址 | 大小(字节) | 名称 | 备注 |
---|---|---|---|
0h | 4 | Image header | 标志应用程序镜像的开始 |
4h | 4 | RAM start pointer | 指向BootROM加载应用程序启动代码的RAM地址 |
8h | 4 | RAM entry pointer | 指向复位后启动目标核的起始位置。对于Cortex-M7,它对应于VTOR。 对于A53,它对应于代码执行的起始位置。这个指针应该在应用程序镜像被下载的SRAM区域内。 |
Ch | 4 | Code length | 镜像中代码段的长度。 |
10h | 48 | reserved | 保留未使用 |
40h | 代码长度 | Code | 代码大小可以是任意大小,直到系统SRAM的最大大小。 |
其中,前四个字节的header的结构如下所示:
5.2 RAM start pointer和RAM entry pointer
关于其中提到的RAM起始指针和RAM入口指针可能不是很好理解,进一步解释如下:
- ram start pointer:是指向要将应用程序启动代码第一个字节加载到的RAM地址。这意味着BootROM会从这个指定的内存地址开始将应用程序代码从存储介质(如闪存)复制到RAM中。
- ram entry pointer:是指向应用程序实际开始执行的入口点的地址。这可以看作是系统重置后CPU开始执行代码的第一个地址。对于Cortex-M7核,这个指针对应于VTOR(向量表偏移寄存器)的值,而对于A53核,它指向代码执行的起始点。
所以简单来说,ram start pointer定义了代码在RAM中的加载位置,而ram entry pointer定义了处理器从哪里开始执行代码,这两者为BootROM提供了必要的信息来正确加载和启动应用程序。
5.3 μSDHC启动场景下的注意点
在通过μSDHC接口进行应用程序启动时,若IVT的BCW中的BOOT_SEQ等于0,BootROM会使用从34008000h到34079C00h的地址范围进行其内部操作。这一地址范围内的空间不应该被应用程序在启动周期间使用,以避免潜在的冲突或数据损坏。
此外,BootROM在μSDHC启动的情况下,还会使用从34002000h开始的4KB SRAM内存空间用于ADMA(高级直接内存访问)。因此,为了确保启动过程的顺利进行以及数据的完整性,应用程序启动镜像在μSDHC启动的情况下,也不应该与这个特定的内存位置重叠。
总之,在设计应用程序启动逻辑时,特别是在使用μSDHC作为启动介质的场景下,需要避开BootROM使用的这些特定内存区域,以保证启动流程的正确性和应用程序的稳定运行。这是因为BootROM需要这些特定的内存区域来执行其启动过程中的一些关键操作,例如加载启动代码、临时存储数据等。如果应用程序不小心覆盖了这些区域,可能会导致启动失败或运行时错误。
六、Serial Boot镜像
未使能安全启动的场景下,Serial Boot镜像结构如下所示:
偏移地址 | 大小(字节) | 名称 | 备注 |
---|---|---|---|
0h | 4 | Image header | 标志应用程序镜像的开始 |
4h | 4 | RAM start pointer | 指向BootROM加载应用程序启动代码的RAM地址 |
8h | 4 | RAM entry pointer | 指向复位后启动目标核的起始位置。对于Cortex-M7,它对应于VTOR。 对于A53,它对应于代码执行的起始位置。只有Cortex-M7支持serial boot |
Ch | 4 | Code length | 镜像中代码段的长度。 |
10h | 48 | reserved | 保留未使用 |
40h | 代码长度 | Code | 代码大小可以是任意大小,直到系统SRAM的最大大小。 |
使能安全启动时,镜像结构如下所示:
地址偏移 | 字节数 | 名称 | 注释 |
---|---|---|---|
0h | 4 | Image header | 标志镜像的开始 |
4h | 4 | RAM start pointer | 指向BootROM加载应用程序启动代码的RAM地址。 |
8h | 4 | RAM Entry pointer | 指向复位后启动目标核心的起始。对于Cortex-M7,它对应于VTOR。 (仅支持Cortex-M7的串行启动) |
Ch | 4 | Code length word | 镜像代码段的长度。 |
10h | 4 | Auth mode | 保留给非安全启动。 |
14h | 4 | NSKPUB Key Selector | NSK公钥选择器 |
18h | 40 | Reserved | 保留未使用 |
40h | 4096 | NSKPUB | NXP公钥(16个)用于RSA认证。 |
1040h | 256 | CSKPUB | 客户RSA认证的公钥。 |
1140h | 256 | CSK Signature | CSKPUB认证的RSA签名。 |
1240h | 代码长度 | Code | 代码可以是任何大小,直至SRAM的最大大小。 |
1240h + 代码长度 | 256 | Public key Signature | 镜像认证的公钥签名。 |
其中,前四个字节的header的结构如下所示:
Tip📌:如果Serial Boot镜像是由NXP进行签名的话,CSKPUB 和 CSK 签名字段是保留的
其中,Code length word的结构如下所示:
各位域字段的含义如下:
位域 | 字段 | 描述 |
---|---|---|
31 | NO_ECHO | 表明不要从下一个串行阶段开始回显传入的串行数据。 |
30 : 0 | CODE_SIZE | 要下载的串行启动代码的大小。 |
七、结语
本文仔细描述了启动过程中的关键组件:IVT(中断向量表)、DCD(设备配置数据)和应用程序启动镜像等内容。通过详细的解析和对这些重要部分的讨论,我们了解到它们是如何在设备的启动过程中发挥作用,以及它们如何协同工作以确保系统的顺利启动和运行。
IVT作为镜像索引中心,为系统启动寻找镜像提供了方向。DCD则确保了硬件设备在启动过程中得到正确的配置,而应用程序启动镜像则是启动流程的终极载体。
一个稳定可靠的启动过程是系统整体性能的基石。希望本文能够帮助大家更好地理解和掌握启动相关镜像的复杂性,也期待这些信息能够在你未来的工作中发挥出实际的帮助和价值。
>>>>>>>>> 返回专栏总目录 《S32G3系列芯片——Boot详解》<<<<<<<<<