kvm-hello-world実験
KVMがやっていることを手を動かして体感するための実験記録。QEMU等を一切使わず、/dev/kvmのioctlを直接叩くだけの最小限のCプログラムでVMを起動する。 #virtualization #linux
使ったもの
dpw/kvm-hello-worldというMIT Licenseの約500行のC教材プログラム。QEMUやkvmtoolのような「フル機能のVMM」ではなく、KVM APIの使い方だけを見せるために書かれたもの。
動かし方
git clone https://github.com/dpw/kvm-hello-world
cd kvm-hello-world
make
./kvm-hello-world -s # protected modeでゲストを起動
Ubuntu/Pop!_OS 24.04・GCC 13・binutils 2.42の環境では、Makefileそのままだと2箇所で失敗したため修正が必要だった。
CFLAGSの-Werrorを外す — 新しいGCCが*(long *) 0x400 = 42;(ヌルポインタ相当のアドレスへの書き込み)を-Warray-boundsで警告するようになっており、教材コード自体は正しい意図(アドレス0はゲストのメモリ先頭という意味)なのでビルドを通すために警告を無視するpayload.oを作るld -T payload.ld -o payload.oに-r(relocatable指定)を追加 — 新しいbinutilsは-rなしだと実行可能ファイルを生成してしまい、後続のリンクに使えずエラーになる
実行結果
$ ./kvm-hello-world -s
Testing protected mode
Hello, world!
$ ./kvm-hello-world -p
Testing 32-bit paging
Hello, world!
$ ./kvm-hello-world -l
Testing 64-bit mode
Hello, world!
$ ./kvm-hello-world -r
Testing real mode
real modeのゲスト(guest16.s、アセンブリ6行)はメモリに42を書き込んでhltするだけで文字出力コードがないため、Hello, world!は出ない(エラーが出なければ成功)。
なぜsudoなしで動いたか
/dev/kvmは通常root:kvmグループの0660権限で、一般ユーザーはkvmグループに入っていないとアクセスできない。このマシンではgetfacl /dev/kvmで確認したところ、ユーザーに対する個別ACLエントリ(user:tokuhirom:rw-)が付与されており、それによってsudoなしで直接/dev/kvmを開けた。
コードで分かること
ゲスト側(guest.c)はOSなしの3行程度のプログラムで、ポート0xE9へのoutb命令を1文字ずつ実行するだけ。
for (p = "Hello, world!\n"; *p; ++p)
outb(0xE9, *p);
ホスト側(kvm-hello-world.c)はこの機械語をVMのメモリに直接コピーし、KVM_RUNをループで呼ぶ。ゲストがoutbを実行するたびに「VM exit」が発生し、KVM_EXIT_IOとしてホスト側に制御が戻る。
case KVM_EXIT_IO:
if (vcpu->kvm_run->io.direction == KVM_EXIT_IO_OUT
&& vcpu->kvm_run->io.port == 0xE9) {
fwrite(p + vcpu->kvm_run->io.data_offset,
vcpu->kvm_run->io.size, 1, stdout);
continue; // またKVM_RUNに戻ってゲストを再開
}
ポート0xE9は実在のデバイスではなく、このプログラムが決めた「ただの取り決め」。これがKVMノートで説明した「KVMはデバイスエミュレーションを一切せず、ユーザー空間のVMMがI/Oを肩代わりする」の最小の実例になっている。FirecrackerやQEMUがネットワーク・ディスクに対してやっていることの、極小版がこれだと考えると分かりやすい。
ソース
このリポジトリのnotes/code/kvm-hello-world/に、上記の修正を加えたソース一式を置いてある(makeするだけでビルドできる)。
続き: virtqueue風トイ実験
この実験の「1文字ごとにoutbしてVM exitする」という素朴なI/Oを、virtioのように「まとめて共有メモリに書いて1回だけ通知する」設計に変えるとどれだけVM exit回数が減るかを、この実験の続きとして確認した。