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