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_BYTES | 16 | AES 数据块固定为 128 bit。 |
AES_BLOCK_SIZE_WORDS | 4 | 一个数据块包含 4 个 32-bit word。 |
AES_KEY_128_WORDS | 4 | AES-128 key 为 16 byte。 |
AES_KEY_192_WORDS | 6 | AES-192 key 为 24 byte。 |
AES_KEY_256_WORDS | 8 | AES-256 key 为 32 byte。 |
AES_IV_WORDS | 4 | CBC IV 为 16 byte。 |
HAL_AES_MAX_KEY_SIZE_BYTES | 32 | 软件 key 最大长度。 |
HAL_AES_DMA_BUFFER_ALIGN_BYTES | cache line size | 推荐的 DMA buffer 对齐值。 |
HAL_AES_BUFFER_ALIGN | 同上 | 兼容旧代码的别名。 |
HAL_AES_DMA_BLOCK_BYTES | 16 | ASBNUM 的计数单位。 |
HAL_AES_DMA_SEGMENT_WINDOW_WORDS | 5 | DMA 寄存器窗口包含的 word 数。 |
HAL_AES_DMA_SEGMENT_WINDOW_BYTES | 20 | DMA 寄存器窗口大小为 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 length | EFUSE mode | register key |
|---|---|---|
| AES-128 | mode 0 到 mode 3 | 不允许,key = NULL,key_size_bytes = 0 |
| AES-192 | mode 0 到 mode 3 | 不允许,key = NULL,key_size_bytes = 0 |
| AES-256 | mode 0、1、2 | 必须提供 16 byte register key |
| AES-256 | mode 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;字段说明:
| 字段 | 说明 |
|---|---|
instance | AES 寄存器实例,当前只接受 AES。 |
page_size | 写入 ASCR.PS 的 page size。 |
input_endian | CPU 输入 word 和 DMA input endian 配置。 |
output_endian | CPU 输出 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 = AESpage_size = HAL_AES_PAGE_SIZE_4KBinput_endian = HAL_AES_ENDIAN_BIGoutput_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 时钟门控,并应用基础配置。
参数:
| 参数 | 类型 | 方向 | 说明 |
|---|---|---|---|
haes | hal_aes_handle_t * | 输入/输出 | caller-owned handle。 |
config | const hal_aes_config_t * | 输入 | 初始化配置。 |
返回值:
| 返回值 | 说明 |
|---|---|
IM_OK | 初始化成功。 |
IM_ERR_INVALID_PARAM | 指针、实例、page size 或 endian 参数非法。 |
IM_ERR_BUSY | handle 已经处于 in-use 状态。 |
IM_ERR_HARDWARE | AES 时钟门控使能失败。 |
初始化动作:
清空 handle。
复制配置。
打开
HAL_CPM_ID_GATE_AES。关闭 AES 和所有本地中断使能。
清除已置位的 AESD/DMAD/EKEY_RDD/EID_RDD。
配置 page size 和输入/输出 endian。
关闭 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_READYcallback 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 | 加密或解密。 |
mode | ECB 或 CBC。 |
key_length | AES-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_mode | EFUSE key mode。 |
id_fusion_enable | 是否启用 chip-id fusion。 |
iv | CBC IV;ECB 忽略。 |
input | 一个 16 byte AES block。 |
返回值:
| 返回值 | 说明 |
|---|---|
IM_OK | block 已启动。 |
IM_ERR_INVALID_PARAM | handle、descriptor、input、算法参数、key 或 IV 非法。 |
IM_ERR_NOT_READY | handle 未初始化。 |
IM_ERR_BUSY | handle 不在 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 操作完成并进入
READYoutput_size >= 16输出字节序按
config.output_endian组装
错误条件:
参数为空或容量不足:
IM_ERR_INVALID_PARAMhandle 未初始化:
IM_ERR_NOT_READYhandle 不在
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 / 4ASBNUM = byte_count / 16
启动顺序:
校验 descriptor 和算法参数。
清除旧完成位。
打开 AES DMA mode。
配置 key、IV、方向、mode 和 key length。
写源地址和目标地址。
写源/目标 transfer count 和 block count。
打开 DMA done local interrupt enable。
状态切换到
WAITING_DMA。置位
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[] 的顺序固定为:
| 下标 | 寄存器 | 内容 |
|---|---|---|
| 0 | ASSA | 源物理地址 |
| 1 | ASSTC | 源传输 word 数 |
| 2 | ASDA | 目标物理地址 |
| 3 | ASDTC | 目标传输 word 数 |
| 4 | ASBNUM | AES 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_READYtimeout_us == 0:返回IM_ERR_TIMEOUTsystick 未初始化:返回
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);