このページの目次

KVMのメモリとデバイス仮想化

カバー範囲: EPT/NPT (ステージ2ページテーブル) → MMU仮想化 → virtio (半仮想化) → VFIO (パススルー) → vhost (カーネル空間での高速化) → virtio-net/virtio-blk 詳細解説 カーネルバージョン: 2.6 ~ 6.x

メモリ仮想化: EPT/NPT

3層のアドレス変換:
  GVA (ゲスト仮想アドレス)
    → ゲストページテーブル (ゲストOSが管理)
    → GPA (ゲスト物理アドレス)
      → EPT/NPT (KVMが管理、「ステージ2ページテーブル」)
      → HPA (ホスト物理アドレス)

EPT (Intel Extended Page Tables) / NPT (AMD Nested Page Tables):
  ハードウェアが GVA→GPA→HPA の2次元ページウォーク (24ステップ!) を直接実行
  → KVM がシャドウページテーブル (shadow page table) を維持する必要がない
  → 現代のCPUはすべてハードウェアサポートを備えている

EPT violation: ゲストが自身のページテーブルを変更 → EPTページテーブルが期限切れ → VM exit
  → KVM が EPT マッピングを更新 → VMRESUME

MMU 仮想化

// arch/x86/kvm/mmu/mmu.c
// KVM MMU は2種類のページテーブルを維持する:
//   1. EPTページテーブル (ハードウェア使用): GPN → HPN
//   2. シャドウページテーブル (EPT非対応の旧CPUのみ): GVA → HPA

// TDP (Two-Dimensional Paging) = IntelのEPT、AMDのNPT

// kvm_mmu_page_fault():
//   ゲストが GPA にアクセス → EPT violation → handle_ept_violation()
//     → kvm_mmu_map() → EPT 内で GPA→HPA のマッピングを確立
//     → ゲストに戻る

virtio: 半仮想化IO

// drivers/virtio/
// デザイン原則: ゲストは自分がVM内にあることを認識 → 共有メモリ(virtqueue)を使用して通信
//          実際のハードウェアをシミュレートする必要がない → 極めて高いIOパフォーマンス

// virtio デバイスモデル:
//   フロントエンド (ゲスト): virtio-blk, virtio-net, virtio-scsi, virtio-gpu
//   バックエンド (ホスト): 
//     QEMU (ソフトウェアシミュレーション)
//     vhost (カーネル空間での高速化: vhost-net, vhost-scsi, vhost-vsock)
//     vDPA (ハードウェアアクセラレーション: ネットワークカード/smartNIC)

virtqueue: 共有リングバッファ

// virtio のコア転送メカニズム:
//   1. split virtqueue: 従来のフォーマット (ディスクリプタテーブル + available ring + used ring)
//   2. packed virtqueue (1.1): よりコンパクトでキャッシュラインに優しい

// ゲストがIOをサブミット:
//   ディスクリプタ + available ring に書き込み → kick (ドアベルへの書き込み)
// ホストが消費:
//   ディスクリプタを取得 → IOを処理 → used ring に書き込み → 割込み (MSI-X)
// ゲストが完了:
//   割込み → used ring を読み取り → バッファを解放

vhost: カーネル空間での高速化

// drivers/vhost/net.c
// vhost は virtio のデータパスをカーネルに移動する:
//   ゲスト → virtqueue → vhost (ホストカーネル) → tap デバイス → プロトコルスタック
//   QEMU ユーザー空間をバイパス → レイテンシが約50%削減

// vhost-net:   ネットワーク (最も一般的)
// vhost-scsi:  ストレージ
// vhost-vsock: ゲスト↔ホスト通信 (AF_UNIX を介したVM境界を越えた通信)

VFIO: デバイスパススルー

// 物理PCIeデバイスをゲストに排他的に割り当てる:
//   1. ホスト側でデバイスをアンバインド (echo dev > /sys/bus/pci/drivers/xxx/unbind)
//   2. vfio-pci にバインド (echo vendor device > /sys/bus/pci/drivers/vfio-pci/new_id)
//   3. QEMU: -device vfio-pci,host=01:00.0
//   4. IOMMU による分離: デバイスのDMAはこのVMのメモリのみアクセス可能

// パフォーマンス: ベアメタルに近い (GPU、NVMe をゲストにパススルー)
// 制限: オンライン移行不可 (デバイス状態の保存/復元ができない)

参考

  • ソースコード⁠: arch/x86/kvm/mmu/, drivers/virtio/, drivers/vhost/, drivers/vfio/
  • カーネルドキュメント⁠: Documentation/virt/kvm/, Documentation/driver-api/virtio/
  • LWN: "Virtio without the QEMU middleman (vhost)", "VFIO and device assignment"

キーワード: EPT, NPT, stage-2 page table, virtio, virtqueue, vhost, VFIO, PCI passthrough