Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
L'hypervisor fornisce un meccanismo di chiamata per gli utenti guest. Tali chiamate vengono definite chiamate hypercall. Ogni hypercall definisce un set di parametri di input e/o output. Questi parametri vengono specificati in termini di una struttura di dati basata sulla memoria. Tutti gli elementi delle strutture di dati di input e output vengono riempiti in limiti naturali fino a 8 byte (ovvero gli elementi a due byte devono essere su limiti a due byte e così via).
Una seconda convenzione di chiamata hypercall può essere usata facoltativamente per un subset di hypercall, in particolare quelle con due o meno parametri di input e senza parametri di output. Quando si usa questa convenzione di chiamata, i parametri di input vengono passati nei registri per utilizzo generico.
Una terza convenzione di chiamata hypercall può essere usata facoltativamente per un subset di hypercall in cui il blocco di parametri di input è massimo di 112 byte. Quando si usa questa convenzione di chiamata, i parametri di input vengono passati nei registri, inclusi i registri XMM volatili.
Le strutture di dati di input e output devono essere inserite in memoria su un limite di 8 byte e riempite in un multiplo di 8 byte di dimensioni. I valori all'interno delle aree di spaziatura interna vengono ignorati dall'hypervisor.
Per l'output, l'hypervisor è autorizzato a sovrascrivere le aree di riempimento, ma non è garantito. Se sovrascrive le aree di riempimento, scriverà zeri.
Classi Hypercall
Esistono due classi di hypercall: simple e rep (abbreviazione di "repeat"). Una semplice hypercall esegue una singola operazione e ha un set a dimensione fissa di parametri di input e output. Un rep hypercall agisce come una serie di semplici hypercall. Oltre a un set a dimensione fissa di parametri di input e output, le hypercall rep includono un elenco di elementi di input e/o output a dimensione fissa.
Quando un chiamante richiama inizialmente un hypercall rep, specifica un conteggio dei repository che indica il numero di elementi nell'elenco di parametri di input e/o output. I chiamanti specificano anche un indice iniziale del repository che indica l'input e/o l'elemento di output successivo da utilizzare. L'hypervisor elabora i parametri del repository nell'ordine di elenco, ovvero aumentando l'indice degli elementi.
Per le chiamate successive dell'hypercall del repository, l'indice iniziale del repository indica il numero di elementi completati e, in combinazione con il valore del conteggio dei repository, il numero di elementi rimasti. Ad esempio, se un chiamante specifica un numero di rep pari a 25 e solo 20 iterazioni vengono completate entro i vincoli di tempo, l'hypercall restituisce il controllo al processore virtuale chiamante dopo l'aggiornamento dell'indice di avvio del repository a 20. Quando l'hypercall viene eseguito nuovamente, l'hypervisor riprenderà all'elemento 20 e completerà i rimanenti 5 elementi.
Se si verifica un errore durante l'elaborazione di un elemento, viene fornito un codice di stato appropriato insieme a un conteggio completato dei repository, che indica il numero di elementi elaborati correttamente prima che venga rilevato l'errore. Supponendo che la parola di controllo hypercall specificata sia valida (vedere quanto segue) e gli elenchi di parametri di input/output siano accessibili, l'hypervisor è garantito di tentare almeno un repository, ma non è necessario elaborare l'intero elenco prima di restituire il controllo al chiamante.
Continuazione di Hypercall
Un'hypercall può essere considerata come un'istruzione complessa che accetta molti cicli. L'hypervisor tenta di limitare l'esecuzione di hypercall a 50μs o meno prima di restituire il controllo al processore virtuale che ha richiamato l'hypercall. Alcune operazioni di hypercall sono sufficientemente complesse che una garanzia di 50μs è difficile da fare. L'hypervisor si basa quindi su un meccanismo di continuazione hypercall per alcune hypercall, incluse tutte le forme di hypercall rep.
Il meccanismo di continuazione hypercall è per lo più trasparente per il chiamante. Se un'hypercall non è in grado di completare entro il limite di tempo previsto, il controllo viene restituito al chiamante, ma il puntatore all'istruzione non è avanzato oltre l'istruzione che ha richiamato l'hypercall. In questo modo è possibile gestire gli interrupt in sospeso e pianificare altri processori virtuali. Quando il thread chiamante originale riprende l'esecuzione, eseguirà nuovamente l'istruzione hypercall e procederà in avanti per completare l'operazione.
È garantito che la maggior parte delle chiamate hypercall semplici venga completata entro il limite di tempo previsto. Tuttavia, un numero ridotto di chiamate hypercall semplici potrebbe richiedere più tempo. Queste hypercall usano la continuazione hypercall in modo analogo per rep hypercalls. In questi casi, l'operazione prevede due o più stati interni. La prima chiamata inserisce l'oggetto (ad esempio, la partizione o il processore virtuale) in uno stato e, dopo chiamate ripetute, lo stato passa infine a uno stato terminale. Per ogni hypercall che segue questo modello, vengono descritti gli effetti collaterali visibili degli stati interni intermedi.
Atomicità e ordinamento di hypercall
Tranne dove indicato, l'azione eseguita da un hypercall è atomica sia per quanto riguarda tutte le altre operazioni guest (ad esempio, le istruzioni eseguite all'interno di un guest) che tutte le altre hypercall eseguite nel sistema. Una semplice iperchiamata esegue una singola azione atomica; una hypercall rep esegue più azioni atomice indipendenti.
Le chiamate hypercall semplici che usano la continuazione di hypercall possono comportare più stati interni visibili esternamente. Tali chiamate comprendono più operazioni atomiche.
Ogni azione di hypercall può leggere i parametri di input e/o scrivere i risultati. Gli input per ogni azione possono essere letti con qualsiasi granularità e in qualsiasi momento dopo l'esecuzione dell'hypercall e prima dell'esecuzione dell'azione. I risultati, ovvero i parametri di output, associati a ogni azione possono essere scritti in qualsiasi granularità e in qualsiasi momento dopo l'esecuzione dell'azione e prima della restituzione dell'hypercall.
L'ospite deve evitare l'esame e/o la manipolazione di qualsiasi parametro di input o output correlato a un'hypercall in esecuzione. Anche se un processore virtuale che esegue un'hypercall non sarà in grado di farlo (poiché l'esecuzione guest viene sospesa fino a quando non viene restituita l'hypercall), non c'è nulla che impedisca ad altri processori virtuali di farlo. I guest che si comportano in questo modo possono arrestarsi in modo anomalo o causare danneggiamenti all'interno della partizione.
Ambienti hypercall legali
Le chiamate Hypercall possono essere richiamate solo dalla modalità processore guest con privilegi più elevati. Nelle piattaforme x64 questo significa modalità protetta con un livello di privilegio corrente (CPL) pari a zero. Anche se il codice in modalità reale viene eseguito con un CPL effettivo pari a zero, le hypercall non sono consentite in modalità reale. Un tentativo di richiamare un'hypercall all'interno di una modalità processore non valida genererà un'eccezione #UD (operazione non definita) su x64 e un'eccezione di istruzione non definita in ARM64.
Tutte le hypercall devono essere richiamate tramite l'interfaccia hypercall definita dall'architettura (vedere di seguito). Un tentativo di richiamare un'hypercall con qualsiasi altro mezzo (ad esempio, la copia del codice dalla tabella codici hypercall in un percorso alternativo e l'esecuzione da questa posizione) potrebbe comportare un'eccezione non definita (#UD). L'hypervisor non garantisce il recapito di questa eccezione.
Requisiti di allineamento
I chiamanti devono specificare l'indirizzo fisico guest a 64 bit dei parametri di input e/o output. I puntatori gpa devono essere allineati a 8 byte. Se l'hypercall non include parametri di input o output, l'hypervisor ignora il puntatore dell'oggetto Criteri di gruppo corrispondente.
Gli elenchi di parametri di input e output non possono sovrapporsi o superare i limiti di pagina. Le pagine di input e output hypercall devono essere pagine gpa e non pagine "sovrapposte". Se il processore virtuale scrive i parametri di input in una pagina di sovrapposizione e specifica un oggetto Criteri di gruppo all'interno di questa pagina, l'accesso hypervisor all'elenco dei parametri di input non è definito.
L'hypervisor consentirà di verificare che la partizione chiamante possa leggere dalla pagina di input prima di eseguire l'hypercall richiesto. Questa convalida è costituita da due controlli: viene eseguito il mapping dell'oggetto Criteri di gruppo specificato e l'oggetto Criteri di gruppo è contrassegnato come leggibile. Se uno di questi test ha esito negativo, l'hypervisor genera un messaggio di intercettazione della memoria. Per le hypercall con parametri di output, l'hypervisor convaliderà che la partizione possa scrivere nella pagina di output. Questa convalida è costituita da due controlli: viene eseguito il mapping dell'oggetto Criteri di gruppo specificato e l'oggetto Criteri di gruppo è contrassegnato come scrivibile.
Input hypercall
I chiamanti specificano un'hypercall in base a un valore a 64 bit denominato valore di input hypercall. Il formato è il seguente:
| Campo | BITS | Informazioni fornite |
|---|---|---|
| Call Code | 15-0 | Specifica l'hypercall richiesto |
| Veloce | 16 | Specifica se l'hypercall usa la convenzione di chiamata basata su registro: 0 = basata sulla memoria, 1 = basata su registro |
| Dimensioni dell'intestazione variabile | 26-17 | Dimensioni di un'intestazione di variabile, in QWORDS. |
| RsvdZ | 30-27 | Deve essere zero |
| Annidato | 31 | Specifica che l'hypercall deve essere gestito dall'hypervisor L0 in un ambiente annidato. |
| Conteggio rep | 43-32 | Numero totale di rep (per la chiamata del repository, deve essere zero in caso contrario) |
| RsvdZ | 47-44 | Deve essere zero |
| Indice di avvio rep | 59-48 | Indice iniziale (per la chiamata rep, deve essere zero in caso contrario) |
| RsvdZ | 63-60 | Deve essere zero |
Per le hypercall rep, il campo conteggio rep indica il numero totale di rep. L'indice iniziale del repository indica la ripetizione specifica rispetto all'inizio dell'elenco (zero indica che il primo elemento dell'elenco deve essere elaborato). Pertanto, il valore del conteggio dei repository deve essere sempre maggiore dell'indice di inizio del repository.
Convenzioni di registrazione hypercall (x86/x64)
In x86/x64, registrare il mapping per gli input di hypercall quando il flag Fast è zero sono i seguenti:
| x64 | x86 | Informazioni fornite |
|---|---|---|
| RCX | EDX:EAX | Valore di input hypercall |
| RDX | EBX:ECX | Criteri di gruppo dei parametri di input |
| R8 | EDI:ESI | Criteri di gruppo dei parametri di output |
Il valore di input hypercall viene passato nei registri insieme a un oggetto Criteri di gruppo che punta ai parametri di input e output.
I mapping dei registri dipendono dal fatto che il chiamante sia in esecuzione in modalità a 32 bit (x86) o a 64 bit (x64). L'hypervisor determina la modalità del chiamante in base al valore di EFER. LMA e CS.L. Se vengono impostati entrambi questi flag, si presuppone che il chiamante sia un chiamante a 64 bit.
Registrare il mapping per gli input hypercall quando il flag Fast è uno:
| x64 | x86 | Informazioni fornite |
|---|---|---|
| RCX | EDX:EAX | Valore di input hypercall |
| RDX | EBX:ECX | Parametro di input |
| R8 | EDI:ESI | Parametro di output |
Il valore di input hypercall viene passato nei registri insieme ai parametri di input.
Convenzioni di registrazione hypercall (ARM64 SMCCC)
In ARM64, le hypercall vengono eseguite usando l'istruzione "HVC #0". Le chiamate rispettano la convenzione di chiamata SMCCC (SMCCC) ARM64.
Il mapping dei registri per gli input di hypercall è il seguente:
| Register | Informazioni fornite |
|---|---|
| X0 | Identificatore di funzione SMCCC |
| X1 | Valore di input hypercall |
| X2 | Parametro di input |
| X3 | Parametro di output |
L'identificatore di funzione SMCCC in X0 segue questo formato:
| BITS | Campo | Value | Description |
|---|---|---|---|
| 31 | Resa della chiamata | 0 | Sempre 0 |
| 30 | Convenzione di chiamata | 1 | 1 per convenzioni di chiamata HVC64 |
| 29:24 | Tipo di chiamata al servizio | 6 | 6 per chiamate al servizio Hypervisor specifiche del fornitore |
| 23:16 | Riservato | 0 | Riservato, deve essere zero (Res0) |
| 15:0 | Numero funzione | 1 | 1 indica che il codice di chiamata HV è definito in X1 |
Formato completo identificatore funzione: 0x46000001
Convenzioni di registrazione hypercall (ARM64 HVC #1)
Per motivi cronologici, l'interfaccia dell'hypervisor ARM64 supporta anche una convenzione di chiamata diversa. Le hypercall vengono eseguite con l'istruzione "HVC #1". È consigliabile usare la convenzione di chiamata SMCCC per il nuovo codice.
Il mapping dei registri per gli input di hypercall è il seguente:
| Register | Informazioni fornite |
|---|---|
| X0 | Valore di input hypercall |
| X1 | Parametro di input |
| X2 | Parametro di output |
Intestazioni di input Hypercall con dimensioni variabili
La maggior parte delle intestazioni di input hypercall ha dimensioni fisse. La quantità di dati di intestazione passati dal guest all'hypervisor viene quindi specificata in modo implicito dal codice hypercall e non deve essere specificata separatamente. Tuttavia, alcune hypercall richiedono una quantità variabile di dati di intestazione. Queste hypercall in genere hanno un'intestazione di input a dimensione fissa e un input di intestazione aggiuntivo di dimensioni variabili.
Un'intestazione di dimensioni variabili è simile a un input hypercall fisso (allineato a 8 byte e ridimensionato a un multiplo di 8 byte). Il chiamante deve specificare la quantità di dati che fornisce come intestazioni di input. Questa dimensione viene fornita come parte del valore di input hypercall (vedere "Dimensioni intestazione variabile" nella tabella precedente).
Poiché le dimensioni dell'intestazione fissa sono implicite, anziché fornire le dimensioni totali dell'intestazione, nei controlli di input viene fornita solo la parte variabile:
Variable Header Bytes = {Total Header Bytes - sizeof(Fixed Header)} rounded up to nearest multiple of 8
Variable Header Size = Variable Header Bytes / 8
Non è consentito specificare una dimensione di intestazione variabile diversa da zero per una hypercall non documentata in modo esplicito come accettazione di intestazioni di input con dimensioni variabili. In questo caso, l'hypercall genererà un codice restituito di HV_STATUS_INVALID_HYPERCALL_INPUT.
È possibile che per una determinata chiamata di un hypercall che accetti intestazioni di input con dimensioni variabili che tutto l'input dell'intestazione si adatta interamente all'interno dell'intestazione a dimensione fissa. In questi casi, l'intestazione di input con dimensioni variabili è di dimensioni zero e i bit corrispondenti nell'input hypercall devono essere impostati su zero.
In tutti gli altri aspetti, le hypercall che accettano intestazioni di input con dimensioni variabili sono altrimenti simili alle hypercall di intestazione di input a dimensione fissa per quanto riguarda le convenzioni di chiamata. È anche possibile che un'intestazione di dimensioni variabile hypercall supporti anche la semantica dei repository. In tal caso, gli elementi del repository si trovano dopo l'intestazione nel modo consueto, ad eccezione del fatto che le dimensioni totali dell'intestazione includono sia le parti fisse che quelle variabili. Tutte le altre regole rimangono invariate, ad esempio il primo elemento rep deve essere allineato a 8 byte.
Input Hypercall rapido XMM (x86/x64)
Nelle piattaforme x86/x64, l'hypervisor supporta l'uso di hypercall XMM veloci, che consente ad alcune hypercall di sfruttare le prestazioni migliorate dell'interfaccia di hypercall veloce anche se richiedono più di due parametri di input. L'interfaccia hypercall veloce XMM usa sei registri XMM per consentire al chiamante di passare un blocco di parametri di input fino a 112 byte.
La disponibilità dell'interfaccia hypercall veloce XMM è indicata tramite la foglia CPUID "Identificazione funzionalità Hypervisor" (0x40000003):
- Bit 4: è disponibile il supporto per il passaggio dell'input di hypercall tramite registri XMM.
Si noti che è presente un flag separato per indicare il supporto per l'output rapido XMM. Qualsiasi tentativo di usare questa interfaccia quando l'hypervisor non indica la disponibilità genererà un errore #UD.
Registra mapping (solo input)
| x64 | x86 | Informazioni fornite |
|---|---|---|
| RCX | EDX:EAX | Valore di input hypercall |
| RDX | EBX:ECX | Blocco di parametri di input |
| R8 | EDI:ESI | Blocco di parametri di input |
| XMM0 | XMM0 | Blocco di parametri di input |
| XMM1 | XMM1 | Blocco di parametri di input |
| XMM2 | XMM2 | Blocco di parametri di input |
| XMM3 | XMM3 | Blocco di parametri di input |
| XMM4 | XMM4 | Blocco di parametri di input |
| XMM5 | XMM5 | Blocco di parametri di input |
Il valore di input hypercall viene passato nei registri insieme ai parametri di input. I mapping dei registri dipendono dal fatto che il chiamante sia in esecuzione in modalità a 32 bit (x86) o a 64 bit (x64). L'hypervisor determina la modalità del chiamante in base al valore di EFER. LMA e CS.L. Se vengono impostati entrambi questi flag, si presuppone che il chiamante sia un chiamante a 64 bit. Se il blocco di parametri di input è inferiore a 112 byte, tutti i byte aggiuntivi nei registri vengono ignorati.
Registrare l'input di chiamata rapida (ARM64 SMCCC)
Nelle piattaforme ARM64, l'hypervisor supporta l'uso di hypercall veloci di registrazione, che consente ad alcune hypercall di sfruttare le prestazioni migliorate dell'interfaccia hypercall veloce anche se richiedono più di due parametri di input. L'interfaccia register fast hypercall usa 15 registri per utilizzo generico per consentire al chiamante di passare un blocco di parametri di input fino a 120 byte.
Registra mapping (solo input)
| Register | Informazioni fornite |
|---|---|
| X0 | Identificatore di funzione SMCCC |
| X1 | Valore di input hypercall |
| X2 - X17 | Blocco di parametri di input |
Se il blocco di parametri di input è inferiore a 120 byte, tutti i byte aggiuntivi nei registri vengono ignorati.
Registrare l'input di chiamata rapida (ARM64 HVC #1)
L'interfaccia register fast hypercall usa sedici registri per utilizzo generico per consentire al chiamante di passare un blocco di parametri di input fino a 128 byte di dimensioni.
Registra mapping (solo input)
| Register | Informazioni fornite |
|---|---|
| X0 | Valore di input hypercall |
| X1 - X17 | Blocco di parametri di input |
Se il blocco di parametri di input è inferiore a 128 byte, tutti i byte aggiuntivi nei registri vengono ignorati.
Output di Hypercall
Tutte le hypercall restituiscono un valore a 64 bit denominato valore del risultato di hypercall. Il formato è il seguente:
| Campo | BITS | Comment |
|---|---|---|
| Result | 15-0 |
HV_STATUS codice che indica l'esito positivo o negativo |
| Rsvd | 31-16 | I chiamanti devono ignorare il valore in questi bit |
| Rep completate | 43-32 | Numero di rep completati |
| RsvdZ | 63-40 | I chiamanti devono ignorare il valore in questi bit |
Per le hypercall rep, il campo reps complete è il numero totale di rep completati e non relativo all'indice iniziale del repository. Ad esempio, se il chiamante ha specificato un indice iniziale del repository pari a 5 e un numero di rep pari a 10, il campo di completamento dei repository indica 10 al completamento corretto.
Il valore del risultato dell'hypercall viene passato nuovamente nei registri.
In x64, il mapping dei registri dipende dal fatto che il chiamante sia in esecuzione in modalità a 32 bit (x86) o a 64 bit (x64) (vedere sopra). Il mapping dei registri per gli output di hypercall è il seguente:
| x64 | x86 | Informazioni fornite |
|---|---|---|
| RAX | EDX:EAX | Valore risultato Hypercall |
In ARM64 il mapping dei registri per gli output di hypercall è il seguente:
| Register | Informazioni fornite |
|---|---|
| X0 | Valore risultato Hypercall |
Output hypercall rapido XMM (x86/x64)
Analogamente al modo in cui l'hypervisor supporta gli input hypercall veloci XMM, è possibile condividere gli stessi registri per restituire l'output. Questa funzionalità è supportata solo nelle piattaforme x64.
La possibilità di restituire l'output tramite registri XMM è indicata tramite la foglia CPUID "Identificazione funzionalità Hypervisor" (0x40000003):
- Bit 15: è disponibile il supporto per la restituzione dell'output di hypercall tramite registri XMM.
Si noti che è presente un flag separato per indicare il supporto per l'input rapido XMM. Qualsiasi tentativo di usare questa interfaccia quando l'hypervisor non indica la disponibilità genererà un errore #UD.
Registra mapping (input e output)
I registri che non vengono usati per passare i parametri di input possono essere usati per restituire l'output. In altre parole, se il blocco di parametri di input è inferiore a 112 byte (arrotondato fino al blocco allineato a 16 byte più vicino), i registri rimanenti restituiranno l'output di hypercall.
| x64 | Informazioni fornite |
|---|---|
| RDX | Input o blocco di output |
| R8 | Input o blocco di output |
| XMM0 | Input o blocco di output |
| XMM1 | Input o blocco di output |
| XMM2 | Input o blocco di output |
| XMM3 | Input o blocco di output |
| XMM4 | Input o blocco di output |
| XMM5 | Input o blocco di output |
Ad esempio, se il blocco di parametri di input è di 20 byte, l'hypervisor ignorerà i 12 byte seguenti. I rimanenti 80 byte conterranno l'output hypercall (se applicabile).
Registrare l'output delle chiamate veloci (ARM64 SMCCC)
Nelle piattaforme ARM64, analogamente al modo in cui l'hypervisor supporta l'input di hypercall veloce, gli stessi registri possono essere condivisi per restituire l'output.
Registra mapping (input e output)
I registri che non vengono usati per passare i parametri di input possono essere usati per restituire l'output. In altre parole, se il blocco di parametri di input è inferiore a 120 byte (arrotondato fino al blocco allineato a 8 byte più vicino), i registri rimanenti restituiranno l'output di hypercall.
| Register | Informazioni fornite |
|---|---|
| X2 - X17 | Input o blocco di output |
Ad esempio, se il blocco di parametri di input è di 20 byte, l'hypervisor ignorerà i 4 byte seguenti. I rimanenti 96 byte conterranno l'output hypercall (se applicabile).
Registrare l'output della chiamata rapida (ARM64 HVC #1)
Analogamente alle versioni di SMCCC, l'interfaccia HVC #1 usa gli stessi registri per restituire l'output.
Registra mapping (input e output)
I registri che non vengono usati per passare i parametri di input possono essere usati per restituire l'output. In altre parole, se il blocco di parametri di input è inferiore a 128 byte (arrotondato fino al blocco allineato a 8 byte più vicino), i registri rimanenti restituiranno l'output di hypercall.
| Register | Informazioni fornite |
|---|---|
| X1 - X17 | Input o blocco di output |
Ad esempio, se il blocco di parametri di input è di 20 byte, l'hypervisor ignorerà i 4 byte seguenti. I rimanenti 104 byte conterranno l'output hypercall (se applicabile).
Registri volatili (x86/x64)
Hypercalls modificherà solo i valori di registro specificati nelle condizioni seguenti:
- RAX (x64) e EDX:EAX (x86) vengono sempre sovrascritti con il valore del risultato hypercall e i parametri di output, se presenti.
- Le hypercall rep modificheranno RCX (x64) e EDX:EAX (x86) con il nuovo indice iniziale del repository.
- HvCallSetVpRegisters può modificare tutti i registri supportati con tale hypercall.
- RDX, R8 e XMM0 fino a XMM5, se usato per l'input di hypercall veloce, rimangono invariati. Tuttavia, i registri usati per l'output di hypercall veloce possono essere modificati, tra cui RDX, R8 e XMM0 fino a XMM5. Hyper-V modificheranno solo questi registri per l'output di hypercall veloce, limitato a x64.
Registri volatili (ARM64 SMCCC)
Hypercalls modificherà solo i valori di registro specificati nelle condizioni seguenti:
- X0 viene sempre sovrascritto con il valore del risultato hypercall e i parametri di output, se presenti.
- Rep hypercalls modificherà X1 con il nuovo indice di avvio del repository.
- HvCallSetVpRegisters può modificare tutti i registri supportati con tale hypercall.
- X2 - X17, se usato per l'input di hypercall veloce, rimangono invariati. Tuttavia, i registri usati per l'output di hypercall veloce possono essere modificati, tra cui X2 - X17. Hyper-V modificheranno solo questi registri per l'output di hypercall veloce.
Registri volatili (ARM64 HVC #1)
Hypercalls modificherà solo i valori di registro specificati nelle condizioni seguenti:
- X0 viene sempre sovrascritto con il valore del risultato hypercall e i parametri di output, se presenti.
- Rep hypercalls modificherà X0 con il nuovo indice di avvio del repository.
- HvCallSetVpRegisters può modificare tutti i registri supportati con tale hypercall.
- X1 - X17, se usato per l'input di hypercall veloce, rimangono invariati. Tuttavia, i registri usati per l'output di hypercall veloce possono essere modificati, incluso X1 - X17. Hyper-V modificheranno solo questi registri per l'output di hypercall veloce.
Restrizioni relative alle chiamate hypercall
Le chiamate hypercall possono avere restrizioni associate che devono essere soddisfatte affinché eseguano la funzione prevista. Se non vengono soddisfatte tutte le restrizioni, l'hypercall terminerà con un errore appropriato. Verranno elencate le restrizioni seguenti, se presenti:
- La partizione chiamante deve disporre di un privilegio specifico
- La partizione su cui viene eseguita l'azione deve trovarsi in uno stato specifico(ad esempio "Attivo")
Codici di stato hypercall
Ogni hypercall è documentato come restituzione di un valore di output che contiene diversi campi. Un campo valore di stato (di tipo HV_STATUS) viene usato per indicare se la chiamata ha avuto esito positivo o negativo.
Validità del parametro di output in hypercall non riuscito
Se non diversamente specificato in modo esplicito, quando un'hypercall ha esito negativo ( ovvero, il campo risultato del valore del risultato hypercall contiene un valore diverso HV_STATUS_SUCCESSda ), il contenuto di tutti i parametri di output è indeterminato e non deve essere esaminato dal chiamante. Solo quando l'hypercall ha esito positivo, tutti i parametri di output appropriati contengono risultati validi e previsti.
Ordinamento delle condizioni di errore
L'ordine in cui vengono rilevate le condizioni di errore e segnalate dall'hypervisor non è definito. In altre parole, se esistono più errori, l'hypervisor deve scegliere quale condizione di errore segnalare. La priorità deve essere assegnata a tali codici di errore che offrono maggiore sicurezza, ovvero l'intento di impedire all'hypervisor di rivelare informazioni ai chiamanti privi di privilegi sufficienti. Ad esempio, il codice HV_STATUS_ACCESS_DENIED di stato è il codice di stato preferito rispetto a uno che rivelerebbe alcune informazioni sul contesto o sullo stato puramente basate sui privilegi.
Codici di stato hypercall comuni
Diversi codici di risultato sono comuni a tutte le hypercall e pertanto non sono documentati singolarmente per ogni hypercall. Questi includono:
| Codice di stato | Condizione di errore |
|---|---|
HV_STATUS_SUCCESS |
Chiamata riuscita. |
HV_STATUS_INVALID_HYPERCALL_CODE |
Il codice hypercall non viene riconosciuto. |
HV_STATUS_INVALID_HYPERCALL_INPUT |
Il numero di rep non è corretto( ad esempio, un numero di rep diverso da zero viene passato a una chiamata non del repository o viene passato un numero di rep zero a una chiamata del repository). |
| L'indice iniziale del repository non è minore del numero di rep. | |
| Un bit riservato nel valore di input hypercall specificato è diverso da zero. | |
HV_STATUS_INVALID_ALIGNMENT |
Il puntatore dell'input o dell'output dell'oggetto Criteri di gruppo specificato non è allineato a 8 byte. |
| Il parametro di input o output specificato elenca le pagine dell'intervallo. | |
| Il puntatore dell'oggetto Criteri di gruppo di input o di output non rientra nei limiti dello spazio Criteri di gruppo. |
Il codice HV_STATUS_SUCCESS restituito indica che non è stata rilevata alcuna condizione di errore.
Segnalazione dell'identità del sistema operativo guest
Il sistema operativo guest in esecuzione all'interno della partizione deve identificarsi nell'hypervisor scrivendone la firma e la versione in un msr (HV_X64_MSR_GUEST_OS_ID/HvRegisterGuestOsId) prima di poter richiamare le hypercall. Questo msr è a livello di partizione ed è condiviso tra tutti i processori virtuali.
Il valore del registro è inizialmente zero.
In x86/x64, è necessario scrivere un valore diverso da zero nell'ID sistema operativo guest MSR prima che la tabella codici hypercall possa essere abilitata (vedere Definizione dell'interfaccia Hypercall (x86/x64) . Se questo registro viene successivamente azzerato, la tabella codici hypercall verrà disabilitata.
In ARM64 è necessario scrivere un valore diverso da zero nell'ID sistema operativo guest MSR prima di poter richiamare i codici hypercall. L'eccezione è l'hypercallters HvCallSetVpRegisters/HvCallGetVpRegisters . Per altre informazioni, vedere la rispettiva documentazione.
#define HV_X64_MSR_GUEST_OS_ID 0x40000000
#define HvRegisterGuestOsId 0x00090002
In ARM64 è supportato solo HvRegisterGuestOsId, che deve essere scritto usando l'hypercall HvCallSetVpRegisters nel processore di avvio.
Identità del sistema operativo guest per sistemi operativi proprietari
Di seguito è riportata la codifica consigliata per questo msr. Alcuni campi potrebbero non essere validi per alcuni sistemi operativi guest.
| BITS | Campo | Description |
|---|---|---|
| 15:0 | Numero di build | Indica il numero di build del sistema operativo |
| 23:16 | Versione del servizio | Indica la versione del servizio (ad esempio, il numero "Service Pack") |
| 31:24 | Versione minore | Indica la versione secondaria del sistema operativo |
| 39:32 | Versione principale | Indica la versione principale del sistema operativo |
| 47:40 | ID sistema operativo | Indica la variante del sistema operativo. La codifica è univoca per il fornitore. I sistemi operativi Microsoft sono codificati come segue: 0=Undefined, 1=MS-DOS®, 2=Windows® 3.x, 3=Windows® 9x, 4=Windows® NT (e derivati), 5=Windows® CE |
| 62:48 | ID fornitore | Indica il fornitore del sistema operativo guest. Il valore 0 è riservato. Vedere l'elenco dei fornitori di seguito. |
| 63 | Tipo di sistema operativo | Indica il tipo di sistema operativo. Un valore pari a 0 rappresenta un sistema operativo proprietario (origine chiusa). Il valore 1 rappresenta un sistema operativo open source. |
I valori del fornitore vengono allocati da Microsoft. Per richiedere un nuovo fornitore, inviare un problema nel repository della documentazione di virtualizzazione di GitHub (https://aka.ms/VirtualizationDocumentationIssuesTLFS).
| Fornitore | Value |
|---|---|
| Microsoft | 0x0001 |
| HPE | 0x0002 |
| BlackBerry | 0x0003 |
| LANCOM | 0x0200 |
Identità del sistema operativo guest MSR per sistemi operativi open source
La codifica seguente è disponibile come materiale sussidiario per i fornitori di sistemi operativi open source che intendono essere conformi a questa specifica. È consigliabile che i sistemi operativi open source adottino la convenzione seguente.
| BITS | Campo | Description |
|---|---|---|
| 15:0 | Numero di build | Informazioni specifiche della distribuzione (ad esempio, numero di build). |
| 47:16 | Versione | Informazioni sulla versione del kernel upstream. |
| 55:48 | ID sistema operativo | Informazioni aggiuntive sul fornitore |
| 62:56 | Tipo di sistema operativo | Tipo di sistema operativo (ad esempio, Linux, FreeBSD e così via). Vedere l'elenco dei tipi di sistema operativo noti di seguito |
| 63 | Open Source | Il valore 1 indica un sistema operativo open source. |
I valori del tipo di sistema operativo vengono allocati da Microsoft. Per richiedere un nuovo tipo di sistema operativo, inviare un problema nel repository della documentazione di virtualizzazione di GitHub (https://aka.ms/VirtualizationDocumentationIssuesTLFS).
| Tipo di sistema operativo | Value |
|---|---|
| Linux | 0x1 |
| FreeBSD | 0x2 |
| Xen | 0x3 |
| Illumos | 0x4 |
Definizione dell'interfaccia Hypercall (x86/x64)
In x86/x64, le chiamate Hypercall vengono richiamate usando un codice operativo speciale. Poiché questo codice operativo differisce tra le implementazioni di virtualizzazione, è necessario che l'hypervisor astrae questa differenza. Questa operazione viene eseguita tramite una pagina hypercall speciale. Questa pagina viene fornita dall'hypervisor e viene visualizzata all'interno dello spazio Criteri di gruppo del guest. Il guest è necessario per specificare il percorso della pagina programmando l'MSR Guest Hypercall.
#define HV_X64_MSR_HYPERCALL 0x40000001
| BITS | Description | Attributes |
|---|---|---|
| 63:12 | Hypercall GPFN - Indica il numero di pagina fisica guest della pagina hypercall | Lettura/scrittura |
| 11:2 | RsvdP. I bit devono essere ignorati nelle letture e mantenuti nelle scritture. | Riservato |
| 1 | Bloccato. Indica se msr non è modificabile. Se impostato, questo msr viene bloccato impedendo così la rilocazione della pagina hypercall. Una volta impostato, solo una reimpostazione del sistema può cancellare il bit. | Lettura/scrittura |
| 0 | Abilitare la pagina hypercall | Lettura/scrittura |
La pagina hypercall può essere posizionata in qualsiasi punto all'interno dello spazio Criteri di gruppo del guest, ma deve essere allineata a pagina. Se il guest tenta di spostare la pagina hypercall oltre i limiti dello spazio Criteri di gruppo, quando viene scritto msr verrà generato un errore di #GP.
Questo msr è un msr a livello di partizione. In altre parole, viene condiviso da tutti i processori virtuali nella partizione. Se un processore virtuale scrive correttamente in MSR, un altro processore virtuale leggerà lo stesso valore.
Prima che la pagina hypercall sia abilitata, il sistema operativo guest deve segnalarne l'identità scrivendo la firma della versione in un msr separato (HV_X64_MSR_GUEST_OS_ID). Se non è stata specificata alcuna identità del sistema operativo guest, i tentativi di abilitare l'hypercall avranno esito negativo. Il bit di abilitazione rimarrà zero anche quando ne scrive uno. Inoltre, se l'identità del sistema operativo guest viene cancellata su zero dopo che la pagina hypercall è stata abilitata, diventerà disabilitata.
La pagina hypercall viene visualizzata come "sovrimpressione" nello spazio Criteri di gruppo; vale a dire, copre qualsiasi altro elemento mappato all'intervallo GpA. Il contenuto è leggibile ed eseguibile dal guest. I tentativi di scrittura nella pagina hypercall genereranno un'eccezione di protezione (#GP). Dopo che la pagina hypercall è stata abilitata, richiamare una hypercall implica semplicemente una chiamata all'inizio della pagina.
Di seguito è riportato un elenco dettagliato dei passaggi necessari per stabilire la pagina hypercall:
- Il guest legge CPUID foglia 1 e determina se un hypervisor è presente controllando il bit 31 del registro ECX.
- Il guest legge 0x40000000 foglia CPUID per determinare il numero massimo di foglia CPUID dell'hypervisor (restituito nel registro EAX) e cpuID foglia 0x40000001 per determinare la firma dell'interfaccia (restituita nel registro EAX). Verifica che il valore foglia massimo sia almeno 0x40000005 e che la firma dell'interfaccia sia uguale a "Hv#1". Questa firma implica l'implementazione
HV_X64_MSR_GUEST_OS_IDHV_X64_MSR_HYPERCALLdi eHV_X64_MSR_VP_INDEX. - Il guest scrive l'identità del sistema operativo in MSR
HV_X64_MSR_GUEST_OS_IDse tale registro è zero. - Il guest legge l'msr hypercall (
HV_X64_MSR_HYPERCALL). - Il guest controlla il bit Abilita pagina Hypercall. Se è impostata, l'interfaccia è già attiva e i passaggi 6 e 7 devono essere omessi.
- L'ospite trova una pagina all'interno del relativo spazio Criteri di gruppo, preferibilmente quella non occupata da RAM, MMIO e così via. Se la pagina è occupata, l'ospite deve evitare di usare la pagina sottostante per altri scopi.
- Il guest scrive un nuovo valore in Hypercall MSR (
HV_X64_MSR_HYPERCALL) che include l'oggetto Criteri di gruppo del passaggio 6 e imposta il bit Abilita pagina Hypercall per abilitare l'interfaccia. - Il guest crea un mapping va eseguibile all'oggetto Criteri di gruppo della pagina hypercall.
- Il guest consulta la foglia CPUID 0x40000003 per determinare quali funzionalità dell'hypervisor sono disponibili. Dopo aver stabilito l'interfaccia, il guest può avviare un'hypercall. A tale scopo, popola i registri in base al protocollo hypercall e invia una chiamata all'inizio della pagina hypercall. Il guest deve presupporre che la pagina hypercall esegua l'equivalente di un vicino restituito (0xC3) per tornare al chiamante. Di conseguenza, l'hypercall deve essere richiamato con uno stack valido.
Definizione dell'interfaccia Hypercall (ARM64)
Poiché ARM64 supporta in modo nativo l'istruzione HVC, l'hypervisor non richiede una configurazione aggiuntiva per abilitare le hypercall.
Interfaccia Hypercall estesa
Le chiamate hypercall con codici di chiamata precedenti 0x8000 sono note come hypercall estese. Le hypercall estese usano la stessa convenzione di chiamata delle normali hypercall e appaiono identiche dal punto di vista di una macchina virtuale guest. Le hypercall estese vengono gestite internamente in modo diverso all'interno dell'hypervisor Hyper-V.
È possibile eseguire query sulle funzionalità di hypercall estese con HvExtCallQueryCapabilities.