Interfaccia Hypercall
L'hypervisor fornisce un meccanismo di chiamata per gli ospiti. Tali chiamate vengono definite hypercall. Ogni hypercall definisce un set di parametri di input e/o di 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 inseriti nei 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 nessun parametro 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 è fino a 112 byte. Quando si usa questa convenzione chiamante, i parametri di input vengono passati nei registri, inclusi i registri XMM volatili.
Le strutture di dati di input e di output devono essere posizionate in memoria su un limite di 8 byte e riempite in più di 8 byte di dimensioni. I valori all'interno delle aree di riempimento vengono ignorati dall'hypervisor.
Per l'output, l'hypervisor è consentito (ma non garantito) sovrascrivere le aree di riempimento. Se sovrascrive le aree di riempimento, scriverà zero.
Classi Hypercall
Esistono due classi di hypercall: semplice e rep (breve per "ripeti"). Una semplice hypercall esegue una singola operazione e ha un set fisso di parametri di input e output. Un rep hypercall agisce come una serie di semplici hypercall. Oltre a un set fisso di parametri di input e output, rep hypercalls comporta un elenco di elementi di input e/o di output di dimensioni fisse.
Quando un chiamante richiama inizialmente un hypercall rep, specifica un numero di rep che indica il numero di elementi nell'elenco di parametri di input e/o di output. I chiamanti specificano anche un indice di avvio del repository che indica l'elemento di input e/o di output successivo che deve essere utilizzato. L'hypervisor elabora i parametri del repository nell'ordine di elenco, ovvero aumentando l'indice degli elementi.
Per le chiamate successive dell'hypercall rep, l'indice di avvio del repository indica il numero di elementi completati e, in combinazione con il valore del conteggio rep, il numero di elementi rimasti. Ad esempio, se un chiamante specifica un numero di rep di 25 e solo 20 iterazioni vengono completate entro i vincoli di tempo, l'hypercall restituisce il controllo al processore virtuale chiamante dopo aver aggiornato l'indice di avvio del repository a 20. Quando l'hypercall viene eseguito nuovamente, l'hypervisor riprenderà all'elemento 20 e completerà i restanti 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 reps, che indica il numero di elementi elaborati correttamente prima dell'errore. Supponendo che la parola di controllo hypercall specificata sia valida (vedere la seguente) e gli elenchi di parametri di input/output siano accessibili, l'hypervisor è garantito tentare almeno una replica, ma non è necessario elaborare l'intero elenco prima di restituire il controllo al chiamante.
Continuazione Hypercall
Un hypercall può essere considerato 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 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 hypercall rep.
Il meccanismo di continuazione hypercall è principalmente 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 alle istruzioni non è avanzato oltre l'istruzione che ha richiamato l'hypercall. Ciò consente di gestire gli interruzioni in sospeso e di pianificare altri processori virtuali. Quando il thread chiamante originale riprende l'esecuzione, eseguirà nuovamente l'istruzione hypercall e eseguirà lo stato di avanzamento verso il completamento dell'operazione.
La maggior parte delle hypercall semplici è garantita per il completamento entro il limite di tempo previsto. Tuttavia, un numero ridotto di semplici hypercall potrebbe richiedere più tempo. Queste hypercall usano la continuazione hypercall in modo simile a rep hypercall. In questi casi, l'operazione comporta 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 viene infine passato a uno stato terminale. Per ogni hypercall che segue questo modello, vengono descritti gli effetti collaterali visibili degli stati interni intermedi.
Hypercall Atomicity and Ordering
Tranne dove indicato, l'azione eseguita da un hypercall è atomica sia rispetto a tutte le altre operazioni guest (ad esempio le istruzioni eseguite all'interno di un guest) sia tutte le altre hypercall eseguite nel sistema. Una semplice hypercall esegue un'unica azione atomica; un rep hypercall esegue più azioni atomice indipendenti.
Le hypercall semplici che usano la continuazione hypercall possono comportare più stati interni visibili esternamente. Tali chiamate comprendono più operazioni atomiche.
Ogni azione hypercall può leggere parametri di input e/o scrivere risultati. Gli input per ogni azione possono essere letti in 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 che l'hypercall restituisca.
Il guest 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 (perché l'esecuzione guest non viene sospesa fino a quando l'hypercall restituisce), non è possibile impedire ad altri processori virtuali di farlo. I guest che si comportano in questo modo possono arrestare o causare il danneggiamento all'interno della partizione.
Ambienti Hypercall legali
Le chiamate Hypercall possono essere richiamate solo dalla modalità processore guest con privilegi. In x64 platfoms questo significa modalità protetta con un livello di privilegi corrente (CPL) pari a zero. Anche se il codice in modalità reale viene eseguito con un CPL effettivo pari a zero, le chiamate hypercall non sono consentite in modalità reale. Un tentativo di richiamare una hypercall all'interno di una modalità processore illegale genererà un'eccezione #UD (operazione non definita).
Tutte le hypercall devono essere richiamate tramite l'interfaccia hypercall definita dall'architettura (vedere di seguito). Un tentativo di richiamare un hypercall per qualsiasi altro mezzo (ad esempio, copiare il codice dalla tabella codici hypercall in un percorso alternativo ed eseguirlo da lì) potrebbe causare un'eccezione non definita (#UD). L'hypervisor non è garantito per recapitare questa eccezione.
Requisiti di allineamento
I chiamanti devono specificare l'indirizzo fisico guest a 64 bit (GPA) dei parametri di input e/o output. I puntatori Criteri di gruppo devono essere allineati a 8 byte. Se l'hypercall non comporta parametri di input o output, l'hypervisor ignora il puntatore Criteri di gruppo corrispondente.
Gli elenchi di parametri di input e output non possono sovrapporsi o attraversare i limiti di pagina. Le pagine di input e output hypercall devono essere pagine Criteri di gruppo e non "sovrapposizione". 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 convalida che la partizione chiamante può leggere dalla pagina di input prima di eseguire l'hypercall richiesto. Questa convalida è costituita da due controlli: l'oggetto Criteri di gruppo specificato viene mappato 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 convalida che la partizione può essere scritta nella pagina di output. Questa convalida è costituita da due controlli: l'oggetto Criteri di gruppo specificato viene mappato 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 token è formattato come illustrato di seguito:
Campo | BITS | Informazioni fornite |
---|---|---|
Chiama codice | 15-0 | Specifica quale hypercall viene 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 delle variabili | 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 del repository, deve essere zero in caso contrario) |
RsvdZ | 63-60 | Deve essere zero |
Per rep hypercall, il campo conteggio rep indica il numero totale di rep. L'indice iniziale del repository indica la ripetizione particolare relativa all'inizio dell'elenco (zero indica che il primo elemento nell'elenco deve essere elaborato). Pertanto, il valore del conteggio rep deve essere sempre maggiore dell'indice iniziale del repository.
Registrare il mapping per gli input hypercall quando il flag Fast è zero:
x64 | x86 | Informazioni fornite |
---|---|---|
RCX | EDX:EAX | Valore di input Hypercall |
RDX | EBX:ECX | Criteri di gruppo di parametri di input |
R8 | EDI:ESI | Parametri di output Criteri di gruppo |
Il valore di input hypercall viene passato nei registri insieme a un oggetto Criteri di gruppo che punta ai parametri di input e output.
In x64, i mapping di registrazione dipendono dal fatto che il chiamante sia in esecuzione in modalità x86 a 32 bit o a 64 bit (x64). L'hypervisor determina la modalità del chiamante in base al valore di EFER. LMA e CS.L. Se entrambi questi flag sono impostati, 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.
Intestazioni di input Hypercall di 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 di dimensioni fisse e un input di intestazione aggiuntivo di dimensioni variabili.
Un'intestazione di dimensioni variabile è simile a un input hypercall fisso (allineato a 8 byte e ridimensionato a più 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é la dimensione dell'intestazione fissa è implicita, anziché fornire le dimensioni totali dell'intestazione, viene fornita solo la parte variabile nei controlli di input:
Variable Header Bytes = {Total Header Bytes - sizeof(Fixed Header)} rounded up to nearest multiple of 8
Variable HeaderSize = Variable Header Bytes / 8
Non è possibile specificare una dimensione dell'intestazione di variabile non zero per una hypercall non documentata in modo esplicito come accettare intestazioni di input con dimensioni variabili. In tal caso, l'hypercall comporterà un codice restituito di HV_STATUS_INVALID_HYPERCALL_INPUT
.
È possibile che per una determinata chiamata di un hypercall che accetta intestazioni di input di dimensioni variabili che tutti gli input di intestazione si adattano interamente all'interno dell'intestazione di dimensione fissa. In questi casi, l'intestazione di input con dimensioni variabili è zero e i bit corrispondenti nell'input hypercall devono essere impostati su zero.
In tutti gli altri aspetti, le chiamate hypercall che accettano intestazioni di input di dimensioni variabili sono altrimenti simili alle intestazioni di input di dimensioni fisse hypercall per quanto riguarda le convenzioni di chiamata. È anche possibile che un hypercall di dimensioni variabile supporti la semantica del repository. In tal caso, gli elementi del repository si trovano dopo l'intestazione in modo consueto, ad eccezione del fatto che le dimensioni totali dell'intestazione includono sia le parti fisse che le variabili. Tutte le altre regole rimangono uguali, ad esempio il primo elemento rep deve essere allineato a 8 byte.
Input hypercall rapido XMM
Nelle piattaforme x64, l'hypervisor supporta l'uso di hypercall veloci XMM, che consente ad alcuni hypercall di sfruttare le prestazioni migliorate dell'interfaccia 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 di dimensioni.
La disponibilità dell'interfaccia hypercall veloce XMM è indicata tramite il nome CPUID Foglia (0x40000003) "Hypervisor Feature Identification" (Identificazione funzionalità Hypervisor):
- Bit 4: è disponibile il supporto per il passaggio dell'input hypercall tramite i registri XMM.
Si noti che è presente un flag separato per indicare il supporto per l'output veloce XMM. Qualsiasi tentativo di usare questa interfaccia quando l'hypervisor non indica la disponibilità genera un errore di #UD.
Registrare il 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à x86 a 32 bit o a 64 bit (x64). L'hypervisor determina la modalità del chiamante in base al valore di EFER. LMA e CS.L. Se entrambi questi flag sono impostati, si presuppone che il chiamante sia un chiamante a 64 bit. Se il blocco dei parametri di input è inferiore a 112 byte, vengono ignorati eventuali byte aggiuntivi nei registri.
Output hypercall
Tutte le hypercall restituiscono un valore a 64 bit denominato valore del risultato hypercall. Il token è formattato come illustrato di seguito:
Campo | BITS | Commento |
---|---|---|
Risultato | 15-0 | HV_STATUS codice che indica l'esito positivo o l'errore |
Rsvd | 31-16 | I chiamanti devono ignorare il valore in questi bit |
Reps complete | 43-32 | Numero di rep completate correttamente |
RsvdZ | 63-40 | I chiamanti devono ignorare il valore in questi bit |
Per rep hypercall, il campo completo dei reps è il numero totale di reps complete e non relative 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 completo dei rep indica 10 al completamento corretto.
Il valore del risultato hypercall viene passato di nuovo nei registri. Il mapping del registro dipende dal fatto che il chiamante sia in esecuzione in modalità x86 a 32 bit o a 64 bit (x64). Il mapping dei registri per gli output hypercall è il seguente:
x64 | x86 | Informazioni fornite |
---|---|---|
RAX | EDX:EAX | Valore del risultato Hypercall |
Output hypercall rapido XMM
Analogamente al modo in cui l'hypervisor supporta 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 i registri XMM è indicata tramite la foglia CPUID "Identificazione funzionalità Hypervisor" (0x40000003):
- Bit 15: è disponibile il supporto per la restituzione dell'output hypercall tramite i 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à genera un errore di #UD.
Registrare il 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 hypercall.
x64 | Informazioni fornite |
---|---|
RDX | Blocco di input o output |
R8 | Blocco di input o output |
XMM0 | Blocco di input o output |
XMM1 | Blocco di input o output |
XMM2 | Blocco di input o output |
XMM3 | Blocco di input o output |
XMM4 | Blocco di input o output |
XMM5 | Blocco di input o output |
Ad esempio, se il blocco dei parametri di input è pari a 20 byte, l'hypervisor ignora i 12 byte seguenti. I restanti 80 byte contengono l'output hypercall (se applicabile).
Registri volatili
Hypercall modifica solo i valori di registro specificati nelle condizioni seguenti:
- RAX (x64) e EDX:EAX (x86) vengono sempre sovrascritti con i parametri di risultato hypercall e output, se presenti.
- Le hypercall rep modificano RCX (x64) e EDX:EAX (x86) con il nuovo indice di avvio del repository.
- HvCallSetVpRegisters può modificare tutti i registri supportati con tale hypercall.
- RDX, R8 e XMM0 fino a XMM5, quando usato per l'input hypercall veloce, rimangono invariati. Tuttavia, i registri usati per l'output hypercall rapido possono essere modificati, tra cui RDX, R8 e XMM0 tramite XMM5. Hyper-V modifica solo questi registri per l'output hypercall rapido, limitato a x64.
Restrizioni hypercall
Le chiamate hypercall possono avere restrizioni associate a loro per eseguire la loro funzione prevista. Se tutte le restrizioni non vengono soddisfatte, l'hypercall termina con un errore appropriato. Le restrizioni seguenti verranno elencate, se si applicano:
- La partizione chiamante deve avere un particolare privilegio
- La partizione in corso deve essere in uno stato specifico (ad esempio "Attivo")
Codici di stato Hypercall
Ogni hypercall è documentato come restituire un valore di output contenente diversi campi. Viene usato un campo valore di stato (di tipo HV_STATUS
) per indicare se la chiamata ha avuto esito positivo o non riuscito.
Validità del parametro di output in Hypercall non riuscito
A meno che non sia indicato in modo esplicito, quando un hypercall ha esito negativo , ovvero il campo risultato del valore del risultato hypercall contiene un valore diverso HV_STATUS_SUCCESS
da ), 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 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, la finalità di impedire all'hypervisor di rivelare informazioni ai chiamanti senza privilegi sufficienti. Ad esempio, il codice di stato è il codice HV_STATUS_ACCESS_DENIED
di stato preferito su uno che rivelerebbe alcune informazioni di contesto o 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. tra cui:
Codice stato | Condizione di errore |
---|---|
HV_STATUS_SUCCESS |
La chiamata ha avuto esito positivo. |
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 non zero viene passato a una chiamata non rep o a un numero di rep zero viene passato 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 Criteri di gruppo di input o output specificato non è allineato a 8 byte. |
Gli elenchi di parametri di input o output specificati si estendono sulle pagine. | |
Il puntatore Criteri di gruppo di input o 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
) 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. Prima che sia possibile abilitare la tabella codici hypercall, vedere Definizione dell'interfaccia Hypercall. Se il registro viene successivamente azzerato, la tabella codici hypercall verrà disabilitata.
#define HV_X64_MSR_GUEST_OS_ID 0x40000000
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 | Descrizione |
---|---|---|
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 secondaria | 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 i tipi di sistema operativo. Il valore 0 indica un sistema operativo di origine chiuso proprietario. Il valore 1 indica un sistema operativo open source. |
I valori fornitore vengono allocati da Microsoft. Per richiedere un nuovo fornitore, segnalare un problema nel repository della documentazione di virtualizzazione GitHub (https://aka.ms/VirtualizationDocumentationIssuesTLFS).
Vendor | Valore |
---|---|
Microsoft | 0x0001 |
HPE | 0x0002 |
LANCOM | 0x0200 |
Identità del sistema operativo guest MSR per sistemi operativi open source
La codifica seguente viene offerta come materiale sussidiario per open source fornitori di sistemi operativi che intendono conformarsi a questa specifica. È consigliabile che open source sistemi operativi adattino la convenzione seguente.
BITS | Campo | Descrizione |
---|---|---|
15:0 | Numero di build | Informazioni aggiuntive |
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, segnalare un problema nel repository della documentazione di virtualizzazione GitHub (https://aka.ms/VirtualizationDocumentationIssuesTLFS).
Tipo di sistema operativo | Valore |
---|---|
Linux | 0x1 |
FreeBSD | 0x2 |
Xen | 0x3 |
Illumos | 0x4 |
Definizione dell'interfaccia Hypercall
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 di iperchiamata 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 | Descrizione | Attributi |
---|---|---|
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 dell'utente 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 di 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 se ne viene scritto uno. Inoltre, se l'identità del sistema operativo guest viene cancellata su zero dopo l'abilitazione della pagina hypercall, l'identità del sistema operativo guest diventerà disabilitata.
La pagina hypercall viene visualizzata come "sovrimpressione" nello spazio Criteri di gruppo; vale a dire che copre qualsiasi altro elemento mappato all'intervallo Criteri di gruppo. 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 un'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 la foglia CPUID dell'hypervisor massima (restituita 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_ID
HV_X64_MSR_HYPERCALL
di eHV_X64_MSR_VP_INDEX
. - Se il registro è zero, il guest scrive l'identità del sistema operativo in MSR
HV_X64_MSR_GUEST_OS_ID
. - Il guest legge l'MSR Hypercall (
HV_X64_MSR_HYPERCALL
). - Il guest controlla il bit Abilita pagina Hypercall. Se è impostato, l'interfaccia è già attiva e i passaggi 6 e 7 devono essere omessi.
- L'ospite trova una pagina all'interno dello spazio Criteri di gruppo, preferibilmente quella non occupata da RAM, MMIO e così via. Se la pagina è occupata, l'utente guest deve evitare di usare la pagina sottostante per altri scopi.
- Il guest scrive un nuovo valore nell'MSR Hypercall (
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 il 0x40000003 foglia CPUID per determinare le funzionalità dell'hypervisor 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 ritorno vicino (0xC3) per tornare al chiamante. Di conseguenza, l'hypercall deve essere richiamato con uno stack valido.
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.