BitVisor
BitVisorDay 16

BitVisorのMSR Bitmapについて

これはBitVisor Advent Calendar 2018の16日目の記事です.

@morimolymolyです.

研究でBitVisorを扱っています.よろしくおねがいします.

Twitterブログもやっています.

今日はBitVisorのMSR周り,特にMSR Bitmapのお話をします.


MSR Bitmapとは

通常,MSRへのアクセスがあった場合,毎回VM Exitが起こりゲストからハイパーバイザへと制御が移ります.しかしVMExitなどのコンテキストスイッチはオーバーヘッドになるため,不要なVMExitは減らすべきです.そこで特定のMSRアクセスのみトラップして,ほかをパススルーするために,BitVisorではMSR Bitmapを導入しています.

Exception BitmapやPFEC_MASK(PageFault Error Code Match)やPFEC_MATCH(PageFault Error Code Match)も例外やページフォールトを選択的にトラップするための手段で,MSR Bitmapと似ていますね.

さて,MSR Bitmapには以下の4種類あります.


  • Read bitmap for low MSRs: MSRのIndexが00000000H to 00001FFFH

  • Read bitmap for high MSRs : MSRのIndexがC0000000H to C0001FFFH.MSR Bitmapのアドレスに0x400足したところ.

  • Write bitmap for low MSRs : MSRのインデックスが00000000H to 00001FFFH.MSR Bitmapのアドレスに0x800足したところ.

  • Write bitmap for high MSRs: MSRのインデックスがC0000000H to C0001FFFH.MSR Bitmapのアドレスに0xC00足したところ.


BitVisorでのMSR Bitmapの扱い

MSR Bitmapはcore/msr_pass.cにて実装されています.

static void msr_pass_init (void)が初期化部分です.

基本的にはcurrent->vmctl.msrpassを引数をセットして呼び出しています.

vmctlはAMD-VとIntel VT-xを抽象化するレイヤです.

それぞれ,core/svm.ccore/vt.cにてstatic struct vmctl_func funcに代入しているところが関数ポインタの初期化部分なので,追いかけるときはここを起点として読みます.

msrpassはそれぞれ,core/svm_msr.ccore/vt_msr.cに実装があります.

ここではIntel Vt-xの実装を読んでみましょう.

void

vt_msrpass (u32 msrindex, bool wr, bool pass)
{
u8 *p;

switch (msrindex) {
case MSR_IA32_SYSENTER_CS:
case MSR_IA32_SYSENTER_ESP:
case MSR_IA32_SYSENTER_EIP:
// 省略...
case MSR_IA32_MTRR_PHYSMASK8:
case MSR_IA32_MTRR_PHYSMASK9:
case MSR_IA32_PAT:
pass = false;
break;
case MSR_IA32_MTRRCAP:
case MSR_IA32_FEATURE_CONTROL:
case MSR_IA32_VMX_PROCBASED_CTLS2:
if (!wr)
pass = false;
break;
}
p = current->u.vt.msrbmp->msrbmp;
if (wr)
p += 0x800;
if (msrindex <= 0x1FFF)
vt_setmsrbmp (p, msrindex, !pass);
else if (msrindex >= 0xC0000000 && msrindex <= 0xC0001FFF)
vt_setmsrbmp (p + 0x400, msrindex - 0xC0000000, !pass);
}

msrindexはMSRのインデックス,wrは書き込みならtrue,passはpass-throughするならtrueです.トラップしたい場合はpassをfalseにします.

static void

vt_setmsrbmp (u8 *p, u32 bitoffset, int bit)
{
if (bit)
p[bitoffset >> 3] |= 1 << (bitoffset & 7);
else
p[bitoffset >> 3] &= ~(1 << (bitoffset & 7));
}

ここが書き込み部分.


宣伝:仮想化技術slack HyperVillage

特に活動しているわけではないですが,仮想化技術関連のslackを立ち上げました.

招待URL

4人しか人がいないですが,ぜひ入ってくれるとうれしいです.(あわよくば実装の相談など……)