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

BHyVe Code Reading

BHyVe Code Reading

Takuya ASADA

May 26, 2012
Tweet

More Decks by Takuya ASADA

Other Decks in Technology

Transcript

  1. 1
    BHyVe code reading
    @syuu1228

    View Slide

  2. 2
    お手元にソースコードをご
    用意下さい
    https://github.com/lattera/b
    hyve

    View Slide

  3. 3
    1, BHyVe 概要

    View Slide

  4. 4
    BHyVe とは

    FreeBSD 版の Linux KVM のようなもの

    Intel VT を用いたハイパーバイザ
    ● 開発の初期段階でごく限定的な機能が実装されている
                ↓
    最低限のハイパーバイザ実装のよいサンプルになりそう

    View Slide

  5. 5
    Web Site
    http://www.bhyve.org/

    View Slide

  6. 6
    実装状況

    Intel VT-x, EPT 必須 (= Nehalem 以降必須 )

    BIOS 非対応 (disk ブート出来ない )

    対応デバイス :
    – PCI

    virtio-net, virtio-blk

    pci passthrough(VT-d)

    pci UART
    – paravirtual console/debug port

    対応 OS: FreeBSD 8, 9, 10

    View Slide

  7. 7
    割り込み

    MSI 割り込みのみ対応

    割り込みコントローラは Local APIC のみ実装

    View Slide

  8. 8
    2,動作の流れ

    View Slide

  9. 9
    おさらい: Linux KVM

    View Slide

  10. 10
    Intel VT 向け VMM の動作の流れ
    1.VMCS にゲスト環境の設定をロード
    2.CPU に VMCS をセット
    3.VMLAUNCH でゲストモードに切り替え
    4 .ゲスト環境実行
    5 .何らかの trap 要因が発生、 VMExit する
    6.VMExit 要因を調べ、要因に合わせたエミュレーション処
    理を行う
    7.3 に戻る
    エミュレータが欲しいなら、 QEMU を使えばいいじゃない

    View Slide

  11. 11
    QEMU
    KVM
    Linux kernel
    IOCTL
    Guest kernel
    User
    program
    VMLAUNCH
    VMExit
    Linux KVM 動作イメージ

    View Slide

  12. 12
    Intel VT 向け VMM の動作の流れ
    1.VMCS にゲスト環境の設定をロード
    2.CPU に VMCS をセット
    3.VMLAUNCH でゲストモードに切り替え
    4 .ゲスト環境実行
    5 .何らかの trap 要因が発生、 VMExit する
    6.VMExit 要因を調べ、要因に合わせたエミュレーション処
    理を行う
    7.3 に戻る
    白いところを KVM がやる。黄色いところを QEMU がやる。

    View Slide

  13. 13
    BHyVe は?

    View Slide

  14. 14
    /usr/sbin/bhyve
    vmm.ko
    BSD kernel
    IOCTL(VM_RUN)
    Guest kernel
    User
    program
    VMLAUNCH
    VMExit
    BHyVe 動作イメージ

    View Slide

  15. 15
    Intel VT 向け VMM の動作の流れ
    1.VMCS にゲスト環境の設定をロード
    2.CPU に VMCS をセット
    3.VMLAUNCH でゲストモードに切り替え
    4 .ゲスト環境実行
    5 .何らかの trap 要因が発生、 VMExit する
    6.VMExit 要因を調べ、要因に合わせたエミュレーション処
    理を行う
    7.3 に戻る
    白いところを vmm.ko がやる。黄色いところを /usr/sbin/bhyve が
    やる。

    View Slide

  16. 16
    /usr/sbin/bhyve の動作(1)

    src/usr.sbin/bhyve/fbsdrun.c:669
    fbsdrun_addcpu() で CPU0 のスレッドを作成
    – src/usr.sbin/bhyve/fbsdrun.c:209
    pthread_create(fbsdrun_start_thread)

    src/usr.sbin/bhyve/fbsdrun.c:195
    vm_loop()
    – src/usr.sbin/bhyve/fbsdrun.c:476
    while(1) {vm_run();}

    View Slide

  17. 17
    /usr/sbin/bhyve の動作(2)

    src/usr.sbin/bhyve/fbsdrun.c:476
    while(1) {
    vm_run();
    – src/lib/libvmmapi/vmmapi.c:265
    ioctl(VM_RUN) vmm.ko に VMX non root mode への切り替
    えを依頼

    src/usr.sbin/bhyve/fbsdrun.c:494
    handler[exitcode]() EXIT_REASON に対応するエミュレー
    ション処理を呼び出し

    View Slide

  18. 18
    3,ゲスト OS ローダ

    View Slide

  19. 19
    何故ゲスト OS ローダが必要か

    BHyVe には BIOS がない

    HDD のブートセクタから起動されるブートローダは BIOS に依存
    している為、例え /usr/sbin/bhyve が起動時にブートセクタをロー
    ドして実行しても動作しない

    BIOS のエミュレーションを実装する代わりにゲストの FreeBSD
    カーネルをゲストメモリ空間にロードして、いきなりカーネルを
    実行している
    → Xen の domU と同じ
    ● ロードを行うプログラムとゲストの実行を行うプログラムを分離
    している
    – ロード: /usr/sbin/bhyveload
    – 実行: /usr/sbin/bhyve

    View Slide

  20. 20
    bhyveload の動作 - vm_create

    src/usr.sbin/bhyveload/bhyveload.c:557
    vm_create(vmname) で /dev/vmm/%s に device file を作成
    – src/lib/libvmmapi/vmmapi.c:85
    sysctl 経由で device file 作成を vmm.ko に依頼

    View Slide

  21. 21
    bhyveload の動作 - vm_setup_memory

    src/usr.sbin/bhyveload/bhyveload.c:570
    vm_setup_memory() で membase へゲスト空間を mmap
    – src/lib/libvmmapi/vmmapi.c:139
    vmm.ko へ ioctl(VM_MAP_MEMORY) でゲスト空間をアロケート
    vmm.ko への mmap でゲスト空間を membase へマップ

    View Slide

  22. 22
    bhyveload の動作 - vm_open

    usr.sbin/bhyveload/bhyveload.c:564
    vm_open(vmname) で /dev/vmm/%s を open()
    – src/lib/libvmmapi/vmmapi.c:92
    vm_open()

    src/lib/libvmmapi/vmmapi.c:67
    vm_device_open()

    View Slide

  23. 23
    bhyveload の動作 – userboot.so

    usr.sbin/bhyveload/bhyveload.c:589
    – FreeBSD のブートローダをユーザ空間で動くように移植したも

    – メモリやレジスタへの読み書きを wrap 、ゲストのメモリ空間
    /レジスタへアクセス
    – (メモリ空間は mmap 、レジスタの読み書きは ioctl 経由で
    VMM が管理するゲストのデスクリプタへ)
    – これを利用して kload が実装されている
    – ( Linux における kexec と同じ)

    View Slide

  24. 24
    bhyveload の動作 – userboot.so

    usr.sbin/bhyveload/bhyveload.c:589
    dlopen で userboot.so を開く

    usr.sbin/bhyveload/bhyveload.c:594
    dlsym で loader_main 関数のアドレスを取得

    usr.sbin/bhyveload/bhyveload.c:603
    loader_main 関数を実行

    View Slide

  25. 25
    bhyveload の動作 – userboot.so

    loader_main 関数は boot2 とほぼ同じ動作を行うが、引数で渡
    しているコールバック関数で以下のような処理を仮想化してい

    – コンソールの読み書き cb_putc, cb_getc, cb_poll
    – ファイルの操作 cb_open, cb_close, cb_isdir, cb_read, cb_readdir,
    cb_seek, cb_stat
    – ディスクの読み書き cb_diskread
    – メモリの読み書き cb_copyin, cb_copyout, cb_getmem
    – レジスタの読み書き cb_setreg, cb_setmsr, cb_setcr, cb_setgdt, cb_exec

    View Slide

  26. 26
    bhyveload の動作 – cb_copyin, cb_copyout

    src/usr.sbin/bhyveload/bhyveload.c:297
    membase へ memcpy

    src/usr.sbin/bhyveload/bhyveload.c:313
    membase から memcpy

    View Slide

  27. 27
    bhyveload の動作 – cb_setreg, cb_exec

    src/usr.sbin/bhyveload/bhyveload.c:327
    vm_set_register でレジスタセット

    src/usr.sbin/bhyveload/bhyveload.c:434
    vm_setup_freebsd_registers でレジスタなどの初期化
    – src/lib/libvmmapi/vmmapi_freebsd.c:63
    vm_set_register, vm_set_desc で各種レジスタを初期化

    View Slide

  28. 28
    bhyveload の動作 –
    vm_setup_freebsd_registers

    src/lib/libvmmapi/vmmapi_freebsd.c:63
    – CR0 = PE | PG | NE # ページング、プロテクトモード
    – CR4 = PAE | VMXE # PAE 、 VMX 有効
    – EFER = LME | LMA # long mode 有効
    – GDT 初期化&セグメントレジスタ初期化
    – タスクレジスタ初期化
    – ページテーブル& CR3 初期化
    – RSP 初期化
    – エントリポイント設定

    View Slide

  29. 29
    4, IO デバイス
    エミュレーション

    View Slide

  30. 30
    ゲストカーネルのコンフィグレーション
    device pci
    device bvmconsole
    device bvmdebug
    device mptable
    ACPI や多くのデバイスは無効
    virtio.ko, if_vtnet.ko, virtio_pci.ko, virtio_blk.ko はモジュール
    としてビルド
    パラバーチャルなデバイスしか無い点は Xen の domU に
    近い

    View Slide

  31. 31
    /usr/sbin/bhyve
    vmm.ko
    BSD kernel
    IOCTL return
    Guest kernel
    VMExit
    IO エミュレーション
    IO 命令
    console
    PCI
    net blk
    io emulation 実行

    View Slide

  32. 32
    /usr/sbin/bhyve の動作 – IO emulation

    src/usr.sbin/bhyve/fbsdrun.c:494
    handler[exitcode]() EXIT_REASON に対応するエミュレー
    ション処理を呼び出し
    – src/usr.sbin/bhyve/fbsdrun.c:465
    IO の場合は VM_EXITCODE_INOUT なので vmexit_inout

    src/usr.sbin/bhyve/fbsdrun.c:281
    EAX の値を取得して emulate_inout()

    View Slide

  33. 33
    /usr/sbin/bhyve の動作 – IO emulation

    src/usr.sbin/bhyve/inout.c:72
    inout_handers[port].handler(in, port, bytes, eax)
    port = 0x220 なら console
    ( src/usr.sbin/bhyve/consport.c:127 で定義)
    – src/usr.sbin/bhyve/consport.c:101
    in = 1 ならキーボードから一文字を読んで eax に書く
    in = 0 なら eax から一文字読んで画面に書く

    View Slide

  34. 34
    3, vmm.ko の提供するイ
    ンタフェース

    View Slide

  35. 35
    sysctl

    src/sys/amd64/vmm/vmm_dev.c:387
    – hw.vmm.create(name)
    /dev/vmm/${name} に新しい VM インスタンスを指す
    デバイスファイルを作成
    – hw.vmm.destroy(name)
    /dev/vmm/${name} の VM インスタンスを削除

    View Slide

  36. 36
    /dev/vmm/${name} へのファイル API

    read/write
    – src/sys/amd64/vmm/vmm_dev.c:184
    ゲスト空間の読み書き( offset = ゲストの物理アドレス)

    mmap
    – src/sys/amd64/vmm/vmm_dev.c:347
    ゲスト空間のマップ
    (先頭ポインタがゲストの物理アドレス0番地)

    View Slide

  37. 37
    /dev/vmm/${name} への ioctl (1)

    src/sys/amd64/vmm/vmm_dev.c:144

    VM_RUN: VMLAUNCH させる

    VM_SET_PINNING/VM_GET_PINNING: CPU の固定割当

    VM_MAP_MEMORY: ゲストのメモリ空間割当

    VM_GET_MEMORY_SEG: 未調査

    VM_SET_REGISTER/VM_GET_REGISTER: ゲストレジス
    タの読み書き

    View Slide

  38. 38
    /dev/vmm/${name} への ioctl(2)

    VM_SET_SEGMENT_DESCRIPTOR/VM_GET_SEGMENT_D
    ESCRIPTOR: セグメントレジスタの読み書き

    VM_INJECT_EVENT: 未調査

    VM_LAPIC_IRQ: 未調査

    VM_SET_CAPABILITY/VM_GET_CAPABILITY: VT-x のどの
    機能を使うか(調査中)

    VM_BIND_PPTDEV/VM_UNBIND_PPTDEV: PCI passthrough

    VM_MAP_PPTDEV_MMIO: PCI passthrough

    View Slide

  39. 39
    /dev/vmm/${name} への ioctl (3)

    VM_PPTDEV_MSI: PCI passthorugh

    VM_INJECT_NMI: 未調査

    VM_STATS: 未調査

    VM_STAT_DESC: 未調査

    View Slide