DA14531芯片固件逆向系列(2)- 操作系统底层机制分析
字数 2537 2025-08-24 07:48:09
DA14531芯片固件逆向分析:操作系统底层机制详解
概述
DA145x软件平台采用了由Riviera Waves许可的小型高效实时内核,该内核提供了以下核心功能:
- 任务创建和状态转换
- 任务之间的消息交换
- 计时器管理
- 动态内存分配
- BLE事件的调度和处理
基础数据结构
co_list链表实现
co_list是Riviera Waves系统中广泛使用的单向链表实现,用于存放各种数据如消息数据。
核心数据结构
// 链表中的节点
struct co_list_hdr {
/// 指向下一个链表节点
struct co_list_hdr *next;
};
/// 链表头的结构
struct co_list {
// 链表头节点
struct co_list_hdr *first;
// 链表尾节点
struct co_list_hdr *last;
// 链表中的节点个数
uint32_t cnt;
// 链表中最多节点数
uint32_t maxcnt;
// 链表中最少节点数
uint32_t mincnt;
};
链表操作函数
-
链表初始化 -
co_list_initvoid __fastcall co_list_init(struct co_list *list) { list->first = 0; list->last = 0; list->cnt = 0; list->maxcnt = 0; list->mincnt = -1; } -
插入节点
co_list_push_back- 将节点插入到链表尾部co_list_push_front- 将节点插入到链表头部
-
节点出链表 -
co_list_pop_frontstruct co_list_hdr *__fastcall co_list_pop_front(struct co_list *list) { struct co_list_hdr *item = list->first; if (list->first) { list->first = item->next; if (!item->next) { list->last = 0; } list->cnt--; // 更新mincnt等统计信息 } return item; } -
取出节点 -
co_list_extract- 从指定节点开始取出指定数量的节点
- 注意:如果nb_following超过链表长度会导致空指针问题
-
查找节点 -
co_list_find- 遍历链表查找指定节点
-
链表合并 -
co_list_mergevoid __fastcall co_list_merge(struct co_list *list1, struct co_list *list2) { list1->last->next = list2->first; list1->last = list2->last; list2->first = 0; list1->cnt += list2->cnt; list2->cnt = 0; }
事件调度机制
Riviera Waves实现了事件调度机制,任务可以通知特定的事件处理函数进行事务处理。
事件管理结构
struct ke_event_table_struct {
int pending_event_bits; // 事件状态位
int callback_list[6]; // 事件处理函数数组
};
关键API
-
事件初始化 -
ke_event_initvoid ke_event_init() { memset(p_ke_event_table, 0, sizeof(ke_event_table_struct)); } -
注册事件处理函数 -
ke_event_callback_setuint8_t __fastcall ke_event_callback_set(uint8_t event_type, void (*p_callback)(void)) { if (event_type < 6) { p_ke_event_table->callback_list[event_type] = p_callback; return 0; } return 3; // 错误码 } -
事件调度 -
ke_event_schedule- 检查所有事件状态,调用pending状态的事件处理函数
- 不会自动清除事件状态位,需在回调中调用
ke_event_clear
-
设置/清除事件状态
ke_event_set- 设置事件状态位为1ke_event_clear- 设置事件状态位为0
系统注册的事件处理函数
| 地址 | 事件号 | 回调函数地址 | 回调函数名称 |
|---|---|---|---|
| 0x7F08BB2 | 0x5 | 0x7F08A6E | lld_evt_deffered_elt_handler |
| 0x7F09CCE | 0x0 | 0x7F02744 | llm_encryption_done |
| 0x7F0E5C2 | 0x3 | 0x7F0E58E | event_3_callback_func |
| 0x7F0E956 | 0x4 | 0x7F0E87C | event_4_callback_func |
| 0x7F1CDEC | 0x1 | 0x7F1CCDE | event_1_callback_func |
| 0x7F1D06C | 0x2 | 0x7F1CFFA | event_2_callback_func |
任务管理机制
任务ID组成
typedef uint16_t ke_task_id_t;
// 从类型和索引构建任务ID
#define KE_BUILD_ID(type, index) ((ke_task_id_t)(((index) << 8)|(type)))
// 从任务ID获取类型
#define KE_TYPE_GET(ke_task_id) ((ke_task_id) & 0xFF)
// 从任务ID获取索引
#define KE_IDX_GET(ke_task_id) (((ke_task_id) >> 8) & 0xFF)
任务描述符
struct ke_task_desc {
/// 状态处理函数表(每个状态一个元素)
const struct ke_state_handler* state_handler;
/// 默认状态处理函数
const struct ke_state_handler* default_handler;
/// 状态表(每个实例一个元素)
ke_state_t* state;
/// 任务中状态的最大数量
uint16_t state_max;
/// 任务支持实例的最大索引
uint16_t idx_max;
};
任务操作
-
创建任务 -
ke_task_createuint8_t __fastcall ke_task_create(uint8_t task_type, const struct ke_task_desc *p_task_desc) { if (task_type < 26) { if (!p_task_desc_table_0[task_type]) { p_task_desc_table_0[task_type] = p_task_desc; return 0; } return 4; // 错误码 } return 3; // 错误码 } -
设置任务状态 -
ke_state_setvoid __fastcall ke_state_set(const ke_task_id_t id, const ke_state_t state_id) { int state_idx = HIBYTE(id); if (id < 0x1Au) { ke_task_desc *task = p_task_desc_table_0[id]; if (task->idx_max > state_idx) { task->state[state_idx] = state_id; notify_handle_saved_msg(id); // 通知内核处理保存的消息 } } }
系统任务列表
| 初始化函数 | 地址 | 任务结构地址 |
|---|---|---|
| llc_init | 0x7F02CBE | 0x7F1F1E8 |
| lld_init | 0x7F06E1E | 0x7F1F540 |
| llm_init | 0x7F09CC6 | 0x7F1F578 |
| gtl_init_func | 0x7F0E322 | 0x7F1F7F0 |
| gattc_init | 0x7F125BE | 0x7F1FE44 |
| gattm_init | 0x7F13824 | 0x7F1FF40 |
| l2cc_init | 0x7F13B7A | 0x7F1FFE0 |
| gapc_init | 0x7F1567C | 0x7F2004C |
| gapm_init | 0x7F176D4 | 0x7F201B4 |
消息调度机制
消息结构
struct ke_msg {
struct co_list_hdr hdr; // 链表头
uint32_t saved; // 保存标志
ke_msg_id_t id; // 消息ID
ke_task_id_t dest_id; // 目标任务ID
ke_task_id_t src_id; | 源任务ID
uint16_t param_len; // 参数长度
uint32_t param[1]; // 参数数据
};
消息操作API
-
申请消息 -
ke_msg_allocvoid *__fastcall ke_msg_alloc(const ke_msg_id_t id, const ke_task_id_t dest_id, const ke_task_id_t src_id, const uint16_t param_len) { ke_msg *msg = ke_malloc(param_len + 16, 2); msg->hdr.next = -1; msg->saved = 0; msg->id = id; msg->dest_id = dest_id; msg->src_id = src_id; msg->param_len = param_len; memset(msg->param, 0, param_len); return msg->param; } -
释放消息 -
ke_msg_freeint __fastcall ke_msg_free(int a1) { return ke_free(a1); }- 注意:
ke_msg_alloc返回的是param指针,而ke_msg_free需要ke_msg*指针
- 注意:
-
发送消息 -
ke_msg_sendbool __fastcall ke_msg_send(int param) { ke_msg *msg_hdr = (param - 16); // 关闭中断 co_list_push_back(&p_ke_env->queue_sent, &msg_hdr->hdr); // 恢复中断 return ke_event_set(1u); // 触发事件1 }
内核环境结构
struct ke_env_tag {
/// 已发送但尚未传递给接收者的消息队列
struct co_list queue_sent;
/// 已传递但尚未被接收者消费的消息队列
struct co_list queue_saved;
/// 定时器队列
struct co_list queue_timer;
#if (KE_MEM_RW)
/// 堆内存管理相关字段
struct mblock_free * heap[KE_MEM_BLOCK_MAX];
uint16_t heap_size[KE_MEM_BLOCK_MAX];
#if (KE_PROFILING)
uint16_t heap_used[KE_MEM_BLOCK_MAX];
uint32_t max_heap_used;
#endif
#endif
};
消息处理流程
-
事件1的回调函数
event_1_callback_func处理消息:- 从
queue_sent取出消息 - 先在
custom_msg_handlers中搜索处理函数 - 找不到则调用
get_msg_handler根据消息ID和目标ID搜索 - 调用找到的处理函数
- 处理成功(返回0)则释放消息,返回2则保存到
queue_saved
- 从
-
关键处理逻辑:
msg_handle_result = msg_handle_func(msg->id, msg->param, msg->dest_id, msg->src_id); if (msg_handle_result) { if (msg_handle_result == 2) { msg->saved = 1; co_list_push_back(&p_ke_env_->queue_saved, &msg->hdr); } } else { ke_msg_free(msg); }
总结
Riviera Waves内核通过精心设计的数据结构和机制实现了高效的实时任务调度:
- 链表管理:
co_list提供了高效的内存管理基础 - 事件驱动:6个事件槽位支持灵活的事件响应机制
- 任务管理:26个任务槽位,支持状态机和消息处理
- 消息传递:完善的发送、保存和处理机制
- 内存管理:与消息系统紧密集成的动态内存分配
理解这些底层机制对于DA14531芯片的固件逆向分析和漏洞挖掘至关重要。