Compartilhar via


Temporizadores

O hipervisor fornece serviços de tempo simples. Elas se baseiam em uma fonte de tempo de referência de taxa constante (normalmente o temporizador ACPI em sistemas x64).

Os seguintes serviços de temporizador são fornecidos:

  • Um contador de tempo de referência por partição.
  • Quatro temporizadores sintéticos por processador virtual. Cada temporizador sintético é um temporizador periódico ou de tiro único que entrega uma mensagem ou declara uma interrupção quando ela expira.
  • Um temporizador APIC virtual por processador virtual.
  • Uma iluminação de tempo de referência de partição, com base no suporte da plataforma de host para um iTSC (Contador de Carimbo de Data/Hora Invariável).

Contador de Referência

O hipervisor mantém um contador de tempo de referência por partição. Ele tem a característica de que os acessos sucessivos a ele retornam valores estritamente monotonicamente crescentes (tempo), como visto por todos os processadores virtuais de uma partição. Além disso, o contador de referência é constante de taxa e não afetado por transições de velocidade de processador ou barramento ou estados profundos de economia de energia do processador. O contador de tempo de referência de uma partição é inicializado como zero quando a partição é criada. O contador de referência para todas as partições conta com a mesma taxa, mas a qualquer momento, seus valores absolutos normalmente serão diferentes porque as partições terão tempos de criação diferentes.

O contador de referência continua a contar até que pelo menos um processador virtual não seja suspenso explicitamente.

Registro do Contador de Referência de Partição

Em plataformas x64

Em plataformas x64, o contador de referência de uma partição pode ser acessado por meio de uma MSR em toda a partição.

Endereço MSR Nome do Registro Description
0x40000020 HV_X64_MSR_TIME_REF_COUNT Contagem de referência de tempo (em toda a partição)

Em plataformas ARM64

Nas plataformas ARM64, o contador de referência de uma partição é acessado por meio do registro sintético HvRegisterTimeRefCount usando as hiperchamadas HvCallGetVpRegisters e HvCallSetVpRegisters.

Nome do Registro Description
HvRegisterTimeRefCount Contagem de referência de tempo (em toda a partição)

Comportamento de registro

Quando uma partição é criada, o valor do registro do contador de referência é definido como 0x0000000000000000. Esse valor não pode ser modificado por um processador virtual. Em plataformas x64, qualquer tentativa de gravação no MSR resulta em uma falha de #GP. Em plataformas ARM64, as tentativas de gravação por meio de HvCallSetVpRegisters retornam HV_STATUS_INVALID_PARAMETER.

Iluminação do tempo de referência de partição

O esclarecimento de tempo de referência de partição apresenta uma fonte de tempo de referência para uma partição que não requer uma interceptação no hipervisor. Essa iluminação só está disponível quando a plataforma subjacente oferece suporte a um TSC (Contador de Carimbo de Data/Hora) do processador invariável ou iTSC. Nessas plataformas, a frequência TSC do processador permanece constante, independentemente das alterações na frequência do relógio do processador devido ao uso de estados de gerenciamento de energia, como estados de desempenho do processador ACPI, estados de suspensão ociosos do processador (estados CPI de ACPI), etc.

A iluminação de tempo de referência de partição usa um valor TSC virtual, um deslocamento e um multiplicador para habilitar uma partição de convidado para calcular o tempo de referência normalizado desde a criação da partição, em unidades de 100nS. O mecanismo também permite que uma partição de convidado compute atomicamente o tempo de referência quando a partição de convidado é migrada para uma plataforma com uma taxa TSC diferente e fornece um mecanismo de fallback para dar suporte à migração para plataformas sem o recurso TSC de taxa constante.

Essa instalação não se destina a ser usada como uma fonte de tempo de relógio de parede, pois o tempo de referência computado usando essa instalação parecerá parar durante o tempo em que uma partição de convidado é salva até a restauração subsequente.

Página do contador de carimbo de data/hora de referência de partição

O hipervisor fornece uma página TSC de referência virtual em toda a partição que é sobreposta no espaço GPA da partição. A página do contador de carimbo de data/hora de referência de uma partição é acessada por meio do MSR TSC de referência.

A página TSC de referência é definida usando a seguinte estrutura:

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

Registro de página do TSC (Contador de Carimbo de Data/Hora de Referência)

Um convidado que deseja acessar sua página TSC de referência deve usar um registro sintético. Uma partição que possui o privilégio AccessPartitionReferenceTsc pode acessar o registro.

Em plataformas x64

Em plataformas x64, a página TSC de referência é acessada por meio de um MSR.

Endereço MSR Nome do Registro Description
0x40000021 HV_X64_MSR_REFERENCE_TSC Página TSC de referência
Em plataformas ARM64

Nas plataformas ARM64, a página TSC de referência é acessada por meio do registro sintético HvRegisterReferenceTsc usando as hiperchamadas HvCallGetVpRegisters e HvCallSetVpRegisters.

Nome do Registro Description
HvRegisterReferenceTsc Página TSC de referência
Registrar Layout
Bits Description Attributes
63:12 Número da página GPA Leitura/gravação
11:1 RsvdP (o valor deve ser preservado) Leitura/gravação
0 Enable Leitura/gravação

No momento da criação da partição de convidado, o valor do MSR TSC de referência é 0x0000000000000000. Assim, a página TSC de referência é desabilitada por padrão. O convidado deve habilitar a página TSC de referência definindo o bit 0. Se o endereço base especificado estiver além do final do espaço GPA da partição, a página TSC de referência não estará acessível ao convidado. Ao modificar o registro, os convidados devem preservar o valor dos bits reservados (1 a 11) para compatibilidade futura.

Mecanismo TSC de referência de partição

O tempo de referência da partição é computado pela seguinte fórmula:

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

A multiplicação é uma multiplicação de 64 bits, o que resulta em um número de 128 bits que, em seguida, é deslocado 64 vezes para a direita para obter os 64 bits altos.

O valor de TscScale é usado para ajustar o valor do TSC Virtual em eventos de migração para reduzir as alterações de frequência TSC de uma plataforma para outra.

O valor de TscSequence é usado para sincronizar o acesso ao tempo de referência habilitado se a escala e/ou os campos de deslocamento forem alterados durante a migração ao vivo ou de salvamento. Esse campo serve como um número de sequência incrementado sempre que a escala e/ou os campos de deslocamento são modificados. Um valor especial de 0x0 é usado para indicar que essa instalação não é mais uma fonte confiável de tempo de referência e a VM deve voltar para uma fonte diferente.

O código recomendado para calcular o tempo de referência de partição usando esse esclarecimento é mostrado abaixo:

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;

Temporizadores Sintéticos

Os temporizadores sintéticos fornecem um mecanismo para gerar uma interrupção após algum tempo especificado no futuro. Há suporte para temporizadores de um tiro e periódicos. Um temporizador sintético envia uma mensagem para um SINTx SynIC especificado (fonte de interrupção sintética) após a expiração ou declara uma interrupção, dependendo de como ela é configurada.

O hipervisor garante que um sinal de expiração do temporizador nunca será entregue antes do tempo de expiração. O sinal pode chegar a qualquer momento após o tempo de expiração.

Temporizadores Periódicos

O hipervisor tenta sinalizar temporizadores periódicos regularmente. No entanto, se o processador virtual usado para sinalizar a expiração não estiver disponível, algumas das expirações do temporizador poderão ser atrasadas. Um processador virtual pode estar indisponível porque está suspenso (por exemplo, durante a manipulação de interceptação) ou porque o agendador do hipervisor decidiu que o processador virtual não deve ser agendado em um processador lógico (por exemplo, porque outro processador virtual está usando o processador lógico ou o processador virtual excedeu sua cota).

Se um processador virtual estiver indisponível por um período de tempo suficientemente longo, um período de tempo integral poderá ser perdido. Nesse caso, o hipervisor usa uma das duas técnicas.

A primeira técnica envolve a modulação do período do temporizador, reduzindo de fato o período até que o temporizador "pegue". Se um número significativo de sinais de temporizador tiver sido perdido, o hipervisor poderá ser incapaz de compensar usando a modulação de período. Nesse caso, alguns sinais de expiração de temporizador podem ser ignorados completamente.

Para temporizadores marcados como lentos, o hipervisor usa uma segunda técnica para lidar com a situação em que um processador virtual fica indisponível por um longo período de tempo. Nesse caso, o sinal do temporizador é adiado até que esse processador virtual esteja disponível. Se ele não ficar disponível até pouco antes do próximo temporizador expirar, ele será totalmente ignorado.

Ordenação de expirações do temporizador

Temporizadores sintéticos e virtualizados geram interrupções em ou perto do tempo de expiração designado. Devido ao hardware e outras interações de agendamento, as interrupções podem ser potencialmente atrasadas. Nenhuma ordenação pode ser assumida entre qualquer conjunto de temporizadores.

Temporizadores Sintéticos Diretos

Os temporizadores sintéticos "diretos" afirmam uma interrupção após a expiração do temporizador em vez de enviar uma mensagem para uma fonte de interrupção sintética SynIc. Um temporizador sintético é definido como modo "direto" definindo o campo "DirectMode" das MSRs de configuração do temporizador sintético. O campo "ApicVector" controla o vetor de interrupção que é declarado após a expiração do temporizador.

Registros de temporizador sintético

Os temporizadores sintéticos são configurados usando registros sintéticos associados a cada processador virtual. Cada um dos quatro temporizadores sintéticos tem um par associado de registros (configuração e contagem).

Em plataformas x64

Em plataformas x64, os temporizadores sintéticos são acessados por meio de MSRs usando as instruções RDMSR e WRMSR.

Endereço MSR Nome do Registro Description
0x400000B0 HV_X64_MSR_STIMER0_CONFIG Registro de configuração para o temporizador sintético 0.
0x400000B1 HV_X64_MSR_STIMER0_COUNT Tempo de expiração ou período para o temporizador sintético 0.
0x400000B2 HV_X64_MSR_STIMER1_CONFIG Registro de configuração para o temporizador sintético 1.
0x400000B3 HV_X64_MSR_STIMER1_COUNT Tempo de expiração ou período para o temporizador sintético 1.
0x400000B4 HV_X64_MSR_STIMER2_CONFIG Registro de configuração para o temporizador sintético 2.
0x400000B5 HV_X64_MSR_STIMER2_COUNT Tempo de expiração ou período para o temporizador sintético 2.
0x400000B6 HV_X64_MSR_STIMER3_CONFIG Registro de configuração para o temporizador sintético 3.
0x400000B7 HV_X64_MSR_STIMER3_COUNT Tempo de expiração ou período para o temporizador sintético 3.

Em plataformas ARM64

Nas plataformas ARM64, os temporizadores sintéticos são acessados por meio de registros sintéticos usando as hiperchamadas HvCallGetVpRegisters e HvCallSetVpRegisters.

Nome do Registro Description
HvRegisterStimer0Config Registro de configuração para o temporizador sintético 0.
HvRegisterStimer0Count Tempo de expiração ou período para o temporizador sintético 0.
HvRegisterStimer1Config Registro de configuração para o temporizador sintético 1.
HvRegisterStimer1Count Tempo de expiração ou período para o temporizador sintético 1.
HvRegisterStimer2Config Registro de configuração para o temporizador sintético 2.
HvRegisterStimer2Count Tempo de expiração ou período para o temporizador sintético 2.
HvRegisterStimer3Config Registro de configuração para o temporizador sintético 3.
HvRegisterStimer3Count Tempo de expiração ou período para o temporizador sintético 3.

Nota: No ARM64, os temporizadores sintéticos são opcionais porque o ARM Generic Timer (GIT) pode ser usado diretamente sem incorrer em sobrecarga de virtualização. Os sistemas operacionais convidados devem preferir usar o temporizador genérico de arquitetura para melhorar o desempenho.

Registrar Layout

Registro de configuração do temporizador sintético
Bits Description Attributes
63:20 RsvdZ (o valor deve ser definido como zero) Leitura/gravação
19:16 SINTx – fonte de interrupção sintética Leitura/gravação
15:13 RsvdZ (o valor deve ser definido como zero) Leitura/gravação
12 Modo Direto – Declarar e interromper após a expiração do temporizador. Leitura/gravação
11:4 ApicVector – Controla o vetor de interrupção declarado no modo direto Leitura/gravação
3 AutoEnable - Definir se gravar o contador correspondente implicitamente faz com que o temporizador seja habilitado Leitura/gravação
2 Lento – Definir se o temporizador é lento Leitura/gravação
1 Periódico – Definir se o temporizador é periódico Leitura/gravação
0 Habilitado – definir se o temporizador está habilitado Leitura/gravação

Quando um processador virtual é criado e redefinido, o valor de todos os registros de configuração de temporizador sintético (HV_X64_MSR_STIMER0_CONFIG por meio de HV_X64_MSR_STIMER3_CONFIG) são definidos como 0x0000000000000000. Assim, todos os temporizadores sintéticos são desabilitados por padrão.

Se AutoEnable estiver definido, gravar um valor diferente de zero no registro de contagem correspondente fará com que Enable seja definido e ative o contador. Caso contrário, Habilitar deve ser definido depois de gravar o registro de contagem correspondente para ativar o contador. Para obter informações sobre o registro de contagem, consulte a seção a seguir.

Quando um temporizador de um tiro expira, ele é marcado automaticamente como desabilitado. Os temporizadores periódicos permanecem habilitados até desabilitados explicitamente.

Se um único tiro estiver habilitado e a contagem especificada estiver no passado, ela expirará imediatamente.

Não é permitido definir o campo SINTx como zero para um temporizador habilitado (que não está no modo direto). Se tentar, o temporizador será marcado como desabilitado (ou seja, bit 0 limpo) imediatamente.

Gravar o registro de configuração de um temporizador que já está habilitado pode resultar em um comportamento indefinido. Por exemplo, apenas alterar um temporizador de um tiro para periódico pode não produzir o que se pretende. Os temporizadores sempre devem ser desabilitados antes de alterar outras propriedades.

Registro de contagem de temporizador sintético
Bits Description Attributes
63:0 Contagem – tempo de expiração para temporizadores de um tiro, duração para temporizadores periódicos Leitura/gravação

O valor programado no registro de contagem é um valor de tempo medido em 100 unidades nanossegundos. Gravar o valor zero no registro de Contagem interromperá o contador, desabilitando o temporizador, independentemente da configuração de AutoEnable no registro de configuração.

Observe que o registro count tem permissão para encapsular. A disposição não terá efeito sobre o comportamento do temporizador, independentemente de qualquer propriedade de temporizador.

Para temporizadores de um tiro, ele representa o tempo de expiração absoluto do temporizador. O temporizador expira quando o contador de referência da partição é igual ou maior que o valor de contagem especificado.

Para temporizadores periódicos, a contagem representa o período do temporizador. O primeiro período começa quando o temporizador sintético está habilitado.

Mensagem de expiração do temporizador sintético

As mensagens de expiração do temporizador são enviadas quando um evento de temporizador é acionado. Consulte o HV_TIMER_MESSAGE_PAYLOAD para obter a definição do conteúdo da mensagem.

Registros de temporizador de Time-Unhalted sintético

Os registros de temporizador de Time-Unhalted sintéticos estarão disponíveis em plataformas x64 se uma partição tiver o privilégio AccessSyntheticTimerRegs. A disponibilidade é indicada pelo EDX bit 23 no 0x40000003 folha CPUID de Identificação de Recursos do Hipervisor. Esse recurso não está disponível em plataformas ARM64.

O software convidado pode programar o tempo não inalado sintético para gerar uma interrupção periódica após a execução por um período especificado em 100ns unidades. Quando a interrupção for disparada, o campo SyntheticTimeUnhaltedTimerExpired na Página de Assistência de VP será definido como TRUE. O software convidado pode redefinir esse campo para FALSE. Ao contrário dos contadores de desempenho de arquitetura, o temporizador sintético nunca é redefinido pelo hipervisor e é executado continuamente entre interrupções. Se o campo Vector estiver definido como 2 (o vetor NMI x64), o temporizador fornecerá uma interrupção não mascarada; caso contrário, ele fornece uma interrupção fixa usando o vetor especificado.

Ao contrário dos temporizadores sintéticos regulares que acumulam tempo quando o convidado foi interrompido (ou seja: ficou ocioso), o Temporizador de Time-Unhalted Sintético acumula tempo somente enquanto o convidado não é interrompido.

Em plataformas x64

Em plataformas x64, o temporizador não inalado sintético é acessado por meio de MSRs usando as instruções RDMSR e WRMSR.

Endereço MSR Nome do Registro Description
0x40000114 HV_X64_MSR_STIME_UNHALTED_TIMER_CONFIG Configuração do temporizador de Time-Unhalted sintético
0x40000115 HV_X64_MSR_STIME_UNHALTED_TIMER_COUNT Contagem de temporizador de Time-Unhalted sintético

Registrar Layout

Registro de configuração do temporizador de Time-Unhalted sintético
Bits Description Attributes
63:9 RsvdZ (o valor deve ser definido como zero) Leitura/gravação
8 Enabled Leitura/gravação
7:0 Vector Leitura/gravação

O campo Vector deve ser 2 (para entregar um NMI) ou um valor ≥ 16 (para entregar uma interrupção fixa). Outros valores são inválidos.

Registro de contagem de temporizador de Time-Unhalted sintético
Bits Description Attributes
63:0 Taxa periódica de interrupções em 100 ns unidades Leitura/gravação