qemu-kvm的irqfd机制
qemu-kvm的irqfd机制
irqfd机制与ioeventfd机制类似,其基本原理都是基于eventfd。
ioeventfd机制为Guest提供了向qemu-kvm发送通知的快捷通道,对应地,irqfd机制提供了qemu-kvm向Guest发送通知的快捷通道。
irqfd机制将一个eventfd与一个全局中断号联系起来,当向这个eventfd发送信号时,就会导致对应的中断注入到虚拟机中。
QEMU注册irqfd
与ioeventfd类似,irqfd在使用前必须先初始化一个EventNotifier对象(利用event_notifier_init函数初始化),初始化EventNotifier对象完成之后获得了一个eventfd。
向kvm发送注册中断irqfd请求
获得一个eventfd之后,QEMU通过kvm_irqchip_add_irqfd_notifier_gsi=>kvm_irqchip_assign_irqfd构造kvm_irqchip结构,并向kvm发送ioctl(KVM_IRQFD).
在kvm_irqchip_assign_irqfd中,首先构造了一个kvm_irqfd结构的变量irqfd,其中fd为之前初始化的eventfd,gsi是全局系统中断,flags中定义了是向kvm注册irqfd(flags==0)还是解除注册irqfd(KVM_IRQFD_FLAG_DEASSIGN,也就是flags==1)。flags的bit1(KVM_IRQFD_FLAG_RESAMPLE)表明该中断是否为电平触发。
- KVM_IRQFD_FLAG_RESAMPLE相关信息
当中断处于沿触发模式时,irqfd->fd连接kvm中中断芯片(irqchip)的gsi管脚,也由irqfd->fd负责中断的toggle,以及对用户空间的handler的触发。
当中断处于电平触发模式时,同样irqfd->fd连接kvm中中断芯片的gsi管脚,当中断芯片收到一个EOI(end of interrupt)重采样信号时,gsi进行电平翻转,对用户空间的通知由irqfd->resample_fd完成(resample_fd也是一个eventfd)。
kvm_irqchip_assign_irqfd最后调用kvm_vm_ioctl(s, KVM_IRQFD, &irqfd),向kvm请求注册包含上面构造的kvm_irqfd信息的irqfd。
kvm注册irqfd
收到ioctl(KVM_IRQFD)之后,kvm首先获取传入的数据结构kvm_irqfd的信息,然后调用kvm_irqfd函数。
在kvm_irqfd中,首先分辨传入的kvm_irqfd结构中的flags的bit0要求的是进行irqfd注册还是解除irqfd的注册。如果是前者,则调用kvm_irqfd_assign。
kvm_irqfd_assign的分析中省略定义了CONFIG_HAVE_KVM_IRQ_BYPASS和水平中断的注册情况。这样分析便于理清irqfd的注册框架。
在kvm_irqfd_assign中,首先申请了一个kvm_kernel_irqfd结构类型的变量irqfd,并为之分配空间,之后对irqfd的各子域进行赋值。
kvm_kernel_irqfd结构中有2个work_struct,inject和shutdown,分别负责触发中断和关闭中断,这两个work_struct各自对应的操作函数分别为irqfd_inject和irqfd_shutdown。
kvm_irq_assign调用init_waitqueue_func_entry将irqfd_wakeup函数注册为irqfd中等待队列entry激活时的处理函数。这样任何写入该irqfd对应的eventfd的行为都将导致触发这个函数。
然后kvm_irq_assign利用init_poll_funcptr将irqfd_ptable_queue_proc函数注册为irqfd中的poll table的处理函数。irqfd_ptable_queue_proc会将poll table中对应的wait queue entry加入到waitqueue中去。
kvm_irq_assign接着判断该eventfd是否已经被其它中断使用。
kvm_irq_assign以irqfd->pt为参数,调用eventfd的poll函数,也就是eventfd_poll,后者会调用poll_wait函数,也就是之前为poll table注册的irqfd_ptable_queue_proc函数。irqfd_ptable_queue_proc将irqfd->wait加入到了eventfd的wqh等待队列中。这样,当有其它进程或者内核对eventfd进行write时,就会导致eventfd的wqh等待队列上的对象函数得到执行,也就是irqfd_wakeup函数。
这里只讨论有数据,即flgas中的EPOLLIN置位时,会调用kvm_arch_set_irq_inatomic进行中断注入。
如果kvm_arch_set_irq_inatomic无法注入中断(即非MSI中断或非HV_SINT中断),那么就调用irqfd->inject,即调用irqfd_inject函数。
在irqfd_inject函数中,如果该irqfd配置的中断为边沿触发,则调用2次kvm_set_irq,形成一个中断脉冲,以便kvm中的中断芯片(irqchip)能够感知到这个中断。如果该irqfd配置的中断为电平触发,则调用一次kvm_set_irq,将中断拉至高电平,使irqchip感知到,电平触发的中断信号拉低动作会由后续的irqchip的EOI触发。
总结
irqfd基于eventfd机制,qemu中将一个gsi(全局系统中断号)与eventfd捆绑后,向kvm发送注册irqfd请求,kvm收到请求后将带有gsi信息的eventfd加入到与irqfd有关的等待队列中,一旦有进程向该eventfd写入,等待队列中的元素就会唤醒,并调用相应唤醒函数(irqfd_wakeup)向Guest注入中断,而注入中断这一步骤相关知识与特定的中断芯片如PIC、APIC有关。
__EOF__

本文链接:https://www.cnblogs.com/haiyonghao/p/14440723.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了