TXW81x_IOT-v2.5.3.6升级到TXW81x_FPV-v2.5.4.7 版本flash 加密写入异常
-
TXW81x:XIP 运行时 Flash 加密写(SET_ENCRYPT)不可用 / 极慢
一、环境
项 值 芯片 TXW817-824 SDK hgSDK v2.5.4.3-41396(libflash / libcore 同版本) 运行方式 程序在 SPI Flash XIP 上执行( SPI_NOR_XIP_MODE,QSPI/spi7)OS RTOS(有任务 / mutex; spi_nor_write内os_mutex_lock)镜像布局 ildr@0x10000,iapp@0x90000,size0x100000makecode CodeAddrOffset=0x1000,AesEnable=0分区表 ildr/iapp等带 encrypted 标志工厂烧录 AesEnable=0+ PT encrypted → 上电 txloader:ENCRYPT×N →VERIFY→RUN正常加密 remap 约定(与官方注释一致):
remap_base = partition_flash_addr + CodeAddrOffset = 0x90000 + 0x1000 = 0x91000 // iapp 为例 HDR [0, 0x1000) 明文;body [0x1000, ...) 需硬件加密写入
二、问题描述(摘要)
需求:Loader(XIP)做 OTA 时,按官方方式把 明文 body 写成与 txloader
ENCRYPT后相同的 片上 Flash 密文,以便复位后 VERIFY / 加密 XIP 启动。现象:
- 工厂 / txloader
ENCRYPT:正常(encrypt bin done→verify bin done→ RUN)。 - 应用内官方加密写(见下文伪代码):
- 若按示例
__disable_irq()包住spi_nor_write:触发
** FATAL CALL , IRQ DISABLED **(pend_to_blk_obj,mutex/信号量在关中断下阻塞)。 - 若 去掉关中断(仅保留
SET_ENCRYPT+REMAP+spi_nor_write):能写完,但极慢,实测约24000 ms / 1KB(约 24s/KB,整包 ~750KB body 不可接受)。
- 若按示例
- OTA 只写明文 body(不开
SET_ENCRYPT):Loader 内 CRC 可对;复位后 txloader 不再 ENCRYPT,直接 VERIFY →boot_data_crc compare fail(PT 仍 encrypted)。 - HDR
aes_en=0(与 makecode AesEnable=0 一致):不能让 VERIFY 按明文介质处理;加密策略以 PT encrypted 为准。 - 公开 SDK 无「用 Flash 片内密钥在 RAM 加密 buffer,再明文
spi_nor_write」的 API(仅有通用sysaes,需自备 key;efuse只能取 key 的 CRC)。
诉求:请官方给出 XIP + RTOS 下 对 encrypted 分区做 OTA 加密写的推荐做法(或确认不支持),例如:
- 是否必须把写路径放到 SRAM 再
SET_ENCRYPT? - 是否有 host 预加密 工具/算法与片内一致?
- 是否有接口 强制再次 ENCRYPT(OTA 明文写后)?
SET_ENCRYPT期间与 XIP 取指的官方约束 / 时序(WIP、wip.tms)?
三、官方路径伪代码(问题复现用)
与 SDK/
spi.h注释及官方 sample 中hal_partition_write_encrypt一致:/* __CODE_OFFSET == makecode CodeAddrOffset == 0x1000 */ void official_flash_encrypt_program(uint32_t part_addr, uint32_t dst_offset, /* >= 0x1000 for body */ const uint8_t *plain, uint32_t len) { struct spi_nor_flash *flash = (struct spi_nor_flash *)dev_get(HG_FLASH0_DEVID); uint32_t remap = part_addr + __CODE_OFFSET; /* e.g. 0x91000 */ uint32_t irq; spi_nor_open(flash); /* --- 官方示例常见写法:关中断 --- */ irq = __disable_irq(); spi_nor_ioctl(flash, SPI_XIP_CUSTOM_SET_ENCRYPT, 1, 0); spi_nor_ioctl(flash, SPI_XIP_CUSTOM_SET_REMAP, remap, 0); /* 写 Flash 绝对地址,不是 remap 后的 CPU 地址 */ spi_nor_write(flash, part_addr + dst_offset, (uint8_t *)plain, len); spi_nor_ioctl(flash, SPI_XIP_CUSTOM_SET_ENCRYPT, 0, 0); spi_nor_ioctl(flash, SPI_XIP_CUSTOM_SET_REMAP, 0, 0); enable_irq(irq); spi_nor_close(flash); }对应 SDK 枚举(
sdk/include/hal/spi.h):SPI_XIP_CUSTOM_SET_REMAP, // 配置 remap;需 SET_ENCRYPT=1 才生效 SPI_XIP_CUSTOM_SET_ENCRYPT, // 是否强行加密变体 A(与示例一致,关中断) → 本板 RTOS:
FATAL CALL, IRQ DISABLED。
变体 B(去掉 disable_irq/enable_irq,其余相同) → 本板:功能上可写,~24s/KB。明文对照(同 XIP):
/* HDR 或实验明文 body:不开 ENCRYPT */ spi_nor_open(flash); spi_nor_write(flash, part_addr + dst_offset, plain, len); /* 正常快 */ spi_nor_close(flash);擦除(64KB block)1MB 约百毫秒级,说明普通擦写正常。
四、复现步骤(简)
- 工厂烧录:PT
iappencrypted,AesEnable=0,确认上电有ENCRYPT/VERIFY/RUN。 - 从 XIP Loader 擦除
iapp,写 HDR[0,0x1000)明文(快)。 - 对 body
offset>=0x1000调用上文official_flash_encrypt_program:- 带
__disable_irq→ 观察 FATAL; - 或不关中断 → 打点测量
spi_nor_write耗时(本板 ~24000ms/1024B)。
- 带
- (可选)body 改明文写后
mcu_reset:观察多为INIT→INFO→VERIFY(无 ENCRYPT),encrypted 槽 CRC fail。
五、已排除 / 已观察
项 结论 ioctl 顺序 / remap= part+0x1000/ 绝对地址写与官方一致 仅写 4KB HDR 不会进加密写(预期) 去 BLE、关 PSRAM_HEAP 未把 24s/KB 降到可用 spi7.wip.tms=60000(无 erase-suspend 的 FAQ 配法)erase 仍快;不解释为「每次等满 60s」,但是否加重 ENCRYPT+XIP 待官方确认 HDR aes_en=0不能改为明文 VERIFY 清 PT encrypted 双槽 VERIFY 失败 → END(已恢复)
六、希望官方明确回答
- XIP 执行代码时,是否支持对同 Flash 做
SET_ENCRYPT+spi_nor_write?官方推荐流程是什么? - 示例中的 **
__disable_irq+ spi_nor_write** 在带 mutex 的libflash` 上如何避免 FATAL?是否必须 SRAM 重定位写函数? - 有无 与片内 Flash 密钥一致 的预加密接口/工具(PC 或片上 buffer 加密)?
- OTA 明文写入后,如何 触发与工厂相同的 ENCRYPT?
24000ms/1KB是否为已知限制?可接受优化手段?
七、日志摘录
关中断 FATAL:
enc-wr enter ... (or WR into encrypt body @0x91000) ** FATAL CALL , IRQ DISABLED ** assertation ... pend_to_blk_obj ... Task:iplld_ws不关中断极慢:
enc-wr off=0x1000 size=0x400 24000ms工厂路径正常:
cur_st: ENCRYPT working at 0, encrypt bin done working at 1, encrypt bin done cur_st: VERIFY working at 0, verify bin done cur_st: RUN明文 OTA 后复位(无再 ENCRYPT):
cur_st: INIT → INFO → VERIFY // 无 ENCRYPT ... boot_data_crc compare fail ... - 工厂 / txloader