HSM启动地址
HSM使用ARM的嵌套向量中断控制器(NVIC)作为中断单元。
NVIC允许设计特定的中断节点数和优先级级别。HSM实现了10个中断节点和8个优先级级别。看门狗定时器中断连接到NMI(非屏蔽中断)。
中断映射
由于AES模块的高性能,它没有中断。
向量表偏移寄存器(VTOR)的位30和位31被添加,以允许将向量表基础设置为闪存地址。VTOR的重置值为0000 0000 H。
NVIC是ARM架构中用于管理中断和异常的组件,HSM采用了这一控制器并根据设计实现了特定数量的中断节点和优先级级别。
表格提供了HSM中断的映射概览,包括每个中断的编号、类型、优先级和简要描述。
AES模块由于性能高,没有实现中断功能。
VTOR寄存器的位30和位31用于设置向量表的基础地址,以便指向闪存中的中断处理函数。重置值是16进制的0,意味着在系统启动时,默认使用系统内存的起始地址作为向量表的基础地址。
/*****************************************************************************
* 异常(中断)向量表
*****************************************************************************/
__attribute__((section(".isr_vector"))) // 指定该数组放置在特定的段(节)中
void (* const pfnVectors[])(void) = {
/* 异常编号:优先级 */
(void* const) &_mainstack_end, /* 0: 必须指向RAM段0x2 */
Reset_Handler, /* 1: -3 最高优先级异常 */
NMI_Handler, /* 2: -2 用于看门狗 */
HardFault_Handler, /* 3: -1 默认故障处理程序 */
MemManage_Handler, /* 4: 可编程MPU故障 */
BusFault_Handler, /* 5: 可编程总线故障 */
UsageFault_Handler, /* 6: 可编程使用故障 */
EXC_Reserved, /* 7: 保留 */
EXC_Reserved, /* 8: 保留 */
EXC_Reserved, /* 9: 保留 */
EXC_Reserved, /* 10: 保留 */
SVC_Handler, /* 11: 可编程超级监视器调用 */
DebugMon_Handler, /* 12: 可编程调试监视器 */
EXC_Reserved, /* 13: 保留 */
PendSV_Handler, /* 14: 可编程可挂起请求 */
SysTick_Handler, /* 15: 可编程系统滴答定时器 */
/* 可配置中断 */
Timer0_handler, /* 16: 可编程定时器计数器0 */
Timer1_handler, /* 17: 可编程定时器计数器1 */
Trng_handler, /* 18: 可编程真随机数生成器 */
BridgeService_handler, /* 19: 可编程HSM桥服务 */
BridgeError_handler, /* 20: 可编程HSM桥错误 */
VoltageSensor_handler, /* 21: 可编程电压传感器 */
ExternalInterrupt_handler, /* 22: 可编程外部外设中断 */
ISR_Unimplemented, /* 23: 未实现的中断服务例程,保留 */
PkcReady_handler, /* 24: 可编程PKC就绪 */
PkcError_handler, /* 25: 可编程PKC错误 */
};
数组 pfnVectors 包含了中断处理函数的指针,这些函数将被调用以处理特定的异常或中断。
__attribute__((section(".isr_vector"))) 是一个编译器特定的属性,它指示编译器将这个数组放置到一个名为 “.isr_vector” 的内存段中,这个段通常在程序的开始位置。
数组的第一个元素是一个指向RAM的指针,指向栈的末尾。
随后的每个元素对应一个特定的异常或中断源,以及对应的处理函数。
EXC_Reserved 表示保留的中断向量,尚未使用或不需要处理。
isr_vector 必须映射到HSM扇区所选择的启动地址,这样才可以正常启动。
Reset_Handler
/* 全局变量 */
volatile uint32_t addressBfr;
/*!
* @fn void Reset_Handler(void)
* @brief 从重置向量开始的代码入口点
* @param None
* @return 无返回值
*/
void Reset_Handler(void)
{
extern uint32_t _Vectors, __etext, __data_start__, __data_end__, __bss_start__, __bss_end__;
#if ((0x01 & DEBUG) == 0x01)
/* 使用P00.0作为触发信号,指示HSM何时开始执行代码 */
P00_IOCR0.U = 0x10101080;
#endif
uint32_t *src, *dst;
/* 初始化BSS段变量为零 */
for (dst = &__bss_start__; dst < &__bss_end__; dst++)
*dst = 0;
/* 从复制表初始化数据 */
for (src = &__etext, dst = &__data_start__; dst < &__data_end__; dst++)
*dst++ = *src++;
/* 设置向量表基地址 */
SCB->VTOR = ((uint32_t) &_Vectors);
/* 初始化时钟控制单元(CCU):振荡器和锁相环 */
CCU_Init();
/* 从CPU0系统定时器捕获时间
* 这表示CMAC时间的开始
*/
time0L = STM0_TIM0.U;
time0H = STM0_CAP.U;
/* 跳转到HSM应用的入口点 */
main_app();
}
Reset_Handler函数是程序的入口点,它在系统复位后被调用。
通过宏定义DEBUG控制是否使用P00.0作为HSM开始执行代码的触发信号。
通过两个循环,分别将BSS段的所有变量初始化为零,以及从__etext到__data_end__的数据复制到__data_start__开始的相应位置。
设置了向量表偏移寄存器SCB->VTOR,指向中断向量表的起始地址_Vectors。
调用CCU_Init函数初始化时钟控制单元。
从系统定时器中捕获当前时间,这可能用于后续的时间测量或同步。
最后,调用main_app函数,这通常是应用程序的主函数,从这里开始执行具体的应用程序逻辑。
main_loop
这段代码是一个名为 main_app 的主应用程序入口点函数的例子。以下是代码的中文解释和注释:
/*!
* @fn void main_app(void)
* @brief 启动的入口点
* @param None
* @return 退出时无返回值
*/
void main_app(void)
{
SystemInit(); // 初始化系统
/* 检查SoC(主机)内存与CMAC的一致性 */
if (E_CRYPTO_OK == CheckHashApplication())
{
// TODO: 检查CPU0的程序计数器是否仍在BootROM中
cpu0_PC = *(volatile uint32_t*)(0xF881FE08);
/* 释放AURIX CPU0;安全启动已完成 */
HSM_BRIDGE->HSM2HTF.U = 1;
}
/* 从CPU0系统定时器捕获时间,这表示CMAC时间的结束 */
time1L = STM0_TIM0.U;
time1H = STM0_CAP.U;
/* 启用所有主机中断 */
HSM_BRIDGE->HT2HSMIE.U = 0xFFFFFFFF;
/* 设置桥接中断的优先级 */
NVIC_SetPriority(Bridge_IRQn, 0);
/* 在NVIC中启用桥接中断 */
NVIC_EnableIRQ(Bridge_IRQn);
#if ((DEBUG & 0x08) == 0x08)
/* 启用连接到P33.6的LED的输出引脚 */
P33_IOCR4.B.PC6 = PCx_Output_PushPull_gpio;
#endif
/* 将CMAC和时间信息写回主机 */
uint32_t *dst = HostWritePointer(Boot_ResponseAddress+0x10u);
*dst++ = time0H;
*dst++ = time0L;
*dst++ = time1H;
*dst++ = time1L;
dst += 2; /* 从BootMacSize和BootMacStartAddress偏移 */
/* 将版本和构建信息写回主机 */
GetBuildInfo((uint8_t *)dst);
/**/
dst = HostWritePointer(Boot_ResponseAddress+0x90u);
*dst = cpu0_PC;
/* 使用fSPB=100MHz设置系统滴答定时器为10ms滴答 */
SysTick_Config(SYSTICK_TIMEOUT, SYSTICK_CLK_EXTERNAL);
/* 初始化并生成真正的随机数,以便主机立即可用 */
TrngInit();
/* HSM内核的控制循环 */
while (1)
{
/* 检查来自主机的动作 */
CheckForCommand();
/* 检查是否需要填充TRNG缓冲区 */
Trng_CheckBuffer();
#if 1
/* 健康状态,闪烁LED以指示HSM循环正在运行 */
if (msTicks >= 50)
{
#if ((DEBUG & 0x08) == 0x08)
P33_OMR.U = PORT_TGL_P6;
#endif
msTicks = 0;
}
#endif
}
}
SystemInit() 函数用于初始化系统。
CheckHashApplication() 函数用于验证SoC(System on Chip,系统芯片)内存的完整性。
如果SoC内存检查通过,代码将检查CPU0的程序计数器是否仍在BootROM中,并释放AURIX CPU0。
捕获CPU0系统定时器的时间,表示CMAC时间的结束。
启用所有主机中断,并设置桥接中断的优先级和在NVIC中启用桥接中断。
如果定义了调试宏DEBUG,则启用P33.6引脚的输出,用于控制LED。
将CMAC和时间信息写回主机内存。
使用系统滴答定时器初始化10ms的周期性中断。
初始化并生成真正的随机数,这些随机数对主机来说是立即可用的。
进入HSM内核的控制循环,不断检查来自主机的命令,并检查是否需要填充TRNG(True Random Number Generator,真随机数生成器)缓冲区。
如果定义了调试宏DEBUG,则通过闪烁LED来指示HSM循环正在运行。
SystemInit
这段代码是一个微控制器系统的初始化函数 SystemInit,它设置了系统的核心时钟和一些异常处理选项。以下是代码的中文解释和注释:
/* 时钟设置(100MHz) */
uint32_t SystemCoreClock;
/**
* @brief 设置微控制器系统。
* 初始化系统并更新 SystemFrequency 变量。
*/
void SystemInit( void )
{
/* 初始化进程栈 */
__set_PSP((uint32_t) &_processorstack_end);
/* 添加改变时钟的代码 */
SystemCoreClock = CHIP_FREQ_MAIN_CLK; // 设置系统核心时钟为芯片主时钟频率
/* 启用使用-、总线-和MPU故障异常,并使用处理器时钟 */
SCB->SHCSR |= SCB_SHCSR_USGFAULTENA_Msk
| SCB_SHCSR_BUSFAULTENA_Msk
| SCB_SHCSR_MEMFAULTENA_Msk;
/* 启用除以0故障和未对齐访问陷阱 */
SCB->CCR |= SCB_CCR_DIV_0_TRP_Msk
| SCB_CCR_UNALIGN_TRP_Msk;
}
SystemCoreClock 变量用于存储系统的核心时钟频率。
__set_PSP 函数用于初始化进程栈指针(Process Stack Pointer),这里它被设置为 _processorstack_end 的地址,这通常是进程栈的末尾地址。
SystemCoreClock 被设置为 CHIP_FREQ_MAIN_CLK,这是一个宏,代表芯片的主时钟频率。在这个例子中,它被设置为100MHz。
SCB->SHCSR 寄存器(System Handler Control and State Register,系统处理控制和状态寄存器)被配置为启用几种类型的故障异常。这包括使用故障(Usage Fault)、总线故障(Bus Fault)和存储器管理故障(Memory Management Fault)。
SCB->CCR 寄存器(Configuration and Control Register,配置和控制寄存器)被配置为启用除以0的故障陷阱和未对齐访问的陷阱。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_36750998/article/details/140863442
|