KVM 固有の MSR

Author:

Glauber Costa <glommer@redhat.com>, Red Hat Inc, 2010

KVM は、いくつかの要求を処理するために独自の MSR を使う。

カスタム MSR には専用の範囲が予約されており、0x4b564d00 から 0x4b564dff までである。この領域の外にも MSR はあるが、これらは非推奨であり、使用は 推奨されない。

カスタム MSR の一覧

現在サポートされているカスタム MSR の一覧は次のとおりである:

MSR_KVM_WALL_CLOCK_NEW:

0x4b564d00

data:

ゲスト RAM 内になければならないメモリ領域の、4 バイト境界に整列した 物理アドレス。このメモリは次の構造体のコピーを保持することが想定 されている:

struct pvclock_wall_clock {
       u32   version;
       u32   sec;
       u32   nsec;
 } __attribute__((__packed__));

この構造体のデータはハイパーバイザによって書き込まれる。ハイパーバイザが このデータを更新することは、MSR への書き込み時点でのみ保証される。この 情報を複数回確実に取得したいユーザは、この MSR に複数回書き込む必要が ある。各フィールドの意味は次のとおりである:

version:

ゲストは、時刻情報を取得する前と後で version を確認し、両者が 等しく、かつ偶数であることを確かめなければならない。version が 奇数であれば、更新が進行中であることを示す。

sec:

起動時点の wallclock の秒数。

nsec:

起動時点の wallclock のナノ秒数。

現在の wallclock 時刻を求めるには、MSR_KVM_SYSTEM_TIME_NEW の system_time を加える必要がある。

MSR は CPU ごとのものであるが、この MSR の効果はグローバルであることに 注意。

この MSR の可用性は、使用前に 0x4000001 cpuid リーフのビット 3 で 確認しなければならない。

MSR_KVM_SYSTEM_TIME_NEW:

0x4b564d01

data:

ゲスト RAM 内になければならないメモリ領域の、4 バイト境界に整列した 物理アドレスに、ビット 0 の有効化ビットを加えたもの。このメモリは 次の構造体のコピーを保持することが想定されている:

struct pvclock_vcpu_time_info {
      u32   version;
      u32   pad0;
      u64   tsc_timestamp;
      u64   system_time;
      u32   tsc_to_system_mul;
      s8    tsc_shift;
      u8    flags;
      u8    pad[2];
} __attribute__((__packed__)); /* 32 bytes */

この構造体のデータはハイパーバイザによって定期的に書き込まれる。 VCPU ごとに 1 回の書き込み(登録)だけでよい。この構造体の更新間隔は 任意で、実装に依存する。bit0 == 0 の値が書き込まれるまで、ハイパーバイザは 適切と考える任意の時点でこの構造体を更新してよい。

各フィールドの意味は次のとおりである:

version:

ゲストは、時刻情報を取得する前と後で version を確認し、両者が 等しく、かつ偶数であることを確かめなければならない。version が 奇数であれば、更新が進行中であることを示す。

tsc_timestamp:

この構造体が更新された時点の、現在の VCPU の tsc 値。ゲストは、 現在の tsc からこの値を引くことで、構造体が更新されてからの 経過時間の目安を求められる。

system_time:

この構造体が最後に更新された時点の、スリープ時間を含むホスト側の 単調時間。単位はナノ秒。

tsc_to_system_mul:

tsc 関連の量をナノ秒に変換するときに使う乗数

tsc_shift:

tsc 関連の量をナノ秒に変換するときに使うシフト量。このシフトにより、 tsc_to_system_mul との乗算がオーバーフローしないことが保証される。 正の値は左シフト、負の値は右シフトを表す。

tsc からナノ秒への変換には、さらに 32 ビットの右シフトが含まれる。 この情報を使うと、ゲストは次のようにして CPU ごとの時刻を求められる:

time = (current_tsc - tsc_timestamp)
if (tsc_shift >= 0)
        time <<= tsc_shift;
else
        time >>= -tsc_shift;
time = (time * tsc_to_system_mul) >> 32
time = time + system_time
flags:

このフィールドのビットは、ゲストとハイパーバイザの間で調整された 拡張機能を表す。個々のフラグの可用性は、0x40000001 cpuid リーフで確認しなければならない。現在のフラグは次のとおりである:

フラグビット

cpuid ビット

意味

0

24

複数の CPU にまたがって取得した時刻が単調 であることが保証される

1

N/A

ゲスト vCPU がホストによって一時停止された。 api.txt の 4.70 を参照

この MSR の可用性は、使用前に 0x4000001 cpuid リーフのビット 3 で 確認しなければならない。

MSR_KVM_WALL_CLOCK:

0x11

データと動作:

MSR_KVM_WALL_CLOCK_NEW と同じ。代わりにそちらを使う。

この MSR は KVM の予約範囲の外にあり、将来削除される可能性がある。 使用は非推奨である。

この MSR の可用性は、使用前に 0x4000001 cpuid リーフのビット 0 で 確認しなければならない。

MSR_KVM_SYSTEM_TIME:

0x12

データと動作:

MSR_KVM_SYSTEM_TIME_NEW と同じ。代わりにそちらを使う。

この MSR は KVM の予約範囲の外にあり、将来削除される可能性がある。 使用は非推奨である。

この MSR の可用性は、使用前に 0x4000001 cpuid リーフのビット 0 で 確認しなければならない。

kvmclock の存在を検出するために推奨されるアルゴリズムは次のとおりである:

if (!kvm_para_available())    /* refer to cpuid.txt */
        return NON_PRESENT;

flags = cpuid_eax(0x40000001);
if (flags & 3) {
        msr_kvm_system_time = MSR_KVM_SYSTEM_TIME_NEW;
        msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK_NEW;
        return PRESENT;
} else if (flags & 0) {
        msr_kvm_system_time = MSR_KVM_SYSTEM_TIME;
        msr_kvm_wall_clock = MSR_KVM_WALL_CLOCK;
        return PRESENT;
} else
        return NON_PRESENT;
MSR_KVM_ASYNC_PF_EN:

0x4b564d02

data:

非同期ページフォールト(APF)制御 MSR。

ビット 63〜6 は、ゲスト RAM 内になければならない 64 バイトのメモリ領域の、 64 バイト境界に整列した物理アドレスを保持する。このメモリは次の構造体を 保持することが想定されている:

struct kvm_vcpu_pv_apf_data {
      /* Used for 'page not present' events delivered via #PF */
      __u32 flags;

      /* Used for 'page ready' events delivered via interrupt notification */
      __u32 token;

      __u8 pad[56];
};

MSR のビット 5〜4 は予約済みで、0 であるべきである。ビット 0 は、vCPU で 非同期ページフォールトが有効なときは 1、無効なときは 0 に設定される。 ビット 1 は、vCPU が cpl == 0 のときに非同期ページフォールトを注入できる 場合は 1 である。ビット 2 は、非同期ページフォールトが #PF vmexit として L1 に配送される場合は 1 である。ビット 2 は、CPUID に KVM_FEATURE_ASYNC_PF_VMEXIT が存在する場合にのみ設定できる。ビット 3 は、 'page ready' イベントの割り込みベースの配送を有効にする。ビット 3 は、 CPUID に KVM_FEATURE_ASYNC_PF_INT が存在する場合にのみ設定できる。

'page not present' イベントは、現在は常に合成 #PF 例外として配送される。 これらのイベントの配送中、APF の CR2 レジスタには、不足しているページが 利用可能になったときにゲストへ通知するために使われるトークンが入る。 また、実際の #PF と APF を区別できるようにするため、64 バイトのメモリ 位置の先頭 4 バイト('flags')は、注入時にハイパーバイザによって 書き込まれる。現在サポートされているのは 'flags' の先頭ビットだけで、 これがセットされている場合は、ゲストが非同期の 'page not present' イベントを処理していることを示す。ページフォールトの際に APF の 'flags' が '0' であれば、これが通常のページフォールトであることを 意味する。ゲストは、#PF 例外の処理を終えたら 'flags' をクリアし、次の イベントを配送できるようにするものとされる。

注意: APF の 'page not present' イベントは通常のページフォールトと 同じ例外ベクタを使うため、ゲストは、通常のページフォールトを発生させ 得る何かを行う前に 'flags' を '0' にリセットしなければならない。

64 バイトのメモリ位置の 4〜7 バイト目('token')は、APF の 'page ready' イベントの注入時にハイパーバイザによって書き込まれる。これらのバイトの 内容は、以前に 'page not present' イベントとして CR2 で配送された トークンである。このイベントは、ページが利用可能になったことを示す。 ゲストは、'page ready' イベントの処理を終えたら 'token' に '0' を 書き込み、その位置をクリアした後に MSR_KVM_ASYNC_PF_ACK に '1' を 書き込むものとされる。この MSR への書き込みにより、KVM はキューを 再スキャンし、次に保留中の通知を配送する。

注意: 'page ready' APF の配送に使う割り込みベクタを指定する MSR_KVM_ASYNC_PF_INT は、MSR_KVM_ASYNC_PF_EN で APF の仕組みを有効に する前に書き込む必要がある。そうしないと割り込み #0 が注入され得る。 この MSR は、CPUID に KVM_FEATURE_ASYNC_PF_INT が存在する場合に 利用できる。

注意: 以前は、'page ready' イベントは 'page not present' イベントと 同じ #PF 例外で配送されていたが、これは現在は非推奨である。ビット 3 (割り込みベースの配送)が設定されていない場合、APF イベントは 配送されない。

未処理の APF がある状態で APF を無効にすると、それらは配送されない。

現在、'page ready' APF イベントは常に、'page not present' イベントと 同じ vCPU で配送されるが、ゲストはこれに依存すべきでない。

MSR_KVM_STEAL_TIME:

0x4b564d03

data:

ゲスト RAM 内になければならないメモリ領域の、64 バイト境界に整列した 物理アドレスに、ビット 0 の有効化ビットを加えたもの。このメモリは 次の構造体のコピーを保持することが想定されている:

struct kvm_steal_time {
      __u64 steal;
      __u32 version;
      __u32 flags;
      __u8  preempted;
      __u8  u8_pad[3];
      __u32 pad[11];
}

この構造体のデータはハイパーバイザによって定期的に書き込まれる。 VCPU ごとに 1 回の書き込み(登録)だけでよい。この構造体の更新間隔は 任意で、実装に依存する。bit0 == 0 の値が書き込まれるまで、ハイパーバイザは 適切と考える任意の時点でこの構造体を更新してよい。ゲストは、この構造体が 0 で初期化されていることを確実にしなければならない。

各フィールドの意味は次のとおりである:

version:

シーケンスカウンタ。言い換えると、ゲストは時刻情報を取得する前と 後でこのフィールドを確認し、両者が等しく、かつ偶数であることを 確かめなければならない。version が奇数であれば、更新が進行中で あることを示す。

flags:

現時点では常に 0。将来、この構造体の変更を示すために使われる 可能性がある。

steal:

この vCPU が実行されなかった時間の量(ナノ秒)。vCPU がアイドル 状態であった時間は、steal time として報告されない。

preempted:

この構造体を所有する vCPU が実行中かどうかを示す。0 以外の値は、 vCPU がプリエンプトされたことを意味する。0 は、vCPU が プリエンプトされていないことを意味する。注意: ハイパーバイザが このフィールドをサポートしていない場合は、常に 0 である。

MSR_KVM_EOI_EN:

0x4b564d04

data:

ビット 0 は、vCPU で PV 割り込み終了が有効なときは 1、無効なときは 0 で ある。ビット 1 は予約済みで、0 でなければならない。PV 割り込み終了が 有効な場合(ビット 0 がセット)、ビット 63〜2 は、ゲスト RAM 内にあり 0 に初期化されていなければならない 4 バイトのメモリ領域の、4 バイト境界に 整列した物理アドレスを保持する。

4 バイトのメモリ位置の先頭、つまり最下位ビットは、通常は割り込み注入時に ハイパーバイザによって書き込まれる。値が 1 の場合は、ゲストは apic への EOI の書き込み(MSR または MMIO 書き込みを使用)を省略できる。代わりに、 ゲストメモリ内のこのビットをクリアして EOI を通知すれば十分である。 この位置は後でハイパーバイザによってポーリングされる。値が 0 の場合は、 EOI の書き込みが必要である。

ゲストがこの最適化を無視して、それでも APIC の EOI 書き込みを行うことは 常に安全である。

ハイパーバイザがこの最下位ビットを変更するのは、現在の VCPU コンテキストに ある間だけであることが保証される。つまり、ゲストはハイパーバイザと同期 するためにロックプレフィックスやメモリオーダリングのプリミティブを使う 必要がない。

ただし、ハイパーバイザはこのメモリビットをいつでもセットおよびクリア できる。したがって、ゲストが EOI の apic 書き込みを省略できるかどうかを 検出するためにこのビットをテストしてから、EOI をハイパーバイザに通知 するためにこれをクリアするまでの間に、ハイパーバイザが割り込みをかけて メモリ領域の最下位ビットをクリアしないようにするため、ゲストはメモリ 領域の最下位ビットを読み取ることと、それをクリアすることを、test and clear や compare and exchange のような単一の CPU 命令で行わなければ ならない。

MSR_KVM_POLL_CONTROL:

0x4b564d05

ホスト側のポーリングを制御する。

data:

ビット 0 はホスト側の HLT ポーリング処理を有効(1)または無効(0)に する。

KVM ゲストは、たとえば自分でポーリングを行う場合などに、HLT でホストが ポーリングしないよう要求できる。

MSR_KVM_ASYNC_PF_INT:

0x4b564d06

data:

2 番目の非同期ページフォールト(APF)制御 MSR。

ビット 0〜7: 'page ready' APF イベントの配送に使う APIC ベクタ。 ビット 8〜63: 予約済み

非同期の 'page ready' 通知の配送に使う割り込みベクタ。このベクタは、 MSR_KVM_ASYNC_PF_EN で非同期ページフォールトの仕組みを有効にする前に 設定する必要がある。この MSR は、CPUID に KVM_FEATURE_ASYNC_PF_INT が 存在する場合にのみ利用できる。

MSR_KVM_ASYNC_PF_ACK:

0x4b564d07

data:

非同期ページフォールト(APF)の確認応答。

ゲストが 'page ready' APF イベントの処理を終え、'struct kvm_vcpu_pv_apf_data' の 'token' フィールドをクリアしたら、MSR のビット 0 に '1' を書き込むものとされる。これにより、ホストはキューを再スキャンし、 保留中の通知がまだあるかを確認する。この MSR は、CPUID に KVM_FEATURE_ASYNC_PF_INT が存在する場合に利用できる。

MSR_KVM_MIGRATION_CONTROL:

0x4b564d08

data:

この MSR は、CPUID に KVM_FEATURE_MIGRATION_CONTROL が存在する場合に 利用できる。ビット 0 は、ゲストのライブマイグレーションを許可するか どうかを表す。

ゲストの起動時、ビット 0 は、ゲストが暗号化メモリを持つ場合は 0、 持たない場合は 1 になる。ゲストが KVM_HC_MAP_GPA_RANGE ハイパーコールを 使ってページの暗号化状態をホストに伝えている場合、この MSR のビット 0 を セットして、ゲストのライブマイグレーションを許可できる。