IRQ 8 request_irq,不允许操作

IRQ 8 request_irq, Operation not permitted

我是内核模块开发的新手,在学习过程中,我转向了中断。我的任务是为 IRQ 8 编写一个中断处理程序模块,它将简单地计算该行发生的中断次数并将值存储在 kobject 中。乍一看,这项任务相对容易,但我遇到了奇怪的行为。我写了一个处理程序函数,它简单地增加计数器和 returns 处理中断

static int ir=0;
static irq_handler_t my_handler(int irq_no, void *dev_id, struct pt_regs *regs)
{
    ir++;
    return (irq_handler_t) IRQ_HANDLED;
}

为了挂钩中断处理程序,我在 __init 中调用了 request_irq() 函数,第一个参数是 8,因此 IRQ 8(由 rtc 保留) 处理线路中断

#define RTC_IRQ 8

[...]

int err;
err = request_irq(RTC_IRQ, (irq_handler_t) my_handler,IRQF_SHARED,"rtc0",NULL);
if (err != 0)
    return -1;

对于上面显示的实现,加载内核模块给我 err 等于 -22,即 EINVAL。谷歌搜索后,我发现对于 IRQF_SHARED 标志,最后一个参数不能分配为 NULL。我试图找到一种在模块中获取 rtc->dev_id 的方法,但在某些示例中,他们只是将处理程序类型转换为 (void *),所以我尝试传递 (void *) my_handler。这给了我 insmod

上的标志不匹配警告
genirq: Flags mismatch irq 8. 00000080 (rtc0) vs. 00000000 (rtc0)

并且错误值设置为 -16,我从某些来源读到的意思是“忙”。在尝试找到获取设备 ID 的方法时,我发现中断是由 rtc0 设备发送的,该设备是从 rtc-cmos 父设备“继承”的。

关于这个问题,我在互联网上的不同来源中发现了不同的有争议的线索。有些人说内核在软件时钟同步后禁用 rtc,但事实并非如此,因为在 IRQ 8 行上使用 sudo bash -c ' echo +20 > /sys/class/rtc/rtc0/wakealarm ' 和读取 /proc/interrupts 表明中断按预期工作

其他消息来源指出,所有指向该线路的 request_irq 必须安装 IRQF_SHARED 标志才能共享中断线路。阅读 rtc-cmos 的源文件对我没有任何帮助,因为他们直接通过读写 CMOS

设置中断

我花了很多时间试图找出问题的解决方案,但 RTC 中断似乎在内核模块开发中并不常用,因此很难找到与此案例相关的最新信息,大多数讨论和示例都与使用 SA_SHIRQ-like 标志和 /drivers/examples 文件夹存在于内核源文件中时的实现有关,这是围绕内核版本 2.6。自那时以来,中断和 rtc 内核实现都发生了变化

任何可能有助于解决此问题的 hints/suggestions 将不胜感激。这是我的第一个 Whosebug 问题,所以如果格式有任何错误或令人不安,欢迎您在评论中指出

提前感谢您的帮助

我很久以前就解决了这个问题,但这里有一些解释是为了像我这样的新手。 @stark 为这个问题提供了很好的提示。

要了解的主要事情是内核中不负责任的行为 space 会迅速导致各种“灾难”。这似乎是 Linux 开发人员关闭 users/developers.

越来越多区域的主要原因

阅读此处获取解决方案

因此,在现代内核版本中,您不会随机将处理程序绑定到一条线上并将中断标记为已解决。但是您仍然可以使用 IRQF_SHARED 标志“收听”它们,并且在处理程序的末尾,您通过返回 IRQ_NONE 让中断保持不变,因此您不会破坏其余部分的正确操作内核,如果中断对其他事情至关重要。

解决方法到此结束,接下来补充一些关于内核开发的建议

一开始,请务必了解这不是用户space,您的操作至多会导致内存泄漏或某些文件损坏。在这里你的行为很容易损坏你的内核。如果类似的情况发生在 Windows 上,您将别无选择,只能完全重新安装整个 OS,但在 GNU/Linux 中,情况并非如此。您可以切换到不同的内核,而无需像以前那样经历繁琐的恢复所有内容的过程,因此如果您是一个懒得使用 VM 的铁杆爱好者,那么学习切换内核很快就会派上用场:)