文章目录
- 1. Trap概念与分类
- 1.1 TriCore Trap分类表
- 1.2 三种Trap的区别
- 2. Trap 向量入口的硬件机制
- 2.1 Trap 向量表
- 2.2 入口汇编模板(以 MemFault 为例)
- 2.3 SysCall Trap 的特殊处理
- 3. OS 如何介入三类 Trap
- 3.1 Trap 6: SysCall(主动调用,OS 完全介入)
- 3.2 Trap 1/2: Fault(异常,OS 通过 ProtectionHook 介入)
- 3.3 其他 Trap:Unvalid(未注册异常,OS 致命错误介入
- 4. SysCall 的应用场景
- 4.1 哪些 API 会走 SysCall?
- 4.2 信任函数(CallTrustedFunction)
- 4.3 与多核服务的对比
- 5. Trap 与中断/ISR 的关系
- 5.1 三种异步/同步事件的对比
- 5.2 嵌套关系
- 5.3 Trap 与 Cat2 ISR 的 OS 介入对比
- 6. OS 对 Trap 的三层介入模型
1. Trap概念与分类
Trap 是 TriCore 架构的同步异常(synchronous exception),由 CPU 在执行指令时检测到的异常情况触发,与中断(异步)不同,Trap 总是在触发它的那条指令处发生,且不可屏蔽。
1.1 TriCore Trap分类表
| Trap# | 名称 | 代码宏 | 处理函数 | TIN(子类型)来源 |
| 1 | Memory Fault | Os_Arch_MemFaultEntry | Os_Arch_MemFaultHandler | d15 寄存器 |
| 2 | Instruction Fault | Os_Arch_InsFaultEntry | Os_Arch_InsFaultHandler | d15 寄存器 |
| 6 | System Call | Os_Arch_SysCallEntry | Os_SysCallHandler | a4 寄存器(参数指针) |
| 其他 | Unvalid Exception | Os_Arch_UnvalidException | Os_Arch_Exce_Unhandled | Trap # 本身 |
注意:TC3XX 实际还有 Trap 0(Virtualization Fill)、3(Context Management)、4(Bus Error)、5(Assertion)、7(Non-Maskable Interrupt)等,但 OS 代码中只显式注册了 1、2、6 三类,其他由 Os_Arch_UnvalidException 兜底。
1.2 三种Trap的区别
| 维度 | Trap 1 (MemFault) | Trap 2 (InsFault) | Trap 6 (SysCall) |
| 触发方式 | 自动(硬件检测) | 自动(硬件检测) | 主动(syscall 0 指令) |
| 触发原因 | 访问非法地址、MPU 违例 | 非法指令、未对齐访问 | 用户态请求 OS 服务 |
| 错误性质 | 异常(意外) | 异常(意外) | 正常流程(预期) |
| 参数传递 | d15=TIN, a11=异常地址 | d15=TIN, a11=异常地址 | a4=SysCall 参数指针 |
| OS 介入方式 | ProtectionHook | ProtectionHook | SysCallHandler 派发 |
| 是否返回 | 通常不返回(关闭核) | 通常不返回(关闭核) | 必定返回(继续执行) |
2. Trap 向量入口的硬件机制
2.1 Trap 向量表
TriCore 的 Trap 向量表位于 BIV 寄存器指定的地址,每个 Trap 号占用 32 字节(__trap(x) __vector_table(core) 编译属性自动生成)。OS 通过宏在每个核上注册独立的 Trap 处理函数。
2.2 入口汇编模板(以 MemFault 为例)
.align5;32字节对齐.global OS_MEMFAULT_CODE_START_0;全局符号 OS_MEMFAULT_CODE_START_0:svlcx;保存 Lower Context 到 CSA movh.a a4,%hi:cfg;加载 contextCfg 地址高位 lea a4,[a4]%lo:cfg;加载 contextCfg 地址低位 mov d4,d15;读取 TIN(Trap Identification Number) mov.aa a5,a11;读取异常访问地址 call Os_Arch_MemFaultHandler;调用 C 处理函数 rslcx;恢复 Lower Context rfe;从异常返回- svlcx 保存 Lower Context(通用寄存器 D0-D7, A0-A7)到 CSA(Context Save Area)
- d15 寄存器在 Trap 发生时硬件自动写入 TIN(Trap 子类型号)
- a11 寄存器存放触发异常的访问地址
- rfe 指令恢复 PCXI 并返回到被中断的指令
2.3 SysCall Trap 的特殊处理
void__trap(6)__vector_table(core)osTrap_6_Core##core(void*a4){volatileuint32 pcxi=OS_ZERO_VALUE;volatileuint32 interruptState=OS_ZERO_VALUE;// 1. 从 PCXI 读取被中断代码的中断使能状态(PIE 位)pcxi=OS_ARCH_MFCR(OS_ARCH_PCXI_OFFSET);pcxi=(pcxi&OS_ARCH_PCXI_PIE_MASK)>>OS_ARCH_PCXI_PIE_BIT;// 2. 将 PIE 状态合并到 ICR(中断控制寄存器)interruptState=OS_ARCH_MFCR(OS_ARCH_ICR_OFFSET);interruptState=interruptState|(pcxi<<OS_ARCH_ICR_INT_BIT);OS_ARCH_MTCR(OS_ARCH_ICR_OFFSET,interruptState);// 3. 调用 SysCall 派发器Os_SysCallHandler(a4);// 4. 恢复 ICR 的中断级别到 PCXI 的 PCPN 字段interruptState=OS_ARCH_MFCR(OS_ARCH_ICR_OFFSET)&(OS_ARCH_ICR_INT_LEVEL_MASK|OS_ARCH_ICR_INT_MASK);pcxi=OS_ARCH_MFCR(OS_ARCH_PCXI_OFFSET);pcxi&=~(OS_ARCH_PCXI_PCPN_MASK);pcxi|=(interruptState&OS_ARCH_ICR_INT_LEVEL_MASK)<<OS_ARCH_PCXI_PCPN_BIT;OS_ARCH_MTCR(OS_ARCH_PCXI_OFFSET,pcxi);}为什么 SysCall 要恢复中断级别?
TriCore 的 CSA 上下文中保存了被中断代码的 ICR.IE 和 ICR.CCPN(中断屏蔽级别)。syscall 指令触发 Trap 后:
- 硬件将当前 ICR 状态保存到 PCXI
- Trap 处理函数运行在新的上下文
- 返回前需要把 SysCall 期间可能修改的中断级别写回 PCXI,确保 rfe 恢复正确的中断状态
这与中断/异常的关键区别:SysCall 是"正常调用",可能在中断禁用/启用不同状态下进入和退出,需要保持中断状态的连续性。
3. OS 如何介入三类 Trap
3.1 Trap 6: SysCall(主动调用,OS 完全介入)
触发方式:非信任 App 调用 OS API 时,API 内部执行 syscall 0 指令。
用户态任务(非信任 App)│ ├─ 调用ActivateTask()│ └─ Os_Task_ActivateTask 检测 sysCall=TRUE │ └─Os_Arch_SysCall()执行 syscall 指令 │ │ │ ▼ ★ 触发 Trap6│ osTrap_6_Core0 │ ├─svlcx(保存上下文)│ ├─ 恢复中断状态到 ICR │ ├─ call Os_SysCallHandler │ │ │ │ │ ▼ ★ OS 介入核心 │ │Os_SysCallHandler(sysCallData)│ │ ├─ funcId=sysCallData->funcId(如 ActivateTask_ID)│ │ ├─ func=Os_SysCallFunc_List[funcId]│ │ └─func(sysCallData->Os_SysCallParam)│ │ │ │ │ ▼ 切换到特权模式执行 │ │Os_SysCall_ActivateTask(parameter)│ │ └─ 调用真正的 Os_Task_IntlActivateTask │ │ │ ├─ 恢复中断级别到 PCXI │ ├─rslcx(恢复上下文)│ └─rfe(返回到 syscall 下一条指令)│ └─ 用户态任务继续执行,得到返回值OS 介入要点:
- 特权切换:syscall 指令将 CPU 从 User-0 模式切换到 Supervisor 模式,OS 内核代码可访问全部内存
- 服务派发:Os_SysCallFunc_List 函数指针表(约 50+ 个服务)按 funcId 派发
- 参数传递:通过 a4 寄存器传递 Os_SysCallType* 指针,内含 funcId、中断级别、参数联合体
- 返回值:通过参数结构体的 retVal 字段回传
支持的 SysCall 服务
typedefenum{Os_Syscall_ActivateTask_ID=0U,// 任务管理类Os_Syscall_TerminateTask_ID,Os_Syscall_ChainTask_ID,Os_Syscall_GetTaskId_ID,Os_Syscall_GetTaskState_ID,// ... Alarm、Event、Resource、Spinlock、Counter、ScheduleTable ...Os_Syscall_CallTrustedFunction_ID,// 信任函数调用Os_Syscall_ControlIdle_ID,// 空闲控制Os_Syscall_Monitor_ID,// 监控服务Os_Syscall_Func_Counter}Os_Syscall_FuncId;3.2 Trap 1/2: Fault(异常,OS 通过 ProtectionHook 介入)
触发方式:硬件自动检测,无法预测。
任意代码执行中触发异常 │(如:访问非法地址/执行非法指令)▼ ★ 硬件触发 Trap1或 Trap2osTrap_1_Core0/osTrap_2_Core0 ├─svlcx(保存上下文)├─ mov d4,d15(读取 TIN)├─ mov.aa a5,a11(读取异常地址)├─ call Os_Arch_MemFaultHandler/Os_Arch_InsFaultHandler │ │ │ ▼ ★ OS 介入核心 │Os_Arch_MemFaultHandler(cfg,source,addr)│ ├─OS_ARCH_SETSP(cfg->stackStartAddr)│ │ ★ 切换到内核栈(关键!) │ │ 原因:异常发生时栈可能已损坏,必须用安全的内核栈 │ ├─Os_Arch_StoreFaultInfo(source,addr)│ │ 保存故障信息到局部变量(便于调试) │ └─Os_Hook_CallProtectionHook(E_OS_PROTECTION_MEMORY)│ │ │ ▼ ★ 用户 Hook 决策 │ Os_Hook_CallProtectionHook │ ├─ 关中断 │ ├─ 记录错误状态和调用者 │ ├─ 设置 ProcType=PROTECTHOOK │ ├─ 调用用户配置的ProtectionHook(error)│ │ │ │ │ ▼ 返回 ProtectionReturnType │ │ ├─PRO_IGNORE(忽略)│ │ ├─PRO_TERMINATETASKISR(终止任务/ISR)│ │ ├─PRO_TERMINATEAPPL(终止应用)│ │ └─PRO_SHUTDOWN(关闭 OS)│ │ │ ├─Os_HookProtectionLogical(逻辑处理)│ └─Os_HookProtectionProcess(执行决策)│ ├─ 忽略 → 返回原现场 │ ├─ 终止任务 → Os_Task_TerminateTask │ ├─ 终止应用 → Os_App_TerminateApplication │ └─ 关闭 → Os_Core_Shutdown │ ├─rslcx(恢复上下文)└─rfe(返回)★ 若 ProtectionHook 返回 IGNORE,回到原代码继续 ★ 否则不返回(已切换到新任务或关机)OS 介入要点:
- 栈切换:异常时栈可能已损坏,Os_Arch_Exception.c:148 强制切到内核栈 cfg->stackStartAddr
- ProcType 标记:进入 ProtectionHook 前设置 OS_PROTECTHOOK_TYPE_MASK,OS API 会据此检查是否允许调用
- 用户决策:OS 不直接决定如何处理,而是交给用户配置的 ProtectionHook 回调决策
- 错误码区分:E_OS_PROTECTION_MEMORY(内存错)vs E_OS_PROTECTION_EXCEPTION(指令错)
3.3 其他 Trap:Unvalid(未注册异常,OS 致命错误介入
void__trap(x)__vector_table(core)osTrap_##x##_Core##core(void){Os_Arch_Exce_Unhandled();// ★ 调用 Os_FatalError()}FUNC(void,OS_CODE)Os_Arch_Irq_Unhandled(void){Os_FatalError();// 未注册中断 → 致命错误}FUNC(void,OS_CODE)Os_Arch_Exce_Unhandled(void){Os_FatalError();// 未注册异常 → 致命错误}OS 介入要点:
- 未注册的 Trap(如 Trap 3/4/5/7)直接调用 Os_FatalError
- 这是不可恢复的错误,通常进入死循环或重启
- 用于捕获 OS 未预期的硬件异常,作为最后的兜底
4. SysCall 的应用场景
4.1 哪些 API 会走 SysCall?
通过 grep Os_SysCall( )统计,所有需要特权访问的 OS API 都会在非信任 App 中走 SysCall:
| 模块 | SysCall 服务数 | 典型 API |
| Task | 5 | ActivateTask、TerminateTask、ChainTask、GetTaskID、GetTaskState |
| Alarm | 5 | GetAlarm、GetAlarmBase、SetRelAlarm、SetAbsAlarm、CancelAlarm |
| Event | 1 | SetEvent |
| Resource | 3 | GetResource、ReleaseResource、GetResourceID |
| Spinlock | 4 | GetSpinlock、ReleaseSpinlock、TryToGetSpinlock、GetSpinlockId |
| Counter | 3 | IncrementCounter、GetCounterValue、GetElapsedValue |
| ScheduleTable | 5 | Start/Stop/Next/GetStatus |
| Application | 5 | TerminateApplication、GetApplicationState、GetApplicationID 等 |
| IOC | 4 | IocWrite、IocRead、IocSend、IocReceive |
| TrustFun | 1 | CallTrustedFunction |
| Monitor | 1 | Monitor |
| 其他 | 若干 | ShutdownOS、ShutdownAllCores、ControlIdle |
4.2 信任函数(CallTrustedFunction)
信任函数是特殊的 SysCall 应用:非信任 App 需要执行特权操作(如直接访问硬件寄存器),通过调用预配置的"信任函数"实现。
非信任 App │ ├─CallTrustedFunction(funcIndex,params)│ └─Os_Arch_SysCall()→ Trap6│ └─ Os_SysCallHandler │ └─ Os_SysCall_CallTrustedFunction │ └─ Os_CallTrustedFunctionSimp │ ├─ 切换到信任函数的 MPU 区 │ ├─ 执行用户配置的信任函数(特权模式) │ └─ 切换回原 MPU 区 │ └─ 返回(信任函数执行完毕)4.3 与多核服务的对比
| 维度 | SysCall (Trap 6) | Os_MultiCoreServer |
| 触发场景 | 同核内特权切换 | 跨核服务请求 |
| 通信方式 | 寄存器 a4 传参 | 共享内存 + SRC 软中断 |
| 是否阻塞 | 同步(等返回) | 可同步可异步 |
| 目标 | 本核 OS 内核 | 其他核 OS |
5. Trap 与中断/ISR 的关系
5.1 三种异步/同步事件的对比
| 事件类型 | 触发方式 | 入口指令 | 可屏蔽 | 上下文保存 |
| 中断 (ISR) | 硬件异步 | __interrupt(level) | 可屏蔽(Cat2)/ 不可屏蔽(Cat1) | svlcx + Os_Arch_SaveContext |
| SysCall (Trap 6) | 软件主动 | syscall 0 | 不可屏蔽(Trap 优先级最高) | svlcx |
| Fault (Trap 1/2) | 硬件自动 | __trap(1/2) | 不可屏蔽 | svlcx |
5.2 嵌套关系
Task(User Mode)│ ├─ syscall0──► Trap6(Supervisor Mode)│ │ │ ├─ 可被中断抢占 │ │ └─ISR(Cat2)嵌套 │ │ └─ ISR 中也可 syscall(嵌套 Trap) │ │ │ └─ 可被 Fault 抢占 │ └─ Trap1/2嵌套 │ └─ ProtectionHook 中可再触发 syscall │ └─Fault(Trap1/2)也可在 Task 执行中发生关键设计:Trap 可以嵌套,OS 通过 CSA 链表管理嵌套上下文。
5.3 Trap 与 Cat2 ISR 的 OS 介入对比
| 维度 | Cat2 ISR | Trap 6 (SysCall) | Trap 1/2 (Fault) |
| 入口汇编 | svlcx + Os_Arch_SaveContext + Os_Isr_Entry | svlcx + 恢复 ICR + Os_SysCallHandler | svlcx + 传参 + Os_Arch_*FaultHandler |
| OS 介入函数 | Os_Isr_Entry | Os_SysCallHandler | Os_Hook_CallProtectionHook |
| 上下文切换 | 切到 ISR 栈 | 不切栈(用 Trap 栈) | 切到内核栈 |
| MPU 切换 | 切到 ISR 的 MPU | 自动进特权区 | 自动进特权区 |
| 调度触发 | 退出时可能调度 | 不调度 | 由 ProtectionHook 决定 |
| 资源清理 | 强制释放 Resource/Spinlock | 不需要 | 强制释放 |
6. OS 对 Trap 的三层介入模型
┌─────────────────────────────────────────────────────────────────┐ │ 第0层:硬件自动响应 │ │-保存 PCXI、PC 到 CSA │ │-加载 Trap 向量表入口地址 │ │-写入 TIN 到 d15、异常地址到 a11 │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 第1层:Trap 向量入口(汇编) │ │-svlcx 保存 Lower Context │ │-准备参数(d4=TIN,a5=地址/a4=SysCallData) │ │-call C 处理函数 │ │-rslcx+rfe 返回 │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ 第2层:OS C 处理函数(OS 介入) │ │ │ │ ├─ Trap6(SysCall):│ │ │ Os_SysCallHandler │ │ │ ├─ 查 Os_SysCallFunc_List 函数表 │ │ │ └─ 派发到具体服务(ActivateTask、SetEvent 等) │ │ │ ★ OS 完全介入,作为特权代理执行 │ │ │ │ │ ├─ Trap1/2(Fault):│ │ │ Os_Arch_MemFaultHandler/Os_Arch_InsFaultHandler │ │ │ ├─ 切换到内核栈 │ │ │ ├─ 保存故障信息 │ │ │ └─ Os_Hook_CallProtectionHook │ │ │ ├─ 记录错误状态 │ │ │ ├─ 设置 ProcType=PROTECTHOOK │ │ │ ├─ 调用用户 ProtectionHook │ │ │ └─ 执行决策(忽略/终止任务/终止应用/关机) │ │ │ ★ OS 介入作为错误处理框架 │ │ │ │ │ └─ 其他Trap(Unvalid):│ │ Os_Arch_Exce_Unhandled → Os_FatalError │ │ ★ OS 介入作为致命错误兜底 │ └─────────────────────────────────────────────────────────────────┘