Partilhar via


Temporizadores

O hipervisor fornece serviços de temporização simples. Estes são baseados em uma fonte de tempo de referência de taxa constante (normalmente o temporizador ACPI em sistemas x64).

São prestados os seguintes serviços de temporizador:

  • Um contador de tempo de referência por partição.
  • Quatro temporizadores sintéticos por processador virtual. Cada temporizador sintético é um temporizador de disparo único ou periódico que entrega uma mensagem ou afirma uma interrupção quando ela expira.
  • Um temporizador APIC virtual por processador virtual.
  • Uma iluminação de tempo de referência de partição, baseada no suporte da plataforma host para um contador de carimbo de data/hora invariante (iTSC).

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 acessos sucessivos a ele retornam valores (tempo) estritamente monotonicamente crescentes como visto por todo e qualquer processador virtual de uma partição. Além disso, o contador de referência é constante e não é afetado por transições de velocidade do 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 na 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 enquanto pelo menos um processador virtual não estiver explicitamente suspenso.

Registo de Contador de Referência de Partição

Em plataformas x64

Em plataformas x64, o contador de referência de uma partição pode ser acedido através de um MSR a nível de partição.

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

Nas plataformas ARM64

Nas plataformas ARM64, o contador de referência de uma partição é acedido através do registo sintético HvRegisterTimeRefCount usando as hiperchamadas HvCallGetVpRegisters e HvCallSetVpRegisters.

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

Comportamento dos registos

Quando uma partição é criada, o valor do registo contador de referência é definido para 0x0000000000000000. Esse valor não pode ser modificado por um processador virtual. Em plataformas x64, qualquer tentativa de escrever no MSR resulta numa falha #GP. Nas plataformas ARM64, as tentativas de escrita via registos HvCallSetVpRegisters retornam HV_STATUS_INVALID_PARAMETER.

Iluminação do Tempo de Referência da Partição

A iluminação do tempo de referência da partição apresenta uma fonte de tempo de referência para uma partição que não requer uma intercetação no hipervisor. Essa iluminação está disponível somente quando a plataforma subjacente fornece suporte a um processador invariante Time Stamp Counter (TSC), ou iTSC. Em tais plataformas, a freqüência TSC do processador permanece constante, independentemente das mudanças na freqüência de clock do processador devido ao uso de estados de gerenciamento de energia, como estados de desempenho do processador ACPI, estados de repouso ocioso do processador (estados C ACPI), etc.

A iluminação do tempo de referência da partição usa um valor TSC virtual, um deslocamento e um multiplicador para permitir que uma partição convidada calcule 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 convidada calcule atomicamente o tempo de referência quando a partição convidada é migrada para uma plataforma com uma taxa TSC diferente, e fornece um mecanismo de fallback para suportar a migração para plataformas sem o recurso TSC de taxa constante.

Este recurso não se destina a ser usado como uma fonte de tempo de relógio de parede, uma vez que o tempo de referência calculado usando este recurso 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 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;

Registo de Página do Contador de Carimbo de Hora de Referência (TSC)

Um convidado que deseje aceder à sua página TSC de referência deve usar um registo sintético. Uma partição que possui o privilégio AccessPartitionReferenceTsc pode aceder ao registo.

Em plataformas x64

Nas plataformas x64, a página de referência do TSC é acedida através de um MSR.

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

Nas plataformas ARM64, a página TSC de referência é acedida através do registo sintético HvRegisterReferenceTsc usando as hiperchamadas HvCallGetVpRegisters e HvCallSetVpRegisters.

Nome do Registo Description
HvRegisterReferenceTsc Página TSC de referência
Disposição dos registos
Bits Description Attributes
63:12 Número de página GPA Ler / Escrever
11:1 RsvdP (valor deve ser preservado) Ler / Escrever
0 Enable Ler / Escrever

No momento da criação da partição convidada, o valor da referência TSC MSR é 0x0000000000000000. Assim, a página TSC de referência está desativada 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 registo, os hóspedes 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 é calculado pela seguinte fórmula:

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

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

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

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

O código recomendado para calcular o tempo de referência da partição usando essa iluminação é 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. Ambos os temporizadores one-shot e periódicos são suportados. Um temporizador sintético envia uma mensagem para um SynIC SINTx especificado (fonte de interrupção sintética) após a expiração ou afirma uma interrupção, dependendo de como ele está configurado.

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 podem ser atrasadas. Um processador virtual pode estar indisponível porque está suspenso (por exemplo, durante o tratamento de intercetaçã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 temporizador completo pode ser perdido. Neste caso, o hipervisor usa uma das duas técnicas.

A primeira técnica envolve a modulação do período do temporizador, na verdade, encurtando o período até que o temporizador "recupere". Se um número significativo de sinais de temporizador foram perdidos, o hipervisor pode ser incapaz de compensar usando a modulação de período. Neste caso, alguns sinais de expiração do temporizador podem ser ignorados completamente.

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

Ordenação de expirações do temporizador

Os temporizadores sintéticos e virtualizados geram interrupções no tempo de expiração designado ou próximo dele. Devido ao hardware e outras interações de agendamento, as interrupções podem ser atrasadas. Nenhuma encomenda 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 para o 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 é afirmado após a expiração do temporizador.

Registos temporizadores sintéticos

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

Em plataformas x64

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

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

Nas plataformas ARM64

Nas plataformas ARM64, os temporizadores sintéticos são acedidos através de registos sintéticos usando as hiperchamadas HvCallGetVpRegisters e HvCallSetVpRegisters.

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

Nota: No ARM64, os temporizadores sintéticos são opcionais porque o Temporizador Genérico ARM (GIT) pode ser usado diretamente sem incorrer em sobrecarga de virtualização. Os sistemas operativos convidados devem preferir usar o temporizador genérico arquitetónico para melhor desempenho.

Disposição dos registos

Registro de configuração do temporizador sintético
Bits Description Attributes
63:20 RsvdZ (o valor deve ser definido como zero) Ler / Escrever
19:16 SINTx - fonte de interrupção sintética Ler / Escrever
15:13 RsvdZ (o valor deve ser definido como zero) Ler / Escrever
12 Modo Direto - Afirma e interrompe após a expiração do temporizador. Ler / Escrever
11:4 ApicVector - Controla o vetor de interrupção declarado no modo direto Ler / Escrever
3 AutoEnable - Defina se escrever o contador correspondente implicitamente faz com que o temporizador seja ativado Ler / Escrever
2 Preguiçoso - Defina se o temporizador é preguiçoso Ler / Escrever
1 Periódico - Defina se o temporizador é periódico Ler / Escrever
0 Ativado - definido se o temporizador estiver ativado Ler / Escrever

Quando um processador virtual é criado e reiniciado, o valor de todos os registos sintéticos de configuração do temporizador (HV_X64_MSR_STIMER0_CONFIG a HV_X64_MSR_STIMER3_CONFIG) é definido para 0x0000000000000000. Assim, todos os temporizadores sintéticos são desativados 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, Enable deve ser definido depois de escrever o registro de contagem correspondente, a fim de ativar o contador. Para obter informações sobre o registro de contagem, consulte a seção a seguir.

Quando um temporizador one-shot expira, ele é automaticamente marcado como desativado. Os temporizadores periódicos permanecem ativados até serem explicitamente desativados.

Se uma captura única estiver ativada e a contagem especificada estiver no passado, ela expirará imediatamente.

Não é permitido definir o campo SINTx como zero para um temporizador ativado (que não está no modo direto). Se tentado, o temporizador será marcado como desativado (ou seja, o 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, a mera alteração de um temporizador de one-shot para periódico pode não produzir o pretendido. Os temporizadores devem ser sempre desativados antes de alterar quaisquer outras propriedades.

Registo de Contagem de Temporizadores Sintéticos
Bits Description Attributes
63:0 Contagem — tempo de expiração para temporizadores one-shot, duração para temporizadores periódicos Ler / Escrever

O valor programado no registo Count é um valor de tempo medido em unidades de 100 nanossegundos. Gravar o valor zero no registro Count irá parar o contador, desativando assim o temporizador, independentemente da configuração de AutoEnable no registro de configuração.

Observe que o registro de contagem tem permissão para ser encapsulado. O encapsulamento não terá efeito sobre o comportamento do temporizador, independentemente de qualquer propriedade do temporizador.

Para temporizadores one-shot, representa o tempo de expiração absoluto do temporizador. O temporizador expira quando o contador de referência para a partição é igual ou maior do 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á ativado.

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 a definição da carga útil da mensagem.

Registos temporizadores sintéticos Time-Unhalted

Registos sintéticos Time-Unhalted Timer estão disponíveis em plataformas x64 se uma partição tiver o privilégio AccessSyntheticTimerRegs. A disponibilidade é indicada pelo bit EDX 23 no 0x40000003 folha CPUID de Identificação de Funcionalidades do Hipervisor. Esta funcionalidade não está disponível nas plataformas ARM64.

O software convidado pode programar o temporizador sintético sem interrupção para gerar uma interrupção periódica após a execução por um período de tempo especificado em unidades de 100ns. Quando a interrupção for acionada, o campo SyntheticTimeUnhaltedTimerExpired na página VP Assist será definido como TRUE. O software convidado pode redefinir este campo para FALSE. Ao contrário dos contadores de desempenho arquitetônico, o temporizador sintético nunca é redefinido pelo hipervisor e é executado continuamente entre interrupções. Se o campo Vetorial estiver definido para 2 (o vetor x64 NMI), o temporizador entrega uma Interrupção Não Mascarável; caso contrário, entrega uma interrupção fixa usando o vetor especificado.

Ao contrário dos temporizadores sintéticos normais que acumulam tempo quando o hóspede parou (ou seja: ficou ocioso), o temporizador de Time-Unhalted sintético acumula tempo apenas enquanto o hóspede não está parado.

Em plataformas x64

Nas plataformas x64, o temporizador sintético sem parar é acedido através de MSRs usando as instruções RDMSR e WRMSR.

Endereço MSR Nome do Registo Description
0x40000114 HV_X64_MSR_STIME_UNHALTED_TIMER_CONFIG Configuração do Temporizador Time-Unhalted Sintético
0x40000115 HV_X64_MSR_STIME_UNHALTED_TIMER_COUNT Contagem de Temporizadores de Time-Unhalted Sintéticos

Disposição dos registos

Registo de Configuração do Temporizador Time-Unhalted Sintético
Bits Description Attributes
63:9 RsvdZ (o valor deve ser definido como zero) Ler / Escrever
8 Ativado(a) Ler / Escrever
7:0 Vector Ler / Escrever

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

Registo sintético de contagem de temporizadores Time-Unhalted
Bits Description Attributes
63:0 Taxa periódica de interrupções em unidades de 100 ns Ler / Escrever