Open-Science安全模型:权限、沙箱与凭证的7大信任边界
2026/9/18 8:04:26
经常会遇到两种典型的中断禁用 / 启用实现:一种是基于纯汇编编写的Arch_IntSave/Arch_IntDisable函数,另一种是编译器内置的__enable_irq/__disable_irq内联函数,这两种的区别和功能具体拆解一下。
.globl Arch_IntSave Arch_IntSave: MRS R0, PRIMASK @ 读取PRIMASK寄存器值到R0 CPSID I @ 禁用IRQ中断 BX LR @ 返回 .globl Arch_IntDisable Arch_IntDisable: CPSID I @ 禁用IRQ中断 BX LR @ 返回MRS R0, PRIMASK:将 PRIMASK 寄存器(ARM Cortex-M 核心的中断屏蔽寄存器)的值读取到通用寄存器 R0 中。PRIMASK 是 1 位寄存器,值为 0 时表示中断未屏蔽,值为 1 时表示仅屏蔽普通 IRQ 中断(硬件 FAULT 类异常不受影响)。CPSID I:修改 CPSR(当前程序状态寄存器)的 I 位,直接禁用所有普通 IRQ 中断。BX LR:函数返回,ARM 汇编中通过链接寄存器 LR 返回调用处。/** \brief Enable IRQ Interrupts \details Enables IRQ interrupts by clearing the I-bit in the CPSR. Can only be executed in Privileged modes. */ __STATIC_FORCEINLINE void __enable_irq(void) { __ASM volatile ("cpsie i" : : : "memory"); } /** \brief Disable IRQ Interrupts \details Disables IRQ interrupts by setting the I-bit in the CPSR. Can only be executed in Privileged modes. */ __STATIC_FORCEINLINE void __disable_irq(void) { __ASM volatile ("cpsid i" : : : "memory"); }__STATIC_FORCEINLINE:编译器强内联关键字,确保函数直接嵌入调用处,无函数调用开销。__ASM volatile ("cpsie/cpsid i" : : : "memory"):内联汇编执行中断开关指令,volatile防止编译器优化该指令,memory约束告知编译器该指令会修改内存状态,避免内存重排序。cpsie i:清除 CPSR 的 I 位,启用 IRQ 中断;cpsid i:设置 CPSR 的 I 位,禁用 IRQ 中断。这是二者最核心的区别,也是嵌入式开发中最易踩坑的点:
CPSID I,单纯禁用中断,无任何状态保存;Arch_IntSave则在禁用中断前,先读取当前 PRIMASK 寄存器的值并通过 R0 返回 —— 这意味着Arch_IntSave能保存中断禁用前的原始状态。cpsid i禁用中断,无状态保存;__enable_irq仅执行cpsie i启用中断,二者均不涉及任何中断状态的读取或保存。直接调用
__disable_irq后调用__enable_irq,可能破坏系统原有中断状态 —— 若调用__disable_irq前中断已被禁用,执行__enable_irq会错误启用中断,导致临界区保护失效。
__STATIC_FORCEINLINE实现强内联,汇编指令直接嵌入调用处,无函数调用开销,执行效率与直接写汇编指令一致。内联汇编的中断操作指令,在编译器优化开启时(-O2/-O3),执行周期与纯汇编指令完全一致,且避免了函数调用的栈操作开销。
MSR PRIMASK, R0恢复原始中断状态 —— 即使调用前中断已被禁用,也不会错误启用。示例:; 调用Arch_IntSave保存状态并禁用中断 BL Arch_IntSave PUSH R0 ; 保存原始PRIMASK值到栈 ; 临界区代码(如操作共享资源) POP R0 ; 取出原始PRIMASK值 MSR PRIMASK, R0 ; 恢复中断状态(而非强制启用)cpsie i启用中断,无论调用前中断状态如何,都会直接开启 IRQ—— 若临界区嵌套调用(如 A 函数禁用中断后调用 B 函数,B 函数执行__enable_irq),会导致 A 函数的临界区失去中断保护。cmsis_gcc.h、cmsis_armcc.h中定义),不同编译器的实现可能略有差异(如 GCC 需添加memory约束,ARMCC 则无需),但符合 CMSIS 标准的编译器均提供该接口,可移植性更强。