Hypercall 인터페이스
하이퍼바이저는 게스트를 위한 호출 메커니즘을 제공합니다. 이러한 호출을 하이퍼콜이라고 합니다. 각 하이퍼콜은 입력 및/또는 출력 매개 변수 집합을 정의합니다. 이러한 매개 변수는 메모리 기반 데이터 구조 측면에서 지정됩니다. 입력 및 출력 데이터 구조의 모든 요소는 최대 8바이트의 자연 경계에 패딩됩니다(즉, 2바이트 요소는 2바이트 경계에 있어야 합니다).
두 번째 하이퍼콜 호출 규칙은 선택적으로 하이퍼콜의 하위 집합, 특히 입력 매개 변수가 2개 이하이고 출력 매개 변수가 없는 하이퍼콜에 사용할 수 있습니다. 이 호출 규칙을 사용하는 경우 입력 매개 변수는 범용 레지스터에 전달됩니다.
세 번째 하이퍼콜 호출 규칙은 입력 매개 변수 블록이 최대 112바이트인 하이퍼콜의 하위 집합에 선택적으로 사용할 수 있습니다. 이 호출 규칙을 사용하는 경우 입력 매개 변수는 휘발성 XMM 레지스터를 포함하여 레지스터에 전달됩니다.
입력 및 출력 데이터 구조는 둘 다 8바이트 경계의 메모리에 배치되고 크기가 8바이트인 배수로 패딩되어야 합니다. 패딩 영역 내의 값은 하이퍼바이저에서 무시됩니다.
출력의 경우 하이퍼바이저는 패딩 영역을 덮어쓸 수 있지만 보장되지는 않습니다. 패딩 영역을 덮어쓰면 0이 작성됩니다.
Hypercall 클래스
하이퍼콜에는 단순 및 담당자("반복"의 약어)라는 두 가지 클래스가 있습니다. 간단한 하이퍼콜은 단일 작업을 수행하고 고정 크기의 입력 및 출력 매개 변수 집합을 줍니다. 담당자 하이퍼콜은 일련의 간단한 하이퍼콜처럼 작동합니다. 고정 크기 입력 및 출력 매개 변수 집합 외에도 rep 하이퍼콜에는 고정 크기 입력 및/또는 출력 요소 목록이 포함됩니다.
호출자가 처음에 담당자 하이퍼콜을 호출할 때 입력 및/또는 출력 매개 변수 목록의 요소 수를 나타내는 담당자 수를 지정합니다. 또한 호출자는 사용해야 하는 다음 입력 및/또는 출력 요소를 나타내는 담당자 시작 인덱스도 지정합니다. 하이퍼바이저는 목록 순서로, 즉 요소 인덱스 증가를 통해 rep 매개 변수를 처리합니다.
담당자 하이퍼콜의 후속 호출의 경우 담당자 시작 인덱스는 완료된 요소 수와 rep count 값과 함께 남은 요소 수를 나타냅니다. 예를 들어 호출자가 담당자 수를 25로 지정하고 시간 제약 조건 내에서 20개의 반복만 완료된 경우 하이퍼콜은 담당자 시작 인덱스를 20으로 업데이트한 후 호출 가상 프로세서로 다시 제어를 반환합니다. 하이퍼콜이 다시 실행되면 하이퍼바이저는 요소 20에서 다시 시작하고 나머지 5개 요소를 완료합니다.
요소를 처리할 때 오류가 발생하면 담당자 완료 횟수와 함께 적절한 상태 코드가 제공되어 오류가 발생하기 전에 성공적으로 처리된 요소의 수를 나타냅니다. 지정한 하이퍼콜 컨트롤 단어가 유효하고(다음 참조) 입력/출력 매개 변수 목록에 액세스할 수 있다고 가정하면 하이퍼바이저는 하나 이상의 담당자를 시도하도록 보장되지만, 컨트롤을 호출자에게 다시 반환하기 전에 전체 목록을 처리할 필요는 없습니다.
하이퍼콜 연속
하이퍼콜은 많은 주기가 걸리는 복잡한 명령으로 생각할 수 있습니다. 하이퍼바이저는 하이퍼콜을 호출한 가상 프로세서에 컨트롤을 반환하기 전에 하이퍼콜 실행을 50μs 이하로 제한하려고 시도합니다. 일부 하이퍼콜 작업은 충분히 복잡하여 50μs 보증을 만들기가 어렵습니다. 따라서 하이퍼바이저는 모든 담당자 하이퍼콜 양식을 포함하여 일부 하이퍼콜에 대한 하이퍼콜 연속 메커니즘을 사용합니다.
하이퍼콜 연속 메커니즘은 주로 호출자에게 투명합니다. 지정된 시간 제한 내에서 하이퍼콜을 완료할 수 없는 경우 제어가 호출자에게 다시 반환되지만 명령 포인터는 하이퍼콜을 호출한 명령을 지나서 진행되지 않습니다. 이렇게 하면 보류 중인 인터럽트 처리 및 다른 가상 프로세서를 예약할 수 있습니다. 원래 호출 스레드가 실행을 다시 시작하면 하이퍼콜 명령을 다시 실행하고 작업을 완료하는 방향으로 진행합니다.
대부분의 간단한 하이퍼콜은 지정된 시간 제한 내에서 완료되도록 보장됩니다. 그러나 적은 수의 간단한 하이퍼콜에는 더 많은 시간이 필요할 수 있습니다. 이러한 하이퍼콜은 하이퍼콜 담당자와 비슷한 방식으로 하이퍼콜 연속을 사용합니다. 이러한 경우 작업에는 둘 이상의 내부 상태가 포함됩니다. 첫 번째 호출은 개체(예: 파티션 또는 가상 프로세서)를 하나의 상태로 배치하고 반복된 호출 후에 마지막으로 상태가 터미널 상태로 전환됩니다. 이 패턴을 따르는 각 하이퍼콜에 대해 중간 내부 상태의 표시되는 부작용에 대해 설명합니다.
하이퍼콜 원자성 및 순서 지정
언급된 경우를 제외하고 하이퍼콜에서 수행하는 작업은 다른 모든 게스트 작업(예: 게스트 내에서 실행된 명령) 및 시스템에서 실행되는 다른 모든 하이퍼콜과 관련하여 원자성입니다. 간단한 하이퍼콜은 단일 원자성 작업을 수행합니다. rep 하이퍼콜은 독립적인 여러 원자성 작업을 수행합니다.
하이퍼콜 연속을 사용하는 간단한 하이퍼콜에는 외부에 표시되는 여러 내부 상태가 포함될 수 있습니다. 이러한 호출은 여러 원자성 연산으로 구성됩니다.
각 하이퍼콜 작업은 입력 매개 변수 및/또는 쓰기 결과를 읽을 수 있습니다. 각 작업에 대한 입력은 하이퍼콜이 수행된 후 및 작업이 실행되기 전에 언제든지 세분성으로 읽을 수 있습니다. 각 작업과 연결된 결과(즉, 출력 매개 변수)는 작업이 실행된 후 및 하이퍼콜이 반환되기 전에 언제든지 세분성으로 작성될 수 있습니다.
게스트는 실행 중인 하이퍼콜과 관련된 입력 또는 출력 매개 변수의 검사 및/또는 조작을 피해야 합니다. 하이퍼콜을 실행하는 가상 프로세서는 이 작업을 수행할 수 없지만(하이퍼콜이 반환될 때까지 게스트 실행이 일시 중단되기 때문에) 다른 가상 프로세서가 이를 방지할 수 있는 것은 없습니다. 이러한 방식으로 동작하는 게스트는 파티션 내에서 충돌하거나 손상을 일으킬 수 있습니다.
법적 하이퍼콜 환경
하이퍼콜은 가장 권한 있는 게스트 프로세서 모드에서만 호출할 수 있습니다. x64 platfoms에서는 현재 CPL(권한 수준)이 0인 보호 모드를 의미합니다. 실제 모드 코드는 유효 CPL 0으로 실행되지만 실제 모드에서는 하이퍼콜이 허용되지 않습니다. 잘못된 프로세서 모드 내에서 하이퍼콜을 호출하려고 하면 #UD(정의되지 않은 작업) 예외가 생성됩니다.
아키텍처로 정의된 하이퍼콜 인터페이스를 통해 모든 하이퍼콜을 호출해야 합니다(아래 참조). 다른 방법으로 하이퍼콜을 호출하려고 하면(예: 하이퍼콜 코드 페이지에서 대체 위치로 코드를 복사하고 해당 위치에서 실행) 정의되지 않은 작업(#UD) 예외가 발생할 수 있습니다. 하이퍼바이저가 이 예외를 전달하도록 보장되지 않습니다.
맞춤 요구 사항
호출자는 입력 및/또는 출력 매개 변수의 64비트 GPA(게스트 실제 주소)를 지정해야 합니다. GPA 포인터는 8바이트 정렬되어야 합니다. 하이퍼콜에 입력 또는 출력 매개 변수가 없는 경우 하이퍼바이저는 해당 GPA 포인터를 무시합니다.
입력 및 출력 매개 변수 목록은 페이지 경계를 겹치거나 교차할 수 없습니다. 하이퍼콜 입력 및 출력 페이지는 "오버레이" 페이지가 아닌 GPA 페이지여야 합니다. 가상 프로세서가 입력 매개 변수를 오버레이 페이지에 쓰고 이 페이지 내에서 GPA를 지정하는 경우 입력 매개 변수 목록에 대한 하이퍼바이저 액세스가 정의되지 않습니다.
하이퍼바이저는 요청된 하이퍼콜을 실행하기 전에 호출 파티션이 입력 페이지에서 읽을 수 있도록 유효성을 검사합니다. 이 유효성 검사는 지정된 GPA가 매핑되고 GPA가 읽기 가능한 것으로 표시되는 두 가지 검사로 구성됩니다. 이러한 테스트 중 하나가 실패하면 하이퍼바이저는 메모리 절편 메시지를 생성합니다. 출력 매개 변수가 있는 하이퍼콜의 경우 하이퍼바이저는 파티션을 출력 페이지에 쓸 수 있다는 유효성을 검사합니다. 이 유효성 검사는 지정된 GPA가 매핑되고 GPA가 쓰기 가능한 것으로 표시되는 두 가지 검사로 구성됩니다.
하이퍼콜 입력
호출자는 하이퍼콜 입력 값이라는 64비트 값으로 하이퍼콜을 지정합니다. 다음과 같이 형식이 지정됩니다.
필드 | 비트 | 제공된 정보 |
---|---|---|
호출 코드 | 15-0 | 요청되는 하이퍼콜을 지정합니다. |
빠름 | 16 | 하이퍼콜이 레지스터 기반 호출 규칙을 사용하는지 여부를 지정합니다. 0 = 메모리 기반, 1 = 레지스터 기반 |
변수 헤더 크기 | 26-17 | QWORDS의 변수 헤더 크기입니다. |
RsvdZ | 30-27 | 0이어야 합니다. |
중첩됨 | 31 | 중첩된 환경의 L0 하이퍼바이저에서 하이퍼콜을 처리해야 한다고 지정합니다. |
Rep Count | 43-32 | 총 담당자 수(담당자 호출의 경우 0이어야 함) |
RsvdZ | 47-44 | 0이어야 합니다. |
Rep Start 인덱스 | 59-48 | 시작 인덱스(담당자 호출의 경우 0이어야 함) |
RsvdZ | 63-60 | 0이어야 합니다. |
담당자 하이퍼콜의 경우 담당자 수 필드는 총 담당자 수를 나타냅니다. rep start 인덱스는 목록의 시작을 기준으로 특정 반복을 나타냅니다(0은 목록의 첫 번째 요소가 처리됨을 나타냅니다). 따라서 담당자 개수 값은 항상 담당자 시작 인덱스보다 커야 합니다.
빠른 플래그가 0인 경우 하이퍼콜 입력에 대한 매핑을 등록합니다.
X64 | x86 | 제공된 정보 |
---|---|---|
RCX | EDX:EAX | Hypercall 입력 값 |
RDX | EBX:ECX | 입력 매개 변수 GPA |
R8 | EDI:ESI | 출력 매개 변수 GPA |
하이퍼콜 입력 값은 입력 및 출력 매개 변수를 가리키는 GPA와 함께 레지스터에 전달됩니다.
x64에서 레지스터 매핑은 호출자가 32비트(x86) 또는 64비트(x64) 모드에서 실행되는지 여부에 따라 달라집니다. 하이퍼바이저는 EFER 값에 따라 호출자의 모드를 결정합니다. LMA 및 CS.L. 두 플래그가 모두 설정된 경우 호출자는 64비트 호출자로 간주됩니다.
빠른 플래그가 하나인 경우 하이퍼콜 입력에 대한 매핑을 등록합니다.
X64 | x86 | 제공된 정보 |
---|---|---|
RCX | EDX:EAX | Hypercall 입력 값 |
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 요소는 8바이트 정렬되어야 합니다.
XMM 빠른 하이퍼콜 입력
x64 플랫폼에서 하이퍼바이저는 XMM 빠른 하이퍼콜 사용을 지원하므로 일부 하이퍼콜은 두 개 이상의 입력 매개 변수가 필요하더라도 빠른 하이퍼콜 인터페이스의 향상된 성능을 활용할 수 있습니다. XMM 빠른 하이퍼콜 인터페이스는 6개의 XMM 레지스터를 사용하여 호출자가 최대 112바이트 크기의 입력 매개 변수 블록을 전달할 수 있도록 합니다.
XMM 빠른 하이퍼콜 인터페이스의 가용성은 "하이퍼바이저 기능 식별" CPUID 리프(0x40000003)를 통해 표시됩니다.
- 비트 4: XMM 레지스터를 통해 하이퍼콜 입력을 전달하는 지원을 사용할 수 있습니다.
XMM 빠른 출력에 대한 지원을 나타내는 별도의 플래그가 있습니다. 하이퍼바이저가 가용성을 나타내지 않을 때 이 인터페이스를 사용하려고 하면 #UD 오류가 발생합니다.
매핑 등록(입력 전용)
X64 | x86 | 제공된 정보 |
---|---|---|
RCX | EDX:EAX | Hypercall 입력 값 |
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비트 값을 반환합니다. 다음과 같이 형식이 지정됩니다.
필드 | 비트 | 의견 |
---|---|---|
결과 | 15-0 | HV_STATUS 성공 또는 실패를 나타내는 코드 |
Rsvd | 31-16 | 호출자는 이러한 비트의 값을 무시해야 합니다. |
담당자 완료 | 43-32 | 완료된 담당자 수 |
RsvdZ | 63-40 | 호출자는 이러한 비트의 값을 무시해야 합니다. |
담당자 하이퍼콜의 경우 담당자 전체 필드는 완료된 총 담당자 수이며 담당자 시작 인덱스를 기준으로 하지 않습니다. 예를 들어 호출자가 담당자 시작 인덱스 5를 지정하고 담당자 수가 10인 경우 완료가 성공하면 담당자 전체 필드는 10을 나타냅니다.
하이퍼콜 결과 값은 레지스터에서 다시 전달됩니다. 레지스터 매핑은 호출자가 32비트(x86) 또는 64비트(x64) 모드에서 실행되는지 여부에 따라 달라집니다(위 참조). 하이퍼콜 출력에 대한 레지스터 매핑은 다음과 같습니다.
X64 | x86 | 제공된 정보 |
---|---|---|
RAX | EDX:EAX | Hypercall 결과 값 |
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)를 새 담당자 시작 인덱스로 수정합니다.
- HvCallSetVpRegisters는 해당 하이퍼콜에서 지원되는 모든 레지스터를 수정할 수 있습니다.
- 빠른 하이퍼콜 입력에 사용되는 경우 RDX, R8 및 XMM0~XMM5는 수정되지 않은 상태로 유지됩니다. 그러나 XMM5를 통해 RDX, R8 및 XMM0을 포함하여 빠른 하이퍼콜 출력에 사용되는 레지스터를 수정할 수 있습니다. Hyper-V는 x64로 제한되는 빠른 하이퍼콜 출력에 대해서만 이러한 레지스터를 수정합니다.
하이퍼콜 제한
하이퍼콜은 의도한 기능을 수행하기 위해 관련 제한이 있을 수 있습니다. 모든 제한이 충족되지 않으면 하이퍼콜이 적절한 오류로 종료됩니다. 적용되는 경우 다음 제한 사항이 나열됩니다.
- 호출 파티션은 특정 권한을 소유해야 합니다.
- 작업 중인 파티션이 특정 상태여야 합니다(예: "활성").
Hypercall 상태 코드
각 하이퍼콜은 여러 필드가 포함된 출력 값을 반환하는 것으로 문서화됩니다. 상태 값 필드(형식 HV_STATUS
)는 호출이 성공했는지 실패했는지 여부를 나타내는 데 사용됩니다.
실패한 하이퍼콜의 출력 매개 변수 유효성
달리 명시적으로 명시하지 않는 한 하이퍼콜이 실패하면(즉, 하이퍼콜 결과 값의 결과 필드에 이외의 HV_STATUS_SUCCESS
값이 포함됨) 모든 출력 매개 변수의 콘텐츠는 확정되지 않으며 호출자가 검사해서는 안 됩니다. 하이퍼콜이 성공한 경우에만 모든 적절한 출력 매개 변수에 유효한 예상 결과가 포함됩니다.
오류 조건 순서 지정
하이퍼바이저에서 오류 조건을 검색하고 보고하는 순서는 정의되지 않습니다. 즉, 여러 오류가 있는 경우 하이퍼바이저는 보고할 오류 조건을 선택해야 합니다. 더 큰 보안을 제공하는 오류 코드에 우선 순위를 부여해야 합니다. 하이퍼바이저가 충분한 권한이 없는 호출자에게 정보를 노출하지 못하도록 하기 위한 의도입니다. 예를 들어 상태 코드 HV_STATUS_ACCESS_DENIED
는 권한에 따라 일부 컨텍스트 또는 상태 정보를 표시하는 상태 코드보다 기본 설정 상태 코드입니다.
일반적인 하이퍼콜 상태 코드
여러 결과 코드는 모든 하이퍼콜에 공통적이므로 각 하이퍼콜에 대해 개별적으로 문서화되지 않습니다. 여기에는 다음과 같은 옵션이 포함됩니다.
상태 코드 | 오류 조건 |
---|---|
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입니다. 하이퍼콜 코드 페이지를 사용하도록 설정하려면 먼저 게스트 OS ID MSR에 0이 아닌 값을 기록해야 합니다( Hypercall 인터페이스 설정 참조). 이후에 이 레지스터가 0이 되면 하이퍼콜 코드 페이지가 비활성화됩니다.
#define HV_X64_MSR_GUEST_OS_ID 0x40000000
독점 운영 체제에 대한 게스트 OS ID
다음은 이 MSR에 권장되는 인코딩입니다. 일부 필드는 일부 게스트 OS에 적용되지 않을 수 있습니다.
비트 | 필드 | Description |
---|---|---|
15:0 | 빌드 번호 | OS의 빌드 번호를 나타냅니다. |
23:16 | 서비스 버전 | 서비스 버전(예: "서비스 팩" 번호)을 나타냅니다. |
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)에 문제를 제출하세요.
Vendor | 값 |
---|---|
Microsoft | 0x0001 |
HPE | 0x0002 |
LANCOM | 0x0200 |
오픈 소스 운영 체제용 게스트 OS ID MSR
다음 인코딩은 이 사양을 준수하려는 오픈 소스 운영 체제 공급업체에 대한 지침으로 제공됩니다. 오픈 소스 운영 체제는 다음 규칙을 적용하는 것이 좋습니다.
비트 | 필드 | Description |
---|---|---|
15:0 | 빌드 번호 | 추가 정보 |
47:16 | 버전 | 업스트림 커널 버전 정보입니다. |
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 인터페이스 설정
하이퍼콜은 특수 opcode를 사용하여 호출됩니다. 이 opcode는 가상화 구현마다 다르므로 하이퍼바이저에서 이러한 차이를 추상화해야 합니다. 이 작업은 특수 하이퍼콜 페이지를 통해 수행됩니다. 이 페이지는 하이퍼바이저에서 제공되며 게스트의 GPA 공간 내에 표시됩니다. 게스트는 게스트 Hypercall MSR을 프로그래밍하여 페이지의 위치를 지정해야 합니다.
#define HV_X64_MSR_HYPERCALL 0x40000001
비트 | Description | 특성 |
---|---|---|
63:12 | Hypercall 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_VP_INDEX
.HV_X64_MSR_HYPERCALL
- 게스트는 해당 등록이 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 참조하여 사용할 수 있는 하이퍼바이저 기능을 결정합니다. 인터페이스가 설정되면 게스트가 하이퍼콜을 시작할 수 있습니다. 이렇게 하려면 하이퍼콜 프로토콜당 레지스터를 채우고 하이퍼콜 페이지의 시작 부분에 대한 호출을 실행합니다. 게스트는 하이퍼콜 페이지가 호출자에게 반환하기 위해 거의 반환(0xC3)과 동등한 작업을 수행한다고 가정해야 합니다. 따라서 하이퍼콜은 유효한 스택으로 호출되어야 합니다.
확장 하이퍼콜 인터페이스
0x8000 위의 호출 코드가 있는 하이퍼콜을 확장 하이퍼콜이라고 합니다. 확장 하이퍼콜은 일반 하이퍼콜과 동일한 호출 규칙을 사용하며 게스트 VM의 관점에서 동일하게 표시됩니다. 확장 하이퍼콜은 Hyper-V 하이퍼바이저 내에서 내부적으로 다르게 처리됩니다.
확장 하이퍼콜 기능은 HvExtCallQueryCapabilities를 사용하여 쿼리할 수 있습니다.