これは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
to00001FFFH
- Read bitmap for high MSRs : MSRのIndexが
C0000000H
toC0001FFFH
.MSR Bitmapのアドレスに0x400
足したところ. - Write bitmap for low MSRs : MSRのインデックスが
00000000H
to00001FFFH
.MSR Bitmapのアドレスに0x800
足したところ. - Write bitmap for high MSRs: MSRのインデックスが
C0000000H
toC0001FFFH
.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.c
,core/vt.c
にてstatic struct vmctl_func func
に代入しているところが関数ポインタの初期化部分なので,追いかけるときはここを起点として読みます.
msrpassはそれぞれ,core/svm_msr.c
,core/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人しか人がいないですが,ぜひ入ってくれるとうれしいです.(あわよくば実装の相談など……)