API GUIDE / AES / HAL

G32S10 AES HAL 接口

HAL 层接口:实例定义如下:

1. 资源模型与公开类型

1.1 模块实例与构建开关

项目值
寄存器实例AES
基地址宏AES_IOBASE
基地址0x13430000
驱动开关CONFIG_DRIVER_AES
时钟门控HAL_CPM_ID_GATE_AES
调试开关CONFIG_AES_ENABLE_DEBUG_HELPERS

实例定义如下:

#define AES ((aes_regs_t *)(uintptr_t)AES_IOBASE)

CONFIG_DRIVER_AES 会同时选择 CONFIG_DRIVER_CPM。HAL 在 hal_aes_init() 中打开 AES 门控,在 hal_aes_deinit() 中关闭该门控。

1.2 尺寸与对齐宏

宏当前值说明
AES_BLOCK_SIZE_BYTES16AES 数据块固定为 128 bit。
AES_BLOCK_SIZE_WORDS4一个数据块包含 4 个 32-bit word。
AES_KEY_128_WORDS4AES-128 key 为 16 byte。
AES_KEY_192_WORDS6AES-192 key 为 24 byte。
AES_KEY_256_WORDS8AES-256 key 为 32 byte。
AES_IV_WORDS4CBC IV 为 16 byte。
HAL_AES_MAX_KEY_SIZE_BYTES32软件 key 最大长度。
HAL_AES_DMA_BUFFER_ALIGN_BYTEScache line size推荐的 DMA buffer 对齐值。
HAL_AES_BUFFER_ALIGN同上兼容旧代码的别名。
HAL_AES_DMA_BLOCK_BYTES16ASBNUM 的计数单位。
HAL_AES_DMA_SEGMENT_WINDOW_WORDS5DMA 寄存器窗口包含的 word 数。
HAL_AES_DMA_SEGMENT_WINDOW_BYTES20DMA 寄存器窗口大小为 5 个 32-bit word。

DMA register window:

typedef struct {
    volatile uint32_t *address;
    uint32_t words[HAL_AES_DMA_SEGMENT_WINDOW_WORDS];
} hal_aes_dma_segment_window_t;

address 指向 ASSA,words[] 按 ASSA/ASSTC/ASDA/ASDTC/ASBNUM 顺序排列。

1.3 page size

typedef enum {
    HAL_AES_PAGE_SIZE_DONT_CARE = AES_ASCR_PS_DONT_CARE,
    HAL_AES_PAGE_SIZE_1KB = AES_ASCR_PS_1KB,
    HAL_AES_PAGE_SIZE_2KB = AES_ASCR_PS_2KB,
    HAL_AES_PAGE_SIZE_4KB = AES_ASCR_PS_4KB,
    HAL_AES_PAGE_SIZE_8KB = AES_ASCR_PS_8KB,
    HAL_AES_PAGE_SIZE_16KB = AES_ASCR_PS_16KB,
} hal_aes_page_size_t;

page size 写入 ASCR.PS。hal_aes_config_struct_init() 默认选择 4 KB。

1.4 算法参数类型

typedef enum {
    HAL_AES_DIRECTION_ENCRYPT = 0,
    HAL_AES_DIRECTION_DECRYPT,
} hal_aes_direction_t;

typedef enum {
    HAL_AES_KEY_LENGTH_128 = AES_ASCR_KEYL_128,
    HAL_AES_KEY_LENGTH_192 = AES_ASCR_KEYL_192,
    HAL_AES_KEY_LENGTH_256 = AES_ASCR_KEYL_256,
} hal_aes_key_length_t;

typedef enum {
    HAL_AES_MODE_ECB = AES_ASCR_MODE_ECB,
    HAL_AES_MODE_CBC = AES_ASCR_MODE_CBC,
} hal_aes_mode_t;

typedef enum {
    HAL_AES_ENDIAN_BIG = AES_ENDIAN_BIG,
    HAL_AES_ENDIAN_LITTLE = AES_ENDIAN_LITTLE,
} hal_aes_endian_t;

typedef enum {
    HAL_AES_TRANSFER_CPU = 0U,
    HAL_AES_TRANSFER_DMA,
} hal_aes_transfer_t;

说明:

  • 通用 AES HAL 只支持 ECB 和 CBC。

  • AES-192 和 AES-256 只改变 key 展开长度,数据块仍是 16 byte。

  • input_endian 和 output_endian 分别写入 ASCR.DIN_ENDIAN 和 ASCR.DOUT_ENDIAN。

  • hal_aes_transfer_t 是旧驱动测试使用的数据通路枚举。当前 HAL 通过调用不同 API 区分 CPU 和 DMA,不要求把该枚举写入 hal_aes_config_t。

1.5 key source 与 EFUSE key mode

typedef enum {
    HAL_AES_KEY_SOURCE_SOFTWARE = 0U,
    HAL_AES_KEY_SOURCE_EFUSE,
} hal_aes_key_source_t;

typedef enum {
    HAL_AES_EFUSE_KEY_MODE_0 = AES_ASCR_EKEY_MODE_0,
    HAL_AES_EFUSE_KEY_MODE_1 = AES_ASCR_EKEY_MODE_1,
    HAL_AES_EFUSE_KEY_MODE_2 = AES_ASCR_EKEY_MODE_2,
    HAL_AES_EFUSE_KEY_MODE_3 = AES_ASCR_EKEY_MODE_3,
} hal_aes_efuse_key_mode_t;

EFUSE key 组合规则:

key lengthEFUSE moderegister key
AES-128mode 0 到 mode 3不允许,key = NULL,key_size_bytes = 0
AES-192mode 0 到 mode 3不允许,key = NULL,key_size_bytes = 0
AES-256mode 0、1、2必须提供 16 byte register key
AES-256mode 3不允许,key = NULL,key_size_bytes = 0

软件 key 必须满足:

  • AES-128:16 byte

  • AES-192:24 byte

  • AES-256:32 byte

1.6 HAL 配置

typedef struct {
    aes_regs_t *instance;
    hal_aes_page_size_t page_size;
    hal_aes_endian_t input_endian;
    hal_aes_endian_t output_endian;
} hal_aes_config_t;

typedef hal_aes_config_t hal_aes_init_config_t;

字段说明:

字段说明
instanceAES 寄存器实例,当前只接受 AES。
page_size写入 ASCR.PS 的 page size。
input_endianCPU 输入 word 和 DMA input endian 配置。
output_endianCPU 输出 word 和 DMA output endian 配置。

配置对象在 hal_aes_init() 内按值复制;初始化返回后,调用方无需继续保持该对象有效。

hal_aes_init_config_t 是旧接口名称的兼容别名。

2. HAL 接口规范

2.1 hal_aes_config_struct_init

void hal_aes_config_struct_init(hal_aes_config_t *config);

填充默认配置:

  • instance = AES

  • page_size = HAL_AES_PAGE_SIZE_4KB

  • input_endian = HAL_AES_ENDIAN_BIG

  • output_endian = HAL_AES_ENDIAN_BIG

传入 NULL 时不做任何操作。

2.2 hal_aes_init

error_code_t hal_aes_init(hal_aes_handle_t *haes,
                          const hal_aes_config_t *config);

初始化一个零初始化的 HAL handle,打开 AES 时钟门控,并应用基础配置。

参数:

参数类型方向说明
haeshal_aes_handle_t *输入/输出caller-owned handle。
configconst hal_aes_config_t *输入初始化配置。

返回值:

返回值说明
IM_OK初始化成功。
IM_ERR_INVALID_PARAM指针、实例、page size 或 endian 参数非法。
IM_ERR_BUSYhandle 已经处于 in-use 状态。
IM_ERR_HARDWAREAES 时钟门控使能失败。

初始化动作:

  1. 清空 handle。

  2. 复制配置。

  3. 打开 HAL_CPM_ID_GATE_AES。

  4. 关闭 AES 和所有本地中断使能。

  5. 清除已置位的 AESD/DMAD/EKEY_RDD/EID_RDD。

  6. 配置 page size 和输入/输出 endian。

  7. 关闭 DMA,打开 AES enable。

注意:

  • hal_aes_init() 不申请和使能 SoC AES IRQ。

  • hal_aes_init() 不主动写入 EKEY_CLR,因此上电/reset 阶段形成的 EFUSE reset-read 状态仍然有效。

  • hal_aes_init() 不主动清除硬件中的旧 key、IV 或 data;敏感场景可在使用后调用 hal_aes_abort()。

2.3 hal_aes_callback_register

error_code_t hal_aes_callback_register(hal_aes_handle_t *haes,
                                       hal_aes_callback_type_t type,
                                       hal_aes_callback_t callback);

注册或注销一个 callback slot。callback = NULL 表示注销。

错误条件:

  • handle 未初始化:IM_ERR_NOT_READY

  • callback type 非法:IM_ERR_INVALID_PARAM

  • 当前状态不是 READY:IM_ERR_BUSY

2.4 hal_aes_user_data_set

error_code_t hal_aes_user_data_set(hal_aes_handle_t *haes,
                                   void *user_data);

设置传给全部 AES callback 的上下文指针。该接口只能在 READY 状态调用。

2.5 hal_aes_cpu_block_start

error_code_t hal_aes_cpu_block_start(
    hal_aes_handle_t *haes,
    const hal_aes_cpu_block_t *block);

启动一个 CPU 数据通路 AES block。

hal_aes_cpu_block_t 包含:

字段说明
direction加密或解密。
modeECB 或 CBC。
key_lengthAES-128/192/256。
key_source软件 key 或 EFUSE key。
key软件 key,或 AES-256 EFUSE mode 0/1/2 的 16 byte register key。
key_size_bytes必须符合 key source 和 key length 规则。
efuse_key_modeEFUSE key mode。
id_fusion_enable是否启用 chip-id fusion。
ivCBC IV;ECB 忽略。
input一个 16 byte AES block。

返回值:

返回值说明
IM_OKblock 已启动。
IM_ERR_INVALID_PARAMhandle、descriptor、input、算法参数、key 或 IV 非法。
IM_ERR_NOT_READYhandle 未初始化。
IM_ERR_BUSYhandle 不在 READY 状态。

启动后:

  • 状态切换为 WAITING_CPU

  • 打开 CPU done local interrupt enable

  • 置位 ASCR.AESS 启动运算

  • status 中的 key、IV、input descriptor 在函数返回前已消费

2.6 hal_aes_cpu_result_read

error_code_t hal_aes_cpu_result_read(hal_aes_handle_t *haes,
                                     uint8_t *output,
                                     size_t output_size);

从 ASDO 读取一个 16 byte 结果 block。

调用要求:

  • 必须等待 CPU 操作完成并进入 READY

  • output_size >= 16

  • 输出字节序按 config.output_endian 组装

错误条件:

  • 参数为空或容量不足:IM_ERR_INVALID_PARAM

  • handle 未初始化:IM_ERR_NOT_READY

  • handle 不在 READY 状态:IM_ERR_NOT_READY

2.7 hal_aes_dma_segment_start

error_code_t hal_aes_dma_segment_start(
    hal_aes_handle_t *haes,
    const hal_aes_dma_segment_t *segment);

启动一个完整 DMA AES segment。

hal_aes_dma_segment_t 的算法字段与 CPU block 相同,另有:

字段说明
src_phys_addr设备可见的源物理地址,不能为 0。
dst_phys_addr设备可见的目标物理地址,不能为 0。
byte_count传输字节数,必须非 0 且按 16 byte 对齐。

HAL 根据 byte_count 计算:

  • ASSTC = ASDTC = byte_count / 4

  • ASBNUM = byte_count / 16

启动顺序:

  1. 校验 descriptor 和算法参数。

  2. 清除旧完成位。

  3. 打开 AES DMA mode。

  4. 配置 key、IV、方向、mode 和 key length。

  5. 写源地址和目标地址。

  6. 写源/目标 transfer count 和 block count。

  7. 打开 DMA done local interrupt enable。

  8. 状态切换到 WAITING_DMA。

  9. 置位 ASCR.DMAS。

注意:

  • HAL 不做 cache clean/invalidate。

  • HAL 不做虚拟地址转换。

  • HAL 不复制输入或输出 buffer。

  • src_phys_addr 和 dst_phys_addr 必须在 DMAD 前保持有效。

  • HAL 不自动启动下一个 segment,也不更新 CBC IV;分段和 IV 依赖关系的组织属于上层。

2.8 DMA register-window 接口

error_code_t hal_aes_dma_segment_prepare(
    hal_aes_handle_t *haes,
    const hal_aes_dma_segment_t *segment,
    hal_aes_dma_segment_window_t *window);

error_code_t hal_aes_dma_segment_window_write(
    hal_aes_handle_t *haes,
    const hal_aes_dma_segment_window_t *window);

error_code_t hal_aes_dma_segment_kick(hal_aes_handle_t *haes);

这组接口用于由调用方自己的 DMA engine 更新 AES segment 寄存器,或者由 CPU 完成同样的寄存器写入。

prepare 会:

  • 校验 segment

  • 配置 key、IV、方向、mode、key length 和 AES DMA mode

  • 返回寄存器窗口起点和 5 个待写 word

window->words[] 的顺序固定为:

下标寄存器内容
0ASSA源物理地址
1ASSTC源传输 word 数
2ASDA目标物理地址
3ASDTC目标传输 word 数
4ASBNUMAES block 数

调用方可以由外部 DMA 写入该窗口,也可以调用 hal_aes_dma_segment_window_write() 从 CPU 写入。CPU helper 写完后执行写内存屏障。写入完成后必须调用 hal_aes_dma_segment_kick()。

prepare 不切换 HAL 到 waiting 状态。只有 kick 成功后才进入 WAITING_DMA。

2.9 EFUSE 接口

2.9.1 hal_aes_efuse_reset_read_wait

error_code_t hal_aes_efuse_reset_read_wait(hal_aes_handle_t *haes,
                                           uint32_t timeout_us);

在任务上下文轮询 ASSR.EKEY_RSTD。该状态没有中断使能位。

行为:

  • EKEY_RSTD 已置位:立即返回 IM_OK

  • 已经调用过 hal_aes_efuse_state_clear():返回 IM_ERR_NOT_READY

  • timeout_us == 0:返回 IM_ERR_TIMEOUT

  • systick 未初始化:返回 IM_ERR_NOT_READY

  • 轮询超时:记录并返回 IM_ERR_TIMEOUT

2.9.2 hal_aes_efuse_state_clear

error_code_t hal_aes_efuse_state_clear(hal_aes_handle_t *haes);

置位 ASCR.EKEY_CLR,清除已经加载/fuse 的 key 和 chip-id 状态,同时使后续 EKEY_RSTD reset-read 检查失效。

调用后必须通过 EKEY_RD/EID_RD 原语重新准备 EFUSE 状态。

2.9.3 hal_aes_efuse_key_read_start

error_code_t hal_aes_efuse_key_read_start(
    hal_aes_handle_t *haes,
    const hal_aes_efuse_request_t *request);

配置 EKEY_MODE/ID_FUSION,打开 EKEY_RDD local interrupt,置位 ASCR.EKEY_RD,并进入 WAITING_EKEYRD。

2.9.4 hal_aes_efuse_id_read_start

error_code_t hal_aes_efuse_id_read_start(
    hal_aes_handle_t *haes,
    const hal_aes_efuse_request_t *request);

配置 EKEY_MODE/ID_FUSION,打开 EID_RDD local interrupt,置位 ASCR.EID_RD,并进入 WAITING_EIDRD。

补充说明:

  • hal_aes_efuse_request_t.use_efuse_key 当前不会被 hal_aes.c 读取;实际完成 EFUSE 加解密准备的是 mode、ID fusion 和 EKEY_RD/EID_RD 状态机。

  • 两个 EFUSE read 启动接口都会先关闭其他 AES local interrupt,并清除已置位的 AESD/DMAD/EKEY_RDD/EID_RDD。

2.10 hal_aes_irq_handler

void hal_aes_irq_handler(hal_aes_handle_t *haes);

该函数由持有 IRQ_AES 的 SoC IRQ handler 调用。

处理规则:

  • 读取 ASSR & ASINTEN,只处理已经使能的完成位。

  • 当前 waiting 状态和完成位匹配时:

    • 更新 error_code = IM_OK

    • 状态回到 READY

    • 关闭对应 local interrupt enable

    • 清除对应 W1C pending

    • 调用对应 callback

  • 最后再次清除所有已置位的 AESD/DMAD/EKEY_RDD/EID_RDD。

该函数不会:

  • 推进上层分段

  • 复制 DMA 输出

  • 更新 CBC IV

  • 唤醒线程

  • 执行大量日志

  • 处理没有打开 ASINTEN 的完成位

HAL 不拥有 SoC IRQ。调用顺序应为:

im_irq_request(IRQ_AES, aes_irq_entry, "aes", &handle);
hal_aes_callback_register(&handle, HAL_AES_CALLBACK_CPU_DONE, cpu_done);
hal_aes_callback_register(&handle, HAL_AES_CALLBACK_DMA_DONE, dma_done);
im_irq_enable(IRQ_AES);

IRQ entry 中调用:

hal_aes_irq_handler(&handle);

2.11 hal_aes_abort

error_code_t hal_aes_abort(hal_aes_handle_t *haes);

在任务上下文终止当前操作并恢复 READY:

  • 关闭全部 local interrupt

  • 关闭 DMA mode 和 AES enable

  • 清除 pending

  • 置位 ASCR.CLR 清除硬件中的 IV、key、input 和 output

  • 重新应用基础配置

  • 清除 handle 错误状态

该接口不会清除 ASSR.EKEY_RSTD。

2.12 hal_aes_deinit

error_code_t hal_aes_deinit(hal_aes_handle_t *haes);

关闭本地中断、DMA 和 AES enable,清除 pending,释放 AES CPM gate,并清零 handle。

注意:

  • 本接口不释放 SoC IRQ。

  • 调用方必须先停止 IRQ 投递,再 deinit HAL。

  • 本接口不会主动置位 ASCR.CLR。若需要清除硬件中的 key/IV/data,应在 deinit 前调用 hal_aes_abort()。

  • deinit 返回后该 handle 不可继续使用;再次使用前必须重新调用 hal_aes_init()。

2.13 hal_aes_regs_dump

error_code_t hal_aes_regs_dump(const hal_aes_handle_t *haes);

仅在以下两个条件同时满足时提供实际 dump:

CONFIG_SDK_ENABLE_DEBUG_HELPERS=y
CONFIG_AES_ENABLE_DEBUG_HELPERS=y

否则返回 IM_ERR_UNSUPPORTED。

dump 包含 ASCR、ASSR、ASINTEN、ASSA、ASSTC、ASDA、ASDTC 和 ASBNUM。出于敏感数据和读副作用考虑,ASDI、ASDO、ASKY、ASIV 显示为 skipped。

3. CPU、DMA 与 EFUSE 操作流程

3.1 CPU block

READY
  -> hal_aes_cpu_block_start()
  -> WAITING_CPU
  -> ASSR.AESD
  -> hal_aes_irq_handler()
  -> READY + CPU_DONE callback
  -> hal_aes_cpu_result_read()

CBC 多块运算需要上层按块串联;当前 CPU HAL 原语只处理一个 16 byte block,也不会自动把当前密文块作为下一块 IV。

3.2 DMA segment

READY
  -> hal_aes_dma_segment_start()
  -> WAITING_DMA
  -> ASSR.DMAD
  -> hal_aes_irq_handler()
  -> READY + DMA_DONE callback
  -> caller cache invalidate + output processing

或者:

hal_aes_dma_segment_prepare()   /* READY remains unchanged */
  -> external DMA/CPU writes ASSA/ASSTC/ASDA/ASDTC/ASBNUM
  -> hal_aes_dma_segment_kick()
  -> WAITING_DMA
  -> DMAD

3.3 EFUSE read primitive

hal_aes_efuse_key_read_start() / hal_aes_efuse_id_read_start()
  -> waiting state
  -> EKEY_RDD / EID_RDD
  -> hal_aes_irq_handler()
  -> READY + callback

4. 数据格式、endian 与 cache 契约

4.1 CPU 数据

  • 输入一个 block 写 4 words 到 ASDI。

  • 输入/输出 word 的字节序由 config.input_endian/output_endian 决定。

  • 输出由 hal_aes_cpu_result_read() 写回 16 byte buffer。

4.2 敏感数据

  • HAL handle 本身不会在 deinit 时显式覆盖调用方曾经传入的 key/IV buffer。

  • hal_aes_abort() 会置位 ASCR.CLR,清除硬件内部 key、IV、input 和 output。

  • 如需在关闭 AES 前清理硬件敏感状态,应显式执行 abort。

5. 典型用法

5.1 CPU block

hal_aes_handle_t aes = {0};
hal_aes_config_t config;
hal_aes_cpu_block_t block = {
    .direction = HAL_AES_DIRECTION_ENCRYPT,
    .mode = HAL_AES_MODE_ECB,
    .key_length = HAL_AES_KEY_LENGTH_128,
    .key_source = HAL_AES_KEY_SOURCE_SOFTWARE,
    .key = key,
    .key_size_bytes = 16U,
    .input = input_block,
};
uint8_t output[HAL_AES_BLOCK_SIZE_BYTES];

hal_aes_config_struct_init(&config);
ret = hal_aes_init(&aes, &config);
ret = hal_aes_cpu_block_start(&aes, &block);
/* 等待 IRQ_AES 进入 hal_aes_irq_handler() 并触发 CPU_DONE。 */
ret = hal_aes_cpu_result_read(&aes, output, sizeof(output));
hal_aes_deinit(&aes);