TL

KVMとQEMUによる仮想マシンの実行モデル

なぜKVMだけでVMが動かず、QEMUと組むのか。カーネルがVMX/SVMを握り、QEMUがデバイスを演じる分業を、vCPUスレッドとvirtioまで原理で押さえ、仮想化の性能勘所を掴めます。

応用仮想化KVMQEMUvirtioLinux最終更新: 2026-06-21
TL;DR要点だけ先に
  • 1.KVMはカーネルモジュールで、VT-x/AMD-Vの制御(VMCS/VMCB操作、VM entry/exit)だけを担い、デバイスのエミュレーションは持たない。
  • 2.QEMUはユーザー空間プロセスで、vCPUを各々スレッド化してKVMのioctlでゲストを走らせ、I/O起因のVM exitを受け取ってデバイスをエミュレートする。
  • 3.virtioはゲスト・ホスト共有のリングバッファでI/Oをまとめ、VM exitと割り込みを削減する準仮想化デバイスで、vhostでデータ経路をカーネルへ降ろせる。

なぜKVMとQEMUは分業するのか

Linux の代表的な仮想化スタックは、しばしば「KVM/QEMU」と一語で語られますが、実体は責務の異なる二つの部品です。KVM(Kernel-based Virtual Machine)はカーネルモジュールで、VT-x/AMD-Vの制御という、カーネル特権でしかできない仕事だけを引き受けます。QEMU はユーザー空間のプロセスで、ディスク・ネットワーク・割り込みコントローラといった周辺デバイスを丸ごとエミュレートします。

この分割には理由があります。VMX root/non-root モードの遷移、VMCS の VMREAD/VMWRITEVMLAUNCH/VMRESUME は特権命令で、カーネルでしか実行できません。一方デバイスエミュレーションは複雑かつ多種で、バグや脆弱性も入り込みやすい。これをカーネルに置けば攻撃面が膨らみます。そこで最小限の特権処理(CPU/メモリ仮想化)だけをカーネルに残し、肥大しやすいデバイス模倣はユーザー空間へ追い出すという、マイクロカーネル的な切り分けを採っています。

KVMは「ハイパーバイザの足回り」だけ

KVM 単体では VM は完成しません。KVM が提供するのは「ゲストを non-root で走らせ、VM exit を受け取って返す」という素のループだけです。ディスクが見える・NICが繋がるといった「マシンらしさ」は QEMU(あるいは別のVMM、例: cloud-hypervisor)が与えます。KVM は機構、QEMU は政策、という分担です。

/dev/kvm:ioctlで組み立てる仮想マシン

QEMU は KVM をキャラクタデバイス /dev/kvm への ioctl として使います。システムコールの一種である ioctl が、ユーザー空間 QEMU とカーネル KVM の唯一の境界です。VM 構築の骨格はおおむね次の順序になります。

kvm = open("/dev/kvm", O_RDWR);
vmfd = ioctl(kvm,  KVM_CREATE_VM,  0);      // VM を1つ作る
ioctl(vmfd, KVM_SET_USER_MEMORY_REGION, &mem); // ゲスト物理メモリを登録
vcpufd = ioctl(vmfd, KVM_CREATE_VCPU, 0);   // vCPU を1つ作る
run = mmap(..., vcpufd, 0);                  // vCPU と共有する制御領域
for (;;) {
    ioctl(vcpufd, KVM_RUN, 0);               // ← VM entry。戻ると VM exit
    switch (run->exit_reason) {              // 共有領域に理由が入る
        case KVM_EXIT_IO:   /* QEMUがI/Oをエミュレート */ break;
        case KVM_EXIT_MMIO: /* QEMUがMMIOをエミュレート */ break;
        case KVM_EXIT_HLT:  /* ゲストが停止 */ break;
    }
}

要は KVM_RUN の ioctl がそのまま VM entry に対応します。カーネル内で KVM は VMCS をロードして non-root に入り、ゲストを走らせ、VM exit が起きると ioctl から戻ります。なぜ exit したかは mmap で共有する kvm_run 構造体の exit_reason に書かれ、QEMU はそれを見て分岐します。ゲストのメモリは QEMU プロセスの仮想アドレス空間の一部として確保され(KVM_SET_USER_MEMORY_REGION でゲスト物理→ホスト仮想の対応を登録)、EPT/NPT はこの登録に基づいて構成されます。

vCPUスレッドモデル

ここが実行モデルの核心です。KVM の vCPU は専用ハードウェアではなく、QEMU プロセス内の1本のスレッドです。ゲストの各 CPU に対し QEMU はスレッドを1つ起こし、そのスレッドがひたすら KVM_RUN を呼ぶループを回します。

QEMU プロセス(ユーザー空間)
 ├─ メインループスレッド  … タイマ・モニタ・I/Oイベント処理
 ├─ vCPU スレッド 0  → ioctl(KVM_RUN) ⇄ [カーネル: non-rootでゲスト実行]
 ├─ vCPU スレッド 1  → ioctl(KVM_RUN) ⇄ [カーネル: non-rootでゲスト実行]
 └─ vCPU スレッド N  → ...

この設計の含意は大きいものがあります。第一に、vCPU はホストの通常スレッドなので、ホストのスケジューラ(CFS/EEVDF)がそのまま物理コアへ割り付ける。vCPU の優先度・CPU アフィニティ・cgroup 制限は、普通のプロセスと同じ手段で効きます。第二に、ゲストが KVM_RUN で non-root にいる間、そのスレッドはカーネル内で「ゲストを実行中」という状態にあり、CPU 時間としてはゲストに食われます。第三に、ゲストが多数の vCPU を持っても物理コアが少なければ、ホストスケジューラが時分割するためオーバーコミットが成立します。

VM exitはこのスレッドの足を止める

vCPU スレッドが VM exit を起こすと、いったんユーザー空間 QEMU に戻ってエミュレートし、再び KVM_RUN に入り直します。この往復はVT-xの解説で触れたとおり高コストで、I/O が多いゲストでは exit 回数が性能を直接左右します。後述の virtio は、まさにこの exit を減らすための仕組みです。

トラップ&エミュレートの分担

VM exit の理由ごとに、誰が処理するかは分かれています。カーネルの KVM 内で完結させた方が速いものはカーネルに、複雑なデバイス模倣はユーザー空間 QEMU に、という配分です。

exitの種類処理する場所理由
CPUID・一部MSRKVM(カーネル)短く頻繁で、即値を返すだけ
ローカルAPIC・タイマKVM(in-kernel irqchip)割り込み配送が高頻度・低遅延要求
ポートI/O・MMIOQEMU(ユーザー空間)対象デバイスの状態機械が複雑
virtio通知QEMU/vhostリング処理。vhostならカーネルで完結

割り込みコントローラ(APIC)を KVM 内に置く in-kernel irqchip は典型例です。割り込みのたびにユーザー空間へ戻っていては遅すぎるため、APIC エミュレーションと割り込み注入をカーネルで完結させ、さらに APICv/AVIC が効けば exit すら起こさず配送します。逆に、エミュレートする NIC やディスクコントローラの細かなレジスタ挙動は QEMU が引き受けます。**「速さが要る単純なものはカーネル、複雑なものはユーザー空間」**という一貫した基準で線が引かれています。

virtio:準仮想化I/Oで往復を減らす

エミュレートデバイス(例: e1000 NIC)は実機のレジスタを忠実に真似るため、1パケット送るだけで何度も MMIO アクセス→VM exit を招き、遅くなります。virtio はこの非効率を、ゲストに「自分は仮想環境だ」と認めさせる準仮想化で解きます。実機の模倣をやめ、仮想化に最適化した抽象デバイスをゲスト・ホストで合意するのです。

中核は virtqueue という共有リングバッファです。ゲストとホストが同じ物理メモリ領域を見て、I/O 要求の記述子をそこへ積みます。

ゲスト                         共有メモリ(virtqueue)            ホスト(QEMU/vhost)
  │ 記述子を複数まとめてリングへ積む  ─────►  available ring
  │ kick(1回のVM exit/通知)        ─────►  まとめて取り出し処理
  │                                  ◄─────  used ring に完了を積む
  │ 1回の割り込みでまとめて回収       ◄─────  interrupt(注入)

肝はバッチ化です。多数の I/O を共有リングへ積んでから1回だけ「kick」で相手に知らせるため、1要求あたりの VM exit と割り込みを劇的に減らせます。記述子はゲスト物理アドレスを指し、ホストはそれを自分の空間へ写してデータに触れます(ゼロコピーに近い経路も組める)。

vhostでデータ経路をカーネルへ降ろす

virtio の処理を QEMU(ユーザー空間)で回すと、kick のたびにユーザー空間へ戻る往復が残ります。vhost-net / vhost-blk はこのデータ経路をカーネルのカーネルスレッドへ移し、QEMU を介さずホストカーネル内で virtqueue を処理します。これにより通知も完了割り込みもカーネル内で閉じ、ユーザー空間への戻りが消えてスループットが伸びます。制御(セットアップ)は QEMU、データ転送は vhost、という二段の分業です。

役割を一行で

KVM=CPU/メモリ仮想化の機構(/dev/kvm の ioctl、VMCS操作、VM entry/exit)。QEMU=デバイスエミュレーションとVM組み立て(vCPUスレッド、I/O exit処理)。virtio=準仮想化I/O(virtqueueでバッチ化しexitと割り込みを削減、vhostでデータ経路をカーネルへ)。この三層で押さえると混同しません。

まとめ

  • KVM はカーネルモジュールで VT-x/AMD-V の制御だけを担い、QEMU はユーザー空間でデバイスをエミュレートする。特権処理を最小化し攻撃面を絞る分業。
  • QEMU は /dev/kvm への ioctl で VM を組み立て、KVM_RUN が VM entry に対応する。ゲストメモリは QEMU の仮想空間の一部として登録される。
  • vCPU は QEMU 内の通常スレッドで、ホストスケジューラがそのまま物理コアへ割り付ける。だからアフィニティや cgroup が効き、オーバーコミットも成立する。
  • virtio は共有 virtqueue で I/O をバッチ化し、VM exit と割り込みを減らす準仮想化デバイス。vhost を使えばデータ経路をカーネル内で完結できる。

OS Article

KVMとQEMUによる仮想マシンの実行モデルを実務で読む

TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。

解決すること

仮想化

比較で見る軸

難易度: advanced / カテゴリ: OS / タグ数: 5

導入後に効く点

QEMUはユーザー空間プロセスで、vCPUを各々スレッド化してKVMのioctlでゲストを走らせ、I/O起因のVM exitを受け取ってデバイスをエミュレートする。

先に潰すリスク

用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。

数字・仕様の読み方
難易度
advanced
カテゴリ
OS
タグ数
5

判断チェックリスト

  • 自社の用途が「仮想化 / KVM」に近いか確認する。
  • 強みである「KVMはカーネルモジュールで、VT-x/AMD-Vの制御(VMCS/VMCB操作、VM entry/exit)だけを担い、デバイスのエミュレーションは持たない。」が本当に評価軸になるか確認する。
  • 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
  • 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
  • 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
  • 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。

次に確認する観点

仮想化KVMQEMUvirtioLinux仮想化KVMQEMU