《S32G3系列芯片——Boot详解》系列——HSE软件组件有哪些?如何实现HSE与主机的通信(同步/异步)?如何使用HSE提供的安全服务?
- 一、HSE子系统软件组件
- 1.1 NXP交付用户的HSE固件内容
- 1.2 HSE固件提供的安全服务
- 1.3 HSE固件的一般操作流程概述
- 1.3.1 安装
- 1.3.2 配置
- 1.3.3 使用
- 二、HSE接口
- 2.1 消息单元 (MU)
- 2.1.1 概述
- 2.1.2 服务通道
- 2.1.3 HSE状态
- 2.1.4 中断
- 2.1.5 密钥使用限制
- 2.1.6 XRDC施加的访问限制
- 2.1.7 启用或禁用服务通道
- 2.1.8 HSE MU驱动程序参考示例
博主已开通同名公众号,通过文末或主页二维码关注博主,将为你推送最新、最细、最硬核的车载系统知识和嵌入式开发知识!
学习更多Boot相关内容,获取HSE基于IVT安全启动方案?
>>>>>>>>> 返回专栏总目录 《S32G3系列芯片——Boot详解》<<<<<<<<<
Tip📌:
鼠标悬停双虚线关键词/句,可获得更详细的描述;
建议按照专栏文章目录顺序依次阅读以便了解相关背景知识。尤其建议先通读下:
《Boot过程相关镜像详解:IVT、DCD、App Boot镜像到底是什么?》和 《S32G3系列芯片Boot流程详解!》
读完上一篇文章《到底什么是HSE(Hardware Security Engine-硬件安全引擎)?实现安全启动需要掌握哪些预备知识?》之后,我们应当对HSE子系统及其相关知识有了基本的了解,至少我们知道HSE主要是用于提供多种本地安全服务的。本文将从软件组件结构及其功能上进一步描述HSE子系统。
一、HSE子系统软件组件
HSE子系统有两个软件组件:SBAF和HSE固件。安全启动辅助闪存(Secure Boot Assist Flash,SBAF)是由NXP在生产过程中编程到设备中的软件组件。该软件组件存储在HSE代码闪存区域。SBAF提供的功能包括:
- HSE固件安装
- HSE固件恢复
- 调试授权(比如LC状态推进到OEM_PROD之后,主机的调试功能就会受到保护)
- 分区切换启用(HSE有主分区和备份区,某个分区启动失败会自动尝试切换另一个分区)
- 支持固件更新(OTA升级)
- 安全功能和基于JTAG的恢复模式
HSE固件是提供多种本地安全服务的软件组件,我们主要关注的就是它,接下来将针对HSE固件做更多的具体描述。
1.1 NXP交付用户的HSE固件内容
HSE固件的交付物包括几个文件,具体总结如下表所示:
文件名 | 描述 |
---|---|
hse_interface.h hse_srv_responses.h hse_status_and_errors.h hse_gpr_status.h std_typedefs.h | HSE固件API和安全服务的头文件;需包含在主驱动程序(应用程序)中。 这些文件还包含关于HSE固件可能返回的各种错误代码和状态的说明。 |
hse_srv_.h | 安全服务的头文件;所有服务头文件均包含在hse_interface.h文件中。 |
hse_srv_custom.h | 自定义HSE固件API和安全服务的头文件;需包含在主驱动程序中。 |
hse_config.h hse_target.h hse_platform.h hse_b_config.h hse_compile_abs.h hse_compile_defs.h | 识别所实现的HSE固件特性的头文件,具体取决于选定的配置和目标设备。 所有已启用的HSE特性列在hse_b_config.h文件中(在hse_b_config.h文件中注释或禁用的特性不受支持)。 |
<device>_hse_fw__.bin.pink | 可执行形式的HSE固件;文件名中包含HSE固件平台、软件包版本和数据 (例如:s32k3x4_hse_fw_0.5.0_0.12.0_pb210720.bin.pink),与hse_target.h头文件相关联。 |
1.2 HSE固件提供的安全服务
本地安全服务是指由NXP提供的HSE固件中可用的服务。这些服务共同支持HSE固件的安全性,确保设备在多种情况下能够安全地运行和管理数据。这些本地服务分为以下几类:
-
管理服务:提供安装、配置和测试HSE的功能。
-
密钥管理服务:允许应用程序管理HSE处理的不同密钥集,例如通过加密服务进行管理。
-
加密服务:向应用程序提供加密原语,这些原语被应用程序中的高级安全栈使用。
-
随机数服务:生成随机数流,可用于各种安全协议。
-
内存验证服务:允许应用程序在启动(重置后)和运行时验证不同的内存区域。
-
单调计数器服务:为应用程序提供一组单调计数器,这些计数器可以被读取且只能递增。
1.3 HSE固件的一般操作流程概述
1.3.1 安装
HSE固件的可执行文件以加密和经过认证的形式交付。安装HSE固件的过程包括:
- 将HSE固件传输到HSE代码闪存区域。
- 解密固件。
- 验证固件的真实性。
解密和验证HSE固件真实性所需的密钥由NXP在出货前预先配置在HSE子系统的安全非易失性存储器(Secure NVM)中。HSE固件的安装在设备启动时启动,满足特定条件时,固件可被提供到HSE子系统。有关HSE固件安装的详细信息,后面的推文会详述。
1.3.2 配置
一旦HSE固件可执行文件安装完成,就必须根据系统级定义的安全策略进行配置。该配置步骤涉及:
- 创建和格式化密钥目录,以保存应用程序和HSE使用的密钥。
- 在非易失性密钥目录中配置密钥值和属性。
- 根据特定内存区域的真实性配置应用程序启动条件。
- 配置HSE控制的特定安全策略(例如,周期性内存验证检查)。
- 配置各种单调计数器。
HSE固件的配置在特定条件下由应用程序通过可用的不同HSE服务进行控制和处理。有关HSE固件配置的详细信息,后面的推文会详述。
1.3.3 使用
一旦配置完成,HSE为主机提供一系列安全服务。在此环境下,HSE子系统作为主机的从属,响应来自一个或多个应用CPU子系统的服务请求。
要触发HSE子系统的服务请求,主机需要执行以下步骤:
- 在专用数据结构中格式化(即实例化)请求,这里称为服务描述符,每个字段对应于服务的参数。
- 将服务请求存储在主存中,该内存区域也可以被HSE子系统读取和写入。
- 通过专用消息单元(MU)提供该服务描述符的地址。此操作会触发HSE子系统的中断信号,以指示存在待处理的服务请求。
所有服务请求的最终结果是HSE写入MU中的专用寄存器的服务响应。如果未收到服务响应,可能是固件遇到错误并进入关机模式。在这种情况下,应用程序需要参考MU中的GSR寄存器以获取更多详细信息。这部分内容会新开一个HSE的错误处理章节来描述。
要检查服务的完成情况,主机可以定期检查MU中响应(错误代码)的可用性。主机还可以选择处理HSE子系统通过MU触发的中断请求,这表明服务处理已完成。
HSE子系统对所有系统资源拥有读写访问权限,这些资源也可由主机访问,除非这些资源受到主机的保护(例如,出于安全目的),通过XRDC进行管理。因此,大多数服务请求包含指向字节数组的指针,这些字节数组代表要被HSE读取(和处理)的数据,或者是要由HSE填充的缓冲区。每个服务的详细结构格式需要参考hse的api手册。
Tip📌:自主操作
HSE子系统是上电复位(POR)后的唯一主控单元。HSE在启动后(即在应用程序之前)开始运行,并执行一些不完全对主机可见的各种操作:比如在运行时执行后台内存验证检查,根据后台验证检查和其他条件向主机通报整体安全状态。当然,这些自主操作可以由主机进行配置,他们并不是强制要求实现的。
Tip📌:特殊操作流程
HSE还提供了一个特定的服务允许主机安全地更新HSE固件。此类更新可在任何时间启动,只要HSE固件处于运行状态。关于更多HSE固件更新的内容,后面的推文会详述。
二、HSE接口
2.1 消息单元 (MU)
2.1.1 概述
消息单元(MU)是主机与HSE子系统之间的通信接口。主机用于触发服务请求并接收服务响应;HSE用于接收服务请求、返回服务响应,并提供几种与主机相关的HSE状态信息。
Tip📌:
MU有两个部分,分别称为MUA和MUB。一侧(MUA)由HSE独占控制,另一侧(MUB)由主机控制。在一侧(TRi)写入的值可以在另一侧的相应接收寄存器(RRi)中读取。同样,一侧的选择控制寄存器(例如FCR)与另一侧的状态寄存器(例如FSR)进行交互。
从主机的角度(MUB),每个系统中的MU实例具有以下功能(下文均是从主机的视角看MU):
- 一组可读写的32位发送寄存器(TRi),提供要由HSE处理的服务描述符的地址
- 一组只读的32位接收寄存器(RRi),用于检索服务请求的响应
- 两个只读的32位状态寄存器(FSR和GSR),用于记录HSE状态和系统事件
- 控制和状态寄存器,用于管理对发送和接收寄存器的访问,以及相关的中断信号
可用的MU实例数量及TRi/RRi寄存器的数量视设备(主机)而定。有关不同S32x设备中MU实例数量的详细信息,通常可以参考HSE手册最后一章。
使用消息单元(MU)来管理HSE服务请求和响应的优点有很多:
-
硬件机制:在发送/接收寄存器上设有硬件机制,以避免服务请求的溢出。
-
中断信号:提供中断信号,允许异步管理请求,避免主动等待循环。
-
访问限制配置:每个MU实例可以配置特定的访问限制,例如,可以用来隔离来自不同主控(在不同MU实例中)的请求;这种访问控制可以通过XRDC进行配置。
-
密钥使用限制:可以对MU实例的加密密钥使用进行限制。
2.1.2 服务通道
服务通道是一种临时构造,链接到一个服务请求(一旦启动)并映射到一对TRi/RRi寄存器(在一个MU实例中)。
服务通道 #i 在主机打开之前是空闲的,即当主机在相应的TRi寄存器中写入服务描述符地址时,它才会变为忙碌状态,直到HSE完成服务执行,并且主机已从相应的RRi寄存器中读取响应。
Tip📌:主机可以同时打开的服务通道最大数量等于MU实例的数量乘以TRi寄存器的数量。
服务通道 #i 在以下所有条件为真时为空闲:
- 寄存器 TRi 空:即,之前写入TRi的值已被HSE读取
- 当寄存器TSR的第 #i 位为1时,说明这一点成立。
- 寄存器 RRi 空:即,之前的值已被主机读取
- 当寄存器RSR的第 #i 位为0时,说明这一点成立。
- 服务通道 #i 未在处理中:
- 当寄存器FSR的第 #i 位为0时,说明这一点成立。
服务通道 #i 当主机在TRi中写入要由HSE处理的服务描述符的地址时被打开。
在每个MU实例中找到的第一个空闲服务通道可以用来触发服务请求。服务通道 #0 仅用于请求管理服务:在通道 #0 上触发其他类型的服务会产生错误。其他服务通道则没有服务类别的限制。应避免打开不空闲的服务通道。
以下表格总结了与服务通道 #i 相关的MU寄存器使用情况。
MU寄存器 | 访问权限 | 使用/描述 |
---|---|---|
TRi | 写入(注意表尾Tip) | 包含一个指向服务描述符的32位内存地址 |
TSR bit #i | 只读 | 服务请求已被HSE确认 当主机写入TRi时自动清零 当HSE读取TRi时自动设置为1 |
RRi | 只读 | 包含一个32位整数,指示服务响应(成功/错误) |
RSR bit #i | 只读 | 服务响应已被主机确认 当HSE写入RRi时自动设置为1 当主机读取RRi时自动清零 |
FSR bit #i | 只读 | 服务执行状态 每当服务被确认并排队(即执行中)时,HSE将其设置为1 每当提供服务响应时(即执行完成),HSE将其清零 |
Tip📌:从主机端读取TRi总是返回0x00000000。
2.1.3 HSE状态
在只读寄存器FSR中,位0到15提供了每个服务通道的执行状态,如上表所述(执行中/已完成)。位16到31记录HSE状态位,如下表所示。
Tip📌:
注意,位16到31的值在所有MU实例中都是复制的:从MU实例0的FSR读取这一上层16位字与从任何其他MU实例的FSR读取的结果相同。
位 17 到 20 的HSE状态与安全启动管理相关,这些位的值依赖于SMR #0的定义和验证状态,具体如下表所示。
综上所述,HSE状态的32个字节对应的含义简单总结如下:
位 | 描述 |
---|---|
位0-15 | 每个服务通道的执行状态(进行中/已完成) |
位16-31 | HSE状态位,所有MU实例共享相同的值 |
位17-20 | 与安全启动管理相关的状态位,值依赖于SMR #0的定义和验证状态 |
2.1.4 中断
每个MU实例可以触发三个中断信号给主机,这些信号在以下事件发生时会被触发:
- HSE确认了一个服务请求。
- HSE中的服务执行完成。
- HSE中发生系统事件。
下面的表格描述了每个中断信号相关的HSE动作,以及触发中断信号的条件(即如何取消中断屏蔽)和在中断处理程序中解析的寄存器,以获取中断来源。
Tip📌:
注意,HSE系统事件的中断仅在GSR位从0变为1时才会触发。要将某个位清除为0,主机必须将该位写入1(“w1c”,即“写1以清除”)。
2.1.5 密钥使用限制
主机定义的每个加密密钥组必须与一个或多个MU实例相关联。这些关联由主机在密钥目录格式化期间定义为可配置属性(这部分后续推文会详述)。只有当MU实例与密钥相关联时,通过该实例触发的服务请求才能使用该密钥。通过XRDC将不同的MU实例分配给不同的主控(CPU),HSE强制特定任务或应用程序使用特定的密钥。
2.1.6 XRDC施加的访问限制
XRDC配置可以通过外设访问控制器(PAC)和其外围域访问控制(PDAC)寄存器将每个MU实例分配给一个域ID(DID)。每个域可以分配给不同的CPU子系统,从而允许为不同的应用程序(由不同的CPU子系统运行)隔离使用不同的密钥集。下面的图示说明了不同应用如何被划分以访问HSE子系统中的不同密钥集。
域0与M7_0 CPU子系统的PID相连,而域1与M7_1 CPU子系统MU实例1的PID相连。通过这些关联,两个应用程序可以利用HSE中的NVM目录中声明的两组不同的密钥。
2.1.7 启用或禁用服务通道
主机可以启用或禁用特定MU实例中的服务通道。当主机禁用MU实例时,该MU实例中的所有服务通道将不再由HSE服务。MU实例的启用和禁用通过HSE系统属性进行管理,默认情况下,只有MU实例0是启用的,所有其他MU实例都是禁用的。此外,MU实例0不能被配置为禁用。
2.1.8 HSE MU驱动程序参考示例
下表给出了比较常用的一些驱动接口对应的含义。
如何在一个空闲的channel上触发一个服务请求并等待响应消息(同步方式使用HSE服务):
// trigger a service requests on a free channel
// wait for the response and return (blocking call)
// takes in input the address to the service descriptor
hseSrvResponse_t runSrv(hseSrvDescriptor_t *pSrvDesc)
{
// get a free service channel in MU 0
uint8_t MU = 0;
hseSrvResponse_t hseResp = HSE_SRV_RSP_NOT_SUPPORTED;
uint8_t ch = HSE_MU_GetFreeChannel(MU);
if(ch != HSE_INVALID_CHANNEL)
{
// trigger the service request
HSE_MU_SendRequest(MU, ch, pSrvDesc);
// wait for the response
while(!HSE_MU_IsResponseReady(MU, ch));
hseResp = HSE_MU_ReceiveResponse(MU, ch);
}
return (hseResp);
}
如何在一个特定的channel上触发一个服务请求,等待对请求的应答,然后直到HSE服务完成触发中断(异步方式使用HSE服务):
MU = 0;
ch = 1;
// disable interrupts on HSE acknowledgement
HSE_MU_DisableInterrupts(MU, HSE_INT_ACK_REQUEST, 0xFFFF);
// enable interrupt on HSE response, for the selected service channel
HSE_MU_EnableInterrupts (MU, HSE_INT_RESPONSE, (1 << ch));
// enable all system event interrupts
HSE_MU_EnableInterrupts (MU, HSE_INT_SYS_EVENT, 0xFFFFFFFF);
// trigger the service request and wait for the HSE acknowledgement
if(HSE_MU_GetChannelStatus(MU, ch) == MU_CHANNEL_FREE)
{
HSE_MU_SendRequest(MU, ch, &my_service_request);
while(HSE_MU_IsAckPending(MU, ch));
}
// at this point the service is running in the HSE
// the response is handled in the interrupt handler
.../...
// interrupt handler on MU 0 transmit
hse_interrupt_handler_mu0_tr()
{
.../...
// search for a service channel with a pending response
for(ch = 0; ch < NB_CHANNELS; ch++)
{
if(HSE_MU_IsResponseReady(0, ch))
{
// retrieve the service response and exit
response = HSE_MU_ReceiveResponse(0, ch);
break;
}
}
.../...
}
>>>>>>>>> 返回专栏总目录 《S32G3系列芯片——Boot详解》<<<<<<<<<