iT邦幫忙

2025 iThome 鐵人賽

DAY 8
0

eventfd

在先前的設計中,我們透過 KVM 建立了虛擬的中斷控制器(PIC/IOAPIC),讓 Guest 能夠接收外部中斷。這個做法可以模擬傳統硬體的行為,但對於某些需要頻繁觸發的裝置事件(如鍵盤輸入或網卡收包),將存在效能瓶頸。

這是因為,這類事件必須先由 Host 接收,然後再透過 KVM_IRQ_LINE 把對應的 GSI 拉高,通知 Guest 有中斷發生。這條路徑會經過 kernel → host → KVM → Guest 的多層切換,每一次觸發都伴隨著 VM-exit,顯得笨重。一旦模擬裝置的事件發生得很頻繁,就會浪費大量效能在切換上。

為了解決這個問題,Linux 提供了一個更高效的機制 : eventfd。它將「事件」抽象成一個可寫入的計數器。同時,KVM 也提供了 KVM_IRQFD 介面,允許我們將一個 eventfd 綁定到指定的 IRQ 線(GSI)。
如此當事件被觸發實,只需要往 eventfd 寫入數據,就能直接在 Guest 中觸發對應的 IRQ,無須讓 VM-exit 介入整個過程。

irq_manager 設計

這裡要向我們西前設計的 irq_manager 增加兩件事情

  • 綁定 GSI 與 eventfd (KVM_IRQFD)
  • 提供觸發接口(往 eventfd 寫入數據)
    入此一來,每個模擬設備都可透過 irq_manager 註冊自己的 GSI,並在需要時觸發事件,讓 Guest 收到中斷。
int irq_bind_eventfd(struct irq_manager *mgr, unsigned gsi, int efd)
{
    struct kvm_irqfd args = {
        .fd = efd,
        .gsi = gsi,
        .flags = 0,
    };
    return ioctl(mgr->vmfd, KVM_IRQFD, &args);
}

int irq_trigger(int efd)
{
    uint64_t one = 1;
    return write(efd, &one, sizeof(one));
}

irq_bind_eventfd 用於將 eventfd 綁定到 GSI,綁定完成後只需要透過 write 即可觸發 IRQ,另外這個 one = 1 實際上代表觸發次數,也就是最小的寫入事件,調用 write 實等於告訴 eventfd 目前事件累計多少次。


上一篇
Day07 Real Mode 中斷與 IRQ 測試
下一篇
Day 09 模擬 io 設備
系列文
30 天 hypervisor 入門11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言