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 \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #include \ #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

相关推荐
小鹏linux2 小时前
Ubuntu 22.04 部署开源免费具有精美现代web页面的Casdoor账号管理系统
linux·前端·ubuntu·开源·堡垒机
在角落发呆3 小时前
Linux转发配置:解锁网络互联的核心密码
linux·运维·网络
齐潇宇3 小时前
Zabbix 7 概述与配置
linux·zabbix·监控告警
江公望4 小时前
Ubuntu htop命令,10分钟讲清楚
linux·服务器
哎呦,帅小伙哦4 小时前
Linux 时间:从原子钟到 clock_gettime 的每一面
linux·运维·服务器
张小姐的猫5 小时前
【Linux】多线程 —— 线程互斥
linux·运维·服务器·c++
YuanDaima20485 小时前
Linux 进阶运维与 AI 环境实战:进程管理、网络排错与 GPU 监控
linux·运维·服务器·网络·人工智能
lolo大魔王7 小时前
Linux 数据文件处理实战:排序、搜索、压缩、归档一站式详解
linux·运维·服务器
starvapour7 小时前
Ubuntu切换到Fcitx5中文输入法
linux·运维·ubuntu
lolo大魔王8 小时前
Linux的监测程序
linux·运维·github