我正在Intel Atom处理器(具有 2 个内核的x86_64 )上编写Linux v3.2内核模块。我想禁用一个特定的 IRQ 号,但在 Linux 上这样做有问题。
我正在双启动MS-DOS,通过直接与8259 PIC芯片通信,我可以轻松地禁用 Intel 语法 x86 程序集中的中断:
CLI ; disable all interrupts
MOV DX, 0x21 ; set 8259 ioport address
IN AL, DX ; store current interrupt mask in AL
AND AL, 0xDF ; modify mask to disable IRQ 5
OUT DX, AL ; send new mask to 8259
STI ; reenable interrupts
这工作得很好,我成功地禁用了特定的 IRQ 号。
在Linux中,我知道我必须使用disable_irq
宏来禁用中断,但它似乎没有效果。
#include <linux/interrupt.h>
...
disable_irq(5); // disable IRQ 5
该disable_irq
行位于我的角色驱动程序open
函数的开头。然而,当我打开我的设备节点时,我函数中的其余代码open
照常执行,IRQ 5 保持启用 - 似乎disable_irq
根本没有任何效果。
我不确定我是否disable_irq
正确使用了宏,所以我决定尝试直接内联汇编来验证我的逻辑是否正确。我决定从简单开始,首先尝试禁用所有中断:
__asm__("cli");
然而,甚至这条指令似乎都没有被执行,因为所有的中断仍然处于启用状态。
我现在完全糊涂了,为什么直接汇编不禁用Linux上的中断?在Linux上禁用中断的正确方法是什么?
更新:我发现disable_irq
只有在request_irq
. 这是一个错误,还是预期的行为?
我发现一个似乎模糊地描述了我所看到的行为的线程,但它已经过时了,我不确定它是否仍然与我的 Linux 版本相关。
更新2:
这是我在运行Linux v3.2.0-4的Debian上尝试的内核模块:
#include <linux/module.h>
#include <linux/kernel.h> /* Needed for KERN_INFO */
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irqflags.h> /* Needed for local_irq_disable et al. */
MODULE_LICENSE("GPL");
static unsigned long flags = 0;
static int __init initialization_routine(void)
{
local_irq_save(flags);
local_irq_disable();
/* __asm__("cli"); */
/* disable_irq(15); */
return 0;
}
static void __exit cleanup_routine(void) {
local_irq_restore(flags);
/* __asm__("sti"); */
/* enable_irq(15); */
return;
}
module_init(initialization_routine);
module_exit(cleanup_routine);
disable_irq
/enable_irq
工作正常。我对简单的组装说明不是特别感兴趣(奇怪的是它们不起作用)。此外,我担心为什么local_irq_disable
对任何核心都没有明显的影响——即 IRQ 仍然出现在所有核心上。
要检查中断,我在终端中运行以下命令:
$ watch -d -n 0.5 cat /proc/interrupt
由于disable_irq
现在enable_irq
运行完美,我怀疑我只是忘记了某种初始化代码,或者local_irq_disable
相关功能可能已被弃用或不适用于 x86 处理器?