C 在x86-64上测试linux内核本地中断处理

C 在x86-64上测试linux内核本地中断处理,c,linux-kernel,x86-64,interrupt-handling,C,Linux Kernel,X86 64,Interrupt Handling,我想写一些代码(例如作为一个小的内核模块)来检测在x86-64体系结构上运行的Linux上的本地中断,也就是说,我想写一些处理程序,每当APIC触发本地中断时,内核就会调用这些处理程序 然后,处理程序将检查某个进程当前是否正在运行,并检查该进程的内存 我意识到我试图做的可能不是好的工程实践,但我的目标是为勘探/研究目的创建一个简单的一次性解决方案 在理想情况下,会有类似于request\u irq[1]的函数(据我所知,该函数用于处理来自键盘、网卡等设备的中断),允许我在每次发生本地计时器中断时

我想写一些代码(例如作为一个小的内核模块)来检测在x86-64体系结构上运行的Linux上的本地中断,也就是说,我想写一些处理程序,每当APIC触发本地中断时,内核就会调用这些处理程序

然后,处理程序将检查某个进程当前是否正在运行,并检查该进程的内存

我意识到我试图做的可能不是好的工程实践,但我的目标是为勘探/研究目的创建一个简单的一次性解决方案

在理想情况下,会有类似于
request\u irq
[1]的函数(据我所知,该函数用于处理来自键盘、网卡等设备的中断),允许我在每次发生本地计时器中断时通知内核运行我的代码

有人对如何做到这一点有什么建议吗

内核是否提供用于注册本地中断处理程序的API

如果没有,我可以直接修改内核的源代码来处理中断。我在内核的什么地方可以找到这段代码

编辑:以下是我迄今为止的研究结果。 TLDR:
request\u irq
不是挂接本地计时器中断的方式

根据对Linux内核的理解,表4.2[2],中断向量
0xef
分配给本地APIC定时器中断。内核源代码证实了这一点[3]

由于
request\u irq
将中断向量作为其第一个参数,因此让我们尝试在内核模块中为该向量注册一个处理程序:

#include <linux/module.h>
#include <linux/kernel.h>    // included for KERN_INFO
#include <linux/init.h>      // included for __init and __exit macros

#include <linux/interrupt.h> // included for IRQF_ and request_irq
#include <linux/irqreturn.h> // included for IRQ_NONE
#include <asm/irq_vectors.h> // included for LOCAL_TIMER_VECTOR

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Instrument local timer interrupts");

static int DEVICE_COOKIE = 1;

static int count = 0;

static irqreturn_t handler(int irq, void *dev) {
    count++;
    return IRQ_NONE;
}

static int __init test_init(void) {
    int status;

    printk(KERN_INFO "Running request_irq\n");
    status = request_irq(
        LOCAL_TIMER_VECTOR,
        &handler,
        IRQF_TIMER,
        "foobar",
        &DEVICE_COOKIE);
    if (status == 0) {
        printk(KERN_INFO "Successfully installed handler\n");
        return 0;
    } else {
        printk(
            KERN_INFO "Failed to install handler. error code: %d\n",
            status);
        return -1;
    }
}

static void __exit test_cleanup(void) {
    free_irq(LOCAL_TIMER_VECTOR, &DEVICE_COOKIE);
    printk(KERN_INFO "Goodbye kernel. I saw %d interrupts.\n", count);
}

module_init(test_init);
module_exit(test_cleanup);
#include <linux/kernel.h>    // included for KERN_INFO
#include <linux/init.h>      // included for __init and __exit macros

#include <linux/interrupt.h> // included for IRQF_ and request_irq
#include <linux/irqreturn.h> // included for IRQ_NONE
#include <asm/irq_vectors.h> // included for LOCAL_TIMER_VECTOR
#include <linux/irqnr.h>     // included for irq_to-desc
#include <linux/irqdesc.h>   // included for irq_desc

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Call irq_to_desc(LOCAL_TIMER_VECTOR)");

static int __init test_init(void) {
    struct irq_desc *desc;
    desc = irq_to_desc(LOCAL_TIMER_VECTOR);
    if (!desc) {
        printk(KERN_INFO "irq_to_desc(LOCAL_TIMER_VECTOR) failed");
        return -1;
    }
    return 0;
}

static void __exit test_cleanup(void) {
}

module_init(test_init);
module_exit(test_cleanup);
那么
-EINVAL
从何而来? 通过阅读内核源代码,我们发现
request\u-irq
只是
request\u-irq
[4]的包装<代码>请求\u线程化\u irq调用
irq\u到\u desc
并在调用失败时返回
-EINVAL
。我们可以很容易地检查另一个小型内核模块是否存在这种情况:

#include <linux/module.h>
#include <linux/kernel.h>    // included for KERN_INFO
#include <linux/init.h>      // included for __init and __exit macros

#include <linux/interrupt.h> // included for IRQF_ and request_irq
#include <linux/irqreturn.h> // included for IRQ_NONE
#include <asm/irq_vectors.h> // included for LOCAL_TIMER_VECTOR

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Instrument local timer interrupts");

static int DEVICE_COOKIE = 1;

static int count = 0;

static irqreturn_t handler(int irq, void *dev) {
    count++;
    return IRQ_NONE;
}

static int __init test_init(void) {
    int status;

    printk(KERN_INFO "Running request_irq\n");
    status = request_irq(
        LOCAL_TIMER_VECTOR,
        &handler,
        IRQF_TIMER,
        "foobar",
        &DEVICE_COOKIE);
    if (status == 0) {
        printk(KERN_INFO "Successfully installed handler\n");
        return 0;
    } else {
        printk(
            KERN_INFO "Failed to install handler. error code: %d\n",
            status);
        return -1;
    }
}

static void __exit test_cleanup(void) {
    free_irq(LOCAL_TIMER_VECTOR, &DEVICE_COOKIE);
    printk(KERN_INFO "Goodbye kernel. I saw %d interrupts.\n", count);
}

module_init(test_init);
module_exit(test_cleanup);
#include <linux/kernel.h>    // included for KERN_INFO
#include <linux/init.h>      // included for __init and __exit macros

#include <linux/interrupt.h> // included for IRQF_ and request_irq
#include <linux/irqreturn.h> // included for IRQ_NONE
#include <asm/irq_vectors.h> // included for LOCAL_TIMER_VECTOR
#include <linux/irqnr.h>     // included for irq_to-desc
#include <linux/irqdesc.h>   // included for irq_desc

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Call irq_to_desc(LOCAL_TIMER_VECTOR)");

static int __init test_init(void) {
    struct irq_desc *desc;
    desc = irq_to_desc(LOCAL_TIMER_VECTOR);
    if (!desc) {
        printk(KERN_INFO "irq_to_desc(LOCAL_TIMER_VECTOR) failed");
        return -1;
    }
    return 0;
}

static void __exit test_cleanup(void) {
}

module_init(test_init);
module_exit(test_cleanup);
[1] www.makelinux.net/books/lkd2/ch06lev1sec3

[2] www.safaribooksonline.com/library/view/understanding-the-linux/0596005652/ch04s06.html

[3] lxr.free electrons.com/source/arch/x86/include/asm/irq_vectors.h?v=4.8#L108


[4] lxr.free electronics.com/source/kernel/irq/manage.c?v=4.8#L1634

而不是你而不是我:(“探索/研究目的”-又名游戏黑客……(或更糟)不,不是游戏黑客。我想了解更多关于英特尔TSX中止处理程序的行为。我不明白你所说的“而不是你而不是我:()?在询问之前显示您的代码或进度。不清楚本地中断和TSX中止处理程序之间的连接,但可能是因为您正在开发新的处理程序。但是,我仍然不清楚您到底在问什么。是否要挂接每个中断?还是要检测LINTx引脚的触发?