다음을 통해 공유


타이머

하이퍼바이저는 간단한 타이밍 서비스를 제공합니다. 이는 일정한 속도 참조 시간 원본(일반적으로 x64 시스템의 ACPI 타이머)을 기반으로 합니다.

다음 타이머 서비스가 제공됩니다.

  • 파티션별 참조 시간 카운터입니다.
  • 가상 프로세서당 4개의 가상 타이머. 각 가상 타이머는 메시지를 전달하거나 만료 시 인터럽트를 어설션하는 단일 샷 또는 주기적 타이머입니다.
  • 가상 프로세서당 하나의 가상 APIC 타이머.
  • iTSC(고정 타임스탬프를 카운터)에 대한 호스트 플랫폼의 지원을 기반으로 하는 파티션 참조 시간 인식입니다.

참조 카운터

하이퍼바이저는 파티션별 참조 시간 카운터를 유지 관리합니다. 연속 액세스가 파티션의 모든 가상 프로세서에서 볼 수 있듯이 엄격하게 단조적으로 증가하는(시간) 값을 반환하는 특징이 있습니다. 또한 참조 카운터는 속도 상수이며 프로세서 또는 버스 속도 전환 또는 깊은 프로세서 전원 절약 상태의 영향을 받지 않습니다. 파티션이 만들어지면 파티션의 참조 시간 카운터가 0으로 초기화됩니다. 모든 파티션에 대한 참조 카운터는 같은 속도로 계산되지만, 파티션 생성 시간이 다르기 때문에 항상 절대 값이 다릅니다.

하나 이상의 가상 프로세서가 명시적으로 일시 중단되지 않는 한 참조 카운터는 계속 계산됩니다.

파티션 참조 카운터 레지스터

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(Time Stamp Counter) 또는 iTSC를 지원하는 경우에만 사용할 수 있습니다. 이러한 플랫폼에서 프로세서 TSC 주파수는 ACPI 프로세서 성능 상태, 프로세서 유휴 절전 상태(ACPI C-상태) 등과 같은 전원 관리 상태의 사용으로 인해 프로세서의 클록 빈도 변경에 관계없이 일정하게 유지됩니다.

파티션 참조 시간 인식은 가상 TSC 값, 오프셋 및 승수를 사용하여 게스트 파티션이 파티션 생성 이후 정규화된 참조 시간을 100nS 단위로 계산할 수 있도록 합니다. 또한 이 메커니즘을 사용하면 게스트 파티션이 다른 TSC 속도로 플랫폼으로 마이그레이션될 때 참조 시간을 원자성으로 계산할 수 있으며, 일정한 속도 TSC 기능 없이 플랫폼으로의 마이그레이션을 지원하는 대체 메커니즘을 제공합니다.

이 기능을 사용하여 계산된 참조 시간은 후속 복원까지 게스트 파티션이 저장되는 시간 동안 중지되는 것처럼 보이기 때문에 이 기능은 벽시계 시간의 원본으로 사용되지 않습니다.

파티션 참조 타임스탬프를 카운터 페이지

하이퍼바이저는 파티션의 GPA 공간에 오버레이되는 파티션 전체 가상 참조 TSC 페이지를 제공합니다. 파티션의 참조 타임스탬프 카운터 페이지는 참조 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 값은 저장/복원 또는 실시간 마이그레이션 중에 크기 조정 및/또는 오프셋 필드가 변경된 경우 인식된 참조 시간에 대한 액세스를 동기화하는 데 사용됩니다. 이 필드는 배율 및/또는 오프셋 필드가 수정될 때마다 증가하는 시퀀스 번호로 사용됩니다. 0x0 특수 값은 이 기능이 더 이상 신뢰할 수 있는 참조 시간 원본이 아니고 VM이 다른 원본으로 대체되어야 함을 나타내는 데 사용됩니다.

다음 계몽을 사용하여 파티션 참조 시간을 계산하는 데 권장되는 코드는 다음과 같습니다.

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(가상 인터럽트 원본)에 메시지를 보내거나 구성된 방법에 따라 인터럽트를 어설션합니다.

하이퍼바이저는 타이머 만료 신호가 만료 시간 전에 전달되지 않도록 보장합니다. 신호는 만료 시간 이후 언제든지 도착할 수 있습니다.

주기적 타이머

하이퍼바이저는 정기적으로 주기적인 타이머에 신호를 표시하려고 시도합니다. 그러나 만료를 알리는 데 사용되는 가상 프로세서를 사용할 수 없는 경우 일부 타이머 만료가 지연될 수 있습니다. 가상 프로세서가 일시 중단되었거나(예: 인터셉트 처리 중) 하이퍼바이저의 스케줄러가 논리 프로세서에서 가상 프로세서를 예약하지 않기로 결정했기 때문에(예: 다른 가상 프로세서가 논리 프로세서를 사용 중이거나 가상 프로세서가 할당량을 초과했기 때문에) 가상 프로세서를 사용할 수 없습니다.

가상 프로세서를 충분히 오랜 시간 동안 사용할 수 없는 경우 전체 타이머 기간이 누락될 수 있습니다. 이 경우 하이퍼바이저는 두 가지 기술 중 하나를 사용합니다.

첫 번째 기술에는 타이머 기간 변조가 포함되며, 실제로 타이머가 "catch"될 때까지 기간을 단축합니다. 많은 수의 타이머 신호가 누락된 경우 하이퍼바이저가 기간 변조를 사용하여 보정하지 못할 수 있습니다. 이 경우 일부 타이머 만료 신호를 완전히 건너뛸 수 있습니다.

지연으로 표시된 타이머의 경우 하이퍼바이저는 가상 프로세서를 장기간 사용할 수 없는 상황을 처리하기 위해 두 번째 기술을 사용합니다. 이 경우 이 가상 프로세서를 사용할 수 있게 될 때까지 타이머 신호가 지연됩니다. 다음 타이머가 만료되기 직전까지 사용할 수 없으면 완전히 건너뜁히게 됩니다.

타이머 만료 순서 지정

가상 및 가상화된 타이머는 지정된 만료 시간 또는 그 근처에 인터럽트(interrupts)를 생성합니다. 하드웨어 및 기타 일정 조작으로 인해 인터럽트는 잠재적으로 지연될 수 있습니다. 모든 타이머 집합 간에 순서를 가정할 수 없습니다.

직접 가상 타이머

"직접" 가상 타이머는 SynIc 가상 인터럽트 원본에 메시지를 보내는 대신 타이머 만료 시 인터럽트를 어설션합니다. 가상 타이머는 가상 타이머 구성 MSR의 "DirectMode" 필드를 설정하여 "직접" 모드로 설정됩니다. "ApicVector" 필드는 타이머 만료 시 어설션되는 인터럽트 벡터를 제어합니다.

가상 타이머 레지스터

가상 타이머는 각 가상 프로세서와 연결된 가상 레지스터를 사용하여 구성됩니다. 네 개의 가상 타이머 각각에는 연결된 레지스터 쌍(구성 및 개수)이 있습니다.

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이 설정되고 카운터가 활성화됩니다. 그렇지 않으면 카운터를 활성화하기 위해 해당 개수 레지스터를 작성한 후 활성화를 설정해야 합니다. Count 레지스터에 대한 자세한 내용은 다음 섹션을 참조하세요.

원샷 타이머가 만료되면 자동으로 사용 안 함으로 표시됩니다. 주기적 타이머는 명시적으로 사용하지 않도록 설정될 때까지 계속 사용하도록 설정됩니다.

원샷을 사용하도록 설정하고 지정된 개수가 과거인 경우 즉시 만료됩니다.

활성화된 타이머(직접 모드가 아님)에 대해 SINTx 필드를 0으로 설정할 수 없습니다. 시도하면 타이머가 즉시 비활성화된 것으로 표시됩니다(즉, 비트 0이 지워집니다).

이미 사용하도록 설정된 타이머의 구성 레지스터를 작성하면 정의되지 않은 동작이 발생할 수 있습니다. 예를 들어 타이머를 원샷에서 주기적으로 변경하는 것만으로는 의도한 것이 생성되지 않을 수 있습니다. 타이머는 다른 속성을 변경하기 전에 항상 사용하지 않도록 설정해야 합니다.

가상 타이머 수 레지스터
비트 Description Attributes
63:0 개수 - 일회성 타이머의 만료 시간, 주기적 타이머에 대한 기간 읽기/쓰기

Count 레지스터에 프로그래밍된 값은 100나노초 단위로 측정된 시간 값입니다. Count 레지스터에 값 0을 쓰면 카운터가 중지되므로 구성 레지스터에서 AutoEnable 설정과 관계없이 타이머를 사용하지 않도록 설정합니다.

Count 레지스터는 래핑할 수 있습니다. 래핑은 타이머 속성에 관계없이 타이머의 동작에 영향을 주지 않습니다.

원샷 타이머의 경우 절대 타이머 만료 시간을 나타냅니다. 파티션의 참조 카운터가 지정된 개수 값보다 크거나 같으면 타이머가 만료됩니다.

주기적 타이머의 경우 개수는 타이머의 기간을 나타냅니다. 첫 번째 마침표는 가상 타이머를 사용할 때 시작됩니다.

가상 타이머 만료 메시지

타이머 이벤트가 발생하면 타이머 만료 메시지가 전송됩니다. 메시지 페이로드의 정의는 HV_TIMER_MESSAGE_PAYLOAD 참조하세요.

가상 Time-Unhalted 타이머 레지스터

파티션에 AccessSyntheticTimerRegs 권한이 있는 경우 x64 플랫폼에서 가상 Time-Unhalted 타이머 레지스터를 사용할 수 있습니다. 가용성은 하이퍼바이저 기능 식별 CPUID 리프 0x40000003 EDX 비트 23으로 표시됩니다. 이 기능은 ARM64 플랫폼에서 사용할 수 없습니다.

게스트 소프트웨어는 100ns 단위로 지정된 시간 동안 실행한 후 주기적인 인터럽트를 생성하도록 가상 시간 숨기지 않은 타이머를 프로그래밍할 수 있습니다. 인터럽트가 발생하면 VP 지원 페이지의 VirtualTimeUnhaltedTimerExpired 필드가 TRUE로 설정됩니다. 게스트 소프트웨어는 이 필드를 FALSE로 다시 설정할 수 있습니다. 아키텍처 성능 카운터와 달리 가상 타이머는 하이퍼바이저에 의해 다시 설정되지 않으며 인터럽트 간에 지속적으로 실행됩니다. 벡터 필드가 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으로 설정해야 합니다.) 읽기/쓰기
8 활성화됨 읽기/쓰기
7:0 Vector 읽기/쓰기

벡터 필드는 2(NMI를 전달하려면) 또는 값 ≥ 16이어야 합니다(고정 인터럽트를 전달하려면). 다른 값이 잘못되었습니다.

가상 Time-Unhalted 타이머 수 레지스터
비트 Description Attributes
63:0 100 ns 단위의 정기적인 인터럽트 비율 읽기/쓰기