Upgrade to Pro — share decks privately, control downloads, hide ads and more …

BHyVe Internals

BHyVe Internals

Takuya ASADA

May 26, 2012
Tweet

More Decks by Takuya ASADA

Other Decks in Technology

Transcript

  1. 3 BHyVe とは • FreeBSD 版の Linux KVM のようなもの •

    Intel VT を用いたハイパーバイザ • 開発の初期段階でごく限定的な機能が実装されている             ↓ 最低限のハイパーバイザ実装のよいサンプルになりそう
  2. 4 新しい Web サイトと GSoC web site http://www.bhyve.org/ GSoC 2012:

    BHyVe BIOS emulation to boot legacy systems http://bit.ly/bhyve_bios
  3. 5 実装状況 • Intel VT-x, EPT 必須 (= Nehalem 以降必須

    ) • BIOS 非対応 (disk ブート出来ない ) • 対応デバイス : – virtio-net, virtio-blk – pci passthrough(VT-d) – paravirtual console/debug port – UART • 対応 OS: – FreeBSD 8, 9, 10
  4. 7 使い方 • /boot/loader.conf hw.physmem="0x100000000" (ホストのメモリ割り当てを減らしてゲスト用の領域を 用意) • kldload vmm.ko

    /usr/sbin/bhyveload -m ${lowmem} -M {highmem} -h {bootdir} $ {vmname} /usr/sbin/bhyve -c ${cpus} -m ${lowmem} -M{highmem} \ -s 1,virtio-net,tap0 -s 2,virtio-blk,${diskdev}
  5. 8 各コマンドの役割分担 • /usr/sbin/bhyveload VM インスタンスを作成し、 BSD カーネルを VM インスタンスのメモ

    リ領域にロードして起動可能な状態を作る • /usr/sbin/bhyve bhyveload が初期化した VM インスタンスを実行し、ディス ク、 NIC 、コンソールなどのデバイスエミュレーション処理を行う VM インスタンスの状態は、プロセス内ではなく /dev/vmm/${vmname} というデバイス上、つまりカーネル内に保持される。 このファイルへ read(), write(), mmap() する事により VM 内のメモリ空 間にアクセス出来る。
  6. 9 bhyveload の動作 • sysctl(“hw.vmm.create”, vm_name) → /dev/vmm/${vm_name} を作成 •

    open(/dev/vmm/${vm_name}) • seg.gpa = 0 seg.len = mem_size ioctl(fd, VM_MAP_MEMORY, seg) membase = mmap(NULL, mem_size, PROT_READ| PROT_WRITE, MAP_SHARED, fd, 0) • userboot.so を使って membase の領域へ BSD カーネルを memcpy()
  7. 10 userboot.so • FreeBSD のブートローダをユーザ空間で動くように移植 したもの • メモリやレジスタへの読み書きを wrap 、ゲストのメモリ

    空間/レジスタへアクセス (メモリ空間は mmap 、レジスタの読み書きは ioctl 経由 で VMM が管理するゲストのデスクリプタへ) • これを利用して kload が実装されている ( Linux における kexec と同じ)
  8. 11 bhyve の動作 • open(/dev/vmm/${vm_name}) • デバイス初期化 • pthread_create(fbsdrun_start_thread) fbsdrun_start_thread()

    { while(1) { ioctl(VM_RUN, &vmexit) handler[vmexit.exitcode](&vmexit, &vcpu); } } • メイン関数はデバイスエミュレーションの処理要求イベントを kevent() で待つ
  9. 14 vCPU の初期化 • bhyveload で以下の初期化を実施 – CR0 = PE

    | PG | NE # ページング、プロテクトモード – CR4 = PAE | VMXE # PAE 、 VMX 有効 – EFER = LME | LMA # long mode 有効 – GDT 初期化&セグメントレジスタ初期化 – タスクレジスタ初期化 – ページテーブル& CR3 初期化 – RSP 初期化 – エントリポイント設定
  10. 15 mptable の初期化 • /usr/sbin/bhyve から実行(引数の CPU 数を使用) • (未実装な

    ACPI を使わずに)セカンダリ CPU の情報を OS に伝える • BIOS ROM 領域上にテーブルを用意 • PCI デバイスや割り込みの情報の伝達にも使ってる?
  11. 18 ゲストカーネルのコンフィグレーション device pci device bvmconsole device bvmdebug device mptable

    ACPI や多くのデバイスは無効 virtio.ko, if_vtnet.ko, virtio_pci.ko, virtio_blk.ko はモジュール としてビルド
  12. 19 /usr/sbin/bhyve vmm.ko BSD kernel IOCTL return Guest kernel VMExit

    IO エミュレーション IO 命令 console PCI net blk io emulation 実行
  13. 20 IO エミュレーション • ゲスト OS が in/out 命令を実行、 VMExit

    • vmm.ko で EXIT_REASON_INOUT をハンドル • VM_EXITCODE_INOUT で ioctl を return 、カーネルか ら /usr/sbin/bhyve へ制御を移す • handler[VM_EXITCODE_INOUT]()       ↓ inout_handlers[port].handler() の順にハンドラがコールされ、 IO ポートに割り当てられ たハンドラが実行される
  14. 21 bvm_console • IO 空間の 0x220 に inl / outl

    で読み書き • ゲストドライバ – int getc(void) { return inl(0x220); } – void putc(int c) { outl(0x220, c); } – 割り込みなどない。 • VMM – if (in) { read(fd, &c, 1); *eax = (c & 0xff); }else write(fd, *eax, 1);
  15. 22 PCI バス • CONFIG_ADDRESS レジスタ: 0xcf8 • CONFIG_DATA レジスタ:

    0xcfc – 0xcff • 各仮想 PCI デバイスは初期化時に自分のコンフィグレジ スタの値を設定 • 各仮想 PCI デバイスの IO レジスタはデバイス初期化時に 動的に確保
  16. 23 PCI デバイスの MSI 割り込みサポート • PCI 割り込みとして MSI 割り込みのみサポート

    • デバイス初期化時に configuration space 上の MSI capable フラグ を有効化 • /usr/sbin/bhyve からの割り込み要求は、 VM_LAPIC_IRQ ioctl と して vmm.ko へ送られる 引数として cpuid と vector ナンバを指定 • vmm.ko で ioctl を受けて vlapic にレジスタ値をセット • vmlaunch 前に vlapic の値をチェックして、割り込みがあったら VMCS にフラグをセット
  17. 24 MSR register のエミュレーション • Local APIC をエミュレートする為に、 wrmsr/rdmsr 命令で

    VMExit を発生させ、エミュレーションを行なっている • ほぼ vmm.ko でエミュレーションを行なっているが、初期 化周りの一部の処理で /usr/sbin/bhyve へエミュレーション を行わせている
  18. 25 タイマー • Local APIC Timer vmlaunch 前にタイマーの値を計算、 vlapic へ割り込みを設定

    vmm.ko 内でエミュレーション • TSC rdtsc を trap していないように見える (その場合どうなるんだろう??) • PIT 8254 /usr/sbin/bhybe で IO ポートアクセスのエミュレーションをして いる 割り込むコードが見当たらないような…??
  19. 26 virtio-net, blk • PCI デバイス、 IO エミュレーションと MSI 割り込みを使

    用 • /usr/sbin/bhyve でエミュレーション • MMIO は使っていない (そもそも MMIO に対応していないっぽい…)
  20. 27 pci passthrough(VT-d) • デフォルトでは使わない • Intel VT-d を使って PCI

    デバイスをゲストに割り当てる機 能 • 物理デバイス→ゲストへの割り込み転送は vmm.ko 内で行 なっているが、 io は一度 /usr/sbin/bhyve へ戻しているよう に見える • MMIO 空間は EPT 経由でゲストにマップしている模様
  21. 28 UART • ( bvm_console がダサいので)最近実装されました • てっきり PC の

    COM ポートをエミュレーション出来るよ うにしたのかと思ったら、なんと PCI デバイス…。 • Siig CyberSerial 1-port と自己申告 • IOAPIC 未実装だから割り込みも未実装\ (^o^) /
  22. 29 まとめ • たったこれだけのデバイスエミュレーションで、 (ちょっと苦しいけど)ゲスト OS が動く事が分かる – 但し、準仮想化デバイスを幾つか使っているのでゲスト側ドラ イバが必須

    • 現状では FreeBSD しか動かないが、 FreeBSD カーネルに 依存している訳ではない事がわかる – bhyveload を fork して自分の起動したい OS に対応したものを書 けば、動きそう