Edit online

设计要点

在设计实现 SPI_ENC 的驱动时,主要考虑了 SPI_ENC 的本身特点,以及与 SPI NOR / SPI NAND 驱动的结合。
注: 由于 SPI_ENC 内部使用 eFuse 所提供的密钥,因此不需要通过外部设置密钥函数来设置密钥。

数据读写时启用

SPI NAND / SPI NOR 驱动通过发送命令的方式与 SPI NAND / SPI NOR 器件进行交互,从而实现数据的读写。 在使能 SPI_ENC 之后,SPI NAND / SPI NOR 驱动需要进行区分:

  • 非存储数据的 SPI 传输,不启动 SPI_ENC,按照原有驱动的流程执行

  • 存储数据的 SPI 传输,启动 SPI_ENC 进行加密或者解密

因此 SPI NAND / SPI NOR 驱动需要做一些改动,在对存储数据进行读写时,使用 Crypto API 启动 SPI_ENC。

以 SPI NAND 为例:

初始化 spinand 时,同时进行加密相关的初始化。
spinand_flash_init();
|-> drv_spienc_init()
读操作流程:
spinand_read_page();
|-> SPINAND_FLASH_OPS->read_dataload();
|-> cpos = 1 + 2 + (SPINAND_FLASH_DUMMYBYTE * 8); /* cpos = cmd.nbyte + addr.nbyte + dummy.nbyte */
|-> drv_spienc_set_cfg(0, page * SPINAND_FLASH_PAGE_SIZE, cpos, data_len); /* 配置本次加密数据信息 */
|-> drv_spienc_start(); /* 启动 SPI_ENC */
|-> SPINAND_FLASH_OPS->read_quadoutput(qspi, 0, buf, data_len); /* 调用标准 SPI API 进行数据传输 */
|-> drv_spienc_stop(); /* 停止 SPI_ENC */
|-> drv_spienc_check_empty() /* 检查是否为空 page */
写操作流程:
spinand_write_page();
|-> SPINAND_FLASH_OPS->program_dataload();
|-> cpos = 1 + 2 + (SPINAND_FLASH_DUMMYBYTE * 8); /* cpos = cmd.nbyte + addr.nbyte + dummy.nbyte */
|-> drv_spienc_set_cfg(0, page * SPINAND_FLASH_PAGE_SIZE, cpos, data_len); /* 配置本次加密数据信息 */
|-> drv_spienc_start(); /* 启动 SPI_ENC */
|-> SPINAND_FLASH_OPS->program_dataload(); /* 调用标准 SPI API 进行数据传输 */
|-> drv_spienc_stop(); /* 停止 SPI_ENC */
|-> SPINAND_FLASH_OPS->program_execute();

空数据块的检测

SPI NAND / SPI NOR 在执行了擦除之后,存储单元上的数据被认为是空的,值都是 0xFF 。 但是在使用过程中,读取程序并不一定知道所读取的区域是否是被擦除过,因此在使能了 SPI_ENC 之后, 通过 SPI 读取回来该区域的数据都是被 SPI_ENC 解密后的数据。原本是被擦除后的 0xFF , 读回来的却是其他数据。

带来的问题:

有些程序,如文件系统,会判断读回来的数据是否都为 0xFF ,如果是,则认为是未使用的块,做特殊处理。 现在读回来的数据却被改变了,会导致原来的处理逻辑全部失效。

为了解决上述问题,SPI_ENC 提供了一个空块检测功能。如下图所示:

  • 首先按照正常的流程读取一块数据

  • 传输完成之后,检查 SPI_ENC 的状态,如果提示解密前的所有数据都是 0xFF ,则软件将读取的结果全部置为 0xFF

../../images/spienc_empty_detect1.png
1. 空块检测

相关的软件操作,在 spinand_enc_read()spi_nor_enc_read() 中完成。