HSM自学之路——阶段5安全启动专题与实践

发布时间:2026/10/10 12:49:29
HSM自学之路——阶段5安全启动专题与实践 面向汽车电子 MCU | 芯片CCFC3008PCSN | MCAL | HSM 固件 本文档是安全启动的一页通 实操手册把操作流程、设置参数、时钟配置、其他核启动时间点、代码配置、常见坑全部串起来。 所有接口、结构体、枚举、地址、行号均来自 MCAL 源码 HSM 固件源码原文非臆造。0. 一页看懂安全启动到底在干什么用一句话概括芯片上电后HSM 安全核先跑起来在主核Z4/Z7真正执行应用代码之前先用验签密钥检查这些代码有没有被篡改验签通过才把主核放出去跑不通过就按你配的策略处理复位/降级/锁死。上电 │ ▼ HSM 安全核先启动固件 自己初始化时钟/看门狗/串口 │ ▼ 读取安全启动表存在 D-FlashA/B 双份冗余 getBootEntryPtr() │ ├── bootType NONE ──────────────► 不验签直接放核 ├── 用户调过 IgnoreSecureBoot ──────► 跳过验签直接放核 ├── bootType FAST ──────────────► 先放核边跑边验验签失败再回卷 └── bootType STRICT ────────────► 先验签通过才放核最安全 │ ▼ 验签genAuthTag_RSA / genAuthTag_AES │ ├── 通过 ──► z4_z70_z71_app_boot() 释放主核 └── 失败 ──► operationOnFailRESET 软复位 / LOOP 锁死 / DEGRADE 降级放行三个灵魂概念先背下来概念含义一句话信任根Root of Trust验签用的公钥/密钥是信不信代码的源头密钥在 HSM 里、出不来所以可信验签VerifyHSM 用公钥对代码段算签名、比对你预置的签名签名不对 代码被改过放核Release CoreHSM 写MC_ME.CCTLx/CADDRxMCTL把主核从复位态放出来唯一函数z4_z70_z71_app_boot()1. 背景与核心概念1.1 为什么车规 MCU 一定要安全启动车规要求ISO 21434 网络安全工程 / EVITAECU 上跑的固件必须是可信的。攻击场景OTA 升级包被篡改、Flash 被物理/逻辑攻击改写、供应链植入后门。安全启动的作用保证从上电第一条指令到应用代码整条链每一步都经过完整性 真实性校验任何一环被改系统拒绝启动或进入安全状态。1.2 3008PCSN 的实现方式HSMHSN 安全核独立于主核先于主核启动天然是信任根的宿主。验签密钥RSA 公钥 / AES 对称密钥存在 HSM 的 NVM 密钥区主核拿不到明文。主核代码段在出厂/量产阶段由产线工具或用 HSM 自身算好签名签名连同代码段地址长度一起写进安全启动表。每次复位HSM 都重跑一遍验签保证篡改即被发现。1.3 术语速查本文高频词术语说明Secure Boot Entry安全启动表存在 D-Flash 的一张表记录验签参数hsmSecurebootEntry_tCode Segment代码段要验签的一段主核代码含addresslength最多 8 段Auth Tag签名对代码段算出来的签名值RSA 256 字节 / AES-CMAC 16 字节DevAuth设备认证打开 HSM 受保护功能的授权门质询-应答 CMACbootCore位掩码标记要放哪些核Z4_2 / Z7_0 / Z7_1A/B 双 bank启动表/密钥区各存两份ping-pong 写入防写坏2. 三种启动模式NONE / FAST / STRICT安全启动类型枚举Crypto_LLDriver.h:382~385 固件hsm_common_type.h:352~355typedef uint8_t hsmSecureBootType_t; #define HSM_SECURE_BOOT_TYPE_NONE ((hsmSecureBootType_t)0xFFU) // 不启用 #define HSM_SECURE_BOOT_TYPE_FAST ((hsmSecureBootType_t)0x00U) // 先放核后验签 #define HSM_SECURE_BOOT_TYPE_STRICT ((hsmSecureBootType_t)0x01U) // 先验签后放核2.1 三种模式时序对比核心中的核心固件分流点在HSM_SRV_SecureBootCheck()hsm_secure_boot.c:1096~1248模式放核时机验签时机安全性启动速度适用NONE(0xFF)立即boot(TRUE,FALSE)L1125不验签无最快开发调试、无安全需求FAST(0x00)验签前先放核boot(TRUE,TRUE)L1137放核后并行验中快用户感知零等待快速启动场景验签失败后回卷/复位STRICT(0x01)验签后boot(TRUE,TRUE)L1243放核前先验高慢等验签完成高安全场景网关/域控/VCU关键理解点FAST 的快是相对的——主核先跑起来HSM 在后台验签验签失败再处理但此时主核可能已经跑了一段要靠operationOnFail兜底。STRICT 的慢是绝对的——主核必须等 HSM 把每个代码段都验完、签名匹配才被放出去。NONE 和 IgnoreSecureBoot 都是boot(TRUE,FALSE)第二个参数addrcheckFALSE表示不做地址/校验检查纯粹放核。2.2 失败动作 operationOnFail三个选项枚举Crypto_LLDriver.h:387~390typedef uint8_t hsmSecureBootFailOp_t; #define HSM_SECURE_BOOT_ONFAIL_DEGRADE ((hsmSecureBootFailOp_t)0x00U) // 降级照常放行但不能用认证功能 #define HSM_SECURE_BOOT_ONFAIL_RESET ((hsmSecureBootFailOp_t)0x01U) // 软复位 #define HSM_SECURE_BOOT_ONFAIL_LOOP ((hsmSecureBootFailOp_t)0x02U) // 停核死循环最狠固件落点hsm_secure_boot.c:1212~1226if (g_boot_status HSM_SECURE_BOOT_FAIL){ if (operationOnFail HSM_SECURE_BOOT_ONFAIL_LOOP){ Sysclk_Init_Reback(); stopCore(); while(1){ watchDog_service(); } // 锁死 } else if (operationOnFail HSM_SECURE_BOOT_ONFAIL_RESET){ Sysclk_Init_Reback(); softreset(); // 复位 } else { // DEGRADE srvResp HSM_SRV_RESP_OK; // 降级放行 } }注意LOOP 和 RESET 前都会先调Sysclk_Init_Reback()把时钟回退因为验签阶段 HSM 可能临时升频/降频了失败要还原。3. 安全启动表与 A/B 双 bank 冗余3.1 安全启动表结构hsmSecurebootEntry_t固件侧hsm_common_type.h:897~920NEW_SECURITY_BOOT分支typedef struct { uint32_t validFlag; // 有效性标志 0x87654321 hsmSecureBootType_t bootType; // NONE/FAST/STRICT hsmSecureBootFailOp_t operationOnFail; // DEGRADE/RESET/LOOP uint8_t segCount; // 代码段数量 1~8 uint8_t bootCore; // 位掩码bit2Z4_2, bit0Z7_0, bit1Z7_1 xoscClkCofigData_t xoscClkConfig; // 时钟快照复位后验签用 struct _verify_code_segment codeSeg[8]; // 8 段 {address, length} hsmSecureBootTag_t authTags[8]; // 8 段签名RSA 256B / AES-CMAC 16B HOST_ADDR authKeyHandle; // 验签密钥句柄 hsmKeyType_t authKeyType; // AES / RSA_PUB / RSA_PAIR hsmSmrInstall_t smrInstall; // SMR 安全内存区安装 uint64_t reversed; } hsmSecurebootEntry_t;两个 validFlag 别搞混§19.7 结论标志位置含义值BOOT_VALID_FLAGbank 末尾的HSM_DATA_x_VALID_ADDR8 字节 取反判这张启动表写完整了没有库头文件定义开源未见语义同 0x87654321 套路hsmSecurebootEntry_t.validFlag表结构体第一个字段判这张表内容是否是有效配置0x876543213.2 参数区 A/B 双 bank ping-pong地址布局V229 PCSNhsm_reg_define.h:100~123区域起始entryCOUNTERVALIDA 区0x006100000x6101000x61FFF00x61FFF8B 区0x006200000x6201000x62FFF00x62FFF8VALID_ADDRBOOT_VALID_FLAG 按位取反8 字节两份对得上才认为这张表写完整、有效。COUNTER_ADDR 单调递增 counter 取反8 字节当 A/B 两份都有效时用 counter 判谁更新。ping-pong 写入HSM_Util_FlsSetDataWithBackUphsm_util.c:614~795先擦备份 bank → 搬数据 → counter1 写备份 counter → 写备份 valid → 最后擦旧 bank。这样任何时刻至少有一份完整的有效数据断电/写一半也不会丢。3.3getBootEntryPtr()两级仲裁hsm_secure_boot.c:60~118选 bank 逻辑第一级VALID读 A、B 的 VALID 标志。若 A 无效 → 取 B若 B 无效 → 取 A。第二级COUNTER若 A、B都有效比较 counterflag_b[0]-1 flag_a[0]说明 B 更新 → 取 B否则取 A。兜底若 A、B都无效先 A 后 B最终返回 B 地址此时 B 里可能是全 0xFF出厂未配置或半写坏残留无正确性保证。⚠️ 关键澄清此前踩过的坑getBootEntryPtr的两个 if 判的是无效所以 A/B 同时有效时两个 if 都不进落到 counter 仲裁不会互相覆盖。3.4 第二道闸isBootEntryValid()hsm_secure_boot.c:667~673getBootEntryPtr只返回地址指针、不校验内容。内容是否可用由第二道闸判断用表结构体自身的validFlag字段判断 0x87654321 才有效。特判validFlag 0xFFFFFFFF bootType 0xFF→ 视为从未配置全擦除态等效 NONE直接放行。调用点HSM_SRV_PreSecureBootCheckhsm_secure_boot.c:1038isBootEntryValid()0→ 返回VERIFY_FAILED。结论全 0xFF 放行等效 NONE半写坏/残留垃圾 → 验签失败。4. 端到端操作流程8 大步下面是一条从零到安全启动跑起来的完整链路。每一步都给出做什么 调什么接口 关键参数。第 1 步 导入 DevAuth 密钥AES-128设备认证用 第 2 步 打开 DevAuth 权限质询-应答拿到 SECURE_BOOT 权限 第 3 步 导入验签密钥RSA 公钥 或 AES 对称密钥 第 4 步 对主核代码段算签名RSA PKCS#1 v1.5 SHA-256或 AES-CMAC 第 5 步 配置安全启动表ConfigSecureBoot含时钟快照 第 6 步 查询/自检PreSecureBootCheck / GetSecureBootStatus 第 7 步 复位安全启动表复位后由 HSM 消费 第 8 步 HSM 验签 → 放核自动完成主核此时才真正跑起来第 1 步导入 DevAuth 密钥DevAuth 密钥是一把 AES-128 密钥HSM 用它做设备认证质询-应答。测试代码默认值tester_crypto.c:11uint8 App_DevAuthKey[16] { 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88, 0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88 };密钥句柄三级寻址GET_KEY_HANDLE(catalog, group, slot)(catalog16)|(group8)|slot#define APP_AES128_DEVAUTH_KEY_HANDLE GET_KEY_HANDLE(HSM_KEY_CATALOG_ID_NVM, HSM_KEY_GROUP_SYM, 0)量产注意DevAuth 密钥是设备认证的信任根量产后一旦设为不可导出/不可更新就改不了烧录流程要一次性做对。第 2 步打开 DevAuth 权限App_OpenDevAuth_New()tester_crypto.c:83~137完整流程AppStatus_t App_OpenDevAuth_New(const uint8_t *pKey, uint16_t keyLen, uint8_t devAuthOption) { // 2.1 检查 DevAuth key 是否已存在不存在则导入 status HSM_LLD_GetKeyInfo(APP_AES128_DEVAUTH_KEY_HANDLE, keyInfo); if (STATUS_HSM_KEY_EMPTY status) { HSM_LLD_ImportPlainSymKey(APP_AES128_DEVAUTH_KEY_HANDLE, HSM_KEY_TYPE_AES, HSM_KEY_FLAG_USAGE_SIGN | HSM_KEY_FLAG_USAGE_VERIFY | HSM_KEY_FLAG_USAGE_AUTH, keyLen, pKey); } // 2.2 发起质询DevAuthReqHSM 返回 32 字节 challenge hsmAuthScheme.macScheme.macAlgo HSM_MAC_ALGO_CMAC; Crypto_AutoSar_Ext_DevAuthReq(APP_AES128_DEVAUTH_KEY_HANDLE, devAuthOption, hsmAuthScheme, challenge); // 2.3 本地用同一把 key 对 challenge 算 CMAC应答 HSM_LLD_AesCmacGenerate(HSM_OPERATION_MODE_SINGLE_CALL, APP_AES128_DEVAUTH_KEY_HANDLE, challenge, sizeof(challenge), cmac, cmacLen); // 2.4 回送应答DevAuthRespHSM 比对 CMAC一致则开放权限 Crypto_AutoSar_Ext_DevAuthResp(cmac, cmacLen, NULL, 0); return 0; }DevAuth 权限位Crypto_LLDriver.h:326~332这是门禁能开哪些能力#define HSM_DEV_AUTH_KEY_MGMT (1U 0U) // 密钥管理 #define HSM_DEV_AUTH_USERDATA_MGMT (1U 1U) // 用户数据安全读写 #define HSM_DEV_AUTH_FW_UPDATE (1U 2U) // 固件升级 #define HSM_DEV_AUTH_FLASH_OPERATION (1U 3U) // Flash 操作 #define HSM_DEV_AUTH_SECURE_BOOT (1U 4U) // 安全启动★本文核心 #define HSM_DEV_AUTH_ALL (HSM_DEV_AUTH_SECURE_BOOT | HSM_DEV_AUTH_KEY_MGMT | ...)⚠️ 配置安全启动ConfigSecureBoot前必须先拿到HSM_DEV_AUTH_SECURE_BOOT权限否则固件第一行就返回HSM_SRV_RESP_DEV_NOT_AUTHEDhsm_secure_boot.c:696~699。第 3 步导入验签密钥RSA 公钥以 RSA-2048 为例。密钥句柄tester_crypto_SecureBoot.c:30~36非 EB 分支用 slot 3/4#define APP_RSA2048_DEVAUTH_PUKKEY_HANDLE GET_KEY_HANDLE(HSM_KEY_CATALOG_ID_NVM, HSM_KEY_GROUP_ASYM, 3) // 公钥 #define APP_RSA2048_DEVAUTH_PRIKEY_HANDLE GET_KEY_HANDLE(HSM_KEY_CATALOG_ID_NVM, HSM_KEY_GROUP_ASYM, 4) // 私钥导入公钥只需 modulus publicExponent 两段不需要私钥私钥只在算签名时用放在产线Crypto_HSM_KeyImportExportType App_Rsa2048Pubkey; App_Rsa2048Pubkey.pKey[0] (uint8 *)rsa2048key_modulus; // 模数 N2048 位 App_Rsa2048Pubkey.u16KeyLength[0] 2048; App_Rsa2048Pubkey.pKey[1] (uint8 *)rsa2048key_publicExponent; // 公钥指数 e App_Rsa2048Pubkey.u16KeyLength[1] sizeof(rsa2048key_publicExponent); Crypto_KeyElementSet(APP_RSA2048_PUB_KEY_ID, CRYPTO_KE_CIPHER_KEY, (uint8_t *)App_Rsa2048Pubkey, sizeof(App_Rsa2048Pubkey)); Crypto_KeySetValid(APP_RSA2048_PUB_KEY_ID); // 置有效对称方案AES则导入一把 AES 密钥APP_AES_DEVAUTH_KEY_HANDLE GET_KEY_HANDLE(NVM, SYM, 12)验签用 CMAC。RSA 方案验签用 RSASSA-PKCS1-v1.5 SHA-256签名 256 字节AES 方案签名 16 字节。第 4 步对主核代码段算签名代码段地址宏tester_crypto.h:137~216这是理解要验哪些代码的关键#if (RESOURCE_CHIP_CORE_NUM 1U) // 多核 #define CODE_SEG_0_ADDR_Z4 (0x1100000) // Z4 代码从 0x1100000 起 #else // 单核 #define CODE_SEG_0_ADDR_Z4 (0x1000000) #endif #define CODE_SEG_0_LEN_Z4 (0x00020000) // 每段 128KB #define CODE_SEG_1_ADDR_Z4 (CODE_SEG_0_ADDR_Z4 CODE_SEG_0_LEN_Z4) // ... 依此类推最多 8 段 #define CODE_SEG_0_ADDR_Z7_0 (0x1000000) // Z7_0 代码从 0x1000000 起 #define CODE_SEG_0_ADDR_Z7_1 (0x1080000) // Z7_1 代码从 0x1080000 起填充段表initVerifyCodeSegments_Z4_8Segstester_crypto_SecureBoot.c:276~303verifyCodeSegments appCodeSeg; initVerifyCodeSegments_Z4_8Segs(appCodeSeg); // 填 8 段 {address, length}算签名tester_crypto_SecureBoot.c:624~635for (index 0; index HSM_SECURE_BOOT_MAX_CODE_SEG; index) { if (appCodeSeg.seg[index].address 0 appCodeSeg.seg[index].length ! 0) { HSM_LLD_RsaPkcs1V15GenerateSignature( APP_RSA2048_DEVAUTH_PRIKEY_HANDLE, // 用私钥签 HSM_HASH_ALGO_SHA2_256, // 先 SHA-256 再 RSA (uint8 *)appCodeSeg.seg[index].address, appCodeSeg.seg[index].length, FALSE, g_CodeSignArray.sign[index].authTag0, signatureLength); segNum; } }签名落地把每个段的签名写到 Flash 固定区SECURE_BOOT_CODE_SIGN_ADDR测试代码tester_crypto_SecureBoot.c:637~665用Fls_EraseFls_Write每段写 512 字节。第 5 步配置安全启动表 ConfigSecureBootMCAL 侧接口Crypto_AutoSar_Ext_ConfigSecureBoot()10 个入参对应固件HSM_SRV_ConfigSecureBoothsm_secure_boot.c:677下发命令HSM_SRV_CMD_CONFIG_SECURE_BOOT。retVal Crypto_AutoSar_Ext_ConfigSecureBoot( HSM_SECURE_BOOT_TYPE_STRICT, // ① bootTypeNONE/FAST/STRICT APP_RSA2048_DEVAUTH_PUKKEY_HANDLE, // ② authKeyHandle验签公钥句柄 HSM_SECURE_BOOT_ONFAIL_RESET, // ③ operationOnFailDEGRADE/RESET/LOOP xoscConfigData, // ④ xoscConfig时钟快照可为 NULL appCodeSeg, // ⑤ verifySegs代码段表 {address,length}[8] (codeSigns0 *)signs, // ⑥ signs各段签名指针数组 segNum, // ⑦ signlens/segcnt段数量 1~8 TRUE, // ⑧ bootZ4是否放 Z4_2 核 FALSE, // ⑨ bootZ7_0是否放 Z7_0 核 FALSE); // ⑩ bootZ7_1是否放 Z7_1 核固件侧校验顺序hsm_secure_boot.c:696~900务必记牢排查参数错误按这个顺序检查HSM_DEV_AUTH_SECURE_BOOT权限没开 → DEV_NOT_AUTHEDbootType三选一NONE/FAST/STRICT其他 → INVALID_PARAMbootZ4/bootZ7_0/bootZ7_1至少一个 TRUEbootCore0 → INVALID_PARAMoperationOnFail三选一verifySegs非空NONE 模式可空segCount1~80 或 8 → INVALID_PARAM读验签密钥HSM_Util_ReadKey读不到 → 验签失败genAuthTag_RSA/genAuthTag_AES验签比对预置签名 vs 重算签名不一致 → VERIFY_FAILEDupdateBootEntryInFlash写启动表到 D-FlashA/B ping-pong第 6 步查询 / 自检Crypto_AutoSar_Ext_GetSecureBootStatus(secureBootStatus); // 读回启动状态 Crypto_AutoSar_Ext_PreSecureBootCheck(...); // 复位前预检启动状态值Crypto_LLDriver.h:392~396值含义0x00NOT_START尚未开始验签0x11OK验签通过0x22FAIL验签失败0x33NONE未配置安全启动等效 NONE第 7 步复位ConfigSecureBoot只是把表写进 D-Flash当下不生效。真正生效要等下一次复位HSM 启动后读启动表、验签、放核。第 8 步HSM 自动验签 → 放核复位后 HSM 固件自动走HSM_SRV_SecureBootCheck()§2.1 已详述验签通过后调z4_z70_z71_app_boot()释放主核主核从代码段首地址开始执行。5. 时钟配置两条路径别混安全启动涉及时钟最容易搞混。分清两条链路径接口作用生效时机存哪① 时钟快照ConfigSecureBoot(xoscConfig)把主核完整时钟树镜像给 HSM复位后 HSM 用它初始化自己的时钟验签阶段用复位后安全启动表xoscClkConfig② 立即配分频MCU_HSM_SetClkDiv(divider)/HSM_LLD_SetClkDiv(divider)立即写 HSM_CLKDIV改 HSM 当前分频立即寄存器HSM_CLKDIV5.1 时钟快照xoscClkCofigData_tconvXOSCConfig()tester_crypto_SecureBoot.c:371~507从Mcu_ClockConfigType提取完整时钟树逐个填寄存器值末尾置validFlag 0x87654321。包含MC_CGM 各 SC_DC/AC 分频、XOSC.CTL、IRCOSC.CTL、PLLDIG.PLL0DV/PLL1DV/PLL1FM/PLL1FD 等。void convXOSCConfig(xoscClkCofigData_t* xoscClkConfig, Mcu_ClockConfigType Mcu_ClockConfig) { xoscClkConfig-MC_CGM_SC_DC0_Value (1U 31U) | Mcu_ClockConfig.cgmConfig.sc_dc0; xoscClkConfig-MC_CGM_SC_DC1_Value (1U 31U) | Mcu_ClockConfig.cgmConfig.sc_dc1; // ...几十个寄存器字段 xoscClkConfig-validFlag HSM_SECURE_BOOT_ENTRY_VALID_FLAG; // 0x87654321 }关键结论§17/§18 已核实xoscConfig非必须固件里if (srvReq-xoscConfig ! 0)才 memcpyhsm_secure_boot.c:764~766传 NULL 则不更新时钟字段。它不是当下生效而是随启动表写进 D-Flash复位后由 HSM 消费。HSM 时钟 ≠ 主核时钟xoscClkConfig是镜像给 HSM 验签用的主核自己的时钟仍由应用层Mcu_Init配置。⚠️ 待闭环点源码里只保存未见复位后写回 MC_CGM/PLLDIG/XOSC 寄存器的显式消费点复位后动时钟靠checkAndWaitLowDownClockhsm_secure_boot.c:182Sysclk_Init_Reback仅 extern 声明定义在链接库SET_CLK_DIV写 HSM_CLKDIV。5.2 立即配分频的两条接口链主核想立即给 HSM 配时钟分频有两条现成链§18 已核实标准 MCAL 入口MCU_HSM_SetClkDiv(divider)Mcu_LLDriver.c:4195~4219→ 发SET_ATTR(attrIdHSM_ATTR_ID_CORE_CLK_DIVIDER5)→ 固件hsm_attr.c:274~284写HSM_CLKDIV 0x80000000UL | (val16)。底层 Crypto 专用HSM_LLD_SetClkDiv(divider)Crypto_LLDriver.c:466~488→ 写HSM.ALG_PARAM[1]HOST_FLAGHSM_SRV_CMD_SET_CLK_DIV→ 固件HSM_IRQHandler写 HSM_CLKDIV。主核已经自动调用Mcu_LLD_ConfigureSystemClockDividersMcu_LLDriver.c:614在 HSM 使能时调MCU_HSM_SetClkDiv(sc_dc116)Mcu_LLDriver.c:631无需客户额外写代码。两条路径边界ConfigSecureBoot 的xoscConfig 完整时钟快照复位后验签用SetClkDiv 单个分频值立即改 HSM_CLKDIV。5.3 HSM 时钟上限⚠️ 代码注释明确HSM 时钟 MAX 100MHz配置时钟别超否则验签/运算可能异常。6. 其他核的启动时间点FAST/STRICT/NONE 逐一定位结论先行启动其他核的是 HSM唯一放核函数是z4_z70_z71_app_boot(needVerify, addrcheck)hsm_util.c:4202~4629。6.1 三种模式的放核调用时机hsm_secure_boot.c:1119~1244模式放核调用行号参数说明NONEz4_z70_z71_app_boot(TRUE, FALSE)L1125needVerifyTRUE, addrcheckFALSE不验签直接放核IgnoreSecureBootz4_z70_z71_app_boot(TRUE, FALSE)L1131同上用户主动跳过验签FASTz4_z70_z71_app_boot(TRUE, TRUE)L1137needVerifyTRUE, addrcheckTRUE验签前先放核STRICTz4_z70_z71_app_boot(TRUE, TRUE)L1243needVerifyTRUE, addrcheckTRUE验签后才放核6.2z4_z70_z71_app_boot()内部做了什么hsm_util.c:4202~4629// 伪代码还原按源码行号注释 z4_z70_z71_app_boot(needVerify, addrcheck) { if (z4z7_already_boot) return; // 防重入L4216/4628 // MBIST 检查Z70_MBIST_RESULT 0x5A 才继续L4237~4239 // 在 app_located_addr[8] 里搜 boot header 的 isValidVectorL44/4176 // PCSN写 MC_ME.CCTL1 / CADDR1L4592~4594 // 写 MC_ME.MCTL 触发 DRUN 模式切换L4613~4614 }核释放机制的本质HSM 直接写MC_ME.CCTLx/CADDRx配好各核的启动地址MC_ME.MCTL触发 DRUN 转换不是主核自跳。也就是说主核在被放出来之前一直处于复位/停机态由 HSM 决定何时、从哪个地址让它起跑。6.3 多核 bootCore 位掩码bootCore是位掩码hsm_secure_boot.c:728~738if (srvReq-bootZ4) secureBootEntry.bootCore | 0x01 CORE_ID_Z4_2; // Z4_2 if (srvReq-bootZ7_0) secureBootEntry.bootCore | 0x01 CORE_ID_Z7_0; // Z7_0 if (srvReq-bootZ7_1) secureBootEntry.bootCore | 0x01 CORE_ID_Z7_1; // Z7_1核心 ID 枚举hsm_core.hZ7_00、Z7_11、Z4_22、Z7_3_Check3、Z0_4_HSM4。对应关系bootZ4TRUE→ bit2Z4_2bootZ7_0TRUE→ bit0bootZ7_1TRUE→ bit1。至少一个为 TRUE否则bootCore0→ 参数错误。6.4 三种模式的时间轴可视化【NONE】 上电 → HSM 初始化 → 直接放核 → 主核跑永不验签 【FAST】 上电 → HSM 初始化 → 放核(主核先跑) → HSM 后台验签 → 失败则 operationOnFail 兜底 【STRICT】 上电 → HSM 初始化 → HSM 验签(主核等待) → 通过才放核 → 主核跑 ^ ^ └── 主核处于复位/停机态 ──────────────┘7. 完整代码配置示例RSA-2048 STRICT 单核把 §4 的 8 步串成一段可直接参照的代码精简自tester_crypto_SecureBoot.c:510~689略8. 参数速查总表设置参数一页尽览8.1 ConfigSecureBoot 十参#参数类型/取值必填说明①bootTypeNONE0xFF / FAST0x00 / STRICT0x01是启动模式②authKeyHandleRSA 公钥 / AES 密钥句柄是(非NONE)验签密钥③operationOnFailDEGRADE0 / RESET1 / LOOP2是(非NONE)失败动作④xoscConfig时钟快照指针可 NULL否复位后 HSM 时钟⑤verifySegs{address,length}[8] 指针是(非NONE)代码段表⑥signs各段签名指针数组是(非NONE)签名⑦segcnt1~8是(非NONE)段数量⑧bootZ4TRUE/FALSE至少一个TRUE放 Z4_2⑨bootZ7_0TRUE/FALSE至少一个TRUE放 Z7_0⑩bootZ7_1TRUE/FALSE至少一个TRUE放 Z7_18.2 服务侧结构体对照hsm_srv_type.h:709~726typedef struct { hsmSecureBootType_t bootType; hsmKeyHandle_t authkeyHandle; hsmSecureBootFailOp_t operationOnFail; HOST_ADDR xoscConfig; HOST_ADDR verifySegs; HOST_ADDR signs; uint32_t signlens; boolean bootZ4; boolean bootZ7_0; boolean bootZ7_1; } hsmSecureBootConfigSrv_t;8.3 签名类型对照hsm_common_type.h:832~849// 主核侧uint8_t authTag0[512]RSA 最大 512 字节AES-CMAC 16 字节 typedef struct { uint8_t authTag0[512]; } hostSecureBootTag0_t; // 认证算法SMR/扩展用 #define HSM_AUTH_ALGO_CMAC 0x00 // AES-CMAC #define HSM_AUTH_ALGO_GMAC 0x01 #define HSM_AUTH_ALGO_HMAC 0x02 #define HSM_AUTH_ALGO_SM2 0x03 #define HSM_AUTH_ALGO_ECDSA 0x04 #define HSM_AUTH_ALGO_RSASSA_PKCS1V15 0x05 // ★RSA 安全启动默认 #define HSM_AUTH_ALGO_RSASSA_PSS 0x068.4 验签密钥类型判断hsm_secure_boot.c:1180~1201authKeyType验签函数签名长度HSM_KEY_TYPE_AESgenAuthTag_AES16 字节CMACHSM_KEY_TYPE_RSA_PAIR/RSA_PUBgenAuthTag_RSA256 字节2048 位9. 常见坑与排查清单FAE 实战9.1 配置阶段常见错误现象根因排查返回DEV_NOT_AUTHED没先开 DevAuth SECURE_BOOT 权限确认App_OpenDevAuth_New(..., HSM_DEV_AUTH_SECURE_BOOT)已成功返回INVALID_PARAM bootType errorbootType 不是 0/1/0xFF核对枚举值返回INVALID_PARAM no core is set boot三个 bootZx 全 FALSE至少放一个核返回INVALID_PARAM no valid code segmentsegcnt 为 0 或 8段数量 1~8返回VERIFY_FAILED签名不匹配检查私钥/公钥是否配对、段地址长度是否与签名时一致返回KEY_INVALID验签密钥类型不对确认是 AES 或 RSA_PUB/RSA_PAIR9.2 复位后验签阶段常见错误现象根因排查主核起不来、HSM 复位循环验签失败 ONFAIL_RESET抓 HSM 串口日志看HSM_SECURE_BOOT_FAIL全 0xFF 却直接放行启动表从未配置等效 NONE确认 ConfigSecureBoot 真的写成功了半写坏/残留垃圾 → 验签失败A/B 都无效兜底取了坏数据检查 D-Flash 启动表区域是否被误擦主核时钟不对xoscConfig 没传或没生效分清快照(复位后) vs 立即分频两条链9.3 高频踩坑点速记密钥一次性DevAuth/验签密钥导入后设不可导出不可更新就再也改不了烧录流程一次性做对。生命周期收窄切生命周期后权限收窄、调试口可能被锁量产前规划。HSM 时钟 ≤ 100MHz别超。失败动作提前定义RESET/LOOP/DEGRADE 三者对客户体验差异巨大别让主核带病运行。A/B 双份别只看一份排查启动表问题要看 A、B 两个 bank VALID/COUNTER。FAST 不是不验签FAST 是先放后验失败仍会触发 operationOnFail只是主核已经跑了一段。一句话总结安全启动 上电 HSM 先跑 → 读 A/B 启动表 → 按 NONE/FAST/STRICT 决定先放核还是先验签 → RSA/AES 验签 → 通过由z4_z70_z71_app_boot释放主核时钟走快照(复位后)立即分频两条链密钥与权限是整条链的信任根。