qemu模拟的一个内核驱动 io口中断

printf "\x01\x00\x00\x00" > /dev/qemu-io-intr

gic_poke_irq: mask=0x40000000, offset=0x200 (hwirq=94)

IO-INTR Interrupt triggered! (irq=27, count=12, cpu=0)

IO-INTR Trigger IRQ 27 pending state

/ #

/ #

/ #

/ # cat /proc/interrupts

CPU0

16: 162498 GIC 29 Edge twd

17: 6 GIC 34 Level timer

27: 12 GIC 94 Level qemu-io-intr

29: 0 GIC 47 Level eth0

32: 1065 GIC 41 Level mmci-pl18x (cmd)

33: 40749 GIC 42 Level mmci-pl18x (pio)

34: 8 GIC 44 Level kmi-pl050

35: 100 GIC 45 Level kmi-pl050

36: 241 GIC 37 Level uart-pl011

42: 0 GIC 36 Level rtc-pl031

IPI0: 0 CPU wakeup interrupts

IPI1: 0 Timer broadcast interrupts

IPI2: 0 Rescheduling interrupts

IPI3: 0 Function call interrupts

IPI4: 0 Single function call interrupts

IPI5: 0 CPU stop interrupts

IPI6: 0 IRQ work interrupts

IPI7: 0 completion interrupts

Err: 0

#if 1

#include <linux/module.h>

#include <linux/platform_device.h>

#include <linux/fs.h>

#include <linux/cdev.h>

#include <linux/irq.h>

#include <linux/interrupt.h>

#include <linux/io.h>

#include <linux/sched.h>

#include <linux/uaccess.h>

#include <linux/irqdesc.h>

#include <linux/of.h>

#include <linux/errno.h>

#include <linux/slab.h>

#include <linux/moduleparam.h>

#define DEV_NAME "qemu-io-intr"

static int dev_major = 241;

#define VIRTUAL_IRQ 27 // 内核虚拟中断号

static int irq_count = 0; // 中断计数

static dev_t devno; // 设备号

static struct cdev cdev; // 字符设备结构体

static struct class *io_intr_class;

static int test_irq_dev_id = 1; // 中断dev_id(必须和request_irq保持一致)

// 中断处理函数(自动ACK模式:仅计数+日志,内核自动处理ACK)

irqreturn_t io_intr_handler(int irq, void *dev_id)

{

// 移除手动清除挂起位的代码,由内核自动ACK

irq_count++;

printk(KERN_INFO "IO-INTR Interrupt triggered! (irq=%d, count=%d, cpu=%d)\n",

irq, irq_count, raw_smp_processor_id());

// 返回IRQ_HANDLED后,内核会自动完成中断应答和清除

return IRQ_HANDLED;

}

// write函数:仅触发中断,不手动处理ACK

ssize_t io_intr_write(struct file *filp, const char __user *buf, size_t len, loff_t *off)

{

u32 val = 0;

int ret = 0;

if (len < sizeof(u32)) {

return -EINVAL;

}

ret = copy_from_user(&val, buf, sizeof(u32));

if (ret) {

return -EFAULT;

}

// 仅触发中断,内核自动处理ACK

if (val == 1) {

irq_set_irqchip_state(VIRTUAL_IRQ, IRQCHIP_STATE_PENDING, true);

printk(KERN_INFO "IO-INTR Trigger IRQ %d pending state\n", VIRTUAL_IRQ);

}

return sizeof(u32);

}

// read函数:读取中断计数

ssize_t io_intr_read(struct file *filp, char __user *buf, size_t len, loff_t *off)

{

u32 val = irq_count;

int ret = 0;

if (len < sizeof(u32)) {

return -EINVAL;

}

ret = copy_to_user(buf, &val, sizeof(u32));

if (ret) {

return -EFAULT;

}

return sizeof(u32);

}

// 字符设备操作集

static const struct file_operations io_intr_fops = {

.owner = THIS_MODULE,

.write = io_intr_write,

.read = io_intr_read,

.llseek = default_llseek,

};

// platform驱动probe函数(核心:恢复内核自动ACK流程)

static int io_intr_probe(struct platform_device *pdev)

{

int ret;

// 申请中断:使用内核默认的处理流程(自动ACK)

// 关键:移除IRQF_TRIGGER_RISING,使用Level触发(匹配GIC默认),不手动切换handler

ret = request_irq(VIRTUAL_IRQ, // 中断号27

io_intr_handler, // 中断处理函数

IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND, // Level高电平触发(内核自动ACK)

DEV_NAME, // 中断名称

&test_irq_dev_id); // dev_id(和free_irq保持一致)

if (ret < 0) {

printk(KERN_ERR "IO-INTR request_irq failed (ret=%d)\n", ret);

return ret;

}

// 移除手动切换handler和clear_flags的代码:使用内核默认handler(自动ACK)

// 移除enable_irq:request_irq后内核自动使能中断,避免不平衡警告

printk(KERN_INFO "IO-INTR Request irq %d success (auto ACK mode)\n", VIRTUAL_IRQ);

// 字符设备注册流程

if (dev_major) {

devno = MKDEV(dev_major, 0);

ret = register_chrdev_region(devno, 1, DEV_NAME);

} else {

ret = alloc_chrdev_region(&devno, 0, 1, DEV_NAME);

dev_major = MAJOR(devno); // 动态分配时更新主设备号

}

if (ret < 0) {

free_irq(VIRTUAL_IRQ, &test_irq_dev_id); // 传匹配的dev_id

return ret;

}

cdev_init(&cdev, &io_intr_fops);

cdev.owner = THIS_MODULE;

ret = cdev_add(&cdev, devno, 1);

if (ret < 0) {

unregister_chrdev_region(devno, 1);

free_irq(VIRTUAL_IRQ, &test_irq_dev_id);

return ret;

}

// 创建设备类和设备节点(自动生成/dev/qemu-io-intr)

io_intr_class = class_create(THIS_MODULE, DEV_NAME);

if (IS_ERR(io_intr_class)) {

ret = PTR_ERR(io_intr_class);

cdev_del(&cdev);

unregister_chrdev_region(devno, 1);

free_irq(VIRTUAL_IRQ, &test_irq_dev_id);

return ret;

}

device_create(io_intr_class, NULL, devno, NULL, DEV_NAME);

printk(KERN_INFO "IO-INTR Probed successfully! (irq=%d, major=%d)\n",

VIRTUAL_IRQ, dev_major);

return 0;

}

// platform驱动remove函数(修正free_irq传参)

static int io_intr_remove(struct platform_device *pdev)

{

// 清理设备节点

device_destroy(io_intr_class, devno);

class_destroy(io_intr_class);

cdev_del(&cdev);

unregister_chrdev_region(devno, 1);

// 关键:free_irq的dev_id必须和request_irq一致(不能传NULL)

free_irq(VIRTUAL_IRQ, &test_irq_dev_id);

printk(KERN_INFO "IO-INTR Removed successfully (irq_count=%d)\n", irq_count);

return 0;

}

// 设备树匹配表

static const struct of_device_id io_intr_of_match\[\] = {

{ .compatible = "qemu,io-intr" },

{ },

};

MODULE_DEVICE_TABLE(of, io_intr_of_match);

// platform驱动结构体

static struct platform_driver io_intr_driver = {

.probe = io_intr_probe,

.remove = io_intr_remove,

.driver = {

.name = DEV_NAME,

.of_match_table = io_intr_of_match,

.owner = THIS_MODULE,

},

};

// 注册platform驱动

module_platform_driver(io_intr_driver);

module_param(dev_major, int, S_IRUGO);

MODULE_PARM_DESC(dev_major, "Major device number for qemu-io-intr (0=dynamic)");

MODULE_LICENSE("GPL");

MODULE_AUTHOR("xiao dou AI");

#endif

相关推荐
HLC++8 小时前
Linux的进程间通信
android·linux·服务器
华清远见IT开放实验室9 小时前
实验室建设案例 | 石家庄科技信息职业学院嵌入式实验室——从底层硬件到系统应用,一所应用型高校的嵌入式人才培养这样落地
linux·arm开发·stm32·嵌入式硬件·高校·实验室建设
groundhappy12 小时前
idalib安装和codex ida-mcp配置
linux·开发语言·python
通信小小昕12 小时前
Ubuntu 26.04 中文输入法安装
linux·运维·ubuntu
张小姐的猫13 小时前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
栩栩云生14 小时前
AI 写代码犯的错,早被写进了错题集
linux·安全·ai编程
imc.1115 小时前
linux基础IO
linux·运维·服务器
BelongPanda17 小时前
Linux Nginx 纯手动 Let‘s Encrypt 泛域名证书配置教程
linux·nginx
酷可达拉斯17 小时前
Linux操作系统-shell编程(0)
linux·运维·服务器·python·云计算
2301_7779983417 小时前
Linux中断机制:操作系统如何高效运行
linux·运维·服务器