Hypercall インターフェイス
ハイパーバイザーはゲストの呼び出しメカニズムを提供します。 このような呼び出しはハイパーコールと呼ばれます。 各ハイパーコールは、入力パラメーターまたは出力パラメーターのセットを定義します。 これらのパラメーターは、メモリベースのデータ構造の観点から指定されます。 入力データ構造と出力データ構造のすべての要素は、最大 8 バイトの自然境界に埋め込まれます (つまり、2 バイトの要素は 2 バイト境界上にある必要があります)。
2 つ目のハイパーコール呼び出し規則は、オプションでハイパーコールのサブセット (特に、入力パラメーターが 2 つ以下で出力パラメーターがない場合) に使用できます。 この呼び出し規約を使用する場合、入力パラメーターは汎用レジスタで渡されます。
3 番目のハイパーコール呼び出し規則は、必要に応じて、入力パラメーター ブロックが最大 112 バイトのハイパーコールのサブセットに使用できます。 この呼び出し規則を使用する場合、入力パラメーターは、揮発性 XMM レジスタを含むレジスタに渡されます。
入力データ構造と出力データ構造の両方を 8 バイト境界のメモリに配置し、8 バイトの倍数のサイズに埋め込む必要があります。 パディング領域内の値は、ハイパーバイザーによって無視されます。
出力の場合、ハイパーバイザーはパディング領域を上書きすることが許可されます (ただし、保証されません)。 パディング領域を上書きすると、ゼロが書き込まれます。
Hypercall クラス
ハイパーコールには、simple と rep の 2 つのクラスがあります ("repeat" の略)。 単純なハイパーコールは 1 つの操作を実行し、固定サイズの入力パラメーターと出力パラメーターのセットを持ちます。 担当者ハイパーコールは、一連の単純なハイパーコールのように機能します。 入力パラメーターと出力パラメーターの固定サイズ セットに加えて、rep ハイパーコールには、固定サイズの入力要素または出力要素の一覧が含まれます。
呼び出し元が最初に rep ハイパーコールを呼び出すときに、入力パラメーター リストまたは出力パラメーター リスト内の要素の数を示す担当者数を指定します。 呼び出し元は、次に使用する必要がある入力要素または出力要素を示す rep 開始インデックスも指定します。 ハイパーバイザーは、要素インデックスを増やすことによって、リストの順序で rep パラメーターを処理します。
担当者のハイパーコールの後続の呼び出しの場合、担当者の開始インデックスは完了した要素の数を示し、担当者数の値と組み合わせて残っている要素の数を示します。 たとえば、呼び出し元が担当者数 25 を指定し、時間制約内で 20 回のイテレーションのみが完了した場合、ハイパーコールは、担当者の開始インデックスを 20 に更新した後、呼び出し元の仮想プロセッサに制御を戻します。 ハイパーコールが再実行されると、ハイパーバイザーは要素 20 で再開し、残りの 5 つの要素を完了します。
要素の処理中にエラーが発生した場合は、適切な状態コードと、エラーが発生する前に正常に処理された要素の数を示す、担当者の完了数が指定されます。 指定されたハイパーコール制御ワードが有効であり (以下を参照)、入力/出力パラメーター リストにアクセス可能であると仮定すると、ハイパーバイザーは少なくとも 1 人の担当者を試行することが保証されますが、呼び出し元に制御を戻す前にリスト全体を処理する必要はありません。
Hypercall 継続
ハイパーコールは、多くのサイクルを要する複雑な命令と考えることができます。 ハイパーバイザーは、ハイパーコールを呼び出した仮想プロセッサに制御を返す前に、ハイパーコール実行を 50μs 以下に制限しようとします。 一部のハイパーコール操作は、50μsの保証が困難であるという十分に複雑です。 そのため、ハイパーバイザーは、一部のハイパーコール (すべての担当者ハイパーコール フォームを含む) のハイパーコール継続メカニズムに依存します。
ハイパーコール継続メカニズムは、ほとんどの場合、呼び出し元に対して透過的です。 ハイパーコールが指定された時間内に完了できない場合、制御は呼び出し元に返されますが、命令ポインターはハイパーコールを呼び出した命令を超えて進まれません。 これにより、保留中の割り込みを処理し、他の仮想プロセッサをスケジュールできます。 元の呼び出し元のスレッドが実行を再開すると、ハイパーコール命令が再実行され、操作の完了に向けて前進します。
ほとんどの単純なハイパーコールは、規定された時間制限内で完了することが保証されています。 ただし、単純なハイパーコールの数が少ない場合は、より多くの時間が必要になる場合があります。 これらのハイパーコールは、応答ハイパーコールと同様の方法でハイパーコール継続を使用します。 このような場合、操作には 2 つ以上の内部状態が含まれます。 最初の呼び出しでは、オブジェクト (パーティションや仮想プロセッサなど) が 1 つの状態になり、繰り返し呼び出されると、最終的に状態が終了状態に遷移します。 このパターンに従うハイパーコールごとに、中間内部状態の目に見える副作用について説明します。
ハイパーコール原子性と順序付け
特に記載されている場合を除き、ハイパーコールによって実行されるアクションは、他のすべてのゲスト操作 (たとえば、ゲスト内で実行される命令) と、システムで実行されている他のすべてのハイパーコールの両方に対してアトミックです。 単純なハイパーコールでは、1 つのアトミック アクションが実行されます。rep ハイパーコールは、複数の独立したアトミック アクションを実行します。
ハイパーコール継続を使用する単純なハイパーコールには、外部に表示される複数の内部状態が含まれる場合があります。 このような呼び出しは、複数のアトミック操作で構成されます。
各ハイパーコール アクションは、入力パラメーターを読み取ったり、結果を書き込んだりできます。 各アクションへの入力は、ハイパーコールが行われた後、およびアクションが実行される前に、いつでも任意の粒度で読み取ることができます。 各アクションに関連付けられた結果 (つまり、出力パラメーター) は、任意の粒度で、およびアクションが実行された後、ハイパーコールが戻る前にいつでも書き込まれます。
ゲストは、実行中のハイパーコールに関連する入力または出力パラメーターの検査や操作を回避する必要があります。 ハイパーコールを実行する仮想プロセッサでは実行できません (ハイパーコールが戻るまでゲストの実行が中断されるため)、他の仮想プロセッサがそうするのを防ぐものは何もありません。 この方法でゲストが動作すると、パーティション内でクラッシュまたは破損が発生する可能性があります。
法的ハイパーコール環境
ハイパーコールは、最も特権のあるゲスト プロセッサ モードからのみ呼び出すことができます。 x64 platfoms では、現在の特権レベル (CPL) が 0 の保護モードを意味します。 実モード コードは有効な CPL が 0 で実行されますが、ハイパーコールは実モードでは許可されません。 不正なプロセッサ モード内でハイパーコールを呼び出そうとすると、#UD (未定義の操作) 例外が生成されます。
すべてのハイパーコールは、アーキテクチャで定義されたハイパーコール インターフェイスを介して呼び出す必要があります (下記参照)。 他の方法でハイパーコールを呼び出そうとすると (たとえば、ハイパーコール コード ページから別の場所にコードをコピーしてそこから実行する)、未定義の操作 (#UD) 例外が発生する可能性があります。 ハイパーバイザーでは、この例外が配信されるとは限りません。
配置の要件
呼び出し元は、入力パラメーターまたは出力パラメーターの 64 ビット ゲスト物理アドレス (GPA) を指定する必要があります。 GPA ポインターは 8 バイトアラインする必要があります。 ハイパーコールに入力パラメーターまたは出力パラメーターがない場合、ハイパーバイザーは対応する GPA ポインターを無視します。
入力パラメーターリストと出力パラメーター リストは、ページ境界と重複したり、ページ境界を越えたりすることはできません。 ハイパーコールの入力ページと出力ページは、"オーバーレイ" ページではなく GPA ページであると想定されます。 仮想プロセッサがオーバーレイ ページに入力パラメーターを書き込み、このページ内で GPA を指定した場合、入力パラメーター リストへのハイパーバイザー アクセスは未定義です。
ハイパーバイザーは、要求されたハイパーコールを実行する前に、呼び出し側パーティションが入力ページから読み取ることができることを検証します。 この検証は、指定された GPA がマップされ、GPA が読み取り可能とマークされている 2 つのチェックで構成されます。 これらのテストのいずれかが失敗した場合、ハイパーバイザーはメモリ インターセプト メッセージを生成します。 出力パラメーターを持つハイパーコールの場合、ハイパーバイザーはパーティションが出力ページに書き込むことができることを検証します。 この検証は、指定された GPA がマップされ、GPA が書き込み可能とマークされているという 2 つのチェックで構成されます。
Hypercall 入力
呼び出し元は、ハイパーコール入力値と呼ばれる 64 ビット値でハイパーコールを指定します。 これは次のような形式になります。
フィールド | Bits | 情報提供済み |
---|---|---|
呼び出しコード | 15-0 | 要求されるハイパーコールを指定します |
ファースト (高速) | 16 | ハイパーコールがレジスタベースの呼び出し規約を使用するかどうかを指定します:0 = メモリベース、1 = レジスタベース |
可変ヘッダー サイズ | 26-17 | QWORDS の変数ヘッダーのサイズ。 |
RsvdZ | 30-27 | 0 にする必要があります |
入れ子になっている | 31 | 入れ子になった環境で L0 ハイパーバイザーによってハイパーコールを処理する必要があることを指定します。 |
担当者数 | 43-32 | 担当者の合計数 (担当者呼び出しの場合は、それ以外の場合は 0 にする必要があります) |
RsvdZ | 47-44 | 0 にする必要があります |
Rep Start Index | 59-48 | インデックスの開始 (担当者の呼び出しの場合は、それ以外の場合は 0 にする必要があります) |
RsvdZ | 63-60 | 0 にする必要があります |
担当者ハイパーコールの場合、担当者数フィールドは担当者の合計数を示します。 担当者の開始インデックスは、リストの先頭に対する特定の繰り返しを示します (0 は、リスト内の最初の要素が処理されることを示します)。 そのため、担当者数の値は常に担当者の開始インデックスより大きくする必要があります。
Fast フラグが 0 の場合、ハイパーコール入力のマッピングを登録します。
X64 | x86 | 情報提供済み |
---|---|---|
RCX | EDX:EAX | ハイパーコール入力値 |
RDX | EBX:ECX | 入力パラメーター GPA |
R8 | EDI:ESI | 出力パラメーター GPA |
ハイパーコール入力値は、入力パラメーターと出力パラメーターを指す GPA と共にレジスタに渡されます。
x64 では、レジスタ マッピングは、呼び出し元が 32 ビット (x86) モードまたは 64 ビット (x64) モードで実行されているかどうかによって異なります。 ハイパーバイザーは、EFER の値に基づいて呼び出し元のモードを決定します。LMA と CS.L. これらのフラグの両方が設定されている場合、呼び出し元は 64 ビットの呼び出し元であると見なされます。
Fast フラグが 1 の場合、ハイパーコール入力のマッピングを登録します。
X64 | x86 | 情報提供済み |
---|---|---|
RCX | EDX:EAX | ハイパーコール入力値 |
RDX | EBX:ECX | 入力パラメーター |
R8 | EDI:ESI | [出力パラメーター] |
ハイパーコール入力値は、入力パラメーターと共にレジスタに渡されます。
可変サイズのハイパーコール入力ヘッダー
ほとんどのハイパーコール入力ヘッダーには固定サイズがあります。 したがって、ゲストからハイパーバイザーに渡されるヘッダー データの量は、ハイパーコール コードによって暗黙的に指定されるため、個別に指定する必要はありません。 ただし、一部のハイパーコールでは、可変量のヘッダー データが必要です。 通常、これらのハイパーコールには固定サイズの入力ヘッダーと、可変サイズの追加ヘッダー入力があります。
可変サイズのヘッダーは、固定ハイパーコール入力に似ています (8 バイトにアラインされ、サイズが 8 バイトの倍数になります)。 呼び出し元は、入力ヘッダーとして提供されるデータの量を指定する必要があります。 このサイズは、ハイパーコール入力値の一部として提供されます (上の表の「可変ヘッダー サイズ」を参照)。
固定ヘッダー サイズは暗黙的であるため、ヘッダー の合計サイズを指定する代わりに、変数部分のみが入力コントロールで提供されます。
Variable Header Bytes = {Total Header Bytes - sizeof(Fixed Header)} rounded up to nearest multiple of 8
Variable HeaderSize = Variable Header Bytes / 8
変数サイズの入力ヘッダーを受け入れることとして明示的に文書化されていないハイパーコールに対して、0 以外の変数ヘッダー サイズを指定することは無効です。 このような場合、ハイパーコールは戻りコード HV_STATUS_INVALID_HYPERCALL_INPUT
になります。
可変サイズの入力ヘッダーを受け入れるハイパーコールの特定の呼び出しでは、すべてのヘッダー入力が固定サイズのヘッダー内に完全に収まる可能性があります。 このような場合、可変サイズの入力ヘッダーは 0 サイズで、ハイパーコール入力の対応するビットは 0 に設定する必要があります。
それ以外の点では、可変サイズの入力ヘッダーを受け入れるハイパーコールは、呼び出し規則に関して固定サイズの入力ヘッダーハイパーコールに似ています。 可変サイズのヘッダー ハイパーコールで、さらに担当者セマンティクスをサポートすることもできます。 このような場合、ヘッダーの合計サイズに固定部分と可変部分の両方が含まれる点を除き、rep 要素は通常の方法でヘッダーの後に配置されます。 他のすべてのルールは同じままです。たとえば、最初の rep 要素は 8 バイトアラインされている必要があります。
XMM 高速ハイパーコール入力
x64 プラットフォームでは、ハイパーバイザーは XMM 高速ハイパーコールの使用をサポートしています。これにより、一部のハイパーコールでは、2 つ以上の入力パラメーターが必要な場合でも高速ハイパーコール インターフェイスのパフォーマンスが向上します。 XMM 高速ハイパーコール インターフェイスでは、6 つの XMM レジスタを使用して、呼び出し元が最大 112 バイトのサイズの入力パラメーター ブロックを渡すことができます。
XMM 高速ハイパーコール インターフェイスの可用性は、"ハイパーバイザー機能識別" CPUID リーフ (0x40000003) を介して示されます。
- ビット 4: XMM レジスタを介したハイパーコール入力の受け渡しのサポートが利用可能です。
XMM 高速出力のサポートを示す別のフラグがあることに注意してください。 ハイパーバイザーが可用性を示していない場合にこのインターフェイスを使用しようとすると、#UDエラーが発生します。
マッピングの登録 (入力のみ)
X64 | x86 | 情報提供済み |
---|---|---|
RCX | EDX:EAX | ハイパーコール入力値 |
RDX | EBX:ECX | 入力パラメーター ブロック |
R8 | EDI:ESI | 入力パラメーター ブロック |
XMM0 | XMM0 | 入力パラメーター ブロック |
XMM1 | XMM1 | 入力パラメーター ブロック |
XMM2 | XMM2 | 入力パラメーター ブロック |
XMM3 | XMM3 | 入力パラメーター ブロック |
XMM4 | XMM4 | 入力パラメーター ブロック |
XMM5 | XMM5 | 入力パラメーター ブロック |
ハイパーコール入力値は、入力パラメーターと共にレジスタに渡されます。 レジスタ マッピングは、呼び出し元が 32 ビット (x86) モードまたは 64 ビット (x64) モードで実行されているかどうかによって異なります。 ハイパーバイザーは、EFER の値に基づいて呼び出し元のモードを決定します。LMA と CS.L. これらのフラグの両方が設定されている場合、呼び出し元は 64 ビットの呼び出し元であると見なされます。 入力パラメーター・ブロックが 112 バイトより小さい場合、レジスタ内の余分なバイトはすべて無視されます。
ハイパーコール出力
すべてのハイパーコールは、ハイパーコール結果値と呼ばれる 64 ビット値を返します。 これは次のような形式になります。
フィールド | Bits | コメント |
---|---|---|
結果 | 15-0 | HV_STATUS 成功または失敗を示すコード |
Rsvd | 31-16 | 呼び出し元は、これらのビットの値を無視する必要があります |
Reps completed | 43-32 | 正常に完了した担当者の数 |
RsvdZ | 63-40 | 呼び出し元は、これらのビットの値を無視する必要があります |
担当者ハイパーコールの場合、担当者の完了フィールドは完了した担当者の合計数であり、担当者の開始インデックスに対する相対数ではありません。 たとえば、呼び出し元が担当者の開始インデックス 5 を指定し、担当者数が 10 の場合、担当者の完了フィールドは、正常完了時に 10 を示します。
ハイパーコールの結果値はレジスタに戻されます。 レジスタ マッピングは、呼び出し元が 32 ビット (x86) モードまたは 64 ビット (x64) モード (上記参照) で実行されているかどうかによって異なります。 ハイパーコール出力のレジスタ マッピングは次のとおりです。
X64 | x86 | 情報提供済み |
---|---|---|
RAX | EDX:EAX | ハイパーコール結果の値 |
XMM 高速ハイパーコール出力
ハイパーバイザーが XMM 高速ハイパーコール入力をサポートする方法と同様に、同じレジスタを共有して出力を返すことができます。 これは x64 プラットフォームでのみサポートされます。
XMM レジスタを介して出力を返す機能は、"ハイパーバイザー機能識別" CPUID リーフ (0x40000003) を介して示されます。
- ビット 15: XMM レジスタを介してハイパーコール出力を返すサポートが利用可能です。
XMM 高速入力のサポートを示す別のフラグがあることに注意してください。 ハイパーバイザーが可用性を示していない場合にこのインターフェイスを使用しようとすると、#UDエラーが発生します。
レジスタ マッピング (入力と出力)
入力パラメーターの渡しに使用されていないレジスタを使用して、出力を返すことができます。 つまり、入力パラメーター ブロックが 112 バイトより小さい場合 (最も近い 16 バイトアラインチャンクに切り上げ)、残りのレジスタはハイパーコール出力を返します。
X64 | 情報提供済み |
---|---|
RDX | 入力ブロックまたは出力ブロック |
R8 | 入力ブロックまたは出力ブロック |
XMM0 | 入力ブロックまたは出力ブロック |
XMM1 | 入力ブロックまたは出力ブロック |
XMM2 | 入力ブロックまたは出力ブロック |
XMM3 | 入力ブロックまたは出力ブロック |
XMM4 | 入力ブロックまたは出力ブロック |
XMM5 | 入力ブロックまたは出力ブロック |
たとえば、入力パラメーター ブロックのサイズが 20 バイトの場合、ハイパーバイザーは次の 12 バイトを無視します。 残りの 80 バイトにはハイパーコール出力が含まれます (該当する場合)。
揮発性レジスタ
ハイパーコールでは、次の条件の下でのみ、指定されたレジスタ値が変更されます。
- RAX (x64) と EDX:EAX (x86) は、ハイパーコール結果値と出力パラメーター (存在する場合) で常に上書きされます。
- Rep ハイパーコールは、RCX (x64) と EDX:EAX (x86) を新しい rep 開始インデックスで変更します。
- HvCallSetVpRegisters は、 そのハイパーコールでサポートされている任意のレジスタを変更できます。
- 高速ハイパーコール入力に使用する場合、RDX、R8、XMM0 から XMM5 は変更されません。 ただし、高速ハイパーコール出力に使用されるレジスタは、RDX、R8、XMM0 から XMM5 まで変更できます。 Hyper-V では、高速ハイパーコール出力に対してのみこれらのレジスタが変更され、x64 に制限されます。
ハイパーコールの制限事項
ハイパーコールには、目的の機能を実行するための制限が関連付けられている場合があります。 すべての制限が満たされていない場合、ハイパーコールは適切なエラーで終了します。 該当する場合は、次の制限事項が一覧表示されます。
- 呼び出し元パーティションには特定の特権が必要です
- 処理されるパーティションは、特定の状態である必要があります (例: "Active")
Hypercall 状態コード
各ハイパーコールは、複数のフィールドを含む出力値を返すものとして文書化されています。 状態値フィールド (種類 HV_STATUS
) は、呼び出しが成功したか失敗したかを示すために使用されます。
失敗したハイパーコールの出力パラメーターの有効性
特に明記されていない限り、ハイパーコールが失敗した場合 (つまり、ハイパーコールの結果値の結果フィールドに値以外 HV_STATUS_SUCCESS
の値が含まれる)、すべての出力パラメーターの内容は不確定であり、呼び出し元によって検査されるべきではありません。 ハイパーコールが成功した場合にのみ、すべての適切な出力パラメーターに有効で予期される結果が含まれます。
エラー条件の順序付け
ハイパーバイザーによってエラー状態が検出および報告される順序は未定義です。 つまり、複数のエラーが存在する場合、ハイパーバイザーはレポートするエラー条件を選択する必要があります。 ハイパーバイザーが十分な特権を持たない呼び出し元に情報を明らかにすることを防ぐことを目的として、セキュリティを強化するエラー コードに優先順位を付ける必要があります。 たとえば、状態コード HV_STATUS_ACCESS_DENIED
は、特権に基づいてコンテキストまたは状態情報を純粋に明らかにする状態コードよりも優先される状態コードです。
一般的な Hypercall 状態コード
複数の結果コードはすべてのハイパーコールに共通であるため、ハイパーコールごとに個別に文書化されるわけではありません。 コーディネートは次のとおりです。
status code | エラー状態 |
---|---|
HV_STATUS_SUCCESS |
呼び出しは成功しました。 |
HV_STATUS_INVALID_HYPERCALL_CODE |
ハイパーコール コードが認識されません。 |
HV_STATUS_INVALID_HYPERCALL_INPUT |
担当者数が正しくありません (たとえば、0 以外の担当者数が担当者以外の呼び出しに渡されるか、0 個の担当者数が担当者の呼び出しに渡されます)。 |
担当者の開始インデックスは、担当者数より小さい値ではありません。 | |
指定したハイパーコール入力値の予約ビットが 0 以外です。 | |
HV_STATUS_INVALID_ALIGNMENT |
指定された入力または出力 GPA ポインターが 8 バイトにアラインされていません。 |
指定された入力パラメーターまたは出力パラメーター リストは、ページにまたがっています。 | |
入力または出力の GPA ポインターが GPA 空間の境界内にありません。 |
戻りコード HV_STATUS_SUCCESS
は、エラー条件が検出されなかったことを示します。
ゲスト OS ID の報告
パーティション内で実行されているゲスト OS は、ハイパー呼び出しを呼び出す前に、その署名とバージョンを MSR (HV_X64_MSR_GUEST_OS_ID
) に書き込んでハイパーバイザーに対して自身を識別する必要があります。 この MSR はパーティション全体で、すべての仮想プロセッサ間で共有されます。
このレジスタの値は、最初は 0 です。 ハイパーコール コード ページを有効にする前に、0 以外の値をゲスト OS ID MSR に書き込む必要があります (ハイパー コール インターフェイスの確立を参照)。 その後、このレジスタがゼロになった場合、ハイパーコール コード ページは無効になります。
#define HV_X64_MSR_GUEST_OS_ID 0x40000000
独自のオペレーティング システムのゲスト OS ID
この MSR に推奨されるエンコードを次に示します。 一部のフィールドは、一部のゲスト OS には適用されない場合があります。
Bits | フィールド | 説明 |
---|---|---|
15:0 | ビルド番号 | OS のビルド番号を示します |
23:16 | サービス のバージョン | サービスのバージョン ("service pack" 番号など) を示します。 |
31:24 | マイナー バージョン | OS のマイナー バージョンを示します |
39:32 | メジャー バージョン | OS のメジャー バージョンを示します |
47:40 | OS ID | OS バリアントを示します。 エンコードはベンダーに固有です。 Microsoft オペレーティング システムは、0=Undefined、1=MS-DOS®、2=Windows ® 3.x、3=Windows ® 9x、4=Windows ® NT (および派生物)、5=Windows ® CE としてエンコードされます。 |
62:48 | ベンダ ID | ゲスト OS ベンダーを示します。 値 0 は予約されています。 以下のベンダーの一覧を参照してください。 |
63 | OS の種類 | OS の種類を示します。 値 0 は、独自のクローズド ソース OS を示します。 値 1 は、オープンソース OS を示します。 |
ベンダーの値は、Microsoft によって割り当てられます。 新しいベンダーを要求するには、GitHub仮想化ドキュメント リポジトリ (https://aka.ms/VirtualizationDocumentationIssuesTLFS) に問題を提出してください。
ベンダー | 値 |
---|---|
Microsoft | 0x0001 |
HPE | 0x0002 |
LANCOM | 0x0200 |
オープン ソース オペレーティング システムのゲスト OS ID MSR
この仕様に準拠しようとしているオペレーティング システム ベンダーオープンソースガイダンスとして、次のエンコードが提供されます。 オペレーティング システムオープンソース次の規則を適用することをお勧めします。
Bits | フィールド | 説明 |
---|---|---|
15:0 | ビルド番号 | 追加情報 |
47:16 | Version | アップストリーム カーネルのバージョン情報。 |
55:48 | OS ID | その他のベンダー情報 |
62:56 | OS の種類 | OS の種類 (Linux、FreeBSD など)。 以下の既知の OS の種類の一覧を参照してください |
63 | オープン ソース | 値 1 は、オープンソース OS を示します。 |
OS の種類の値は、Microsoft によって割り当てられます。 新しい OS の種類を要求するには、GitHub仮想化ドキュメント リポジトリ (https://aka.ms/VirtualizationDocumentationIssuesTLFS) に問題を提出してください。
OS の種類 | 値 |
---|---|
Linux | 0x1 |
FreeBSD | 0x2 |
Xen | 0x3 |
Illumos | 0x4 |
Hypercall インターフェイスの確立
ハイパーコールは、特別なオペコードを使用して呼び出されます。 このオペコードは仮想化の実装によって異なるため、ハイパーバイザーがこの違いを抽象化する必要があります。 これは、特殊なハイパーコール ページを介して行われます。 このページはハイパーバイザーによって提供され、ゲストの GPA 空間内に表示されます。 ゲストは、ゲスト Hypercall MSR をプログラミングしてページの場所を指定する必要があります。
#define HV_X64_MSR_HYPERCALL 0x40000001
Bits | 説明 | 属性 |
---|---|---|
63:12 | ハイパーコール GPFN - ハイパーコール ページのゲスト物理ページ番号を示します | 読み取り/書き込み |
11:2 | RsvdP。 読み取りではビットを無視し、書き込み時には保持する必要があります。 | 予約済み |
1 | ロック。 MSR が不変かどうかを示します。 設定した場合、この MSR はロックされているため、ハイパーコール ページの再配置が防止されます。 設定すると、システム リセットのみがビットをクリアできます。 | 読み取り/書き込み |
0 | [ハイパーコールの有効化] ページ | 読み取り/書き込み |
ハイパーコール ページは、ゲストの GPA 領域内の任意の場所に配置できますが、ページアラインされている必要があります。 ゲストが GPA 領域の境界を超えてハイパーコール ページを移動しようとすると、MSR の書き込み時に#GPエラーが発生します。
この MSR はパーティション全体の MSR です。 つまり、パーティション内のすべての仮想プロセッサによって共有されます。 ある仮想プロセッサが MSR に正常に書き込まれると、別の仮想プロセッサが同じ値を読み取ります。
ハイパーコール ページを有効にする前に、ゲスト OS はバージョン署名を別の MSR (HV_X64_MSR_GUEST_OS_ID) に書き込んで ID を報告する必要があります。 ゲスト OS ID が指定されていない場合、ハイパーコールを有効にしようとすると失敗します。 イネーブル ビットは、書き込まれた場合でも 0 のままです。 さらに、ハイパーコール ページが有効になった後にゲスト OS ID が 0 にクリアされると、無効になります。
ハイパーコール ページは、GPA 空間への "オーバーレイ" として表示されます。つまり、GPA 範囲にマップされている他の何でもカバーします。 その内容は、ゲストが読み取り可能で実行可能です。 ハイパーコール ページに書き込もうとすると、保護 (#GP) 例外が発生します。 ハイパーコール ページが有効になった後、ハイパーコールを呼び出すと、ページの先頭への呼び出しが必要になります。
ハイパーコール ページの確立に関連する手順の詳細な一覧を次に示します。
- ゲストは CPUID リーフ 1 を読み取り、レジスタ ECX のビット 31 をチェックしてハイパーバイザーが存在するかどうかを判断します。
- ゲストは CPUID リーフ 0x40000000を読み取り、ハイパーバイザー CPUID リーフの最大数 (レジスタ EAX で返される) と CPUID リーフ 0x40000001を決定して、インターフェイス署名 (レジスタ EAX で返されます) を決定します。 リーフの最大値が少なくとも0x40000005であり、インターフェイスシグネチャが "Hv#1" と等しいことを確認します。 このシグネチャは、それが
HV_X64_MSR_GUEST_OS_ID
意味し、HV_X64_MSR_HYPERCALL
HV_X64_MSR_VP_INDEX
実装されます。 - そのレジスタが 0 の場合、ゲストは OS ID を MSR
HV_X64_MSR_GUEST_OS_ID
に書き込みます。 - ゲストは Hypercall MSR (
HV_X64_MSR_HYPERCALL
) を読み取ります。 - ゲストは、[ハイパーコール ページの有効化] ビットを確認します。 設定されている場合、インターフェイスは既にアクティブであり、手順 6 と 7 は省略する必要があります。
- ゲストは、GPA 領域内のページ (RAM、MMIO などによって占有されていないページ) を見つけます。 ページが占有されている場合、ゲストは他の目的で基になるページを使用しないようにする必要があります。
- ゲストは、手順 6. の GPA を含む Hypercall MSR (
HV_X64_MSR_HYPERCALL
) に新しい値を書き込み、インターフェイスを有効にするために [ハイパーコール ページの有効化] ビットを設定します。 - ゲストは、ハイパーコール ページ GPA への実行可能 VA マッピングを作成します。
- ゲストは CPUID リーフ 0x40000003を調べて、使用可能なハイパーバイザー機能を決定します。 インターフェイスが確立されると、ゲストはハイパーコールを開始できます。 これを行うには、ハイパーコール プロトコルごとにレジスタを設定し、ハイパーコール ページの先頭に CALL を発行します。 ゲストは、ハイパーコール ページが呼び出し元に戻る近いリターン (0xC3) と同等の処理を実行することを想定する必要があります。 そのため、ハイパーコールは有効なスタックで呼び出す必要があります。
拡張ハイパーコール インターフェイス
0x8000以上の呼び出しコードを持つハイパーコールは、拡張ハイパーコールと呼ばれます。 拡張ハイパーコールは、通常のハイパーコールと同じ呼び出し規則を使用し、ゲスト VM の観点からは同じように表示されます。 拡張ハイパーコールは、Hyper-V ハイパーバイザー内で内部的に異なる方法で処理されます。
拡張ハイパーコール機能は、 HvExtCallQueryCapabilities を使用して照会できます。