Delen via


Hypercall-interface

De hypervisor biedt een oproepmechanisme voor gasten. Dergelijke aanroepen worden hypercalls genoemd. Elke hypercall definieert een set invoer- en/of uitvoerparameters. Deze parameters worden opgegeven in termen van een gegevensstructuur op basis van geheugen. Alle elementen van de gegevensstructuren voor invoer en uitvoer worden opgevuld naar natuurlijke grenzen van maximaal 8 bytes (dat wil gezegd: twee-byteelementen moeten zich op twee-bytegrenzen bevinden, enzovoort).

Een tweede hypercall-aanroepconventie kan eventueel worden gebruikt voor een subset hypercalls, met name die met twee of minder invoerparameters en geen uitvoerparameters. Wanneer u deze aanroepconventie gebruikt, worden de invoerparameters doorgegeven in algemene registers.

Een derde hypercall-aanroepconventie kan eventueel worden gebruikt voor een subset hypercalls waarbij het invoerparameterblok maximaal 112 bytes is. Wanneer u deze aanroepconventie gebruikt, worden de invoerparameters doorgegeven in registers, inclusief de vluchtige XMM-registers.

Invoer- en uitvoergegevensstructuren moeten beide in het geheugen worden geplaatst op een grens van 8 bytes en worden opgevuld naar een veelvoud van 8 bytes in grootte. De waarden in de opvullingsregio's worden genegeerd door de hypervisor.

Voor uitvoer mag de hypervisor (maar niet gegarandeerd) opvullingsregio's overschrijven. Als het opvullingsregio's overschrijft, worden er nullen geschreven.

Hypercall-klassen

Er zijn twee klassen hypercalls: eenvoudig en rep (kort voor 'herhalen'). Een eenvoudige hypercall voert één bewerking uit en heeft een set invoer- en uitvoerparameters met vaste grootte. Een rep hypercall fungeert als een reeks eenvoudige hypercalls. Naast een set invoer- en uitvoerparameters met een vaste grootte, omvatten rep-hypercalls een lijst met invoer- en/of uitvoerelementen met vaste grootte.

Wanneer een aanroeper in eerste instantie een rep-hypercall aanroept, geeft deze een aantal vertegenwoordigers op dat het aantal elementen in de invoer- en/of uitvoerparameterlijst aangeeft. Bellers geven ook een beginindex van een vertegenwoordiger op die het volgende invoer- en/of uitvoerelement aangeeft dat moet worden gebruikt. De hypervisor verwerkt repparameters in de lijstvolgorde, dat wil gezegd door de elementindex te verhogen.

Voor volgende aanroepen van de rep-hypercall geeft de beginindex van de vertegenwoordiger aan hoeveel elementen zijn voltooid ( en in combinatie met de waarde voor het aantal vertegenwoordigers ) hoeveel elementen er nog over zijn. Als een beller bijvoorbeeld het aantal vertegenwoordigers van 25 opgeeft en er binnen de tijdsbeperkingen slechts 20 iteraties zijn voltooid, retourneert de hypercall het besturingselement terug naar de aanroepende virtuele processor nadat de herstartindex is bijgewerkt naar 20. Wanneer de hypercall opnieuw wordt uitgevoerd, wordt de hypervisor hervat op element 20 en worden de resterende vijf elementen voltooid.

Als er een fout optreedt bij het verwerken van een element, wordt er een juiste statuscode geleverd, samen met het aantal voltooide vertegenwoordigers, waarmee het aantal elementen wordt aangegeven dat is verwerkt voordat de fout is opgetreden. Ervan uitgaande dat het opgegeven hypercall-besturingselementwoord geldig is (zie het volgende) en de invoer-/uitvoerparameterlijsten toegankelijk zijn, kan de hypervisor gegarandeerd ten minste één rep proberen, maar het is niet vereist om de hele lijst te verwerken voordat u het besturingselement terugstuurt naar de aanroeper.

Vervolg hypercall

Een hypercall kan worden beschouwd als een complexe instructie die veel cycli in beslag neemt. De hypervisor probeert de uitvoering van hypercall te beperken tot 50μs of minder voordat de controle wordt geretourneerd naar de virtuele processor die de hypercall heeft aangeroepen. Sommige hypercall-bewerkingen zijn voldoende complex dat een garantie van 50μs moeilijk te maken is. De hypervisor is daarom afhankelijk van een hypercall-voortzettingsmechanisme voor sommige hypercalls, inclusief alle rep hypercall-formulieren.

Het hypercall-vervolgmechanisme is voornamelijk transparant voor de aanroeper. Als een hypercall niet binnen de voorgeschreven tijdslimiet kan worden voltooid, wordt het besturingselement teruggezet naar de beller, maar wordt de instructiepointer niet verder gevorderd dan de instructie die de hypercall heeft aangeroepen. Hierdoor kunnen wachtende interrupts worden verwerkt en kunnen andere virtuele processors worden gepland. Wanneer de oorspronkelijke aanroepende thread de uitvoering hervat, wordt de hypercall-instructie opnieuw uitgevoerd en wordt de voortgang vooruitgeschoven voor het voltooien van de bewerking.

De meeste eenvoudige hypercalls worden gegarandeerd binnen de voorgeschreven tijdslimiet voltooid. Voor een klein aantal eenvoudige hypercalls kan echter meer tijd nodig zijn. Deze hypercalls gebruiken hypercall-vervolg op een vergelijkbare manier om hypercalls weer te geven. In dergelijke gevallen omvat de bewerking twee of meer interne statussen. Met de eerste aanroep wordt het object (bijvoorbeeld de partitie of virtuele processor) in één status geplaatst, en na herhaalde aanroepen gaat de status ten slotte over naar een terminalstatus. Voor elke hypercall die dit patroon volgt, worden de zichtbare bijwerkingen van tussenliggende interne toestanden beschreven.

Hypercall Atomiciteit en Volgorde

Behalve waar vermeld, is de actie die wordt uitgevoerd door een hypercall atomisch, zowel met betrekking tot alle andere gastbewerkingen (bijvoorbeeld instructies die binnen een gast worden uitgevoerd) als alle andere hypercalls die op het systeem worden uitgevoerd. Een eenvoudige hypercall voert één atomische actie uit; een rep hypercall voert meerdere, onafhankelijke atomische acties uit.

Eenvoudige hypercalls die hypercall-voortzetting gebruiken, kunnen meerdere interne statussen omvatten die extern zichtbaar zijn. Dergelijke aanroepen bestaan uit meerdere atomische bewerkingen.

Elke hypercall-actie kan invoerparameters lezen en/of resultaten schrijven. De invoer voor elke actie kan worden gelezen op elke granulariteit en op elk gewenst moment nadat de hypercall is gemaakt en voordat de actie wordt uitgevoerd. De resultaten (dat wil gezegd de uitvoerparameters) die aan elke actie zijn gekoppeld, kunnen worden geschreven op elke granulariteit en op elk gewenst moment nadat de actie is uitgevoerd en voordat de hypercall wordt geretourneerd.

De gast moet het onderzoek en/of de manipulatie van invoer- of uitvoerparameters met betrekking tot een uitgevoerde hypercall vermijden. Hoewel een virtuele processor die een hypercall uitvoert, dit niet kan doen (omdat de uitvoering van de gast wordt opgeschort totdat de hypercall wordt geretourneerd), is er niets om te voorkomen dat andere virtuele processors dit doen. Gasten die zich op deze manier gedragen, kunnen vastlopen of beschadiging binnen hun partitie veroorzaken.

Hypercalls kunnen alleen worden aangeroepen vanuit de meest bevoegde gastprocessormodus. Op x64-platforms betekent dit de beveiligde modus met een huidige bevoegdheidsniveau (CPL) van nul. Hoewel code in de echte modus wordt uitgevoerd met een effectieve CPL van nul, zijn hypercalls niet toegestaan in de echte modus. Een poging om een hypercall in een illegale processormodus aan te roepen, genereert een uitzondering voor #UD (niet-gedefinieerde bewerking) op x64 en een niet-gedefinieerde instructie-uitzondering op ARM64.

Alle hypercalls moeten worden aangeroepen via de architectuur gedefinieerde hypercall-interface (zie hieronder). Een poging om een hypercall op een andere manier aan te roepen (bijvoorbeeld het kopiëren van de code van de hypercall-codepagina naar een alternatieve locatie en deze daar uit te voeren), kan leiden tot een niet-gedefinieerde bewerking (#UD). De hypervisor is niet gegarandeerd dat deze uitzondering wordt geleverd.

Uitlijningsvereisten

Bellers moeten het fysieke 64-bits gastadres (GPA) van de invoer- en/of uitvoerparameters opgeven. GPA-aanwijzers moeten 8 bytes zijn uitgelijnd. Als de hypercall geen invoer- of uitvoerparameters bevat, negeert de hypervisor de bijbehorende GPA-aanwijzer.

De lijsten met invoer- en uitvoerparameters mogen geen paginagrenzen overlappen of overschrijden. Hypercall-invoer- en uitvoerpagina's zijn naar verwachting GPA-pagina's en niet 'overlay'-pagina's. Als de virtuele processor de invoerparameters naar een overlaypagina schrijft en een GPA opgeeft op deze pagina, is de hypervisortoegang tot de lijst met invoerparameters niet gedefinieerd.

De hypervisor controleert of de aanroepende partitie kan worden gelezen op de invoerpagina voordat de aangevraagde hypercall wordt uitgevoerd. Deze validatie bestaat uit twee controles: de opgegeven GPA is toegewezen en de GPA is gemarkeerd als leesbaar. Als een van deze tests mislukt, genereert de hypervisor een bericht over het onderscheppen van geheugen. Voor hypercalls met uitvoerparameters valideert de hypervisor dat de partitie naar de uitvoerpagina kan schrijven. Deze validatie bestaat uit twee controles: de opgegeven GPA is toegewezen en de GPA is gemarkeerd als beschrijfbaar.

Hypercall-invoer

Bellers geven een hypercall op met een 64-bits waarde die een hypercall-invoerwaarde wordt genoemd. De indeling is als volgt:

Veld Bits Verstrekte informatie
Code aanroepen 15-0 Hiermee geeft u op welke hypercall wordt aangevraagd
Snel 16 Hiermee geeft u op of de hypercall gebruikmaakt van de op register gebaseerde oproepconventie: 0 = geheugen, 1 = registergebaseerde
Grootte van variabele header 26-17 De grootte van een variabele header in QWORDS.
RsvdZ 30-27 Moet nul zijn
Is genest 31 Hiermee geeft u de hypercall moet worden verwerkt door de L0-hypervisor in een geneste omgeving.
Aantal repen 43-32 Totaal aantal repen (voor rep-aanroep moet anders nul zijn)
RsvdZ 47-44 Moet nul zijn
Beginindex van rep 59-48 Index starten (voor rep-aanroep moet anders nul zijn)
RsvdZ 63-60 Moet nul zijn

Voor rep hypercalls geeft het veld aantal reps het totale aantal reps aan. De beginindex van de vertegenwoordiger geeft de specifieke herhaling aan ten opzichte van het begin van de lijst (nul geeft aan dat het eerste element in de lijst moet worden verwerkt). Daarom moet de waarde voor het aantal herhalingen altijd groter zijn dan de beginindex van de rep.

Hypercall-registerconventies (x86/x64)

Registreer op x86/x64 de toewijzing voor hypercall-invoer wanneer de Fast-vlag nul is:

x64 x86 Verstrekte informatie
RCX EDX:EAX Hypercall-invoerwaarde
RDX EBX:ECX GPA-invoerparameters
R8 EDI:ESI GPA-uitvoerparameters

De hypercall-invoerwaarde wordt doorgegeven in registers, samen met een GPA die verwijst naar de invoer- en uitvoerparameters.

De registratietoewijzingen zijn afhankelijk van of de aanroeper wordt uitgevoerd in de 32-bits modus (x86) of de 64-bits modus (x64). De hypervisor bepaalt de modus van de beller op basis van de waarde van EFER. LMA en CS.L. Als beide vlaggen zijn ingesteld, wordt ervan uitgegaan dat de beller een 64-bits beller is.

Registreer toewijzing voor hypercall-invoer wanneer de Fast-vlag er een is:

x64 x86 Verstrekte informatie
RCX EDX:EAX Hypercall-invoerwaarde
RDX EBX:ECX Invoerparameter
R8 EDI:ESI Uitvoerparameter

De hypercall-invoerwaarde wordt doorgegeven in registers, samen met de invoerparameters.

Hypercall-registerconventies (ARM64 SMCCC)

In ARM64 worden hypercalls uitgevoerd met behulp van de instructie 'HVC #0'. De aanroepen voldoen aan de ARM64 SMCCC (SMC Calling Convention).

Registratietoewijzing voor hypercall-invoer is als volgt:

Register Verstrekte informatie
X0 SMCCC, functie-id
X1 Hypercall-invoerwaarde
X2 GPA-invoerparameters
X3 GPA-uitvoerparameters

De SMCCC-functie-id in X0 volgt deze indeling:

Bits Veld Waarde Description
31 Oproep opleveren 0 Altijd 0
30 Oproepconventie 1 1 voor HVC64-belconventies
29:24 Type serviceoproep 6 6 voor leverancierspecifieke hypervisorservice-aanroepen
23:16 Gereserveerd 0 Gereserveerd, moet nul zijn (Res0)
15:0 Functienummer 1 1 geeft aan dat hv-aanroepcode is gedefinieerd in X1

De volledige indeling van de functie-id: 0x46000001

Conventies voor Hypercall-registratie (ARM64 HVC #1)

Om historische redenen ondersteunt de ARM64-hypervisorinterface ook een andere aanroepconventie. De hypercalls worden uitgevoerd met de instructie 'HVC #1'. U wordt aangeraden de SMCCC-aanroepconventie te gebruiken voor nieuwe code.

Registratietoewijzing voor hypercall-invoer is als volgt:

Register Verstrekte informatie
X0 Hypercall-invoerwaarde
X1 GPA-invoerparameters
X2 GPA-uitvoerparameters

Hypercall-invoerkoppen met variabele grootte

De meeste hypercall-invoerheaders hebben een vaste grootte. De hoeveelheid headergegevens die van de gast aan de hypervisor worden doorgegeven, wordt daarom impliciet opgegeven door de hypercall-code en hoeft niet afzonderlijk te worden opgegeven. Voor sommige hypercalls is echter een variabele hoeveelheid headergegevens vereist. Deze hypercalls hebben doorgaans een invoerheader met een vaste grootte en extra headerinvoer met een variabele grootte.

Een header met variabele grootte is vergelijkbaar met een vaste hypercall-invoer (uitgelijnd op 8 bytes en de grootte van een veelvoud van 8 bytes). De aanroeper moet opgeven hoeveel gegevens het levert als invoerheaders. Deze grootte wordt geleverd als onderdeel van de hypercall-invoerwaarde (zie 'Variabele headergrootte' in de bovenstaande tabel).

Omdat de vaste koptekstgrootte impliciet is, in plaats van de totale headergrootte op te geven, wordt alleen het variabele gedeelte opgegeven in de invoerbesturingselementen:

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

Variable Header Size = Variable Header Bytes / 8

Het is illegaal om een niet-nul-variabele headergrootte op te geven voor een hypercall die niet expliciet wordt gedocumenteerd als het accepteren van invoerheaders met een variabele grootte. In dat geval resulteert de hypercall in een retourcode van HV_STATUS_INVALID_HYPERCALL_INPUT.

Het is mogelijk dat voor een bepaalde aanroep van een hypercall die wel invoerheaders van variabele grootte accepteert die alle headerinvoer volledig binnen de koptekst met vaste grootte past. In dergelijke gevallen is de invoerheader van de variabele grootte nul en moeten de bijbehorende bits in de hypercall-invoer worden ingesteld op nul.

In alle andere opzichten zijn hypercalls die invoerkoppen van variabele grootte accepteren, anders vergelijkbaar met hypercalls met een vaste grootte van de invoerheader met betrekking tot aanroepende conventies. Het is ook mogelijk voor een hypercall met een variabele grootte om ondersteuning te bieden voor semantiek van vertegenwoordigers. In dat geval liggen de rep-elementen na de koptekst op de gebruikelijke manier, behalve dat de totale grootte van de koptekst zowel de vaste als variabele delen bevat. Alle andere regels blijven hetzelfde, bijvoorbeeld het eerste rep-element moet 8 byte zijn uitgelijnd.

XMM Fast Hypercall-invoer (x86/x64)

Op x86/x64-platforms ondersteunt de hypervisor het gebruik van snelle XMM-hypercalls, waardoor sommige hypercalls kunnen profiteren van de verbeterde prestaties van de snelle hypercall-interface, ook al vereisen ze meer dan twee invoerparameters. De XMM snelle hypercall-interface maakt gebruik van zes XMM-registers om de aanroeper toe te staan een invoerparameterblok van maximaal 112 bytes in grootte door te geven.

De beschikbaarheid van de XMM snelle hypercall-interface wordt aangegeven via de CPUID Leaf van de Hypervisor-functie (0x40000003):

  • Bit 4: ondersteuning voor het doorgeven van hypercall-invoer via XMM-registers is beschikbaar.

Houd er rekening mee dat er een afzonderlijke vlag is om ondersteuning voor snelle XMM-uitvoer aan te geven. Elke poging om deze interface te gebruiken wanneer de hypervisor niet aangeeft dat beschikbaarheid resulteert in een #UD fout.

Toewijzing registreren (alleen invoer)

x64 x86 Verstrekte informatie
RCX EDX:EAX Hypercall-invoerwaarde
RDX EBX:ECX Invoerparameterblok
R8 EDI:ESI Invoerparameterblok
XMM0 XMM0 Invoerparameterblok
XMM1 XMM1 Invoerparameterblok
XMM2 XMM2 Invoerparameterblok
XMM3 XMM3 Invoerparameterblok
XMM4 XMM4 Invoerparameterblok
XMM5 XMM5 Invoerparameterblok

De hypercall-invoerwaarde wordt doorgegeven in registers, samen met de invoerparameters. De registratietoewijzingen zijn afhankelijk van of de aanroeper wordt uitgevoerd in de 32-bits modus (x86) of de 64-bits modus (x64). De hypervisor bepaalt de modus van de beller op basis van de waarde van EFER. LMA en CS.L. Als beide vlaggen zijn ingesteld, wordt ervan uitgegaan dat de beller een 64-bits beller is. Als het invoerparameterblok kleiner is dan 112 bytes, worden eventuele extra bytes in de registers genegeerd.

Fast Call Input registreren (ARM64 SMCCC)

Op ARM64-platforms ondersteunt de hypervisor het gebruik van snelle hypercalls registreren, waardoor sommige hypercalls kunnen profiteren van de verbeterde prestaties van de snelle hypercall-interface, ook al vereisen ze meer dan twee invoerparameters. De snelle hypercall-interface van het register maakt gebruik van 16 algemene registers om de aanroeper toe te staan een invoerparameterblok van maximaal 128 bytes in grootte door te geven.

Toewijzing registreren (alleen invoer)

Register Verstrekte informatie
X0 SMCCC, functie-id
X1 Hypercall-invoerwaarde
X2 - X17 Invoerparameterblok

Als het invoerparameterblok kleiner is dan 128 bytes, worden eventuele extra bytes in de registers genegeerd.

Snelle oproepinvoer registreren (ARM64 HVC #1)

De snelle hypercall-interface van het register maakt gebruik van zestien algemene registers om de aanroeper toe te staan een invoerparameterblok van maximaal 128 bytes in grootte door te geven.

Toewijzing registreren (alleen invoer)

Register Verstrekte informatie
X0 Hypercall-invoerwaarde
X1 - X17 Invoerparameterblok

Als het invoerparameterblok kleiner is dan 128 bytes, worden eventuele extra bytes in de registers genegeerd.

Hypercall-uitvoer

Alle hypercalls retourneren een 64-bits waarde die een hypercall-resultaatwaarde wordt genoemd. De indeling is als volgt:

Veld Bits Comment
Resultaat 15-0 HV_STATUS code die aangeeft dat de geslaagde of mislukte bewerking is geslaagd
Rsvd 31-16 Bellers moeten de waarde in deze bits negeren
Reps voltooid 43-32 Aantal reps is voltooid
RsvdZ 63-40 Bellers moeten de waarde in deze bits negeren

Voor rep-hypercalls is het volledige veld reps het totale aantal reps voltooid en niet ten opzichte van de beginindex van de rep. Als de aanroeper bijvoorbeeld een beginindex van 5 heeft opgegeven en een aantal vertegenwoordigers van 10, geeft het veld voltooide vertegenwoordigers 10 aan bij een geslaagde voltooiing.

De hypercall-resultaatwaarde wordt doorgegeven in registers.

Op x64 is de registratietoewijzing afhankelijk van of de aanroeper wordt uitgevoerd in de 32-bits modus (x86) of de 64-bits modus (x64) (zie hierboven). De registratietoewijzing voor hypercall-uitvoer is als volgt:

x64 x86 Verstrekte informatie
RAX EDX:EAX Hypercall-resultaatwaarde

In ARM64 is de registratietoewijzing voor hypercall-uitvoer als volgt:

Register Verstrekte informatie
X0 Hypercall-resultaatwaarde

XMM Fast Hypercall-uitvoer (x86/x64)

Net als bij de manier waarop de hypervisor snelle hypercall-invoer van XMM ondersteunt, kunnen dezelfde registers worden gedeeld om uitvoer te retourneren. Dit wordt alleen ondersteund op x64-platforms.

De mogelijkheid om uitvoer via XMM-registers te retourneren, wordt aangegeven via het CPUID Leaf 'Hypervisor Feature Identification' (0x40000003):

  • Bit 15: ondersteuning voor het retourneren van hypercall-uitvoer via XMM-registers is beschikbaar.

Houd er rekening mee dat er een afzonderlijke vlag is om ondersteuning voor snelle XMM-invoer aan te geven. Elke poging om deze interface te gebruiken wanneer de hypervisor niet aangeeft dat beschikbaarheid resulteert in een #UD fout.

Toewijzing registreren (invoer en uitvoer)

Registers die niet worden gebruikt om invoerparameters door te geven, kunnen worden gebruikt om uitvoer te retourneren. Met andere woorden, als het invoerparameterblok kleiner is dan 112 bytes (afgerond op het dichtstbijzijnde 16 byte uitgelijnde segment), retourneren de resterende registers hypercall-uitvoer.

x64 Verstrekte informatie
RDX Invoer- of uitvoerblok
R8 Invoer- of uitvoerblok
XMM0 Invoer- of uitvoerblok
XMM1 Invoer- of uitvoerblok
XMM2 Invoer- of uitvoerblok
XMM3 Invoer- of uitvoerblok
XMM4 Invoer- of uitvoerblok
XMM5 Invoer- of uitvoerblok

Als het invoerparameterblok bijvoorbeeld 20 bytes groot is, negeert de hypervisor de volgende 12 bytes. De resterende 80 bytes bevatten hypercall-uitvoer (indien van toepassing).

Fast Call Output registreren (ARM64 SMCCC)

Op ARM64-platforms, vergelijkbaar met hoe de hypervisor snelle hypercall-invoer ondersteunt, kunnen dezelfde registers worden gedeeld om uitvoer te retourneren.

Toewijzing registreren (invoer en uitvoer)

Registers die niet worden gebruikt om invoerparameters door te geven, kunnen worden gebruikt om uitvoer te retourneren. Met andere woorden, als het invoerparameterblok kleiner is dan 128 bytes (afgerond op het dichtstbijzijnde 8 byte uitgelijnde segment), retourneren de resterende registers hypercall-uitvoer.

Register Verstrekte informatie
X2 - X17 Invoer- of uitvoerblok

Als het invoerparameterblok bijvoorbeeld 20 bytes groot is, negeert de hypervisor de volgende 4 bytes. De resterende 104 bytes bevatten hypercall-uitvoer (indien van toepassing).

Fast Call Output registreren (ARM64 HVC #1)

Net als bij de SMCCC-versies gebruikt de HVC #1-interface dezelfde registers om uitvoer te retourneren.

Toewijzing registreren (invoer en uitvoer)

Registers die niet worden gebruikt om invoerparameters door te geven, kunnen worden gebruikt om uitvoer te retourneren. Met andere woorden, als het invoerparameterblok kleiner is dan 128 bytes (afgerond op het dichtstbijzijnde 8 byte uitgelijnde segment), retourneren de resterende registers hypercall-uitvoer.

Register Verstrekte informatie
X1 - X17 Invoer- of uitvoerblok

Als het invoerparameterblok bijvoorbeeld 20 bytes groot is, negeert de hypervisor de volgende 4 bytes. De resterende 104 bytes bevatten hypercall-uitvoer (indien van toepassing).

Vluchtige registers (x86/x64)

Hypercalls wijzigt alleen de opgegeven registerwaarden onder de volgende voorwaarden:

  1. RAX (x64) en EDX:EAX (x86) worden altijd overschreven met de hypercall-resultaatwaarde en uitvoerparameters, indien van toepassing.
  2. Rep hypercalls wijzigen RCX (x64) en EDX:EAX (x86) met de nieuwe rep start index.
  3. HvCallSetVpRegisters kan alle registers wijzigen die worden ondersteund met die hypercall.
  4. RDX, R8 en XMM0 tot en met XMM5, wanneer deze worden gebruikt voor snelle hypercall-invoer, blijven ongewijzigd. Registers die worden gebruikt voor snelle hypercall-uitvoer kunnen echter worden gewijzigd, waaronder RDX, R8 en XMM0 tot en met XMM5. Hyper-V zal deze registers alleen wijzigen voor snelle hypercall-uitvoer, die beperkt is tot x64.

Vluchtige registers (ARM64 SMCCC)

Hypercalls wijzigt alleen de opgegeven registerwaarden onder de volgende voorwaarden:

  1. X0 wordt altijd overschreven met de hypercall-resultaatwaarde en uitvoerparameters, indien van toepassing.
  2. Met rep-hypercalls wordt X1 gewijzigd met de nieuwe beginindex van de rep.
  3. HvCallSetVpRegisters kan alle registers wijzigen die worden ondersteund met die hypercall.
  4. X2 - X17, wanneer gebruikt voor snelle hypercall-invoer, blijft ongewijzigd. Registers die worden gebruikt voor snelle hypercall-uitvoer kunnen echter worden gewijzigd, waaronder X2 - X17. Hyper-V zal deze registers alleen wijzigen voor snelle hypercall-uitvoer.

Vluchtige registers (ARM64 HVC #1)

Hypercalls wijzigt alleen de opgegeven registerwaarden onder de volgende voorwaarden:

  1. X0 wordt altijd overschreven met de hypercall-resultaatwaarde en uitvoerparameters, indien van toepassing.
  2. Met rep-hypercalls wordt X0 gewijzigd met de nieuwe beginindex van de rep.
  3. HvCallSetVpRegisters kan alle registers wijzigen die worden ondersteund met die hypercall.
  4. X1 - X17, wanneer gebruikt voor snelle hypercall-invoer, blijft ongewijzigd. Registers die worden gebruikt voor snelle hypercall-uitvoer kunnen echter worden gewijzigd, waaronder X1 - X17. Hyper-V zal deze registers alleen wijzigen voor snelle hypercall-uitvoer.

Hypercall-beperkingen

Hypercalls kunnen gekoppelde beperkingen hebben waaraan moet worden voldaan om hun beoogde functie uit te voeren. Als niet aan alle beperkingen wordt voldaan, wordt de hypercall beëindigd met een juiste fout. De volgende beperkingen worden vermeld, indien van toepassing:

  • De aanroepende partitie moet een bepaalde bevoegdheid hebben
  • De partitie waarop wordt gereageerd, moet een bepaalde status hebben (bijvoorbeeld 'Actief')

Hypercall-statuscodes

Elke hypercall wordt gedocumenteerd als het retourneren van een uitvoerwaarde die verschillende velden bevat. Er wordt een statuswaardeveld (van het type HV_STATUS) gebruikt om aan te geven of de aanroep is geslaagd of mislukt.

Geldigheid van uitvoerparameter bij mislukte Hypercalls

Tenzij expliciet anders wordt aangegeven, is de inhoud van alle uitvoerparameters onbepaald wanneer een hypercall mislukt (dat wil gezegd, het resultaatveld van de hypercall-resultaatwaarde een andere waarde bevat dan HV_STATUS_SUCCESS), de inhoud van alle uitvoerparameters is onbepaald en mag niet door de aanroeper worden onderzocht. Alleen wanneer de hypercall slaagt, bevatten alle juiste uitvoerparameters geldige, verwachte resultaten.

Volgorde van foutvoorwaarden

De volgorde waarin foutvoorwaarden worden gedetecteerd en gerapporteerd door de hypervisor, is niet gedefinieerd. Met andere woorden, als er meerdere fouten bestaan, moet de hypervisor kiezen welke foutvoorwaarde moet worden gerapporteerd. Prioriteit moet worden gegeven aan deze foutcodes die een betere beveiliging bieden, de bedoeling is om te voorkomen dat de hypervisor informatie openbaar maakt aan bellers die onvoldoende bevoegdheden hebben. De statuscode is bijvoorbeeld de voorkeursstatuscode HV_STATUS_ACCESS_DENIED ten opzichte van een code die alleen context- of statusinformatie zou onthullen op basis van bevoegdheden.

Algemene Hypercall-statuscodes

Verschillende resultaatcodes zijn gebruikelijk voor alle hypercalls en worden daarom niet voor elke hypercall afzonderlijk gedocumenteerd. Deze omvatten het volgende:

Statuscode Foutvoorwaarde
HV_STATUS_SUCCESS De aanroep is voltooid.
HV_STATUS_INVALID_HYPERCALL_CODE De hypercall-code wordt niet herkend.
HV_STATUS_INVALID_HYPERCALL_INPUT Het aantal vertegenwoordigers is onjuist (bijvoorbeeld een aantal niet-nul repen wordt doorgegeven aan een niet-rep-aanroep of een aantal herhalingen wordt doorgegeven aan een rep-aanroep).
De beginindex van de rep is niet kleiner dan het aantal reps.
Een gereserveerde bit in de opgegeven hypercall-invoerwaarde is niet nul.
HV_STATUS_INVALID_ALIGNMENT De opgegeven GPA-aanwijzer voor invoer of uitvoer is niet uitgelijnd op 8 bytes.
De opgegeven invoer- of uitvoerparameterlijsten omvatten pagina's.
De GPA-aanwijzer voor invoer of uitvoer valt niet binnen de grenzen van de GPA-ruimte.

De retourcode HV_STATUS_SUCCESS geeft aan dat er geen foutvoorwaarde is gedetecteerd.

De identiteit van het gastbesturingssystem rapporteren

Het gastbesturingssystem dat in de partitie wordt uitgevoerd, moet zichzelf identificeren bij de hypervisor door de handtekening en versie ervan naar een MSR (HV_X64_MSR_GUEST_OS_ID/HvRegisterGuestOsId) te schrijven voordat hypercalls kunnen worden aangeroepen. Deze MSR is partitiebreed en wordt gedeeld tussen alle virtuele processors.

De waarde van dit register is in eerste instantie nul.

Op x86/x64 moet een niet-nulwaarde naar de MSR van het gastbesturingssysteem worden geschreven voordat de hypercall-codepagina kan worden ingeschakeld (zie De Hypercall-interface tot stand brengen (x86/x64)). Als dit register vervolgens nul is, wordt de hypercall-codepagina uitgeschakeld.

In ARM64 moet een niet-nulwaarde worden geschreven naar de MSR van het gastbesturingssysteem voordat hypercall-codes kunnen worden aangeroepen. De uitzondering is de HvCallSetVpRegisters/HvCallGetVpRegisters hypercalls . Raadpleeg hun respectieve documentatie voor meer informatie.

#define HV_X64_MSR_GUEST_OS_ID 0x40000000
#define HvRegisterGuestOsId 0x00090002

In ARM64 wordt alleen HvRegisterGuestOsId ondersteund. Deze moet worden geschreven met behulp van de HvCallSetVpRegisters hypercall op de opstartprocessor.

Identiteit van gastbesturingssysteem voor eigen besturingssystemen

Hier volgt de aanbevolen codering voor deze MSR. Sommige velden zijn mogelijk niet van toepassing op sommige gastbesturingssystemen.

Bits Veld Description
15:0 Buildnummer Geeft het buildnummer van het besturingssysteem aan
23:16 Serviceversie Geeft de serviceversie aan (bijvoorbeeld 'servicepack'-nummer)
31:24 Kleine versie Geeft de secundaire versie van het besturingssysteem aan
39:32 Hoofdversie Geeft de primaire versie van het besturingssysteem aan
47:40 Besturingssysteem-id Geeft de variant van het besturingssysteem aan. Codering is uniek voor de leverancier. Microsoft-besturingssystemen worden als volgt gecodeerd: 0=Niet gedefinieerd, 1=MS-DOS®, 2=Windows® 3.x, 3=Windows® 9x, 4=Windows® NT (en derivaten), 5=Windows® CE
62:48 Leverancier-id Geeft de leverancier van het gastbesturingssystem aan. Een waarde van 0 is gereserveerd. Zie de lijst met leveranciers hieronder.
63 Type besturingssysteem Geeft het type besturingssysteem aan. Een waarde van 0 vertegenwoordigt een eigen besturingssysteem (gesloten bron). Een waarde van 1 vertegenwoordigt een opensource-besturingssysteem.

Leverancierswaarden worden door Microsoft toegewezen. Als u een nieuwe leverancier wilt aanvragen, dient u een probleem in in de opslagplaats voor gitHub-virtualisatiedocumentatie (https://aka.ms/VirtualizationDocumentationIssuesTLFS).

Leverancier Waarde
Microsoft 0x0001
HPE 0x0002
BlackBerry 0x0003
LANCOM 0x0200

MSR voor gastbesturingssysteemidentiteit voor opensource-besturingssystemen

De volgende codering wordt aangeboden als richtlijnen voor opensource-leveranciers van besturingssystemen die willen voldoen aan deze specificatie. Het wordt aangeraden dat opensource-besturingssystemen de volgende conventie aannemen.

Bits Veld Description
15:0 Buildnummer Distributiespecifieke informatie (bijvoorbeeld buildnummer).
47:16 Versie Informatie over upstream-kernelversies.
55:48 Besturingssysteem-id Aanvullende informatie over leveranciers
62:56 Type besturingssysteem Type besturingssysteem (bijvoorbeeld Linux, FreeBSD, enz.). Zie de lijst met bekende typen besturingssystemen hieronder
63 Open source Een waarde van 1 geeft een opensource-besturingssysteem aan.

Waarden voor het type besturingssysteem worden toegewezen door Microsoft. Als u een nieuw type besturingssysteem wilt aanvragen, moet u een probleem indienen in de gitHub-opslagplaats voor virtualisatiedocumentatie (https://aka.ms/VirtualizationDocumentationIssuesTLFS).

Type besturingssysteem Waarde
Linux 0x1
FreeBSD 0x2
Xen 0x3
Illumos 0x4

De Hypercall-interface tot stand brengen (x86/x64)

Op x86/x64 worden Hypercalls aangeroepen met behulp van een speciale opcode. Omdat deze opcode verschilt van virtualisatie-implementaties, is het noodzakelijk dat de hypervisor dit verschil abstract maakt. Dit gebeurt via een speciale hypercall-pagina. Deze pagina wordt geleverd door de hypervisor en wordt weergegeven in de GPA-ruimte van de gast. De gast is vereist om de locatie van de pagina op te geven door de Gast Hypercall MSR te programmeren.

#define HV_X64_MSR_HYPERCALL 0x40000001
Bits Description Attributes
63:12 Hypercall GPFN - Geeft het fysieke gastpaginanummer van de hypercall-pagina aan Lezen/schrijven
11:2 RsvdP. Bits moeten worden genegeerd bij leesbewerkingen en bewaard blijven op schrijfbewerkingen. Gereserveerd
1 Op slot. Geeft aan of de MSR onveranderbaar is. Indien ingesteld, wordt deze MSR vergrendeld waardoor de verplaatsing van de hypercall-pagina wordt voorkomen. Na het instellen kan alleen een systeemherstel de bit wissen. Lezen/schrijven
0 Hypercall-pagina inschakelen Lezen/schrijven

De hypercall-pagina kan overal in de GPA-ruimte van de gast worden geplaatst, maar moet op de pagina zijn uitgelijnd. Als de gast de hypercall-pagina buiten de grenzen van de GPA-ruimte probeert te verplaatsen, resulteert een #GP fout wanneer de MSR wordt geschreven.

Deze MSR is een msr voor de hele partitie. Met andere woorden, het wordt gedeeld door alle virtuele processors in de partitie. Als één virtuele processor naar de MSR schrijft, wordt dezelfde waarde gelezen door een andere virtuele processor.

Voordat de hypercall-pagina is ingeschakeld, moet het gastbesturingssystemen de identiteit rapporteren door de versiehandtekening naar een afzonderlijke MSR (HV_X64_MSR_GUEST_OS_ID) te schrijven. Als er geen identiteit van het gastbesturingssystemen is opgegeven, mislukken pogingen om de hypercall in te schakelen. De inschakelende bit blijft nul, zelfs wanneer u er een naar schrijft. Bovendien, als de identiteit van het gastbesturingssystemen is gewist tot nul nadat de hypercall-pagina is ingeschakeld, wordt deze uitgeschakeld.

De hypercall-pagina wordt weergegeven als een 'overlay' voor de GPA-ruimte; Dat wil gezegd, het behandelt wat er nog meer is toegewezen aan het GPA-bereik. De inhoud ervan kan door de gast worden gelezen en uitvoerbaar. Pogingen om naar de hypercall-pagina te schrijven, resulteren in een beveiligingsuitzondering (#GP). Nadat de hypercall-pagina is ingeschakeld, is het aanroepen van een hypercall gewoon een aanroep naar het begin van de pagina.

Hier volgt een gedetailleerde lijst van de stappen die nodig zijn om de hypercall-pagina tot stand te brengen:

  1. De gast leest CPUID leaf 1 en bepaalt of een hypervisor aanwezig is door bit 31 van register ECX te controleren.
  2. De gast leest de CPUID leaf 0x40000000 om het maximale CPUID-blad van de hypervisor te bepalen (geretourneerd in register EAX) en CPUID leaf 0x40000001 om de interfacehandtekening te bepalen (geretourneerd in het register EAX). Er wordt gecontroleerd of de maximale bladwaarde ten minste 0x40000005 is en dat de interfacehandtekening gelijk is aan 'Hv#1'. Deze handtekening impliceert dat HV_X64_MSR_GUEST_OS_IDen HV_X64_MSR_HYPERCALLHV_X64_MSR_VP_INDEX worden geïmplementeerd.
  3. De gast schrijft de identiteit van het besturingssysteem naar de MSR HV_X64_MSR_GUEST_OS_ID als dat register nul is.
  4. De gast leest de Hypercall MSR (HV_X64_MSR_HYPERCALL).
  5. De gast controleert de bit Hypercall-pagina inschakelen. Als deze is ingesteld, is de interface al actief en moet stap 6 en 7 worden weggelaten.
  6. De gast vindt een pagina in de GPA-ruimte, bij voorkeur een pagina die niet wordt bezet door RAM, MMIO, enzovoort. Als de pagina bezet is, moet de gast het gebruik van de onderliggende pagina voor andere doeleinden vermijden.
  7. De gast schrijft een nieuwe waarde naar de Hypercall MSR (HV_X64_MSR_HYPERCALL) die de GPA uit stap 6 bevat en stelt de bit Hypercall-pagina inschakelen in om de interface in te schakelen.
  8. De gast maakt een uitvoerbare VA-toewijzing aan de hypercall-pagina GPA.
  9. De gast raadpleegt CPUID leaf 0x40000003 om te bepalen welke hypervisorfaciliteiten er beschikbaar zijn. Nadat de interface tot stand is gebracht, kan de gast een hypercall initiëren. Hiervoor worden de registers ingevuld volgens het hypercall-protocol en wordt een CALL naar het begin van de hypercall-pagina verzonden. De gast moet ervan uitgaan dat de hypercall-pagina het equivalent van een near return (0xC3) uitvoert om terug te keren naar de beller. Als zodanig moet de hypercall worden aangeroepen met een geldige stack.

De Hypercall-interface (ARM64) tot stand brengen

Omdat ARM64 systeemeigen ondersteuning biedt voor de HVC-instructie, heeft de hypervisor geen aanvullende configuratie nodig om hypercalls in te schakelen.

Uitgebreide Hypercall-interface

Hypercalls met aanroepcodes boven 0x8000 worden uitgebreide hypercalls genoemd. Uitgebreide hypercalls gebruiken dezelfde oproepconventie als normale hypercalls en lijken identiek vanuit het perspectief van een gast-VM. Uitgebreide hypercalls worden intern anders verwerkt binnen de Hyper-V hypervisor.

Uitgebreide hypercall-mogelijkheden kunnen worden opgevraagd met HvExtCallQueryCapabilities.