ARM向け自作ハイパーバイザーT-Visorを公開しました

修士の研究としてつくったARM用ハイパーバイザ「T-Visor」を公開しました。
https://github.com/garasubo/T-Visor

(2016/05/24 ちょっと加筆しました)

背景

組み込みの世界でもLinuxのような汎用システム向けOSが使われるようになる一方、
リアルタイム性の保障やセキュリティ等の観点からリアルタイムOSの需要も高い。
そこで、ハイパーバイザを使って汎用OSとリアルタイムOSを同時に動かす、というような研究や製品が結構あります。
具体例を上げれば、ロボットの姿勢制御などをリアルタイムOSできっちりとやる一方、
画像処理やネットワーク機能とかを使ってクールな機能だけど最悪バグっても安全には支障がないといったものをLinux側で、といった感じです。
実際にARMの一部シリーズではIntel VT-xのような仮想化支援のハードウェア機構が備わっていて、
KVMやXenはこれらに対応してARM上でも動くようになっています。

しかし、XenやKVMはLinuxをベースにしていてシステム全体が重い、リアルタイムでないなどの問題点があります。
Linuxなどのスケジューラは短い一定周期ごとに確実にこれこれをしなければいけない、といったような要請(ハードリアルタイム)を満たしにくいことが知られています。
リアルタイム性や組み込み用途というものを重視しようということで開発したのがT-Visorです。
このT-Visorは動作にLinuxやその他標準ライブラリを要さず、Cortex-A7/A15での動作が可能です。
方式としてはハードウェア上で直接動くType-1型で、仮想マシン上で動くOSをに対して変更がいらない完全仮想化をおこなっています。

ざっくりとした技術的な説明

このT-VisorはARMv7-Aの拡張のひとつであるVirtualization Extensionsを利用することで、
完全仮想化Type-1型のハイパーバイザを実現しています。
この拡張でHypモードというプロセッサモードが追加され、プロセッサ全体に影響を与えるような命令に対してトラップをかけてこのHypモードにさせる、ということが可能です。

メモリアクセスですが、通常のMMUに加えてStage-2のMMUというものがあり、これは仮想マシン上での物理アドレスを中間物理アドレスとして受け取り、
実物理アドレスに変換させたうえでメモリアクセスをさせると言うものです。
これにより、仮想マシンは自由にMMUを使うことができる一方、ハイパーバイザ側でアクセスできるメモリ領域を制限することができます。

仮想デバイスドライバは基本的には実装していません。ARMのIOはすべてMMIOなので、アクセスできるメモリ領域を制限することで、
仮想マシンから触れるデバイスは制限されています。
また、外部からの割り込みも一度ハイパーバイザにトラップされるので、割り込みについてもどの仮想マシンが受け取るかを制御できます。

割り込みに関してはGICという割り込みコントローラで管理されています。
ゲストOSもこのGICを使って割り込みをコントロールするので、競合が起きないよう対応が必要です。
このGICはある程度の部分が仮想化対応されているのですが、ある程度の部分に関してはなされていないので、
先述のStage-2 MMUを使うことで、アクセスをコントロールすることで仮想割り込みコントローラを実装して対応します。

リアルタイム性を保障するためスケジューリング方式が重要になってきますが、ユーザーが設定しやすいようにということを意識してフレームワークが設計されています。
具体的には実装すべき関数をいくつか定め、その中ではあくまでスケジューリングに関することのみを行い、
仮想マシン内部などには干渉する必要がないようにされています。
サンプルとして固定優先度式とEDF方式のスケジューラが実装されていますが、設定により静的にひとつのスケジューラのみが組み込まれるようになっています。

仮想マシンの数やそのメモリ割当等の設定はコンパイル時に決定されます。
現状はソースコードにベタ書きしていく感じになっているので、まともなconfigureについてはfuture workのひとつです。

起動に関してですが、ブートローダはU-Bootを使って動作させていました。
ただし、U-Boot固有の機能に何か依存していたわけではなく、メモリ上に外部からハイパーバイザとゲストOSが展開できるようなものならなんでもよいです。

動作確認として無修正のLinuxを動かし、各種ベンチマークの動作を確認しました。
また、複数のリアルタイムOSを動かして、OS間通信ができることも確認しています。
Xen4.4とも比較実験をおこなっていて、詳細は省きますが、基本的にポジティブな結果が出ました。
ただし、Xen4.5で割り込みに関して性能改善がなされたらしく、そちらとはまだ比べられていません。

主要なソースコードの中身

ソースコード読みたい人向けに簡単に説明しておきます。

  • vcpu.c
    • 仮想CPUの状態管理を行う
  • hyp_call.c
    • 仮想マシンからのhyp例外を管理する
  • virtual_gic.c
    • 割り込みコントローラについての仮想化を担っている
  • schedulers/
    • 各種スケジューラの実装
  • users/
    • この以下のディレクトリのうちひとつを選択することで、ハイパーバイザ上でどのようなアプリケーションを使うかを決定する
  • boards/
    • ハードウェア依存部分を置くところ。

課題と今後やりたいこと

まず第一に、複数OSは動かせることは確認しているものの、ひとつのVMに対して仮想CPUを複数提供することには失敗しています。
また、このハイパーバイザはコアをひとつしか使うことができません。
前者に対してはPSCIというコアを管理するためのインターフェースがARM側では定義されているので、
それに乗っ取り、仮想CPUを操作するインターフェースを実装済みではあるのですが、いざLinuxを動かしてみると起動途中で止まってしまいます。
どうも2つのコアとも処理できるスレッドがなくなってスリープしているようなのですが、はっきりとした原因がわかっていません。
原因として考えられるのは

  • 割り込みコントローラの仮想化部分がバグっていてハードウェアからの信号待ちのようになってしまって動かなくなっている
  • コア間の状態保存・復帰がバグっている
  • キャッシュ・TLBなどが適切にcleanできていない
    などなのですが、未だにはっきりとつかめていません。

また、仮想マシンの管理のconfigがよくない感じなのは前述のとおりなのですが、それ以外にもコードの構造がひどいことは重々承知していて、
そこをまず叩き直さなければならないという話もあります。
そもそも一人で書いているはずなのに気分でコード規約が変わって名前の付け方が色々おかしいとか、もしかしたらインデントも統一されていない部分もあるかも…
あとは今のところ全部C言語とアセンブラで書かれているのですが、C++で書くともっとすっきりするかもしれませんね。

OSや組み込み開発に対してほとんど知識がない状態ではじめたため、かなり拙い部分もありますが、まあなんとか動作することができたのはよかったかなっと

補足

現在、動作確認はCubieboard 2で行っています。
Raspberry Pi2だと割り込みコントローラの関係上、動かすのに大変な労力が必要となります。

あと、課題とかいろいろ書きましたが、現在は基本的に開発止まっています。
私の能力では解決が難しいというのがひとつ、つくったとしてもそれを使ったアプリケーションをつくる機会がないといったモチベーションの問題がひとつです。
ただ、興味ある人がいれば連絡くれると幸いです。ある程度協力できると思います。

ちなみにこのタイミングで公開したのは、ソースコードを多少はマシにしたかったというのもそうなのですが、
これについて書いた論文がリジェクトされたからです。
評価が甘かったりアプリケーションが見えにくかったというのが主な原因なのだろうか、アカデミアの道は厳しいですね。
この手の分野はクローズドソースなものが多すぎたり、ハードウェア依存な部分が多かったりで、実装までこぎつけても評価が…ってなるのは悲しい