local_irq_enable/local_irq_disable local_irq_save/local_irq_restore实现细节

    1、概述 

        local_irq_enable/local_irq_disable和local_irq_save/local_irq_restore两对函数在内核代码中出现的频率非常之高。每个函数的功能描述如下:

        local_irq_enable/local_irq_disable:开关本地CPU总中断。

        local_irq_save:保存当前CPU CPSR寄存器值,然后关闭本地CPU总中断

        local_irq_restore:恢复之前的CPSR寄存器值。

思考1:local_irq_disable关闭中断之后触发的中断丢失了吗?

2、细节实现

下面我们将上面的两对函数的定义贴出来:

include/linux/irqflags.h

#define local_irq_enable() do { raw_local_irq_enable(); } while (0)

#define local_irq_disable() do { raw_local_irq_disable(); } while (0)

#define local_irq_save(flags) do {raw_local_irq_save(flags);} while (0)

#define local_irq_restore(flags) do { raw_local_irq_restore(flags); } while (0)

/*

* Wrap the arch provided IRQ routines to provide appropriate checks.

*/

#define raw_local_irq_disable() arch_local_irq_disable()

#define raw_local_irq_enable() arch_local_irq_enable()

#define raw_local_irq_save(flags) \

do { \

        typecheck(unsigned long, flags); \

        flags = arch_local_irq_save(); \

} while (0)

#define raw_local_irq_restore(flags) \

do { \

        typecheck(unsigned long, flags); \

        arch_local_irq_restore(flags); \

} while (0)

CPSID是一个处理器状态切换指令,用于禁用中断或异常。它由两个部分组成:CPS(Change Processor State)和ID(Interrupt or abort disable)。

这个指令可以单独更改处理器状态寄存器(CPSR)中的 A、I、F 位,但不影响其他位。

CPS指令只能在特权模式下使用,即当程序处于C代码的默认用户模式时,不能直接操作CPS指令,需要使用汇编语言来操作。

此外,CPS指令不能被中断阻塞,且在中断或异常禁止模式下(ID=1),不能使用条件汇编指令。

CPSID的具体用法如下:

  • CPSID I:禁用 IRQ 中断或 abort 异常。
  • CPSID F:禁用 FIQ 中断或 abort 异常。
  • CPSID I PRIMASK=1:关中断,同时设置 PRIMASK 位为 1。
  • CPSID F FAULTMASK=1:关异常,同时设置 FAULTMASK 位为 1。

需要注意的是,CPSID指令在禁用中断或异常时,不会影响其他类型的异常处理,如 NMI、Hard Fault 等。此外,CPSID指令与CPSIE指令是对应的,CPSIE用于开启中断或异常。

arch/arm/include/asm/irqflags.h中关于硬中断内嵌汇编实现:

/*

* CPU interrupt mask handling.

*/

#ifdef CONFIG_CPU_V7M

#define IRQMASK_REG_NAME_R "primask"

#define IRQMASK_REG_NAME_W "primask"

#define IRQMASK_I_BIT 1

#else

#define IRQMASK_REG_NAME_R "cpsr"

/*cpsr_c代表的是这32位中的低8位,也就是控制位*/

#define IRQMASK_REG_NAME_W "cpsr_c"

#define IRQMASK_I_BIT PSR_I_BIT

#endif

#if __LINUX_ARM_ARCH__ >= 6

static inline unsigned long arch_local_irq_save(void)

{

        unsigned long flags;

        asm volatile(

                "mrs %0, " IRQMASK_REG_NAME_R " @ arch_local_irq_save\n"

                "cpsid i"

                : "=r" (flags) : : "memory", "cc");

                return flags;

}

/*CPSIE I:使能 IRQ 中断或 abort 异常*/

static inline void arch_local_irq_enable(void)

{

        asm volatile(

                "cpsie i @ arch_local_irq_enable"

                :

                :

                : "memory", "cc");

}

/*CPSID I:禁用 IRQ 中断或 abort 异常*/

static inline void arch_local_irq_disable(void)

{

        asm volatile(

        "cpsid i @ arch_local_irq_disable"

        :

        :

        : "memory", "cc");

}

#define local_fiq_enable() __asm__("cpsie f @ __stf" : : : "memory", "cc")

#define local_fiq_disable() __asm__("cpsid f @ __clf" : : : "memory", "cc")

/*

* restore saved IRQ & FIQ state

*/

static inline void arch_local_irq_restore(unsigned long flags)

{

        asm volatile(

                "msr " IRQMASK_REG_NAME_W ", %0 @ local_irq_restore"

                :

                : "r" (flags)

                : "memory", "cc");

}

local_irq_enable/local_irq_disable:开关本地CPU总中断。

local_irq_save:保存当前CPU CPSR寄存器值,然后关闭本地CPU总中断

local_irq_restore:恢复之前的CPSR寄存器值。

  • 18
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值