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

自作ハイパーバイザーを作ってNuttXを動かした話

 自作ハイパーバイザーを作ってNuttXを動かした話

Hidenori Matsubayashi

May 24, 2023
Tweet

Other Decks in Science

Transcript

  1. ⾃作ハイパーバイザーを
    作ってNuttXを動かした話
    @HMatsubayashi
    @HidenoriMatsubayashi

    View Slide

  2. はじめに
    本資料は、
    • Arm64 にフォーカスした(他のアーキテクチャには触れない)内容
    • 細かい話より、Hypervisorの仕組みが⼤まかに理解出来ることが⽬的
    • 仕事とは関係がない個⼈的なアクティビティ
    です

    View Slide

  3. なぜHypervisorなのか?なぜ⾃作なのか?
    • 仮想化技術の基礎を学べる
    • Hypervisor ≒ ⼩さなOS + 仮想化
    • OSに必要な基本的な機能が⼀通り必要
    • タスク (vCPU) スケジューラ、MMU/メモリ管理、マルチコアなど
    • ソースコード規模が⼩さい
    • 実⽤的なHypervisorでも数〜10万⾏程度のソースコード規模
    • ⾃作した eVisor は約6500⾏
    • ゲストOSは既存のもの(Linux, NuttXなど)がそのまま動く
    • ⾃作OSだとユーザランドをそれなりに作る必要があり(動作確認などのため)、時間がかかる
    • ⾃作する⽬的
    • 作り⽅と仕組みを学ぶため
    • 徐々に動くようになっていく過程が楽しいから

    View Slide

  4. ⽬次
    • Hypervisorとは?
    • Arm64 Hypervisor の概要と仕組み
    • eVisor (⾃作Hypervisor) を作ってみた
    • 今後

    View Slide

  5. Hypervisorとは?
    • 1台の物理マシン上で複数の仮想マシン (VM) を動かす環境を提供
    • そのVM上でゲストOSは動作
    • ゲストOSは隔離された環境で動作
    • 他のゲストOSには影響を与えない
    • H/Wリソースは必要に応じてゲストOSに割り当て管理
    • 必要に応じて仮想化
    • H/Wの仮想化⽀援機構を出来るだけ利⽤
    • 結局はエミュレータみたいなものだが、Hypervisorは実際のCPU (H/W)
    を利⽤してVMを動かす
    H/W
    Hypervisor
    VM VM VM
    OS OS OS

    View Slide

  6. Type1 と Typ2 の2種類のHypervisor
    • Type1 (Baremetal)
    • H/W上で直接動作し、VMを作成するタイプ
    • 例:
    • Linux KVM (ハードウェアの仮想化はできず、vCPUのみのはず)
    • JAILHOUSE
    • Type2 (Host)
    • H/W上で動作するゲストOSの上で動作し、VMを作成して動かすタイプ
    • 実装/Hypervisorにもよるが、エミュレータに近いイメージ
    • 例:
    • VMware Player
    • QEMU (ただし、KVMを利⽤可能なので厳密にはType2ではない)

    View Slide

  7. ここから先はType1 Hypervisor前提の内容
    (Type2のことは⼀切触れない)

    View Slide

  8. Hypervisor (仮想化) の実現⽅法
    • 基本的な仕組み
    • 前提としてCPUの仮想化⽀援が必須
    • vCPU (VM) の特定の命令やメモリアクセスなどをHypervisorがトラップ
    • Hypervisorに割り込みが⼊る
    • 何の操作が⾏われたか確認して適切な処理を⾏い、再度VMを動かす
    • 必要に応じてH/Wを仮想化する
    • 同⼀のH/Wが複数VMで利⽤される場合
    • なお、メモリマップの設定次第では直接H/Wアクセスの許可も可能
    • 仮想化⽀援機構
    • CPUコア
    • Hypervisor専⽤の動作モードを持っている
    • 特定の動作/メモリアクセス/割り込みをトラップする仕組みを提供
    • H/W
    • これはSoCによるが、あるものとないものがある

    View Slide

  9. Arm64の仮想化⽀援機構 ‒ CPUコア
    • ARMv7-Aから仮想化をサポート
    • EL (Exception Level) という CPUの動作モード(特権モード)がある
    • ELの数値が⼤きいほど、出来ること(特定レジスタへのアクセスなど)が増える
    • ⾃分よりもレベルが低いELの動作をトラップ出来る
    • 例えば、メモリアクセスフォルト、特定のCPUレジスタへのアクセスなどのセンシティブ
    命令など
    • EL0: ユーザアプリ
    • EL1: OS
    • EL2: Hypervisor
    • EL1/0の動作をEL2でトラップし、必要な処理を⾏った後、またEL1に処理を戻す
    • EL3: Firmware (セキュアモニタ)

    View Slide

  10. Arm64の仮想化⽀援機構 ‒ CPUコア
    • CPUタイマー (Arm Generic Timer)
    • 複数VMが動く場合、⾃分以外のVMが動いている間に経過したリアル時間
    (オフセット)を隠蔽する必要あり
    ⇨ 物理的なタイマーに対してオフセットを付与できる仮想タイマー機能あり
    • 詳細: https://zenn.dev/hidenori3/articles/413d8ef0a67463

    View Slide

  11. Arm64の仮想化⽀援機構 ‒ システムコール
    • HVC 命令
    • EL1からEL2に処理を戻す時に利⽤
    • Hypervisor⽤のシステムコールとして利⽤
    • APIを実装していけば KVM みたいなことが可能

    View Slide

  12. Arm64の仮想化⽀援機構 ‒ メモリの仮想化
    • MMU Stage2
    • Hypervisorが利⽤する通常のMMU (Stage1) の仮想アドレスに対し
    て、さらにゲストOS毎に⾃由にメモリをマッピング可能
    • 中間アドレス, IPAなどと呼ぶ
    • ゲストOS毎にメモリ空間を隔離する必要あるため
    • デバイスI/Oの割り当て
    • 必要に応じて仮想デバイスの空間に割り当て
    • もし仮想化の必要がなければ、実アドレスに割り当ても可能
    • メモリの割り当て
    • eVisorはオンデマンドページングで対応
    • 事前に利⽤する領域が確定している、OSの起動⾼速化などが不要
    であれば、事前に割り当ても可能
    • 詳細
    • https://zenn.dev/hidenori3/articles/91494881d318a5

    View Slide

  13. Arm64の仮想化⽀援機構 ‒ 割り込みコントローラ
    • ARM Generic Interrupt Controller (GIC) は v2.0か
    ら仮想化をサポート
    • 本資料ではGICの仕組みを説明
    • なお、GIC以外の割り込みコントローラの仮想化はH/W
    次第
    • 基本的な仕組みは以下
    1. 物理的なIRQをHypervisor (EL2) が⼀旦受ける
    2. IRQ要因を⾒て、それがゲストOS (EL1) 向けのもの
    であれば、EL2からEL1に vIRQ を発⾏
    • IRQ番号はHypervisorが⾃由に設定可能
    3. EL1は通常のIRQとして認識して動く
    • 詳細
    • https://zenn.dev/hidenori3/articles/b5bad28b262db4

    View Slide

  14. GICの割り込み仮想化はソフトウェア対応が必要
    • Hypervisor側で⼀部エミュレーションが必要で少し⾯倒
    GICD (Distributor)
    GICC (CPU interface)
    GICH (Hypervisor)
    GICV (vCPU interface)
    GICD エミュレーション
    GICD (Distributor)
    GICC (CPU interface)
    実際のH/W
    Hypervisor
    vCPU
    MMU Stage2でGICC領域
    をGICVにマッピング
    GICDはvCPU毎にエミュ
    レーションが必要
    GICD: IRQ有効設定などのレジスタ
    GICC: IRQ要因などのレジスタ

    View Slide

  15. ARM64の仮想化⽀援機構 ‒ その他H/W
    • H/Wを複数のゲストOSで利⽤する場合、Hypervisor側で
    • H/Wをフルエミュレート
    • 必要なH/Wレジスタのスナップショット(バックアップ)、VM切り
    替え時にスナップショットも⼀緒にコンテキストスイッチ
    などの対応が必要(H/W側で仮想化⽀援機構がない限り)

    View Slide

  16. ここまで分かれば、
    ⾃作Hypervisorを作ることが出来る!

    View Slide

  17. eVisor (⾃作Hypervisor) 概要
    • 特徴
    • マルチvCPUサポート
    • Hypervisor Shell
    • シリアルコンソール仮想化
    • Hypervisor デバッグ&シェル⽤
    • ゲストOSのシリアル⽤
    • GIC v2サポート
    • ファイルシステム
    • FAT32
    • ドライバ
    • GPIO
    • MailBox
    • MMC (SDカード)
    • UART (PL011)
    • H/Wサポート
    • QEMU
    • Raspberry Pi 4 (BMC2711)
    • なお、未実装機能多数あり
    • マルチコアサポートなど
    • ソースコード
    • https://github.com/HidenoriMatsubayashi/evisor
    H/W
    Driver (GPIO, MMC, UART, Timer, etc)
    FileSystem
    Memory
    Management
    Scheduler
    Virtual
    Machine
    vCPU vCPU vCPU
    EL2
    EL1

    View Slide

  18. NuttX on eVisor on Rasberry Pi4
    • NuttX は RPI4 未サポート
    • 仕⽅がないので、NuttXは
    サポート済みのQEMU向
    けにビルド
    • MMU Stage2で辻褄が合
    うようにメモリとデバイ
    スI/Oを割り当て
    • UARTはNuttXとeVisorの
    両⽅が同時に使えるよう
    にeVisorでエミュレー
    ション

    View Slide

  19. 振り返り
    1. Raspberry Pi4で動くように作り始める
    2. MMUを有効にすると正常に動かずハマる@Raspberry Pi4
    3. 途⽅に暮れ、デバッグのためにQEMUサポートを追加する
    4. QEMUサポート追加し、作業効率が激上げする
    5. NuttXをゲストOSに利⽤するためビルドを開始
    • 当時はQEMU for ARM64のみサポート
    6. NuttXのソースコードを⾒ていると改善ポイントがいくつかあったので、数件のPR (Pull
    request) を作って送るなどする
    7. QEMUでは動くが、Raspberry Pi4 だと動かないバグにハマる
    • このパターンの多くは、キャッシュ周りのバグ(フラッシュ忘れなど)
    8. NuttXがブート成功
    9. eVisorからNuttX側への仮想割り込みが正常に通知されないバグにハマる
    10. NuttXのシェル操作やそこからプログラム実⾏などが出来るようになる
    11. ゼルダの伝説ティアーズオブザキングダム (Switch) 以外何も⼿が付かなくなる(現在)

    View Slide

  20. 今後
    • ゲストOSでLinuxを動かす
    • 未実装機能の実装
    • マルチVM (ゲストOS) のサポート
    • ⼤体は実装済みだが、⼀部のコンテキストスイッチが未実装
    • マルチCPUコアのサポート
    • KVMみたいなAPIの追加
    など
    • ゼロから作る⾃作Hypervisor的な記事(本)を書く

    View Slide

  21. EOF

    View Slide