Sdílet prostřednictvím


Rozhraní Hypercall

Hypervisor poskytuje volající mechanismus pro hosty. Taková volání se označují jako hypercalls. Každý hypercall definuje sadu vstupních a/nebo výstupních parametrů. Tyto parametry jsou určeny z hlediska datové struktury založené na paměti. Všechny prvky vstupních a výstupních datových struktur jsou vycpané na přirozené hranice až 8 bajtů (to znamená, že dva bajtové prvky musí být na dvou bajtových hranicích atd.).

Druhou konvenci volání hypercallu lze volitelně použít pro podmnožinu hypercallů – zejména pro ty, které mají dva nebo méně vstupních parametrů a žádné výstupní parametry. Při použití této konvence volání se vstupní parametry předávají v registrech pro obecné účely.

Třetí konvenci volání hypercall lze volitelně použít pro podmnožinu hypercallů, kde vstupní blok parametru je až 112 bajtů. Při použití této konvence volání se vstupní parametry předávají v registrech, včetně těkavých registrů XMM.

Vstupní i výstupní datové struktury musí být umístěny v paměti na 8 bajtové hranici a vycpané na násobek 8 bajtů ve velikosti. Hypervisor ignoruje hodnoty v oblastech odsazení.

Pro výstup může hypervisor přepsat oblasti odsazení (ale není zaručeno). Pokud přepíše oblasti odsazení, zapíše nuly.

Hypercall – třídy

Existují dvě třídy hypercallů: simple a rep (zkratka pro "repeat"). Jednoduchý hypercall provádí jednu operaci a má sadu vstupních a výstupních parametrů s pevnou velikostí. Hypercall rep funguje jako řada jednoduchých hypervolací. Kromě sady vstupních a výstupních parametrů s pevnou velikostí zahrnují hypercally rep seznam vstupních a výstupních prvků s pevnou velikostí.

Když volající zpočátku vyvolá hypercall rep, určuje počet opakování, který označuje počet prvků v seznamu vstupních a/nebo výstupních parametrů. Volající také určují index zahájení opakování, který označuje další vstupní nebo výstupní prvek, který by měl být spotřebován. Hypervisor zpracovává parametry rep v pořadí seznamu – to znamená zvýšením indexu prvků.

Pro následné vyvolání hypercallu rep indikuje počáteční index opakování, kolik prvků bylo dokončeno – a ve spojení s hodnotou počtu opakování – kolik prvků zbývá. Pokud například volající určuje počet opakování 25 a v časových omezeních se dokončí pouze 20 iterací, vrátí hypercall řízení zpět do volajícího virtuálního procesoru po aktualizaci indexu spuštění rep na 20. Při opětovném spuštění hypercallu se hypervisor obnoví v elementu 20 a dokončí zbývající 5 prvků.

Pokud při zpracování prvku dojde k chybě, zobrazí se odpovídající stavový kód spolu s dokončeným počtem opakování, který označuje počet prvků, které byly úspěšně zpracovány před zjištěním chyby. Za předpokladu, že zadané slovo ovládacího prvku hypercall je platné (viz následující) a seznamy vstupních a výstupních parametrů jsou přístupné, je zaručeno, že se hypervisor pokusí alespoň o jednu rep, ale není nutné zpracovat celý seznam před vrácením ovládacího prvku zpět volajícímu.

Pokračování hypercallu

Hypercall si lze představit jako složitou instrukci, která trvá mnoho cyklů. Hypervisor se pokusí omezit provádění hypercallu na 50μs nebo méně, než se vrátí řízení do virtuálního procesoru, který vyvolal hypercall. Některé hypervolací operace jsou dostatečně složité, že je obtížné zajistit záruku 50 μs. Hypervisor proto spoléhá na mechanismus pokračování hypercallu pro některé hypercally – včetně všech formulářů hypercall rep.

Mechanismus pokračování hypercallu je pro volajícího většinou transparentní. Pokud hypercall není schopen dokončit v rámci předepsaného časového limitu, ovládací prvek se vrátí zpět volajícímu, ale ukazatel instrukce není pokročilý po instrukci, která vyvolala hypercall. To umožňuje zpracování čekajících přerušení a naplánování dalších virtuálních procesorů. Když původní volající vlákno obnoví provádění, znovu spustí instrukce hypercallu a bude pokračovat směrem k dokončení operace.

Většina jednoduchých hypercallů se zaručuje dokončení v rámci předepsaného časového limitu. Malý počet jednoduchých hypercallů ale může vyžadovat více času. Tyto hypercally používají pokračování hypercallu podobným způsobem, jak převést hypercally. V takových případech operace zahrnuje dva nebo více vnitřních stavů. První vyvolání umístí objekt (například oddíl nebo virtuální procesor) do jednoho stavu a po opakovaném vyvolání se stav nakonec převede na terminálový stav. Pro každý hypercall, který se řídí tímto vzorem, jsou popsány viditelné vedlejší účinky přechodných vnitřních stavů.

Hypercall Atomicity and Ordering

Kromě případů, kdy je uvedeno, je akce prováděná hypercallem atomická jak s ohledem na všechny ostatní operace hosta (například instrukce prováděné v rámci hosta), tak všechny ostatní hypercally, které se v systému spouští. Jednoduchý hypercall provádí jednu atomické akce; Hypercall zástupce provádí více nezávislých atomických akcí.

Jednoduché hypercally, které používají pokračování hypercallu, mohou zahrnovat více interních stavů, které jsou externě viditelné. Taková volání tvoří několik atomických operací.

Každá akce hypercallu může číst vstupní parametry a/nebo zapisovat výsledky. Vstupy pro každou akci lze číst v libovolné členitosti a kdykoli po provedení hypercallu a před provedením akce. Výsledky (tj. výstupní parametry) přidružené ke každé akci mohou být zapsány v libovolné členitosti a kdykoli po provedení akce a před vrácením hypercallu.

Host se musí vyhnout kontrole nebo manipulaci se vstupními nebo výstupními parametry souvisejícími s prováděním hypercallu. Zatímco virtuální procesor, který spouští hypercall, nebude schopen to udělat (protože jeho spuštění hosta je pozastaveno, dokud hypercall nevrátí), není nic, co by zabránilo jiným virtuálním procesorům. Hosté, kteří se tímto způsobem chovají, můžou dojít k chybovému ukončení nebo poškození v rámci oddílu.

Hypercalls lze vyvolat pouze z režimu nejprivilegovaného procesoru hosta. Na platformách x64 to znamená chráněný režim s aktuální úrovní oprávnění (CPL) nuly. I když se kód v reálném režimu spouští s efektivním CPL nuly, hypercalls nejsou povoleny v reálném režimu. Při pokusu o vyvolání hypercallu v režimu nelegálního procesoru se vygeneruje výjimka #UD (nedefinovaná operace) na platformě x64 a nedefinovaná výjimka instrukce v ARM64.

Všechny hypercally by se měly vyvolat prostřednictvím architekturálně definovaného rozhraní hypercall (viz níže). Pokus o vyvolání hypercallu jakýmkoli jiným způsobem (například zkopírováním kódu ze stránky kódu hypercall do alternativního umístění a jeho spuštěním) může dojít k výjimce nedefinované operace (#UD). Hypervisor není zaručen, že tuto výjimku doručí.

Požadavky na zarovnání

Volající musí zadat 64bitovou fyzickou adresu hosta (GPA) vstupních a/nebo výstupních parametrů. Ukazatele GPA musí být zarovnané na 8 bajtů. Pokud hypercall neobsahuje žádné vstupní nebo výstupní parametry, hypervisor ignoruje odpovídající ukazatel GPA.

Seznamy vstupních a výstupních parametrů se nesmí překrývat ani překrývat hranice stránek. Očekává se, že vstupní a výstupní stránky hypercallu budou stránky GPA, nikoli stránky překrytí. Pokud virtuální procesor zapíše vstupní parametry na překryvnou stránku a určí zásadu zásad skupiny na této stránce, není definován přístup hypervisoru k seznamu vstupních parametrů.

Hypervisor ověří, že volající oddíl může číst ze vstupní stránky před spuštěním požadovaného hypercallu. Toto ověření se skládá ze dvou kontrol: zadaná zásada zásad skupiny je namapovaná a gpA je označená jako čitelná. Pokud některý z těchto testů selže, hypervisor vygeneruje zprávu zachycení paměti. U hypervolaků s výstupními parametry hypervisor ověří, že oddíl může zapisovat na výstupní stránku. Toto ověření se skládá ze dvou kontrol: zadaná hodnota GPA je namapovaná a gpA je označena jako zapisovatelná.

Hypercall – vstupy

Volající určují hypercall 64bitovou hodnotou, která se nazývá vstupní hodnota hypercallu. Formátuje se takto:

Obor Bity Zadané informace
Kód volání 15-0 Určuje, který hypercall se požaduje.
Rychlé 16 Určuje, jestli hypercall používá konvenci volání založené na registru: 0 = založená na paměti, 1 = založená na registru.
Velikost záhlaví proměnné 26-17 Velikost hlavičky proměnné v QWORDS.
RsvdZ 30-27 Musí být nula.
Je vnořený. 31 Určuje, že hypercall by měl zpracovat hypervisor L0 v vnořeném prostředí.
Počet opakování 43-32 Celkový počet rep call (pro volání rep, musí být nula jinak)
RsvdZ 47-44 Musí být nula.
Spustit index rep 59-48 Počáteční index (pro volání rep musí být nula v opačném případě)
RsvdZ 63-60 Musí být nula.

U hypercallů rep označuje pole počet rep celkový počet opakování. Index zahájení opakování označuje konkrétní opakování vzhledem k začátku seznamu (nula označuje, že se má zpracovat první prvek v seznamu). Proto musí být hodnota počtu opakování vždy větší než počáteční index opakování.

Konvence registru Hypercall (x86/x64)

Na platformě x86/x64 zaregistrujte mapování pro vstupy hypercall, pokud je příznak Fast nulový, jsou následující:

x64 x86 Zadané informace
RCX EDX:EAX Vstupní hodnota hypercallu
RDX EBX:ECX GpA vstupních parametrů
R8 EDI:ESI Výstupní parametry GPA

Vstupní hodnota hypercallu se předává v registrech spolu s GPA, která odkazuje na vstupní a výstupní parametry.

Mapování registru závisí na tom, jestli je volající spuštěný v 32bitovém (x86) nebo 64bitovém režimu (x64). Hypervisor určuje režim volajícího na základě hodnoty EFER. LMA a CS.L. Pokud jsou oba tyto příznaky nastavené, předpokládá se, že volající je 64bitový volající.

Zaregistrujte mapování pro vstupy hypercall, pokud je příznak Fast jeden:

x64 x86 Zadané informace
RCX EDX:EAX Vstupní hodnota hypercallu
RDX EBX:ECX Vstupní parametr
R8 EDI:ESI Výstupní parametr

Vstupní hodnota hypercallu se předává v registrech spolu se vstupními parametry.

Konvence registru Hypercall (ARM64 SMCCC)

V ARM64 se hypercalls spouští pomocí instrukce "HVC #0". Volání dodržují konvenci volání SMCCC (ARM64 SMC).

Mapování registru pro vstupy hypercall jsou následující:

Register Zadané informace
X0 Identifikátor funkce SMCCC
X1 Vstupní hodnota hypercallu
X2 Vstupní parametr
X3 Výstupní parametr

Identifikátor funkce SMCCC v X0 se řídí tímto formátem:

Bity Obor Hodnota Description
31 Volání s výnosem 0 Vždy 0
30 Konvence volání 1 1 pro konvence volání HVC64
29:24 Typ volání služby 6 6 pro volání služeb hypervisoru specifických pro dodavatele
23:16 Rezervováno 0 Rezervovaná hodnota musí být nula (Res0)
15:0 Číslo funkce 1 1 označuje, že kód volání HV je definován v X1.

Úplný formát identifikátoru funkce: 0x46000001

Konvence registru Hypercall (ARM64 HVC #1)

Z historických důvodů podporuje rozhraní hypervisoru ARM64 také jinou konvenci volání. Hypervolají se pomocí instrukce "HVC #1". Pro nový kód doporučujeme použít konvenci volání SMCCC.

Mapování registru pro vstupy hypercall jsou následující:

Register Zadané informace
X0 Vstupní hodnota hypercallu
X1 Vstupní parametr
X2 Výstupní parametr

Hlavičky vstupu Hypercall s proměnnou velikostí

Většina hlaviček vstupu hypercall má pevnou velikost. Množství dat hlavičky předávaných z hosta do hypervisoru je proto implicitně určeno kódem hypercall a není nutné je zadávat samostatně. Některé hypercally však vyžadují proměnlivé množství dat hlavičky. Tyto hypervolají obvykle vstupní hlavičku s pevnou velikostí a další vstup hlavičky, který má proměnnou velikost.

Hlavička s proměnnou velikostí se podobá pevnému vstupu hypercall (zarovnaného na 8 bajtů a velikosti násobku 8 bajtů). Volající musí určit, kolik dat poskytuje jako vstupní hlavičky. Tato velikost se poskytuje jako součást vstupní hodnoty hypercallu (viz "Velikost hlavičky proměnné" v tabulce výše).

Vzhledem k tomu, že pevná velikost záhlaví je implicitní, místo zadání celkové velikosti záhlaví je ve vstupních ovládacích prvcích zadána pouze proměnná část:

Variable Header Bytes = {Total Header Bytes - sizeof(Fixed Header)} rounded up to nearest multiple of 8

Variable Header Size = Variable Header Bytes / 8

Je neplatné zadat nenulovou velikost hlavičky hlavičky hypercallu, která není explicitně zdokumentovaná jako přijetí vstupních hlaviček s proměnnou velikostí. V takovém případě hypercall způsobí návratový kód .HV_STATUS_INVALID_HYPERCALL_INPUT

Je možné, že pro dané vyvolání hypercallu, který přijímá vstupní hlavičky s proměnlivou velikostí, které všechny vstupy hlavičky zcela odpovídají hlavičce pevné velikosti. V takových případech je vstupní hlavička proměnné velikosti nulová a odpovídající bity ve vstupu hypercall by měly být nastaveny na nulu.

Ve všech ostatních případech jsou hypercally, které přijímají vstupní hlavičky s proměnlivou velikostí, podobné hypercallům vstupní hlavičky s pevnou velikostí, pokud jde o konvence volání. Hypercall hlavičky s proměnlivou velikostí také podporuje sémantiku rep. V takovém případě prvky rep leží za záhlavím obvyklým způsobem, s tím rozdílem, že celková velikost záhlaví zahrnuje pevné i proměnné části. Všechna ostatní pravidla zůstávají stejná, například první prvek rep musí být zarovnaný 8 bajtů.

XMM Fast Hypercall Input (x86/x64)

Hypervisor na platformách x86/x64 podporuje použití rychlých volání XMM, což umožňuje některým hypervolacím využívat lepší výkon rozhraní rychlého hypercallu, i když vyžadují více než dva vstupní parametry. Rozhraní XMM fast hypercall používá šest registrů XMM, aby volajícímu umožnilo předat vstupní blok parametru o velikosti až 112 bajtů.

Dostupnost rozhraní rychlého hypercallu XMM je uvedena prostřednictvím typu "Hypervisor Feature Identification" (Identifikace funkce hypervisoru) – list CPUID (0x40000003):

  • Bit 4: Podpora předávání vstupu hypercall prostřednictvím registrů XMM je k dispozici.

Všimněte si, že existuje samostatný příznak, který označuje podporu rychlého výstupu XMM. Jakýkoli pokus o použití tohoto rozhraní, pokud hypervisor neindikuje dostupnost, bude mít za následek chybu #UD.

Mapování registru (pouze vstup)

x64 x86 Zadané informace
RCX EDX:EAX Vstupní hodnota hypercallu
RDX EBX:ECX Blok vstupního parametru
R8 EDI:ESI Blok vstupního parametru
XMM0 XMM0 Blok vstupního parametru
XMM1 XMM1 Blok vstupního parametru
XMM2 XMM2 Blok vstupního parametru
XMM3 XMM3 Blok vstupního parametru
XMM4 XMM4 Blok vstupního parametru
XMM5 XMM5 Blok vstupního parametru

Vstupní hodnota hypercallu se předává v registrech spolu se vstupními parametry. Mapování registru závisí na tom, jestli je volající spuštěný v 32bitovém (x86) nebo 64bitovém režimu (x64). Hypervisor určuje režim volajícího na základě hodnoty EFER. LMA a CS.L. Pokud jsou oba tyto příznaky nastavené, předpokládá se, že volající je 64bitový volající. Pokud je vstupní blok parametru menší než 112 bajtů, budou všechny nadbytečné bajty v registrech ignorovány.

Registrace vstupu rychlého volání (ARM64 SMCCC)

Hypervisor na platformách ARM64 podporuje použití rychlých hypercallů pro registraci, což umožňuje některým hypervolacím využít lepší výkon rozhraní rychlého volání, i když vyžadují více než dva vstupní parametry. Rozhraní pro rychlý hypercall pro registraci používá 15 registrů pro obecné účely, aby volajícímu umožnilo předat vstupní blok parametru o velikosti až 120 bajtů.

Mapování registru (pouze vstup)

Register Zadané informace
X0 Identifikátor funkce SMCCC
X1 Vstupní hodnota hypercallu
X2 – X17 Blok vstupního parametru

Pokud je vstupní blok parametru menší než 120 bajtů, budou všechny nadbytečné bajty v registrech ignorovány.

Registrace vstupu rychlého volání (ARM64 HVC #1)

Rozhraní hypercallu pro registraci používá šestnáct registrů pro obecné účely, aby volajícímu umožnil předat vstupní blok parametru o velikosti až 128 bajtů.

Mapování registru (pouze vstup)

Register Zadané informace
X0 Vstupní hodnota hypercallu
X1 – X17 Blok vstupního parametru

Pokud je vstupní blok parametru menší než 128 bajtů, budou všechny nadbytečné bajty v registrech ignorovány.

Výstupy hypercallu

Všechny hypercally vrátí 64bitovou hodnotu označovanou jako výsledná hodnota hypercallu. Formátuje se takto:

Obor Bity Comment
Result 15-0 HV_STATUS kód označující úspěch nebo selhání
Rsvd 31-16 Volající by měli ignorovat hodnotu v těchto bitech.
Zástupci se dokončili. 43-32 Počet úspěšně dokončených opakování
RsvdZ 63-40 Volající by měli ignorovat hodnotu v těchto bitech.

V případě hypercallů rep je celé pole reps complete (celkový počet opakování) dokončený, nikoli relativní vzhledem k indexu zahájení opakování. Pokud například volající zadal index zahájení opakování 5 a počet opakování 10, pole dokončení zástupců by při úspěšném dokončení označilo 10.

Výsledná hodnota hypercallu se předává zpět v registrech.

Mapování registru na platformě x64 závisí na tom, jestli volající běží v 32bitovém (x86) nebo 64bitovém (x64) režimu (viz výše). Mapování registru pro výstupy hypercallu je následující:

x64 x86 Zadané informace
RAX EDX:EAX Hodnota výsledku hypercallu

V ARM64 je mapování registru pro výstupy hypercallu následující:

Register Zadané informace
X0 Hodnota výsledku hypercallu

XMM Fast Hypercall Output (x86/x64)

Podobně jako hypervisor podporuje rychlé vstupy hypercallu XMM, stejné registry je možné sdílet, aby se vrátil výstup. To se podporuje jenom na platformách x64.

Schopnost vracet výstup prostřednictvím registrů XMM je uvedena prostřednictvím typu "Hypervisor Feature Identification" (Id funkce hypervisoru) (0x40000003):

  • Bit 15: Podpora vrácení výstupu hypercall prostřednictvím registrů XMM je k dispozici.

Všimněte si, že existuje samostatný příznak, který označuje podporu rychlého vstupu XMM. Jakýkoli pokus o použití tohoto rozhraní, pokud hypervisor neindikuje dostupnost, bude mít za následek chybu #UD.

Mapování registru (vstup a výstup)

K vrácení výstupu je možné použít registry, které se nepoužívají k předávání vstupních parametrů. Jinými slovy, pokud je blok vstupního parametru menší než 112 bajtů (zaokrouhlený nahoru na nejbližší blok zarovnaných 16 bajtů), zbývající registry vrátí výstup hypercallu.

x64 Zadané informace
RDX Vstupní nebo výstupní blok
R8 Vstupní nebo výstupní blok
XMM0 Vstupní nebo výstupní blok
XMM1 Vstupní nebo výstupní blok
XMM2 Vstupní nebo výstupní blok
XMM3 Vstupní nebo výstupní blok
XMM4 Vstupní nebo výstupní blok
XMM5 Vstupní nebo výstupní blok

Pokud má například vstupní blok parametru velikost 20 bajtů, hypervisor by ignoroval následující 12 bajtů. Zbývající 80 bajtů by obsahovaly výstup hypercall (pokud je k dispozici).

Registrace výstupu rychlého volání (ARM64 SMCCC)

Na platformách ARM64, podobně jako hypervisor podporuje registraci rychlých vstupů hypercall, je možné stejné registry sdílet, aby se vrátil výstup.

Mapování registru (vstup a výstup)

K vrácení výstupu je možné použít registry, které se nepoužívají k předávání vstupních parametrů. Jinými slovy, pokud je vstupní blok parametru menší než 120 bajtů (zaokrouhlený nahoru na nejbližší 8 bajtový blok zarovnaný do bloku), zbývající registry vrátí výstup hypercallu.

Register Zadané informace
X2 – X17 Vstupní nebo výstupní blok

Pokud má například vstupní blok parametru velikost 20 bajtů, hypervisor by ignoroval následující 4 bajty. Zbývající 96 bajtů by obsahovaly výstup hypercall (pokud je k dispozici).

Registrace výstupu rychlého volání (ARM64 HVC #1)

Podobně jako verze SMCCC používá rozhraní HVC #1 stejné registry k vrácení výstupu.

Mapování registru (vstup a výstup)

K vrácení výstupu je možné použít registry, které se nepoužívají k předávání vstupních parametrů. Jinými slovy, pokud je vstupní blok parametru menší než 128 bajtů (zaokrouhlený nahoru na nejbližší 8 bajtový blok zarovnaný do bloku), zbývající registry vrátí výstup hypercallu.

Register Zadané informace
X1 – X17 Vstupní nebo výstupní blok

Pokud má například vstupní blok parametru velikost 20 bajtů, hypervisor by ignoroval následující 4 bajty. Zbývajících 104 bajtů by obsahovalo výstup hypercall (pokud je k dispozici).

Volatilní registry (x86/x64)

Hypercalls upraví pouze zadané hodnoty registru za následujících podmínek:

  1. RAX (x64) a EDX:EAX (x86) se vždy přepíšou hodnotou výsledku hypercallu a výstupními parametry, pokud existují.
  2. Hypercalls rep upraví RCX (x64) a EDX:EAX (x86) pomocí nového indexu startu rep.
  3. HvCallSetVpRegisters může upravit všechny registry, které jsou podporovány s tímto hypercallem.
  4. RdX, R8 a XMM0 až XMM5, pokud se používá pro rychlý vstup hypercall, zůstanou nezměněné. Registrace používané pro rychlý výstup hypercall je však možné upravit, včetně RDX, R8 a XMM0 až XMM5. Hyper-V tyto registry upraví pouze pro rychlý výstup hypercallu, který je omezen na x64.

Volatilní registry (ARM64 SMCCC)

Hypercalls upraví pouze zadané hodnoty registru za následujících podmínek:

  1. X0 se vždy přepíše hodnotou výsledku hypercallu a výstupními parametry, pokud existuje.
  2. Hypercalls rep upraví X1 s novým indexem spuštění rep.
  3. HvCallSetVpRegisters může upravit všechny registry, které jsou podporovány s tímto hypercallem.
  4. X2 – X17, pokud se používá pro rychlý vstup hypercall, zůstávají nezměněné. Registrace používané pro rychlý výstup hypercall je však možné upravit, včetně X2 – X17. Hyper-V tyto registry upraví pouze pro rychlý výstup hypercallu.

Volatilní registry (ARM64 HVC #1)

Hypercalls upraví pouze zadané hodnoty registru za následujících podmínek:

  1. X0 se vždy přepíše hodnotou výsledku hypercallu a výstupními parametry, pokud existuje.
  2. Hypercalls rep upraví X0 pomocí nového indexu spuštění rep.
  3. HvCallSetVpRegisters může upravit všechny registry, které jsou podporovány s tímto hypercallem.
  4. X1 – X17, pokud se používá pro rychlý vstup hypercall, zůstávají nezměněné. Registrace používané pro rychlý výstup hypercall je však možné upravit, včetně X1 – X17. Hyper-V tyto registry upraví pouze pro rychlý výstup hypercallu.

Omezení hypercallu

Hypercalls může mít přidružená omezení, která musí být splněna, aby mohli provést zamýšlenou funkci. Pokud nejsou splněna všechna omezení, hypercall se ukončí s příslušnou chybou. V případě použití budou uvedena následující omezení:

  • Volající oddíl musí mít konkrétní oprávnění.
  • Oddíl, na který se pracuje, musí být v určitém stavu (např. Aktivní).

Stavové kódy hypercallu

Každý hypercall je zdokumentován jako vrácení výstupní hodnoty, která obsahuje několik polí. Pole hodnoty stavu (typu HV_STATUS) slouží k označení, jestli bylo volání úspěšné nebo neúspěšné.

Platnost výstupního parametru u neúspěšných hypercallů

Pokud není výslovně uvedeno jinak, pokud hypercall selže (to znamená, že výsledné pole hodnoty výsledku hypercallu obsahuje jinou hodnotu než HV_STATUS_SUCCESS), obsah všech výstupních parametrů je neurčitý a volající by neměl zkoumat. Pouze v případě, že hypercall proběhne úspěšně, budou všechny příslušné výstupní parametry obsahovat platné, očekávané výsledky.

Řazení chybových podmínek

Pořadí, ve kterém jsou zjištěny chybové stavy a hlášeny hypervisorem, není definováno. Jinými slovy, pokud existuje více chyb, musí hypervisor zvolit, který chybový stav se má hlásit. Priorita by měla být udělena těmto kódům chyb nabízejícím větší zabezpečení. Cílem je zabránit hypervisoru odhalit informace volajícím, kteří nemají dostatečná oprávnění. Stavový kód je například upřednostňovaný stavový kód HV_STATUS_ACCESS_DENIED před kódem, který by odhalil určité kontextové nebo stavové informace čistě na základě oprávnění.

Běžné stavové kódy hypercallu

Několik kódů výsledků je společné pro všechny hypercally, a proto nejsou zdokumentovány pro každý hypercall jednotlivě. Patří mezi ně následující:

Stavový kód Chybový stav
HV_STATUS_SUCCESS Volání bylo úspěšné.
HV_STATUS_INVALID_HYPERCALL_CODE Kód hypercallu není rozpoznán.
HV_STATUS_INVALID_HYPERCALL_INPUT Počet opakování je nesprávný (například nenulový počet opakování se předá volání bez rep nebo se do volání zástupce předá nulový počet opakování).
Index zahájení opakování není menší než počet opakování.
Rezervovaný bit v zadané vstupní hodnotě hypercall je nenulový.
HV_STATUS_INVALID_ALIGNMENT Zadaný vstupní nebo výstupní ukazatel GPA není zarovnaný na 8 bajtů.
Zadaný vstupní nebo výstupní parametr obsahuje stránky rozsahu.
Vstupní nebo výstupní ukazatel GPA není v mezích prostoru GPA.

Návratový kód HV_STATUS_SUCCESS označuje, že nebyl zjištěn žádný chybový stav.

Vytváření sestav identity hostovaného operačního systému

Hostovaný operační systém spuštěný v rámci oddílu se musí sám identifikovat hypervisor napsáním jeho podpisu a verze do MSR (HV_X64_MSR_GUEST_OS_ID/HvRegisterGuestOsId), aby mohl vyvolat hypercalls. Tento msR je rozdělený na oddíly a sdílí se mezi všemi virtuálními procesory.

Hodnota tohoto registru je zpočátku nula.

Na platformě x86/x64 musí být nenulová hodnota zapsána do MSR ID hostovaného operačního systému, aby bylo možné povolit znakovou stránku hypercallu (viz Vytvoření rozhraní Hypercall (x86/x64)). Pokud je tento registr následně nulový, kódová stránka hypercall bude zakázána.

V ARM64 musí být před vyvolání kódy hypercallu zapsána nenulová hodnota do MSR ID hostovaného operačního systému. Výjimkou jsou hypercally HvCallSetVpRegisters/HvCallGetVpRegisters . Další informace najdete v příslušné dokumentaci.

#define HV_X64_MSR_GUEST_OS_ID 0x40000000
#define HvRegisterGuestOsId 0x00090002

V ARM64 se podporuje pouze HvRegisterGuestOsId, který se musí zapsat pomocí hypercallu HvCallSetVpRegisters na spouštěcím procesoru.

Identita hostovaného operačního systému pro vlastní operační systémy

Toto je doporučené kódování pro tento msR. Některá pole nemusí platit pro některé hostovaný operační systém.

Bity Obor Description
15:0 Číslo sestavení Určuje číslo buildu operačního systému.
23:16 Verze služby Označuje verzi služby (například číslo aktualizace Service Pack).
31:24 Menší verze Označuje podverzi operačního systému.
39:32 Hlavní verze Označuje hlavní verzi operačního systému.
47:40 ID operačního systému Označuje variantu operačního systému. Kódování je pro dodavatele jedinečné. Operační systémy Microsoftu jsou kódovány takto: 0=Undefined, 1=MS-DOS®, 2=Windows® 3.x, 3=Windows® 9x, 4=Windows® NT (a deriváty), 5=Windows® CE
62:48 ID dodavatele Označuje dodavatele hostovaného operačního systému. Hodnota 0 je vyhrazena. Podívejte se na seznam dodavatelů níže.
63 Typ operačního systému Označuje typ operačního systému. Hodnota 0 představuje proprietární (uzavřený zdroj) operační systém. Hodnota 1 představuje opensourcový operační systém.

Hodnoty dodavatelů přiděluje Microsoft. Pokud chcete požádat o nového dodavatele, vytvořte problém v úložišti dokumentace virtualizace GitHubu (https://aka.ms/VirtualizationDocumentationIssuesTLFS).

Prodejce Hodnota
Microsoft 0x0001
HPE 0x0002
BlackBerry 0x0003
LANCOM 0x0200

Identita hostovaného operačního systému MSR pro opensourcové operační systémy

Následující kódování je nabízeno jako pokyny pro dodavatele opensourcového operačního systému, kteří mají v úmyslu splňovat tuto specifikaci. Navrhuje se, aby opensourcové operační systémy přijaly následující konvenci.

Bity Obor Description
15:0 Číslo sestavení Informace specifické pro distribuci (např. číslo buildu).
47:16 Version Informace o verzi upstreamového jádra
55:48 ID operačního systému Další informace o dodavateli
62:56 Typ operačního systému Typ operačního systému (např. Linux, FreeBSD atd.). Seznam známých typů operačního systému najdete níže.
63 Open source Hodnota 1 označuje opensourcový operační systém.

Hodnoty typu operačního systému přidělují Microsoft. Pokud chcete požádat o nový typ operačního systému, vytvořte problém v úložišti dokumentace virtualizace GitHubu (https://aka.ms/VirtualizationDocumentationIssuesTLFS).

Typ operačního systému Hodnota
Operační systém Linux 0x1
FreeBSD 0x2
Xen 0x3
Illumos 0x4

Vytvoření rozhraní Hypercall (x86/x64)

Na platformě x86/x64 se volání Hypercalls vyvolá pomocí speciálního opcode. Vzhledem k tomu, že se tento opcode liší mezi implementacemi virtualizace, je nutné, aby hypervisor tento rozdíl abstrahuje. To se provádí prostřednictvím speciální stránky hypercall. Tato stránka je poskytována hypervisorem a zobrazí se v prostoru zásad skupiny hosta. Host musí zadat umístění stránky programováním hosta Hypercall MSR.

#define HV_X64_MSR_HYPERCALL 0x40000001
Bity Description Attributes
63:12 Hypercall GPFN – označuje číslo fyzické stránky hosta na stránce hypercall. Čtení/zápis
11:2 RsvdP. Bity by měly být při čtení ignorovány a zachovány při zápisech. Rezervováno
1 Zamčený. Označuje, jestli je msR neměnný. V případě nastavení je tento msR uzamčen, čímž brání přemístění stránky hypercall. Po nastavení může bit vymazat pouze resetování systému. Čtení/zápis
0 Povolení stránky hypercall Čtení/zápis

Hypercall page může být umístěn kdekoli v prostoru zásad skupiny hosta, ale musí být zarovnaný na stránce. Pokud se host pokusí přesunout stránku hypercallu mimo hranice prostoru GPA, při zápisu msR dojde k chybě #GP.

Jedná se o msR na úrovni oddílů. Jinými slovy, sdílí ho všechny virtuální procesory v oddílu. Pokud jeden virtuální procesor úspěšně zapíše do msR, jiný virtuální procesor přečte stejnou hodnotu.

Před povolením stránky hypercall musí hostovaný operační systém hlásit svou identitu zápisem podpisu verze do samostatného msR (HV_X64_MSR_GUEST_OS_ID). Pokud nebyla zadána žádná identita hostovaného operačního systému, pokusy o povolení hypercallu selžou. Bit povolení zůstane nulový i při zápisu do něj. Pokud se navíc identita hostovaného operačního systému po povolení stránky hypercall vymaže na nulu, bude zakázaná.

Stránka hypercall se zobrazí jako překrytí prostoru GPA; to znamená, že pokrývá cokoli jiného je namapováno na rozsah GPA. Jeho obsah je čitelný a spustitelný hostem. Při pokusu o zápis na stránku hypercall dojde k výjimce ochrany (#GP). Jakmile je stránka hypercall povolená, vyvolání hypercallu jednoduše zahrnuje volání na začátek stránky.

Následuje podrobný seznam kroků, které se týkají vytvoření stránky hypercallu:

  1. Host načte CPUID list 1 a určuje, jestli je hypervisor přítomný kontrolou bitu 31 registru ECX.
  2. Host přečte list CPUID 0x40000000 k určení maximálního listu CPUID hypervisoru (vráceného v registru EAX) a list CPUID 0x40000001 k určení podpisu rozhraní (vráceného v registru EAX). Ověřuje, že maximální hodnota listu je alespoň 0x40000005 a že se podpis rozhraní rovná "Hv#1". Tento podpis znamená, HV_X64_MSR_HYPERCALL že HV_X64_MSR_GUEST_OS_IDa HV_X64_MSR_VP_INDEX jsou implementovány.
  3. Host zapíše svou identitu operačního systému do MSR HV_X64_MSR_GUEST_OS_ID , pokud je tato registrace nula.
  4. Host přečte hypercall MSR (HV_X64_MSR_HYPERCALL).
  5. Host zkontroluje bit stránky Hypercall. Pokud je nastavené, rozhraní je již aktivní a kroky 6 a 7 by měly být vynechány.
  6. Host najde stránku v prostoru GPA, nejlépe ten, který není obsazen ram, MMIO atd. Pokud je stránka obsazená, host by se měl vyhnout použití podkladové stránky pro jiné účely.
  7. Host zapíše novou hodnotu do hypercall MSR (HV_X64_MSR_HYPERCALL), která zahrnuje GPA z kroku 6 a nastaví bit Povolit hypercall Page pro povolení rozhraní.
  8. Host vytvoří spustitelné mapování VA na hypercall page GPA.
  9. Host se 0x40000003 na cpuID, aby určil, která hypervisorová zařízení jsou k dispozici. Po vytvoření rozhraní může host zahájit hypercall. Provede to tak, že naplní registry podle protokolu hypercall a vydá volání na začátek stránky hypercall. Host by měl předpokládat, že stránka hypercall provede ekvivalent blízkého návratu (0xC3) pro návrat volajícího. Hypercall se proto musí vyvolat s platným zásobníkem.

Vytvoření rozhraní Hypercall (ARM64)

Vzhledem k tomu, že ARM64 nativně podporuje instrukce HVC, hypervisor k povolení hypercallů nepotřebuje další konfiguraci.

Rozšířené rozhraní Hypercall

Hypercalls with call codes above 0x8000 are known as extended hypercalls. Rozšířené hypercally používají stejnou konvenci volání jako normální hypercalls a z hlediska hostovaného virtuálního počítače se zobrazují stejně. Rozšířené hypercally se interně zpracovávají odlišně v rámci hypervisoru Hyper-V.

Rozšířené možnosti hypercallu je možné dotazovat pomocí HvExtCallQueryCapabilities.