LWNのKVM/ARMの記事の簡単なまとめ

LWNにSupporting KVM on the ARM architectureという記事が公開されていたので、ざっくりとまとめてみました。著者の一人はChristoffer DallというKVM/ARMの開発者の方です。

※書き終わってから、記事はまだ無料公開されているわけではないことを思い出したので、前半だけ公開することにします。もし続きが気になる方はLWNを購読してください(宣伝)。 どうやら無料公開されたようなのでこちらも全文公開します。もちろん正しい情報を得たい方はLWNの記事をご参照ください。

注意:私はあまりARMアーキテクチャは詳しくないので、解釈が間違っているかもしれません。

HYPモード

  • Intel VT-xの場合はringと直交するroot/non-root operationが導入され、ホストはroot、ゲストはnon-rootで動作する
  • ARMでは、既存のUSR/SVCモード等*1に追加する形で、ハイパーバイザ用のHYPモードが導入された
    • HYPモードはカーネルが動作するSVCモードより権限が高い
  • USR/SVCモードにはページテーブルベースレジスタ(x86のCR3相当)が2つあってユーザ/カーネルを分離できるがHYPモードには一つしかない
    • TTBR0とTTBR1
    • (とはいえ、元々Linuxは2つのうちの1つしか使ってなかったような?)
  • SVCモード(カーネル)のコードを再利用するKVMとはあまり相性が良くない
    • カーネルSVCモードとHYPモードの両方で動かす必要があるため
    • ハイパーバイザをHYPモードだけで動かせるXenの方が相性が良い?

アドレス変換

  • EPTのように、ゲスト物理→ホスト物理変換(ステージ2変換)のテーブルを追加

KVM/ARMの設計

動作概要

  • qemuを使うの点は他のアーキテクチャと同じ
  • qemuがioctl(KVM_VCPU_RUN)すると最終的にHVC命令を発行してHYPモード移行する
  • そこでKVM/ARMはゲストのコンテキストを準備してUSR/SVCモードにジャンプする
  • 割り込みやステージ2変換のフォールトやセンシティブ命令が発行されたりするとHYPモードに戻る(トラップする)
  • KVM/ARMはコンテキストをホストのものに戻してSVCモードに移行する
  • HYPモードへトラップした理由を調べてエミュレーション等を行なう点も他のアーキテクチャと同じ
  • 割り込み(要調査) 調査しました→ [id:kvm:20130711:1373554471]
    • VM実行中に割り込みが起きるとHYPモードにトラップする
    • (この時点で割り込みは止められている)
    • 状態をホストのものに戻し(SVCモードに移行するってこと?)、再度割り込みを許可する
    • 再度、割り込みが起きるが今度はHYPモードにトラップせず(そうならないように設定している?)、ホストの割り込みハンドラ(おそらくIRQモード)が実行される
    • この2回目の割り込みのオーバヘッドは(ゲスト→ホスト切り替えのコストに比べると)無視出来るほど小さい(らしい)

ブート

  • ブートローダは常に(CPUが対応していれば)HYPモードでカーネルを起動する
  • HYP対応カーネルの場合、KVM/ARM等のために小さなスタブハンドラを仕込む
  • HYP対応でない場合でも、明示的にSVCモードに移行しているので問題ない
    • そういえば確かにそんなコードがあったような
  • カーネルが圧縮されている場合
    • 解凍前にスタブを仕込む
    • SVCモードに移行してキャッシュ(MMU)を有効にする
      • キャッシュが効いてないと遅い
      • HYPモードでMMUを有効にしようとするとLPAE対応しないといけないのでしんどい
    • 解凍する
    • スタブを使ってHYPモードに戻ってカーネルを起動
  • スタブの役割
    • KVM/ARM等サブシステムにHYPモード用の割り込みベクタのアドレスを変更できるようにする
      • HYP Vector Base Address Register (HVBAR)
    • HYPモード用のページテーブルもストレートマッピングしておくことで、サブシステムが指定した関数を簡単にHYPモードで実行可能になる
      • これはブート後も同じはず
    • HVBARはブート後にはHYPモード用の適切な割り込みベクタを指すように設定される
  • HYPモード用の割り込みベクタ
    • ゲストからHYPモードへ戻ってきた時も、ホストでHVCを呼んでHYPモードへトラップした時も同じハンドラを実行する
    • ステージ2ページテーブルレジスタのVMIDフィールドを見て、ゲスト(VMID>0)かホスト(VMID==0)を判断する

仮想GICとタイマ

  • 古いARMではタイマへのアクセスはMMIOで単に(qemuで)エミュレーションするだけだと、とても遅い
    • ホストカーネルでエミュレーションしてもまだ遅い
  • ARMv7(の仮想化拡張では?)仮想/物理カウンタと仮想/物理タイマが導入された
    • 仮想カウンタ/タイマはどのモードでもアクセス可能
    • 物理カウンタ/タイマはHYPモードでのみアクセス可能
  • なので、仮想カウンタ/タイマを使う限りにおいてはHYPモードへトラップしない
  • 疑問: 仮想カウンタ/タイマを使うようにゲストカーネルを書き換えないといけない?それとも仮想という名前がついているけど、実際はゲストは気にしなくても良いもの?
  • GICにはdistributorという機能があり、割り込みのマスクや割り込みの優先度設定や割り込みのアフィニティ等を制御する機能をもつ
  • 通常のGICでは、割り込み後のGICへのackやEOI毎にHYPモードへトラップするためオーバヘッドが生じる
  • VGICはトラップすることなく仮想割り込みへのackやEOIを可能とする
  • またKVM/ARM(HYPモード?)でしかアクセスできない仮想制御インタフェースが追加され、仮想割り込みを発生させるときに使われる
  • distributorへアクセスする頻度はそれほど高くないため、仮想distributorは提供されていない
  • KVM/ARMはホストカーネル内でGICエミュレーションを行なう
  • ハードウェア割り込みが発生した場合は常にHYPモードへトラップし、ホストの割り込みハンドラが割り込みを処理する
  • VGICも仮想タイマも、物理割り込みを仮想割り込みとしてVMへ割り込みをかけることはできない
  • そのため、VMのタイマ割り込みはホストがハンドルしてKVM/ARMが仮想割り込みとしてゲストに割り込みをかける

*1:割り込み用にIRQやABTといったモードも存在する