Category

RustでマイクロKVM実装

Linuxカーネルの仮想化技術であるKVM。rust-vmmが提供する各種クレートを用いてFirecrackerのような軽量VMMを実装します。

14件の記事

ゲストVM上でhttpdを起動しホストからアクセスする——TCPだけタイムアウトするvirtio-netのfeature bit設定ミス

[virtio-netデバイスを自前実装してTAP経由でホストと通信する](/tech/articles/rust-kvm-virtio-net-tap)で確認したping疎通の上に、ゲスト内でbusybox httpdを起動し、実際にホストからHTTPでアクセスします。ホスト自身からの直接アクセスに加え、TAPのサブネットに直接は入れない別マシンからのアクセスを、簡易なTCPリバースプロキシで中継して確認します。合わせて、ICMPは通るのにTCP接続だけがタイムアウトする現象の原因になった、virtio-netのfeature bit設定ミスを扱います。

続きを読む

VMライフサイクルをシグナルとCLIで管理する——ブロック中のKVM_RUNをSIGUSR1で起こす

カーネルイメージのパスやvCPU数といった設定をコマンドライン引数化し、Ctrl+CやSIGTERMを受けたときに複数vCPUのスレッドをすべて合流させてから終了する仕組みを実装します。アイドル中のvCPUはKVM_RUNの中でブロックされたままになるため、単純なフラグでは気づけません。SIGUSR1で個別スレッドを起こす方法と、SIGINT/SIGTERMをsigwaitで同期的に受け取る方法を扱います。

続きを読む

複数vCPUをスレッドで実行しSMP起動させる——Intel MPテーブルとCPUIDのAPIC ID

1つのvCPUだけで動かしてきたVMMを、複数のvCPUをそれぞれ専用スレッドで実行する構成に変更します。KVM_CREATE_VCPUで複数vCPUを作るだけではゲストカーネルはSMP環境だと気づかないため、Intel MPテーブルを自前で組み立ててゲストへ伝え、CPUIDのAPIC IDをvCPUごとに設定します。CPUIDのHTT関連ビットを不用意に書き換えるとAPの起動判定が壊れるという落とし穴も扱います。

続きを読む

virtio-blockデバイスを自前実装してディスクイメージを読み書きする——2つのvirtio-mmioデバイスを共存させる

virtio-netに続いて、ディスクイメージをバックエンドとするvirtio-blockデバイスを自前実装しました。2つ目のvirtio-mmioスロットを追加して2つのデバイスを同時に扱えるようにし、ゲストからのセクタ単位read/writeがホスト側のディスクイメージへ正しく反映されることを、双方向のマーカー書き込みで確認します。

続きを読む

virtio-netデバイスを自前実装してTAP経由でホストと通信する——ping疎通で動作確認する

virtio-mmioとvirtqueueの基礎の上に、virtio-netデバイスを自前実装しました。ゲストの送受信キューをホストのTAPデバイスへ橋渡しすることで、ゲストVMとホストの間でイーサネットフレームをやり取りできるようにし、ARP解決とICMP ping疎通で動作確認します。

続きを読む

virtio-mmioとvirtqueueを自前で実装する——virtio-consoleで動作確認する

実ハードウェアの模倣ではなく仮想化専用に設計されたVIRTIOの基礎を、virtio-mmio transportとsplit virtqueue(descriptor table/avail ring/used ring)を自前実装することで学びます。既に組み込み対応済みのvirtio-consoleドライバを題材に、レジスタの読み書きからキューの通知処理、実際の割り込み配送までを一通り繋げて動作確認します。

続きを読む

vm-superioでUART 16550を正確にエミュレートし、KVM_IRQ_LINEで実際に割り込みを配線する

シリアルコンソールの実装を、レジスタ単位を大幅に省略した最小スタブからrust-vmmのvm-superioクレートへ置き換えます。まず割り込みを配線しない状態でレジスタ精度だけを上げ、ゲストカーネル側の挙動がどう変わるかを観察したうえで、KVM_IRQ_LINEによる実際の割り込み配線を行い、/proc/interruptsのカウントから割り込みが実際に使われていることを確認します。

続きを読む

vCPUを実行して実際にLinuxカーネルを起動する——Intel VMX向け設定とin-kernel irqchip、initramfs

linux-loaderでゲストメモリへ組み立てたカーネルイメージとboot_paramsを、実際にvCPU上で実行します。Intel VMX特有のTSS/identity map設定、in-kernel irqchipとPIT、64bitロングモード直接エントリ用のページテーブル、最小限のシリアル・CMOSエミュレーションを実装し、initramfs内のRust製initがユーザースペースとして実行されるところまでを確認します。

続きを読む

linux-loaderでLinuxカーネルをロードする——boot protocolのzero pageとe820マップ

rust-vmmのlinux-loaderクレートを使い、bzImage形式のLinuxカーネルをゲストメモリへロードします。Linux x86 boot protocolが要求するboot_params(zero page)とe820メモリマップを組み立て、ホスト側から読み返して内容を確認します。vCPUの作成・実行はまだ行いません。

続きを読む

rust-vmmが提供するクレートでKVMを操作する——kvm-ioctls/kvm-bindings/vm-memory

rust-vmmプロジェクトが提供するkvm-ioctls/kvm-bindings/vm-memoryクレートを使ってKVMを操作します。ioctl番号の計算やC構造体の移植といった、自前で書くと手間がかかる部分がクレート側の型やメソッドに置き換わる例をいくつか紹介します。

続きを読む

ゲストメモリを複数リージョンに分割する——KVMのメモリスロットとホスト・ゲスト間の直接共有

前回1つだけだったメモリリージョンを、コード用とデータ用の2つのスロットに分割し、ゲストが書き込んだ値をホストがioctlを介さず直接読み出すところまでを実装します。KVM_SET_USER_MEMORY_REGIONが表しているものと、ゲスト物理アドレスとホスト仮想アドレスの対応関係を整理します。

続きを読む

生ioctlでKVMを叩く——12バイトの機械語だけを実行する最小VM

kvm-ioctlsやkvm-bindingsといったクレートを使わず、libcの生ioctl呼び出しだけでKVMを操作し、カーネルもデバイスも用意せずリアルモードで12バイトの機械語だけを実行する最小のVMをRustで組み立てます。ioctl番号の計算方法や、KVMのC構造体をRustにそのまま移植する際の注意点も扱います。

続きを読む

KVMとは何か——ハードウェア仮想化支援とVM Exitの仕組み

RustでFirecrackerのような軽量VMMを実装するにあたり、まずKVMがLinuxカーネルの中でどう位置づけられているか、CPUのハードウェア仮想化支援機能が何を解決しているか、そしてVMMがKVMをどういう手順で呼び出してゲストを実行するのかを整理します。

続きを読む

RustでマイクロKVM実装 - 用語集

これまでの記事に登場した専門用語を、仮想化の基礎・KVM API・rust-vmmクレート・CPU/x86アーキテクチャ・割り込み/タイマー・ブートプロセス・VIRTIO・開発環境の8カテゴリに分けて整理します。記事の追加にあわせて随時更新します。

続きを読む