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

相关推荐
程序员老赵2 小时前
超全 Docker 镜像源配置指南|Windows/Mac/Linux一键搞定,拉镜像再也不卡顿
linux·后端·容器
门豪杰2 小时前
Ubuntu下安装Claude Code
linux·运维·ubuntu·claude·claude code
总要冲动一次2 小时前
离线安装 percona-xtrabackup-24
linux·数据库·mysql·centos
桌面运维家2 小时前
Windows/Linux双启动:BIOS/UEFI多配置桌面创建指南
linux·运维·windows
xlp666hub3 小时前
【Linux驱动实战】:字符设备驱动之内核态与用户态数据交互
linux·面试
久绊A3 小时前
服务器新硬盘初始化与挂载
linux·挂载
IMPYLH3 小时前
Linux 的 chroot 命令
linux·运维·服务器
克莱因3583 小时前
Linux Cent OS7 at定时任务
linux·运维·服务器
RisunJan3 小时前
Linux命令-make(GNU的工程化编译工具)
linux·运维·gnu