榮樂 英樹
株式会社イーゲル
2021-12-01 BitVisor Summit 10
BitVisor 2021年の主な変更
点
1
2
BitVisor 2021年の主な変更点
 10コア20スレッド対応
 ヒープ割り当て改善
 CPU新機能対応
 雑多な改良
 その他バグ修正等
2
3
10コア20スレッド対応
コア数が増えた近年のプロセッサではVMMのヒープ不
足の問題が発生
ヒープはRAMから予約した128MiBのうちVMM本体の
テキストやデータ等を引いた残りで、これを例えば256
MiBに増やすことで対応は可能

増やす場合はcore/mm.cのVMMSIZE_ALLマクロを変
更
128MiBを維持したままでも、ヒープ割り当て改良で対
応が可能
4
ヒープ割り当て改良ポイント
EPT/RVIのテーブル用に1論理CPUあたり4MiBを確保
していた
ヒープ割り当て効率

1論理CPUごとに確保するstruct vcpuが525832バイト、2のべき乗単位
のサイズで確保するため実際には1048576バイトを割り当て、およそ4
9.9%が無駄に

1025〜4095バイトの確保に1ページ4096バイトを割り当て、特に1025
〜2048バイトの確保では1ページの半分以上が無駄に

1024バイト以下の確保も無駄な部分あり

管理用データ構造にも改良の余地あり
5
EPT/RVIの4MiBを減らす
EPT/RVIのテーブル用に4MiBを確保していた理由

以前は2MiBページに非対応だったため、4MiB (1024ページ) のテーブル
があっても、2GiB分のアドレス空間 (524288ページ) へのアクセスです
べて使い切っていた

現在は大部分に2MiBページを使用するので使い切ることがほぼない
実装: 最初16ページ、必要に応じて最大256ページまで
動的に増やす形に変更した
6
効率改善: ページ単位割り当て
2のべき乗単位の他に、2種類のサイズの組み合わせを
扱えるようにした
Alignmentは今までどおり2のべき乗単位で大きなほう
のサイズとすることで互換性を保つ
実装: ページ管理データのタイプを増やして対応
確保バイト数 Alignment 実際の割り当
てバイト数
無駄になる割合
改良前 525832 1048576 1048576 約49.9%
改良後 525832 1048576 524288+
4096
1%未満
7
効率改善: 4096バイト未満割り当
て (改良前)
従来は1ページをベースとして確保し各サイズに分割、
その中に管理データも含めていたため、未使用部分が
大きく、空き領域探索時間削減のためベース解放はし
ていなかった
確保バイト
数
ベースサイズ/
分割数
管理データ
バイト数
(64bit時)
ベースあたり
実際の
割り当て数
ベースあたり
割り当て
バイト数
16 4096/256 55 252 4032
32 4096/128 39 126 4032
64 4096/64 31 63 4032
128 4096/32 27 31 3968
256 4096/16 25 15 3840
512 4096/8 24 7 3584
1024 4096/4 24 3 3072
8
効率改善: 4096バイト未満割り当
て (改良後)
ページ単位の管理構造に追加情報をもたせ、128〜204
8バイトのsmallと、それより小さなtinyで異なる管理方
法にする
確保バイト
数
ベースサイズ/
分割数
タイプ/ベース
内管理データ
バイト数
実際の
割り当て数
ベースあたり
割り当て
バイト数
16 512/32 tiny/32 30 480
32 1024/32 tiny/32 31 992
64 2048/32 tiny/32 31 1984
128 4096/32 small/0 32 4096
256 4096/16 small/0 16 4096
512 4096/8 small/0 8 4096
1024 4096/4 small/0 4 4096
2048 4096/2 small/0 2 4096
9
効率改善: Small割り当て
Smallの128,256,512,1024,2048バイトの割り当ては、
ベースとなる1ページから32,16,8,4,2個の割り当てであ
り、最大32ビットのビットマップで管理できる
ページ単位の管理構造に32ビットのビットマップと割
り当てサイズを追加する
32ビットは演算命令で探索ができ、全体の解放の
チェックも時間がかからないためベース解放も行う
リスト構造にはページ単位の空き領域管理用のリスト
構造を流用する
10
効率改善: Tiny割り当て
Tinyの16,32,64バイトは従来と似た方法だが、ページか
らではなく、512,1024,2048バイトをベースとして、32
分割して使用する
リストとビットマップの管理領域に32バイトを使う
512,1024,2048バイト単位のアドレスの先頭が管理領域
で、残りがtiny割り当てとなる
32ビットは演算命令で探索ができ、全体の解放の
チェックも時間がかからないためベース解放も行う
ページ全体分の数を確保した場合のヒープ使用効率と
しては少し下がる
11
効率改善: 管理用データ構造のス
リム化
ページ単位の割り当てサイズを保持していたallocsize[]
配列を廃止

単なるシフト演算なので、RAM参照より計算したほうが速い
ページ管理構造体から仮想アドレスを削除

物理アドレスから簡単に計算できる
ページ管理構造体に入れているサイズやタイプ等を8
ビットにすることで、構造体サイズを小さく保ちつつ
機械語は複雑にならないように

32バイト単位にすることで配列のオフセットアドレスの計算もシンプル
になる
12
ヒープ割り当て改良結果 (VMM
ヒープ空き領域サイズ比較)
2コア4スレッド環境において

従来版: 68208 KiB

+ struct pageを40バイトから32バイトに縮小: 68464 KiB

+ ページ単位割り当て効率改善: 70964 KiB

+ 4096バイト未満割り当て効率改善: 71012 KiB
8コア16スレッド環境において

従来版: 22412 KiB

改良版: 100640 KiB
13
ヒープ割り当て改良結果 (実行時
間比較)
改良前後でallocとfreeの実行時間比較、単位はサイクル数
1 15 bytes 2097152 times: alloc 73049→42328 free 36867→46975
2 31 bytes 1082401 times: alloc 31679→22543 free 19288→24363
3 2000 bytes 16777 times: alloc 1105→701 free 528→648
4 4000 bytes 8388 times: alloc 572→326 free 273→294
5 8192 bytes 4096 times: alloc 289→206 free 131→151
6 12288 bytes 2730 times: alloc 206→197 free 89→188
7 16384 bytes 2048 times: alloc 159→113 free 66→74
考察

1, 2: allocは探索が速くなって減少、freeはベースの解放が増えたために増加

3, 4, 5, 6, 7: allocは内部実装見直しに伴いロック回数が減ったため減少

3: ページより小さい単位の割り当てになったためにfreeが増加

4, 5, 7: freeは以前とほぼ同じ

6: サイズ組み合わせでfreeが増加
14
CPU新機能対応
 Hardware Feedback Interface

物理アドレスをMSRに設定し、CPUがそこに性能やエネルギー効率に関
する情報を書き込む仕組み

VMM領域の破壊を避けるためアドレスチェックを行い、隠蔽もできるよ
うにした

config.vmm.conceal_hw_feedback
 Processor Trace

物理アドレスをMSR等に設定し、CPUがトレース情報を書き込む仕組み

VMM領域の破壊を避けるため、config.vmm.allow_ptの設定値に応じて処
理するようにした。設定値 0: 隠蔽 / 1: 仮想マシンの物理アドレスを使用
する機能にCPUが対応していればそれを使い、対応していなければ隠蔽
/ 2: パススルー (unsafe)
15
雑多な改良
nvme_io改良

VMMからNVMeのコマンド発行の際のエラーコード・タイムアウト導入
UEFI Graphics Output Protocol VGA driver追加

デバッグ用画面出力。ゲストオペレーティングシステムではefifbのよう
なデバイスドライバーを選択しておく必要あり。
プロセス (保護ドメイン) の読み取り専用セクション共
有

従来は読み取り専用の区別なくすべてヒープから割り当てていたが、読
み取り専用セクションを共有するよう変更。SQLiteのようにコードが数
百KBのプロセスを実行しても、読み取り専用部分は読み取り専用で共
有され複製されない。
16
その他バグ修正等
苦労したバグの修正
問題があったバグの修正
小さな修正・改良等
17
苦労したバグの修正
OSXSAVEとPKEの修正: CPUIDで制御レジスターのビットが読めるよう
修正

VMware Fusion 12 on macOSで、XSAVEがサポートされていない旨のエラーが出ていた
bnx受信が遅れる問題があり、レジスターのダミー読み取りを追加

NFSが遅い→パケットキャプチャーを見るとところどころ負荷が下がっている→SSHなど他の
通信をきっかけに「詰まりがとれた」ように流れ出すので、割り込みか?→受信の際は割り込
みクリア後にキューを読めば、問題ないはず... しかし、割り込みクリア後にダミー読み取りが
必要だった
NVMeコマンドを壊すことがあったバグを修正

Windowsアプリケーションがクラッシュして使えないことがある、という、再現しにくい形で
発覚した
NVMeデバイス側問題の回避策実装

コントローラーリセットの際に、本来クリアされるべきデバイス側の割り込みマスクがクリア
されないデバイスがあり、VMMから強制リセット後、割り込みが一切発生しないまま起動しよ
うとしてオペレーティングシステムがタイムアウトしてしまう問題があった
18
問題があったバグの修正
NVMeレジスターのキャッシュ禁止マップ: iMac Pro (2017) でNVMeのレジ
スターに割り当てられるアドレスがMTRRでキャッシュ禁止の範囲に入って
いなかった模様
MSI-X対応NVMeでNULL pointer dereferenceが発生していた問題の修正:
QEMU対応
NVMe: 以前入れた割り込みマスク中の割り込みに対するmacOS 10.12での
問題回避策が、今度はWindowsで問題になってしまったのでオプションにし
た
panic backtrace無限ループ対策: 64ビット版で”global”初期化処理中にpanic
が発生した場合に無限ループになっていた
timeバグ: Windows起動中にVMMでNVMeのタイムアウトが発生したが、実
際には時刻処理のバグにより時刻が飛んでしまったのが原因だった
ミニOSでの起動ができなくなっていたバグの修正: BIOS環境の動作確認を
しばらくしていなかったため...
19
小さな修正・改良等 1/2
 NVMeリセット時ロック: レジスターハン
ドラーやcompletion queueを見る時やnv
me_ioで共有ロック、リセット処理で排他
ロック
 NVMe Per-Vector Masking Capableの隠
蔽の実装が間違っていて機能していな
かった
 ACPI DRHD Device Scopeの読み取りが
不正だったバグ修正
 ACPI RMRRをPCI root complexが複数あ
る環境 (iMac Pro等) でも正しく作成
 VT-dのcapabilitiesをきちんと隠蔽
 msgregister/msgopen/newprocessで使わ
れる文字列が内部バッファーに固定長で
転送されていた問題を修正 (文字列の後
ろの何かまでコピーされていた)
 プロセス機能のディスクリプターの範
囲チェックが一部抜けていたのを修正
、さらにそれ以外も配列参照部分にas
sertionを追加
as_passvm translateのVMM領域隠蔽
部分のバグ修正
 EPTの2MiB page対応チェック追加
(たぶん未対応のEPT対応CPUはない)
 PCI初期化ルーチンの怪しいところの
修正
 virtio-net: デッドロックの可能性が
あった部分の対処
 telnet-dbgsh: 出力が多くて内部バッ
ファーがいっぱいになると待たずに捨
ててしまう問題を修正
20
小さな修正・改良等 2/2
cacheルーチンをわかりやすくした
DMARまわりのコードを見やすくした
ACPI DRHD 確保メモリーサイズの削減
boot/uefi-loader: "make clean" で消されないファイルが
あったのを修正
boot/login-simple: ビルド時の警告が出ないようにした
21
BitVisor 2021年の主な変更点
まとめ
 10コア20スレッド対応
 ヒープ割り当て改善
 CPU新機能対応
 雑多な改良
 その他バグ修正等
21
最新リポジトリ
http://bitvisor.sf.net

BitVisor Summit 10「1. BitVisor 2021年の主な変更点」