次の方法で共有


タイマー

ハイパーバイザーは、単純なタイミング サービスを提供します。 これらは、一定レートの基準時間ソース (通常は x64 システムの ACPI タイマー) に基づいています。

次のタイマー サービスが提供されます。

  • パーティションごとの参照時間カウンター。
  • 仮想プロセッサあたり 4 つの合成タイマー。 各合成タイマーは、メッセージを配信するか、有効期限が切れたときに割り込みをアサートする、シングル ショットまたは定期的なタイマーです。
  • 仮想プロセッサごとに 1 つの仮想 APIC タイマー。
  • インバリアント タイム スタンプ カウンター (iTSC) に対するホスト プラットフォームのサポートに基づくパーティション参照時間の対応。

参照カウンター

ハイパーバイザーは、パーティションごとの参照時間カウンターを保持します。 それに連続的なアクセスは厳密に単調に増加する(時間)値をパーティションのすべての仮想プロセッサによって見られるように返す特性があります。 さらに、基準カウンタはレート定数であり、プロセッサまたはバス速度の遷移やプロセッサの詳細な省電力状態の影響を受けません。 パーティションの参照時間カウンターは、パーティションの作成時にゼロに初期化されます。 すべてのパーティションの参照カウンターは同じレートでカウントされますが、パーティションの作成時間が異なるため、通常は絶対値が異なります。

少なくとも 1 つの仮想プロセッサが明示的に中断されていない限り、参照カウンターはカウントアップを続けます。

パーティション参照カウンター レジスタ

x64 プラットフォームの場合

x64 プラットフォームでは、パーティション全体の MSR を介してパーティションの参照カウンターにアクセスできます。

MSR アドレス レジスタ名 Description
0x40000020 HV_X64_MSR_TIME_REF_COUNT 時間参照数 (パーティション全体)

ARM64 プラットフォームの場合

ARM64 プラットフォームでは、HvCallGetVpRegisters および HvCallSetVpRegisters ハイパーコールを使用して、HvRegisterTimeRefCount 合成レジスタを介してパーティションの参照カウンターにアクセスします。

レジスタ名 Description
HvRegisterTimeRefCount 時間参照数 (パーティション全体)

レジスタの動作

パーティションが作成されると、参照カウンター レジスタの値が0x0000000000000000に設定されます。 この値は、仮想プロセッサでは変更できません。 x64 プラットフォームでは、MSR に書き込もうとすると、#GP 障害が発生します。 ARM64 プラットフォームでは、HvCallSetVpRegisters を介して書き込もうとすると、HV_STATUS_INVALID_PARAMETERが返されます。

パーティション参照時間の対応

パーティション参照時間の対応化では、ハイパーバイザーへのインターセプトを必要としないパーティションへの参照タイム ソースが表示されます。 この対応は、基になるプラットフォームがインバリアント プロセッサ タイム スタンプ カウンター (TSC) または iTSC のサポートを提供する場合にのみ使用できます。 このようなプラットフォームでは、ACPI プロセッサのパフォーマンス状態、プロセッサアイドル スリープ状態 (ACPI C 状態) などの電源管理状態の使用により、プロセッサのクロック周波数の変化に関係なく、プロセッサ TSC 周波数は一定のままです。

パーティション参照時間の対応化では、仮想 TSC 値、オフセット、乗数を使用して、ゲスト パーティションがパーティションの作成以降の正規化された参照時間を 100nS 単位で計算できるようにします。 また、このメカニズムにより、ゲスト パーティションが異なる TSC レートでプラットフォームに移行されるときに、ゲスト パーティションが参照時間をアトミックに計算でき、一定レートの TSC 機能なしでプラットフォームへの移行をサポートするためのフォールバック メカニズムが提供されます。

この機能は、この機能を使用して計算された参照時間は、ゲスト パーティションが後続の復元まで保存されている間に停止するように見えるので、ウォール クロック時間のソースを使用するためのものではありません。

[パーティション参照タイム スタンプ カウンター] ページ

ハイパーバイザーは、パーティション全体の仮想参照 TSC ページを提供します。このページは、パーティションの GPA 領域にオーバーレイされます。 パーティションの参照タイム スタンプ カウンター ページには、参照 TSC MSR を介してアクセスします。

参照 TSC ページは、次の構造を使用して定義されます。

typedef struct
{
   volatile UINT32 TscSequence;
   UINT32 Reserved1;
   volatile UINT64 TscScale;
   volatile INT64 TscOffset;
   UINT64 Reserved2[509];
} HV_REFERENCE_TSC_PAGE;

参照タイム スタンプ カウンター (TSC) ページ レジスタ

参照 TSC ページにアクセスするゲストは、合成レジスタを使用する必要があります。 AccessPartitionReferenceTsc 特権を持つパーティションは、レジスタにアクセスできます。

x64 プラットフォームの場合

x64 プラットフォームでは、参照 TSC ページに MSR 経由でアクセスします。

MSR アドレス レジスタ名 Description
0x40000021 HV_X64_MSR_REFERENCE_TSC TSC ページを参照する
ARM64 プラットフォームの場合

ARM64 プラットフォームでは、HvCallGetVpRegisters および HvCallSetVpRegisters ハイパーコールを使用して、HvRegisterReferenceTsc 合成レジスタを介して参照 TSC ページにアクセスします。

レジスタ名 Description
HvRegisterReferenceTsc TSC ページを参照する
レイアウトの登録
ビット Description Attributes
63:12 GPA ページ番号 読み取り/書き込み
11:1 RsvdP (値は保持する必要があります) 読み取り/書き込み
0 Enable 読み取り/書き込み

ゲスト パーティションの作成時に、参照 TSC MSR の値が0x0000000000000000されます。 したがって、参照 TSC ページは既定で無効になっています。 ゲストは、ビット 0 を設定して参照 TSC ページを有効にする必要があります。 指定したベース アドレスがパーティションの GPA 領域の末尾を超えている場合、参照 TSC ページにはゲストからアクセスできません。 レジスタを変更する場合、ゲストは、将来の互換性のために予約ビット (1 から 11) の値を保持する必要があります。

パーティション参照 TSC メカニズム

パーティション参照時間は、次の数式で計算されます。

ReferenceTime = ((VirtualTsc * TscScale) >> 64) + TscOffset

乗算は 64 ビット乗算であり、その結果、128 ビット番号が右に 64 回シフトされ、上位 64 ビットが取得されます。

TscScale 値は、あるプラットフォームから別のプラットフォームへの TSC 頻度の変更を軽減するために、移行イベント間で仮想 TSC 値を調整するために使用されます。

TscSequence 値は、保存/復元またはライブ マイグレーション中にスケール フィールドまたはオフセット フィールドが変更された場合に、対応する参照時刻へのアクセスを同期するために使用されます。 このフィールドは、スケールフィールドまたはオフセットフィールドが変更されるたびにインクリメントされるシーケンス番号として機能します。 この機能が参照時間の信頼できるソースではなくなったため、VM が別のソースにフォールバックする必要があることを示すには、0x0の特別な値が使用されます。

この対応を使用してパーティション参照時間を計算するための推奨されるコードを次に示します。

do
{
    StartSequence = ReferenceTscPage->TscSequence;
    if (StartSequence == 0)
    {
        // 0 means that the Reference TSC enlightenment is not available at
        // the moment, and the Reference Time can only be obtained from
        // reading the Reference Counter MSR.
        ReferenceTime = rdmsr(HV_X64_MSR_TIME_REF_COUNT);
        return ReferenceTime;
    }

    Tsc = rdtsc();

    // Assigning Scale and Offset should neither happen before
    // setting StartSequence, nor after setting EndSequence.
    Scale = ReferenceTscPage->TscScale;
    Offset = ReferenceTscPage->TscOffset;

    EndSequence = ReferenceTscPage->TscSequence;
} while (EndSequence != StartSequence);

// The result of the multiplication is treated as a 128-bit value.
ReferenceTime = ((Tsc * Scale) >> 64) + Offset;
return ReferenceTime;

合成タイマー

合成タイマーは、将来指定された時間が経過した後に割り込みを生成するためのメカニズムを提供します。 ワンショット タイマーと定期的タイマーの両方がサポートされています。 合成タイマーは、有効期限が切れた時点で指定された SynIC SINTx (合成割り込みソース) にメッセージを送信するか、構成方法に応じて割り込みをアサートします。

ハイパーバイザーは、タイマーの有効期限シグナルが有効期限前に配信されることは決してないことを保証します。 シグナルは、有効期限後にいつでも到着する可能性があります。

定期的なタイマー

ハイパーバイザーは定期的なタイマーの通知を定期的に試行します。 ただし、有効期限の通知に使用する仮想プロセッサが使用できない場合は、タイマーの有効期限の一部が遅れる可能性があります。 仮想プロセッサが中断されている (インターセプト処理中など) か、ハイパーバイザーのスケジューラが仮想プロセッサを論理プロセッサでスケジュールしないことを決定したため (たとえば、別の仮想プロセッサが論理プロセッサを使用しているか、仮想プロセッサがそのクォータを超えたために) 使用できない可能性があります。

仮想プロセッサが十分に長い期間使用できない場合は、完全なタイマー期間が失われる可能性があります。 この場合、ハイパーバイザーは 2 つの手法のいずれかを使用します。

1 つ目の手法では、タイマー期間の変調が含まれます。実際には、タイマーが "追いつく" まで期間を短縮します。 かなりの数のタイマー信号が見落とされた場合、ハイパーバイザーはピリオド変調を使用して補正できない可能性があります。 この場合、一部のタイマー有効期限シグナルは完全にスキップされる可能性があります。

遅延としてマークされているタイマーの場合、ハイパーバイザーは、仮想プロセッサが長時間使用できない状況に対処するために 2 番目の手法を使用します。 この場合、タイマー信号は、この仮想プロセッサが使用可能になるまで遅延されます。 次のタイマーが期限切れになる直前まで使用できなくなった場合は、完全にスキップされます。

タイマーの有効期限の順序付け

合成タイマーと仮想化タイマーは、指定された有効期限付近で割り込みを生成します。 ハードウェアやその他のスケジュール操作により、割り込みが遅延する可能性があります。 タイマーのセット間で順序付けを想定することはできません。

Direct Synthetic Timers

"ダイレクト" 合成タイマーは、SynIc 合成割り込みソースにメッセージを送信するのではなく、タイマーの有効期限が切れた時点で割り込みをアサートします。 合成タイマー構成 MSR の "DirectMode" フィールドを設定することで、合成タイマーを "ダイレクト" モードに設定します。 "ApicVector" フィールドは、タイマーの有効期限時にアサートされる割り込みベクトルを制御します。

合成タイマー レジスタ

合成タイマーは、各仮想プロセッサに関連付けられている合成レジスタを使用して構成されます。 4 つの合成タイマーのそれぞれに、レジスタのペア (構成とカウント) が関連付けられています。

x64 プラットフォームの場合

x64 プラットフォームでは、RDMSR および WRMSR 命令を使用して、合成タイマーに MSR 経由でアクセスします。

MSR アドレス レジスタ名 Description
0x400000B0 HV_X64_MSR_STIMER0_CONFIG 合成タイマー 0 の構成レジスタ。
0x400000B1 HV_X64_MSR_STIMER0_COUNT 合成タイマー 0 の有効期限または期間。
0x400000B2 HV_X64_MSR_STIMER1_CONFIG 合成タイマー 1 の構成レジスタ。
0x400000B3 HV_X64_MSR_STIMER1_COUNT 合成タイマー 1 の有効期限または期間。
0x400000B4 HV_X64_MSR_STIMER2_CONFIG 合成タイマー 2 の構成レジスタ。
0x400000B5 HV_X64_MSR_STIMER2_COUNT 合成タイマー 2 の有効期限または期間。
0x400000B6 HV_X64_MSR_STIMER3_CONFIG 合成タイマー 3 の構成レジスタ。
0x400000B7 HV_X64_MSR_STIMER3_COUNT 合成タイマー 3 の有効期限または期間。

ARM64 プラットフォームの場合

ARM64 プラットフォームでは、合成タイマーは HvCallGetVpRegisters および HvCallSetVpRegisters ハイパーコールを使用して合成レジスタを介してアクセスされます。

レジスタ名 Description
HvRegisterStimer0Config 合成タイマー 0 の構成レジスタ。
HvRegisterStimer0Count 合成タイマー 0 の有効期限または期間。
HvRegisterStimer1Config 合成タイマー 1 の構成レジスタ。
HvRegisterStimer1Count 合成タイマー 1 の有効期限または期間。
HvRegisterStimer2Config 合成タイマー 2 の構成レジスタ。
HvRegisterStimer2Count 合成タイマー 2 の有効期限または期間。
HvRegisterStimer3Config 合成タイマー 3 の構成レジスタ。
HvRegisterStimer3Count 合成タイマー 3 の有効期限または期間。

メモ: ARM64 では、仮想化のオーバーヘッドを発生させずに ARM 汎用タイマー (GIT) を直接使用できるため、合成タイマーは省略可能です。 パフォーマンスを向上させるには、ゲスト オペレーティング システムでアーキテクチャ 汎用タイマーを使用することをお勧めします。

レイアウトの登録

合成タイマー構成レジスタ
ビット Description Attributes
63:20 RsvdZ (値は 0 に設定する必要があります) 読み取り/書き込み
19:16 SINTx - 合成割り込みソース 読み取り/書き込み
15:13 RsvdZ (値は 0 に設定する必要があります) 読み取り/書き込み
12 ダイレクト モード - タイマーの有効期限が切れるとアサートおよび割り込まれます。 読み取り/書き込み
11:4 ApicVector - 直接モードでアサートされた割り込みベクトルを制御します 読み取り/書き込み
3 AutoEnable - 対応するカウンターを書き込むとタイマーが暗黙的に有効になる場合に設定されます 読み取り/書き込み
2 遅延 - タイマーが遅延の場合に設定する 読み取り/書き込み
1 定期的 - タイマーが定期的な場合に設定 読み取り/書き込み
0 有効 - タイマーが有効になっている場合に設定 読み取り/書き込み

仮想プロセッサを作成してリセットすると、すべての合成タイマー構成レジスタの値 (HV_X64_MSR_STIMER3_CONFIGを介してHV_X64_MSR_STIMER0_CONFIG) が0x0000000000000000に設定されます。 したがって、すべての合成タイマーは既定で無効になっています。

AutoEnable が設定されている場合、対応するカウント レジスタに 0 以外の値を書き込むと、Enable が設定され、カウンターがアクティブになります。 それ以外の場合は、カウンターをアクティブにするために、対応するカウント レジスタを書き込んだ後に Enable を設定する必要があります。 カウント レジスタの詳細については、次のセクションを参照してください。

ワンショット タイマーの有効期限が切れると、自動的に無効としてマークされます。 定期的なタイマーは、明示的に無効になるまで有効なままです。

ワンショットが有効になっていて、指定した数が過去の場合、すぐに期限切れになります。

有効なタイマー (直接モードではない) の場合、SINTx フィールドを 0 に設定することはできません。 試行すると、タイマーはすぐに無効 (つまり、ビット 0 がクリア) とマークされます。

既に有効になっているタイマーの構成レジスタを記述すると、未定義の動作が発生する可能性があります。 たとえば、タイマーを 1 回のショットから定期的に変更するだけでは、意図した内容が生成されない場合があります。 タイマーは、他のプロパティを変更する前に常に無効にする必要があります。

合成タイマーカウント レジスタ
ビット Description Attributes
63:0 Count - ワンショット タイマーの有効期限、定期的なタイマーの期間 読み取り/書き込み

Count レジスタにプログラミングされた値は、100 ナノ秒単位で測定された時間値です。 Count レジスタに値 0 を書き込むと、カウンターが停止し、構成レジスタの AutoEnable の設定に関係なくタイマーが無効になります。

Count レジスタのラップが許可されていることに注意してください。 ラップは、タイマー プロパティに関係なく、タイマーの動作には影響しません。

ワンショット タイマーの場合は、絶対タイマーの有効期限を表します。 タイマーは、パーティションの参照カウンターが指定されたカウント値以上になると期限切れになります。

定期的なタイマーの場合、カウントはタイマーの期間を表します。 最初の期間は、合成タイマーが有効になったときに開始されます。

合成タイマーの有効期限メッセージ

タイマーの有効期限メッセージは、タイマー イベントが発生したときに送信されます。 メッセージ ペイロードの定義については、 HV_TIMER_MESSAGE_PAYLOAD を参照してください。

合成 Time-Unhalted タイマー レジスタ

パーティションに AccessSyntheticTimerRegs 特権がある場合は、x64 プラットフォームで合成 Time-Unhalted タイマー レジスタを使用できます。 可用性は、ハイパーバイザー機能識別 CPUID リーフ 0x40000003の EDX ビット 23 によって示されます。 この機能は、ARM64 プラットフォームでは使用できません。

ゲスト ソフトウェアは、100ns 単位で指定された時間の実行後に定期的な割り込みを生成する合成時間なしのタイマーをプログラムできます。 割り込みが発生すると、VP アシスト ページの SyntheticTimeUnhaltedTimerExpired フィールドが TRUE に設定されます。 ゲスト ソフトウェアは、このフィールドを FALSE にリセットできます。 アーキテクチャ パフォーマンス カウンターとは異なり、合成タイマーはハイパーバイザーによってリセットされることはなく、割り込み間で継続的に実行されます。 Vector フィールドが 2 (x64 NMI ベクトル) に設定されている場合、タイマーはマスク不可能な割り込みを提供します。それ以外の場合は、指定されたベクターを使用して固定割り込みを提供します。

ゲストが停止したときに時間を蓄積する通常の合成タイマー (つまり、アイドル状態になった場合) とは異なり、合成 Time-Unhalted タイマーは、ゲストが停止していない間だけ時間を蓄積します。

x64 プラットフォームの場合

x64 プラットフォームでは、RDMSR および WRMSR 命令を使用して、合成時間非ハルト タイマーに MSR 経由でアクセスします。

MSR アドレス レジスタ名 Description
0x40000114 HV_X64_MSR_STIME_UNHALTED_TIMER_CONFIG 合成 Time-Unhalted タイマーの構成
0x40000115 HV_X64_MSR_STIME_UNHALTED_TIMER_COUNT 合成 Time-Unhalted タイマー数

レイアウトの登録

合成 Time-Unhalted タイマー構成レジスタ
ビット Description Attributes
63:9 RsvdZ (値は 0 に設定する必要があります) 読み取り/書き込み
Enabled 読み取り/書き込み
7:0 Vector 読み取り/書き込み

Vector フィールドは、2 (NMI を配信する場合) または値 ≥ 16 (固定割り込みを提供する場合) である必要があります。 その他の値は無効です。

合成 Time-Unhalted タイマー カウント レジスタ
ビット Description Attributes
63:0 100 ns 単位の割り込みの周期レート 読み取り/書き込み