123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355 |
- /** @file
- X64 #VC Exception Handler functon.
- Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <Base.h>
- #include <Uefi.h>
- #include <Library/BaseMemoryLib.h>
- #include <Library/LocalApicLib.h>
- #include <Library/MemEncryptSevLib.h>
- #include <Library/CcExitLib.h>
- #include <Register/Amd/Msr.h>
- #include <Register/Intel/Cpuid.h>
- #include <IndustryStandard/InstructionParsing.h>
- #include "CcExitVcHandler.h"
- //
- // Instruction execution mode definition
- //
- typedef enum {
- LongMode64Bit = 0,
- LongModeCompat32Bit,
- LongModeCompat16Bit,
- } SEV_ES_INSTRUCTION_MODE;
- //
- // Instruction size definition (for operand and address)
- //
- typedef enum {
- Size8Bits = 0,
- Size16Bits,
- Size32Bits,
- Size64Bits,
- } SEV_ES_INSTRUCTION_SIZE;
- //
- // Intruction segment definition
- //
- typedef enum {
- SegmentEs = 0,
- SegmentCs,
- SegmentSs,
- SegmentDs,
- SegmentFs,
- SegmentGs,
- } SEV_ES_INSTRUCTION_SEGMENT;
- //
- // Instruction rep function definition
- //
- typedef enum {
- RepNone = 0,
- RepZ,
- RepNZ,
- } SEV_ES_INSTRUCTION_REP;
- typedef struct {
- UINT8 Rm;
- UINT8 Reg;
- UINT8 Mod;
- } SEV_ES_INSTRUCTION_MODRM_EXT;
- typedef struct {
- UINT8 Base;
- UINT8 Index;
- UINT8 Scale;
- } SEV_ES_INSTRUCTION_SIB_EXT;
- //
- // Instruction opcode definition
- //
- typedef struct {
- SEV_ES_INSTRUCTION_MODRM_EXT ModRm;
- SEV_ES_INSTRUCTION_SIB_EXT Sib;
- UINTN RegData;
- UINTN RmData;
- } SEV_ES_INSTRUCTION_OPCODE_EXT;
- //
- // Instruction parsing context definition
- //
- typedef struct {
- GHCB *Ghcb;
- SEV_ES_INSTRUCTION_MODE Mode;
- SEV_ES_INSTRUCTION_SIZE DataSize;
- SEV_ES_INSTRUCTION_SIZE AddrSize;
- BOOLEAN SegmentSpecified;
- SEV_ES_INSTRUCTION_SEGMENT Segment;
- SEV_ES_INSTRUCTION_REP RepMode;
- UINT8 *Begin;
- UINT8 *End;
- UINT8 *Prefixes;
- UINT8 *OpCodes;
- UINT8 *Displacement;
- UINT8 *Immediate;
- INSTRUCTION_REX_PREFIX RexPrefix;
- BOOLEAN ModRmPresent;
- INSTRUCTION_MODRM ModRm;
- BOOLEAN SibPresent;
- INSTRUCTION_SIB Sib;
- UINTN PrefixSize;
- UINTN OpCodeSize;
- UINTN DisplacementSize;
- UINTN ImmediateSize;
- SEV_ES_INSTRUCTION_OPCODE_EXT Ext;
- } SEV_ES_INSTRUCTION_DATA;
- //
- // Non-automatic Exit function prototype
- //
- typedef
- UINT64
- (*NAE_EXIT) (
- GHCB *Ghcb,
- EFI_SYSTEM_CONTEXT_X64 *Regs,
- SEV_ES_INSTRUCTION_DATA *InstructionData
- );
- //
- // SEV-SNP Cpuid table entry/function
- //
- typedef PACKED struct {
- UINT32 EaxIn;
- UINT32 EcxIn;
- UINT64 Unused;
- UINT64 Unused2;
- UINT32 Eax;
- UINT32 Ebx;
- UINT32 Ecx;
- UINT32 Edx;
- UINT64 Reserved;
- } SEV_SNP_CPUID_FUNCTION;
- //
- // SEV-SNP Cpuid page format
- //
- typedef PACKED struct {
- UINT32 Count;
- UINT32 Reserved1;
- UINT64 Reserved2;
- SEV_SNP_CPUID_FUNCTION function[0];
- } SEV_SNP_CPUID_INFO;
- /**
- Return a pointer to the contents of the specified register.
- Based upon the input register, return a pointer to the registers contents
- in the x86 processor context.
- @param[in] Regs x64 processor context
- @param[in] Register Register to obtain pointer for
- @return Pointer to the contents of the requested register
- **/
- STATIC
- UINT64 *
- GetRegisterPointer (
- IN EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN UINT8 Register
- )
- {
- UINT64 *Reg;
- switch (Register) {
- case 0:
- Reg = &Regs->Rax;
- break;
- case 1:
- Reg = &Regs->Rcx;
- break;
- case 2:
- Reg = &Regs->Rdx;
- break;
- case 3:
- Reg = &Regs->Rbx;
- break;
- case 4:
- Reg = &Regs->Rsp;
- break;
- case 5:
- Reg = &Regs->Rbp;
- break;
- case 6:
- Reg = &Regs->Rsi;
- break;
- case 7:
- Reg = &Regs->Rdi;
- break;
- case 8:
- Reg = &Regs->R8;
- break;
- case 9:
- Reg = &Regs->R9;
- break;
- case 10:
- Reg = &Regs->R10;
- break;
- case 11:
- Reg = &Regs->R11;
- break;
- case 12:
- Reg = &Regs->R12;
- break;
- case 13:
- Reg = &Regs->R13;
- break;
- case 14:
- Reg = &Regs->R14;
- break;
- case 15:
- Reg = &Regs->R15;
- break;
- default:
- Reg = NULL;
- }
- ASSERT (Reg != NULL);
- return Reg;
- }
- /**
- Update the instruction parsing context for displacement bytes.
- @param[in, out] InstructionData Instruction parsing context
- @param[in] Size The instruction displacement size
- **/
- STATIC
- VOID
- UpdateForDisplacement (
- IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,
- IN UINTN Size
- )
- {
- InstructionData->DisplacementSize = Size;
- InstructionData->Immediate += Size;
- InstructionData->End += Size;
- }
- /**
- Determine if an instruction address if RIP relative.
- Examine the instruction parsing context to determine if the address offset
- is relative to the instruction pointer.
- @param[in] InstructionData Instruction parsing context
- @retval TRUE Instruction addressing is RIP relative
- @retval FALSE Instruction addressing is not RIP relative
- **/
- STATIC
- BOOLEAN
- IsRipRelative (
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;
- Ext = &InstructionData->Ext;
- return ((InstructionData->Mode == LongMode64Bit) &&
- (Ext->ModRm.Mod == 0) &&
- (Ext->ModRm.Rm == 5) &&
- (InstructionData->SibPresent == FALSE));
- }
- /**
- Return the effective address of a memory operand.
- Examine the instruction parsing context to obtain the effective memory
- address of a memory operand.
- @param[in] Regs x64 processor context
- @param[in] InstructionData Instruction parsing context
- @return The memory operand effective address
- **/
- STATIC
- UINT64
- GetEffectiveMemoryAddress (
- IN EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;
- UINT64 EffectiveAddress;
- Ext = &InstructionData->Ext;
- EffectiveAddress = 0;
- if (IsRipRelative (InstructionData)) {
- //
- // RIP-relative displacement is a 32-bit signed value
- //
- INT32 RipRelative;
- RipRelative = *(INT32 *)InstructionData->Displacement;
- UpdateForDisplacement (InstructionData, 4);
- //
- // Negative displacement is handled by standard UINT64 wrap-around.
- //
- return Regs->Rip + (UINT64)RipRelative;
- }
- switch (Ext->ModRm.Mod) {
- case 1:
- UpdateForDisplacement (InstructionData, 1);
- EffectiveAddress += (UINT64)(*(INT8 *)(InstructionData->Displacement));
- break;
- case 2:
- switch (InstructionData->AddrSize) {
- case Size16Bits:
- UpdateForDisplacement (InstructionData, 2);
- EffectiveAddress += (UINT64)(*(INT16 *)(InstructionData->Displacement));
- break;
- default:
- UpdateForDisplacement (InstructionData, 4);
- EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement));
- break;
- }
- break;
- }
- if (InstructionData->SibPresent) {
- INT64 Displacement;
- if (Ext->Sib.Index != 4) {
- CopyMem (
- &Displacement,
- GetRegisterPointer (Regs, Ext->Sib.Index),
- sizeof (Displacement)
- );
- Displacement *= (INT64)(1 << Ext->Sib.Scale);
- //
- // Negative displacement is handled by standard UINT64 wrap-around.
- //
- EffectiveAddress += (UINT64)Displacement;
- }
- if ((Ext->Sib.Base != 5) || Ext->ModRm.Mod) {
- EffectiveAddress += *GetRegisterPointer (Regs, Ext->Sib.Base);
- } else {
- UpdateForDisplacement (InstructionData, 4);
- EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement));
- }
- } else {
- EffectiveAddress += *GetRegisterPointer (Regs, Ext->ModRm.Rm);
- }
- return EffectiveAddress;
- }
- /**
- Decode a ModRM byte.
- Examine the instruction parsing context to decode a ModRM byte and the SIB
- byte, if present.
- @param[in] Regs x64 processor context
- @param[in, out] InstructionData Instruction parsing context
- **/
- STATIC
- VOID
- DecodeModRm (
- IN EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;
- INSTRUCTION_REX_PREFIX *RexPrefix;
- INSTRUCTION_MODRM *ModRm;
- INSTRUCTION_SIB *Sib;
- RexPrefix = &InstructionData->RexPrefix;
- Ext = &InstructionData->Ext;
- ModRm = &InstructionData->ModRm;
- Sib = &InstructionData->Sib;
- InstructionData->ModRmPresent = TRUE;
- ModRm->Uint8 = *(InstructionData->End);
- InstructionData->Displacement++;
- InstructionData->Immediate++;
- InstructionData->End++;
- Ext->ModRm.Mod = ModRm->Bits.Mod;
- Ext->ModRm.Reg = (RexPrefix->Bits.BitR << 3) | ModRm->Bits.Reg;
- Ext->ModRm.Rm = (RexPrefix->Bits.BitB << 3) | ModRm->Bits.Rm;
- Ext->RegData = *GetRegisterPointer (Regs, Ext->ModRm.Reg);
- if (Ext->ModRm.Mod == 3) {
- Ext->RmData = *GetRegisterPointer (Regs, Ext->ModRm.Rm);
- } else {
- if (ModRm->Bits.Rm == 4) {
- InstructionData->SibPresent = TRUE;
- Sib->Uint8 = *(InstructionData->End);
- InstructionData->Displacement++;
- InstructionData->Immediate++;
- InstructionData->End++;
- Ext->Sib.Scale = Sib->Bits.Scale;
- Ext->Sib.Index = (RexPrefix->Bits.BitX << 3) | Sib->Bits.Index;
- Ext->Sib.Base = (RexPrefix->Bits.BitB << 3) | Sib->Bits.Base;
- }
- Ext->RmData = GetEffectiveMemoryAddress (Regs, InstructionData);
- }
- }
- /**
- Decode instruction prefixes.
- Parse the instruction data to track the instruction prefixes that have
- been used.
- @param[in] Regs x64 processor context
- @param[in, out] InstructionData Instruction parsing context
- **/
- STATIC
- VOID
- DecodePrefixes (
- IN EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- SEV_ES_INSTRUCTION_MODE Mode;
- SEV_ES_INSTRUCTION_SIZE ModeDataSize;
- SEV_ES_INSTRUCTION_SIZE ModeAddrSize;
- UINT8 *Byte;
- //
- // Always in 64-bit mode
- //
- Mode = LongMode64Bit;
- ModeDataSize = Size32Bits;
- ModeAddrSize = Size64Bits;
- InstructionData->Mode = Mode;
- InstructionData->DataSize = ModeDataSize;
- InstructionData->AddrSize = ModeAddrSize;
- InstructionData->Prefixes = InstructionData->Begin;
- Byte = InstructionData->Prefixes;
- for ( ; ; Byte++, InstructionData->PrefixSize++) {
- //
- // Check the 0x40 to 0x4F range using an if statement here since some
- // compilers don't like the "case 0x40 ... 0x4F:" syntax. This avoids
- // 16 case statements below.
- //
- if ((*Byte >= REX_PREFIX_START) && (*Byte <= REX_PREFIX_STOP)) {
- InstructionData->RexPrefix.Uint8 = *Byte;
- if ((*Byte & REX_64BIT_OPERAND_SIZE_MASK) != 0) {
- InstructionData->DataSize = Size64Bits;
- }
- continue;
- }
- switch (*Byte) {
- case OVERRIDE_SEGMENT_CS:
- case OVERRIDE_SEGMENT_DS:
- case OVERRIDE_SEGMENT_ES:
- case OVERRIDE_SEGMENT_SS:
- if (Mode != LongMode64Bit) {
- InstructionData->SegmentSpecified = TRUE;
- InstructionData->Segment = (*Byte >> 3) & 3;
- }
- break;
- case OVERRIDE_SEGMENT_FS:
- case OVERRIDE_SEGMENT_GS:
- InstructionData->SegmentSpecified = TRUE;
- InstructionData->Segment = *Byte & 7;
- break;
- case OVERRIDE_OPERAND_SIZE:
- if (InstructionData->RexPrefix.Uint8 == 0) {
- InstructionData->DataSize =
- (Mode == LongMode64Bit) ? Size16Bits :
- (Mode == LongModeCompat32Bit) ? Size16Bits :
- (Mode == LongModeCompat16Bit) ? Size32Bits : 0;
- }
- break;
- case OVERRIDE_ADDRESS_SIZE:
- InstructionData->AddrSize =
- (Mode == LongMode64Bit) ? Size32Bits :
- (Mode == LongModeCompat32Bit) ? Size16Bits :
- (Mode == LongModeCompat16Bit) ? Size32Bits : 0;
- break;
- case LOCK_PREFIX:
- break;
- case REPZ_PREFIX:
- InstructionData->RepMode = RepZ;
- break;
- case REPNZ_PREFIX:
- InstructionData->RepMode = RepNZ;
- break;
- default:
- InstructionData->OpCodes = Byte;
- InstructionData->OpCodeSize = (*Byte == TWO_BYTE_OPCODE_ESCAPE) ? 2 : 1;
- InstructionData->End = Byte + InstructionData->OpCodeSize;
- InstructionData->Displacement = InstructionData->End;
- InstructionData->Immediate = InstructionData->End;
- return;
- }
- }
- }
- /**
- Determine instruction length
- Return the total length of the parsed instruction.
- @param[in] InstructionData Instruction parsing context
- @return Length of parsed instruction
- **/
- STATIC
- UINT64
- InstructionLength (
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- return (UINT64)(InstructionData->End - InstructionData->Begin);
- }
- /**
- Initialize the instruction parsing context.
- Initialize the instruction parsing context, which includes decoding the
- instruction prefixes.
- @param[in, out] InstructionData Instruction parsing context
- @param[in] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in] Regs x64 processor context
- **/
- STATIC
- VOID
- InitInstructionData (
- IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,
- IN GHCB *Ghcb,
- IN EFI_SYSTEM_CONTEXT_X64 *Regs
- )
- {
- SetMem (InstructionData, sizeof (*InstructionData), 0);
- InstructionData->Ghcb = Ghcb;
- InstructionData->Begin = (UINT8 *)Regs->Rip;
- InstructionData->End = (UINT8 *)Regs->Rip;
- DecodePrefixes (Regs, InstructionData);
- }
- /**
- Report an unsupported event to the hypervisor
- Use the VMGEXIT support to report an unsupported event to the hypervisor.
- @param[in] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in] Regs x64 processor context
- @param[in] InstructionData Instruction parsing context
- @return New exception value to propagate
- **/
- STATIC
- UINT64
- UnsupportedExit (
- IN GHCB *Ghcb,
- IN EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- UINT64 Status;
- Status = VmgExit (Ghcb, SVM_EXIT_UNSUPPORTED, Regs->ExceptionData, 0);
- if (Status == 0) {
- GHCB_EVENT_INJECTION Event;
- Event.Uint64 = 0;
- Event.Elements.Vector = GP_EXCEPTION;
- Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;
- Event.Elements.Valid = 1;
- Status = Event.Uint64;
- }
- return Status;
- }
- /**
- Validate that the MMIO memory access is not to encrypted memory.
- Examine the pagetable entry for the memory specified. MMIO should not be
- performed against encrypted memory. MMIO to the APIC page is always allowed.
- @param[in] Ghcb Pointer to the Guest-Hypervisor Communication Block
- @param[in] MemoryAddress Memory address to validate
- @param[in] MemoryLength Memory length to validate
- @retval 0 Memory is not encrypted
- @return New exception value to propogate
- **/
- STATIC
- UINT64
- ValidateMmioMemory (
- IN GHCB *Ghcb,
- IN UINTN MemoryAddress,
- IN UINTN MemoryLength
- )
- {
- MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State;
- GHCB_EVENT_INJECTION GpEvent;
- UINTN Address;
- //
- // Allow APIC accesses (which will have the encryption bit set during
- // SEC and PEI phases).
- //
- Address = MemoryAddress & ~(SIZE_4KB - 1);
- if (Address == GetLocalApicBaseAddress ()) {
- return 0;
- }
- State = MemEncryptSevGetAddressRangeState (
- 0,
- MemoryAddress,
- MemoryLength
- );
- if (State == MemEncryptSevAddressRangeUnencrypted) {
- return 0;
- }
- //
- // Any state other than unencrypted is an error, issue a #GP.
- //
- DEBUG ((
- DEBUG_ERROR,
- "MMIO using encrypted memory: %lx\n",
- (UINT64)MemoryAddress
- ));
- GpEvent.Uint64 = 0;
- GpEvent.Elements.Vector = GP_EXCEPTION;
- GpEvent.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;
- GpEvent.Elements.Valid = 1;
- return GpEvent.Uint64;
- }
- /**
- Handle an MMIO event.
- Use the VMGEXIT instruction to handle either an MMIO read or an MMIO write.
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in, out] Regs x64 processor context
- @param[in, out] InstructionData Instruction parsing context
- @retval 0 Event handled successfully
- @return New exception value to propagate
- **/
- STATIC
- UINT64
- MmioExit (
- IN OUT GHCB *Ghcb,
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- UINT64 ExitInfo1, ExitInfo2, Status;
- UINTN Bytes;
- UINT64 *Register;
- UINT8 OpCode, SignByte;
- UINTN Address;
- Bytes = 0;
- OpCode = *(InstructionData->OpCodes);
- if (OpCode == TWO_BYTE_OPCODE_ESCAPE) {
- OpCode = *(InstructionData->OpCodes + 1);
- }
- switch (OpCode) {
- //
- // MMIO write (MOV reg/memX, regX)
- //
- case 0x88:
- Bytes = 1;
- //
- // fall through
- //
- case 0x89:
- DecodeModRm (Regs, InstructionData);
- Bytes = ((Bytes != 0) ? Bytes :
- (InstructionData->DataSize == Size16Bits) ? 2 :
- (InstructionData->DataSize == Size32Bits) ? 4 :
- (InstructionData->DataSize == Size64Bits) ? 8 :
- 0);
- if (InstructionData->Ext.ModRm.Mod == 3) {
- //
- // NPF on two register operands???
- //
- return UnsupportedExit (Ghcb, Regs, InstructionData);
- }
- Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
- if (Status != 0) {
- return Status;
- }
- ExitInfo1 = InstructionData->Ext.RmData;
- ExitInfo2 = Bytes;
- CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes);
- Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
- VmgSetOffsetValid (Ghcb, GhcbSwScratch);
- Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
- if (Status != 0) {
- return Status;
- }
- break;
- //
- // MMIO write (MOV moffsetX, aX)
- //
- case 0xA2:
- Bytes = 1;
- //
- // fall through
- //
- case 0xA3:
- Bytes = ((Bytes != 0) ? Bytes :
- (InstructionData->DataSize == Size16Bits) ? 2 :
- (InstructionData->DataSize == Size32Bits) ? 4 :
- (InstructionData->DataSize == Size64Bits) ? 8 :
- 0);
- InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);
- InstructionData->End += InstructionData->ImmediateSize;
- //
- // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
- // Use a STATIC_ASSERT to be certain the code is being built as X64.
- //
- STATIC_ASSERT (
- sizeof (UINTN) == sizeof (UINT64),
- "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
- );
- Address = 0;
- CopyMem (
- &Address,
- InstructionData->Immediate,
- InstructionData->ImmediateSize
- );
- Status = ValidateMmioMemory (Ghcb, Address, Bytes);
- if (Status != 0) {
- return Status;
- }
- ExitInfo1 = Address;
- ExitInfo2 = Bytes;
- CopyMem (Ghcb->SharedBuffer, &Regs->Rax, Bytes);
- Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
- VmgSetOffsetValid (Ghcb, GhcbSwScratch);
- Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
- if (Status != 0) {
- return Status;
- }
- break;
- //
- // MMIO write (MOV reg/memX, immX)
- //
- case 0xC6:
- Bytes = 1;
- //
- // fall through
- //
- case 0xC7:
- DecodeModRm (Regs, InstructionData);
- Bytes = ((Bytes != 0) ? Bytes :
- (InstructionData->DataSize == Size16Bits) ? 2 :
- (InstructionData->DataSize == Size32Bits) ? 4 :
- 0);
- InstructionData->ImmediateSize = Bytes;
- InstructionData->End += Bytes;
- Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
- if (Status != 0) {
- return Status;
- }
- ExitInfo1 = InstructionData->Ext.RmData;
- ExitInfo2 = Bytes;
- CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, Bytes);
- Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
- VmgSetOffsetValid (Ghcb, GhcbSwScratch);
- Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
- if (Status != 0) {
- return Status;
- }
- break;
- //
- // MMIO read (MOV regX, reg/memX)
- //
- case 0x8A:
- Bytes = 1;
- //
- // fall through
- //
- case 0x8B:
- DecodeModRm (Regs, InstructionData);
- Bytes = ((Bytes != 0) ? Bytes :
- (InstructionData->DataSize == Size16Bits) ? 2 :
- (InstructionData->DataSize == Size32Bits) ? 4 :
- (InstructionData->DataSize == Size64Bits) ? 8 :
- 0);
- if (InstructionData->Ext.ModRm.Mod == 3) {
- //
- // NPF on two register operands???
- //
- return UnsupportedExit (Ghcb, Regs, InstructionData);
- }
- Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
- if (Status != 0) {
- return Status;
- }
- ExitInfo1 = InstructionData->Ext.RmData;
- ExitInfo2 = Bytes;
- Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
- VmgSetOffsetValid (Ghcb, GhcbSwScratch);
- Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
- if (Status != 0) {
- return Status;
- }
- Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
- if (Bytes == 4) {
- //
- // Zero-extend for 32-bit operation
- //
- *Register = 0;
- }
- CopyMem (Register, Ghcb->SharedBuffer, Bytes);
- break;
- //
- // MMIO read (MOV aX, moffsetX)
- //
- case 0xA0:
- Bytes = 1;
- //
- // fall through
- //
- case 0xA1:
- Bytes = ((Bytes != 0) ? Bytes :
- (InstructionData->DataSize == Size16Bits) ? 2 :
- (InstructionData->DataSize == Size32Bits) ? 4 :
- (InstructionData->DataSize == Size64Bits) ? 8 :
- 0);
- InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);
- InstructionData->End += InstructionData->ImmediateSize;
- //
- // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
- // Use a STATIC_ASSERT to be certain the code is being built as X64.
- //
- STATIC_ASSERT (
- sizeof (UINTN) == sizeof (UINT64),
- "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
- );
- Address = 0;
- CopyMem (
- &Address,
- InstructionData->Immediate,
- InstructionData->ImmediateSize
- );
- Status = ValidateMmioMemory (Ghcb, Address, Bytes);
- if (Status != 0) {
- return Status;
- }
- ExitInfo1 = Address;
- ExitInfo2 = Bytes;
- Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
- VmgSetOffsetValid (Ghcb, GhcbSwScratch);
- Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
- if (Status != 0) {
- return Status;
- }
- if (Bytes == 4) {
- //
- // Zero-extend for 32-bit operation
- //
- Regs->Rax = 0;
- }
- CopyMem (&Regs->Rax, Ghcb->SharedBuffer, Bytes);
- break;
- //
- // MMIO read w/ zero-extension ((MOVZX regX, reg/memX)
- //
- case 0xB6:
- Bytes = 1;
- //
- // fall through
- //
- case 0xB7:
- DecodeModRm (Regs, InstructionData);
- Bytes = (Bytes != 0) ? Bytes : 2;
- Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
- if (Status != 0) {
- return Status;
- }
- ExitInfo1 = InstructionData->Ext.RmData;
- ExitInfo2 = Bytes;
- Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
- VmgSetOffsetValid (Ghcb, GhcbSwScratch);
- Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
- if (Status != 0) {
- return Status;
- }
- Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
- SetMem (Register, (UINTN)(1 << InstructionData->DataSize), 0);
- CopyMem (Register, Ghcb->SharedBuffer, Bytes);
- break;
- //
- // MMIO read w/ sign-extension (MOVSX regX, reg/memX)
- //
- case 0xBE:
- Bytes = 1;
- //
- // fall through
- //
- case 0xBF:
- DecodeModRm (Regs, InstructionData);
- Bytes = (Bytes != 0) ? Bytes : 2;
- Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
- if (Status != 0) {
- return Status;
- }
- ExitInfo1 = InstructionData->Ext.RmData;
- ExitInfo2 = Bytes;
- Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
- VmgSetOffsetValid (Ghcb, GhcbSwScratch);
- Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
- if (Status != 0) {
- return Status;
- }
- if (Bytes == 1) {
- UINT8 *Data;
- Data = (UINT8 *)Ghcb->SharedBuffer;
- SignByte = ((*Data & BIT7) != 0) ? 0xFF : 0x00;
- } else {
- UINT16 *Data;
- Data = (UINT16 *)Ghcb->SharedBuffer;
- SignByte = ((*Data & BIT15) != 0) ? 0xFF : 0x00;
- }
- Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
- SetMem (Register, (UINTN)(1 << InstructionData->DataSize), SignByte);
- CopyMem (Register, Ghcb->SharedBuffer, Bytes);
- break;
- default:
- DEBUG ((DEBUG_ERROR, "Invalid MMIO opcode (%x)\n", OpCode));
- Status = GP_EXCEPTION;
- ASSERT (FALSE);
- }
- return Status;
- }
- /**
- Handle a MWAIT event.
- Use the VMGEXIT instruction to handle a MWAIT event.
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in, out] Regs x64 processor context
- @param[in] InstructionData Instruction parsing context
- @retval 0 Event handled successfully
- @return New exception value to propagate
- **/
- STATIC
- UINT64
- MwaitExit (
- IN OUT GHCB *Ghcb,
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- DecodeModRm (Regs, InstructionData);
- Ghcb->SaveArea.Rax = Regs->Rax;
- VmgSetOffsetValid (Ghcb, GhcbRax);
- Ghcb->SaveArea.Rcx = Regs->Rcx;
- VmgSetOffsetValid (Ghcb, GhcbRcx);
- return VmgExit (Ghcb, SVM_EXIT_MWAIT, 0, 0);
- }
- /**
- Handle a MONITOR event.
- Use the VMGEXIT instruction to handle a MONITOR event.
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in, out] Regs x64 processor context
- @param[in] InstructionData Instruction parsing context
- @retval 0 Event handled successfully
- @return New exception value to propagate
- **/
- STATIC
- UINT64
- MonitorExit (
- IN OUT GHCB *Ghcb,
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- DecodeModRm (Regs, InstructionData);
- Ghcb->SaveArea.Rax = Regs->Rax; // Identity mapped, so VA = PA
- VmgSetOffsetValid (Ghcb, GhcbRax);
- Ghcb->SaveArea.Rcx = Regs->Rcx;
- VmgSetOffsetValid (Ghcb, GhcbRcx);
- Ghcb->SaveArea.Rdx = Regs->Rdx;
- VmgSetOffsetValid (Ghcb, GhcbRdx);
- return VmgExit (Ghcb, SVM_EXIT_MONITOR, 0, 0);
- }
- /**
- Handle a WBINVD event.
- Use the VMGEXIT instruction to handle a WBINVD event.
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in, out] Regs x64 processor context
- @param[in] InstructionData Instruction parsing context
- @retval 0 Event handled successfully
- @return New exception value to propagate
- **/
- STATIC
- UINT64
- WbinvdExit (
- IN OUT GHCB *Ghcb,
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- return VmgExit (Ghcb, SVM_EXIT_WBINVD, 0, 0);
- }
- /**
- Handle a RDTSCP event.
- Use the VMGEXIT instruction to handle a RDTSCP event.
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in, out] Regs x64 processor context
- @param[in] InstructionData Instruction parsing context
- @retval 0 Event handled successfully
- @return New exception value to propagate
- **/
- STATIC
- UINT64
- RdtscpExit (
- IN OUT GHCB *Ghcb,
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- UINT64 Status;
- DecodeModRm (Regs, InstructionData);
- Status = VmgExit (Ghcb, SVM_EXIT_RDTSCP, 0, 0);
- if (Status != 0) {
- return Status;
- }
- if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||
- !VmgIsOffsetValid (Ghcb, GhcbRcx) ||
- !VmgIsOffsetValid (Ghcb, GhcbRdx))
- {
- return UnsupportedExit (Ghcb, Regs, InstructionData);
- }
- Regs->Rax = Ghcb->SaveArea.Rax;
- Regs->Rcx = Ghcb->SaveArea.Rcx;
- Regs->Rdx = Ghcb->SaveArea.Rdx;
- return 0;
- }
- /**
- Handle a VMMCALL event.
- Use the VMGEXIT instruction to handle a VMMCALL event.
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in, out] Regs x64 processor context
- @param[in] InstructionData Instruction parsing context
- @retval 0 Event handled successfully
- @return New exception value to propagate
- **/
- STATIC
- UINT64
- VmmCallExit (
- IN OUT GHCB *Ghcb,
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- UINT64 Status;
- DecodeModRm (Regs, InstructionData);
- Ghcb->SaveArea.Rax = Regs->Rax;
- VmgSetOffsetValid (Ghcb, GhcbRax);
- Ghcb->SaveArea.Cpl = (UINT8)(Regs->Cs & 0x3);
- VmgSetOffsetValid (Ghcb, GhcbCpl);
- Status = VmgExit (Ghcb, SVM_EXIT_VMMCALL, 0, 0);
- if (Status != 0) {
- return Status;
- }
- if (!VmgIsOffsetValid (Ghcb, GhcbRax)) {
- return UnsupportedExit (Ghcb, Regs, InstructionData);
- }
- Regs->Rax = Ghcb->SaveArea.Rax;
- return 0;
- }
- /**
- Handle an MSR event.
- Use the VMGEXIT instruction to handle either a RDMSR or WRMSR event.
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in, out] Regs x64 processor context
- @param[in] InstructionData Instruction parsing context
- @retval 0 Event handled successfully
- @return New exception value to propagate
- **/
- STATIC
- UINT64
- MsrExit (
- IN OUT GHCB *Ghcb,
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- UINT64 ExitInfo1, Status;
- ExitInfo1 = 0;
- switch (*(InstructionData->OpCodes + 1)) {
- case 0x30: // WRMSR
- ExitInfo1 = 1;
- Ghcb->SaveArea.Rax = Regs->Rax;
- VmgSetOffsetValid (Ghcb, GhcbRax);
- Ghcb->SaveArea.Rdx = Regs->Rdx;
- VmgSetOffsetValid (Ghcb, GhcbRdx);
- //
- // fall through
- //
- case 0x32: // RDMSR
- Ghcb->SaveArea.Rcx = Regs->Rcx;
- VmgSetOffsetValid (Ghcb, GhcbRcx);
- break;
- default:
- return UnsupportedExit (Ghcb, Regs, InstructionData);
- }
- Status = VmgExit (Ghcb, SVM_EXIT_MSR, ExitInfo1, 0);
- if (Status != 0) {
- return Status;
- }
- if (ExitInfo1 == 0) {
- if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||
- !VmgIsOffsetValid (Ghcb, GhcbRdx))
- {
- return UnsupportedExit (Ghcb, Regs, InstructionData);
- }
- Regs->Rax = Ghcb->SaveArea.Rax;
- Regs->Rdx = Ghcb->SaveArea.Rdx;
- }
- return 0;
- }
- /**
- Build the IOIO event information.
- The IOIO event information identifies the type of IO operation to be performed
- by the hypervisor. Build this information based on the instruction data.
- @param[in] Regs x64 processor context
- @param[in, out] InstructionData Instruction parsing context
- @return IOIO event information value
- **/
- STATIC
- UINT64
- IoioExitInfo (
- IN EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- UINT64 ExitInfo;
- ExitInfo = 0;
- switch (*(InstructionData->OpCodes)) {
- //
- // INS opcodes
- //
- case 0x6C:
- case 0x6D:
- ExitInfo |= IOIO_TYPE_INS;
- ExitInfo |= IOIO_SEG_ES;
- ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
- break;
- //
- // OUTS opcodes
- //
- case 0x6E:
- case 0x6F:
- ExitInfo |= IOIO_TYPE_OUTS;
- ExitInfo |= IOIO_SEG_DS;
- ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
- break;
- //
- // IN immediate opcodes
- //
- case 0xE4:
- case 0xE5:
- InstructionData->ImmediateSize = 1;
- InstructionData->End++;
- ExitInfo |= IOIO_TYPE_IN;
- ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16);
- break;
- //
- // OUT immediate opcodes
- //
- case 0xE6:
- case 0xE7:
- InstructionData->ImmediateSize = 1;
- InstructionData->End++;
- ExitInfo |= IOIO_TYPE_OUT;
- ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT;
- break;
- //
- // IN register opcodes
- //
- case 0xEC:
- case 0xED:
- ExitInfo |= IOIO_TYPE_IN;
- ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
- break;
- //
- // OUT register opcodes
- //
- case 0xEE:
- case 0xEF:
- ExitInfo |= IOIO_TYPE_OUT;
- ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
- break;
- default:
- return 0;
- }
- switch (*(InstructionData->OpCodes)) {
- //
- // Single-byte opcodes
- //
- case 0x6C:
- case 0x6E:
- case 0xE4:
- case 0xE6:
- case 0xEC:
- case 0xEE:
- ExitInfo |= IOIO_DATA_8;
- break;
- //
- // Length determined by instruction parsing
- //
- default:
- ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
- : IOIO_DATA_32;
- }
- switch (InstructionData->AddrSize) {
- case Size16Bits:
- ExitInfo |= IOIO_ADDR_16;
- break;
- case Size32Bits:
- ExitInfo |= IOIO_ADDR_32;
- break;
- case Size64Bits:
- ExitInfo |= IOIO_ADDR_64;
- break;
- default:
- break;
- }
- if (InstructionData->RepMode != 0) {
- ExitInfo |= IOIO_REP;
- }
- return ExitInfo;
- }
- /**
- Handle an IOIO event.
- Use the VMGEXIT instruction to handle an IOIO event.
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in, out] Regs x64 processor context
- @param[in] InstructionData Instruction parsing context
- @retval 0 Event handled successfully
- @return New exception value to propagate
- **/
- STATIC
- UINT64
- IoioExit (
- IN OUT GHCB *Ghcb,
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- UINT64 ExitInfo1, ExitInfo2, Status;
- BOOLEAN IsString;
- ExitInfo1 = IoioExitInfo (Regs, InstructionData);
- if (ExitInfo1 == 0) {
- return UnsupportedExit (Ghcb, Regs, InstructionData);
- }
- IsString = ((ExitInfo1 & IOIO_TYPE_STR) != 0) ? TRUE : FALSE;
- if (IsString) {
- UINTN IoBytes, VmgExitBytes;
- UINTN GhcbCount, OpCount;
- Status = 0;
- IoBytes = IOIO_DATA_BYTES (ExitInfo1);
- GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes;
- OpCount = ((ExitInfo1 & IOIO_REP) != 0) ? Regs->Rcx : 1;
- while (OpCount != 0) {
- ExitInfo2 = MIN (OpCount, GhcbCount);
- VmgExitBytes = ExitInfo2 * IoBytes;
- if ((ExitInfo1 & IOIO_TYPE_IN) == 0) {
- CopyMem (Ghcb->SharedBuffer, (VOID *)Regs->Rsi, VmgExitBytes);
- Regs->Rsi += VmgExitBytes;
- }
- Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
- VmgSetOffsetValid (Ghcb, GhcbSwScratch);
- Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2);
- if (Status != 0) {
- return Status;
- }
- if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
- CopyMem ((VOID *)Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes);
- Regs->Rdi += VmgExitBytes;
- }
- if ((ExitInfo1 & IOIO_REP) != 0) {
- Regs->Rcx -= ExitInfo2;
- }
- OpCount -= ExitInfo2;
- }
- } else {
- if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
- Ghcb->SaveArea.Rax = 0;
- } else {
- CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));
- }
- VmgSetOffsetValid (Ghcb, GhcbRax);
- Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);
- if (Status != 0) {
- return Status;
- }
- if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
- if (!VmgIsOffsetValid (Ghcb, GhcbRax)) {
- return UnsupportedExit (Ghcb, Regs, InstructionData);
- }
- CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));
- }
- }
- return 0;
- }
- /**
- Handle a INVD event.
- Use the VMGEXIT instruction to handle a INVD event.
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in, out] Regs x64 processor context
- @param[in] InstructionData Instruction parsing context
- @retval 0 Event handled successfully
- @return New exception value to propagate
- **/
- STATIC
- UINT64
- InvdExit (
- IN OUT GHCB *Ghcb,
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- return VmgExit (Ghcb, SVM_EXIT_INVD, 0, 0);
- }
- /**
- Fetch CPUID leaf/function via hypervisor/VMGEXIT.
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in] EaxIn EAX input for cpuid instruction
- @param[in] EcxIn ECX input for cpuid instruction
- @param[in] Xcr0In XCR0 at time of cpuid instruction
- @param[in, out] Eax Pointer to store leaf's EAX value
- @param[in, out] Ebx Pointer to store leaf's EBX value
- @param[in, out] Ecx Pointer to store leaf's ECX value
- @param[in, out] Edx Pointer to store leaf's EDX value
- @param[in, out] Status Pointer to store status from VMGEXIT (always 0
- unless return value indicates failure)
- @param[in, out] Unsupported Pointer to store indication of unsupported
- VMGEXIT (always false unless return value
- indicates failure)
- @retval TRUE CPUID leaf fetch successfully.
- @retval FALSE Error occurred while fetching CPUID leaf. Callers
- should Status and Unsupported and handle
- accordingly if they indicate a more precise
- error condition.
- **/
- STATIC
- BOOLEAN
- GetCpuidHyp (
- IN OUT GHCB *Ghcb,
- IN UINT32 EaxIn,
- IN UINT32 EcxIn,
- IN UINT64 XCr0,
- IN OUT UINT32 *Eax,
- IN OUT UINT32 *Ebx,
- IN OUT UINT32 *Ecx,
- IN OUT UINT32 *Edx,
- IN OUT UINT64 *Status,
- IN OUT BOOLEAN *UnsupportedExit
- )
- {
- *UnsupportedExit = FALSE;
- Ghcb->SaveArea.Rax = EaxIn;
- VmgSetOffsetValid (Ghcb, GhcbRax);
- Ghcb->SaveArea.Rcx = EcxIn;
- VmgSetOffsetValid (Ghcb, GhcbRcx);
- if (EaxIn == CPUID_EXTENDED_STATE) {
- Ghcb->SaveArea.XCr0 = XCr0;
- VmgSetOffsetValid (Ghcb, GhcbXCr0);
- }
- *Status = VmgExit (Ghcb, SVM_EXIT_CPUID, 0, 0);
- if (*Status != 0) {
- return FALSE;
- }
- if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||
- !VmgIsOffsetValid (Ghcb, GhcbRbx) ||
- !VmgIsOffsetValid (Ghcb, GhcbRcx) ||
- !VmgIsOffsetValid (Ghcb, GhcbRdx))
- {
- *UnsupportedExit = TRUE;
- return FALSE;
- }
- if (Eax) {
- *Eax = (UINT32)(UINTN)Ghcb->SaveArea.Rax;
- }
- if (Ebx) {
- *Ebx = (UINT32)(UINTN)Ghcb->SaveArea.Rbx;
- }
- if (Ecx) {
- *Ecx = (UINT32)(UINTN)Ghcb->SaveArea.Rcx;
- }
- if (Edx) {
- *Edx = (UINT32)(UINTN)Ghcb->SaveArea.Rdx;
- }
- return TRUE;
- }
- /**
- Check if SEV-SNP enabled.
- @retval TRUE SEV-SNP is enabled.
- @retval FALSE SEV-SNP is disabled.
- **/
- STATIC
- BOOLEAN
- SnpEnabled (
- VOID
- )
- {
- MSR_SEV_STATUS_REGISTER Msr;
- Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);
- return !!Msr.Bits.SevSnpBit;
- }
- /**
- Calculate the total XSAVE area size for enabled XSAVE areas
- @param[in] XFeaturesEnabled Bit-mask of enabled XSAVE features/areas as
- indicated by XCR0/MSR_IA32_XSS bits
- @param[in] XSaveBaseSize Base/legacy XSAVE area size (e.g. when
- XCR0 is 1)
- @param[in, out] XSaveSize Pointer to storage for calculated XSAVE area
- size
- @param[in] Compacted Whether or not the calculation is for the
- normal XSAVE area size (leaf 0xD,0x0,EBX) or
- compacted XSAVE area size (leaf 0xD,0x1,EBX)
- @retval TRUE XSAVE size calculation was successful.
- @retval FALSE XSAVE size calculation was unsuccessful.
- **/
- STATIC
- BOOLEAN
- GetCpuidXSaveSize (
- IN UINT64 XFeaturesEnabled,
- IN UINT32 XSaveBaseSize,
- IN OUT UINT32 *XSaveSize,
- IN BOOLEAN Compacted
- )
- {
- SEV_SNP_CPUID_INFO *CpuidInfo;
- UINT64 XFeaturesFound = 0;
- UINT32 Idx;
- *XSaveSize = XSaveBaseSize;
- CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase);
- for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {
- SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];
- if (!((CpuidFn->EaxIn == 0xD) &&
- ((CpuidFn->EcxIn == 0) || (CpuidFn->EcxIn == 1))))
- {
- continue;
- }
- if (XFeaturesFound & (1ULL << CpuidFn->EcxIn) ||
- !(XFeaturesEnabled & (1ULL << CpuidFn->EcxIn)))
- {
- continue;
- }
- XFeaturesFound |= (1ULL << CpuidFn->EcxIn);
- if (Compacted) {
- *XSaveSize += CpuidFn->Eax;
- } else {
- *XSaveSize = MAX (*XSaveSize, CpuidFn->Eax + CpuidFn->Ebx);
- }
- }
- /*
- * Either the guest set unsupported XCR0/XSS bits, or the corresponding
- * entries in the CPUID table were not present. This is an invalid state.
- */
- if (XFeaturesFound != (XFeaturesEnabled & ~3UL)) {
- return FALSE;
- }
- return TRUE;
- }
- /**
- Check if a CPUID leaf/function is indexed via ECX sub-leaf/sub-function
- @param[in] EaxIn EAX input for cpuid instruction
- @retval FALSE cpuid leaf/function is not indexed by ECX input
- @retval TRUE cpuid leaf/function is indexed by ECX input
- **/
- STATIC
- BOOLEAN
- IsFunctionIndexed (
- IN UINT32 EaxIn
- )
- {
- switch (EaxIn) {
- case CPUID_CACHE_PARAMS:
- case CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS:
- case CPUID_EXTENDED_TOPOLOGY:
- case CPUID_EXTENDED_STATE:
- case CPUID_INTEL_RDT_MONITORING:
- case CPUID_INTEL_RDT_ALLOCATION:
- case CPUID_INTEL_SGX:
- case CPUID_INTEL_PROCESSOR_TRACE:
- case CPUID_DETERMINISTIC_ADDRESS_TRANSLATION_PARAMETERS:
- case CPUID_V2_EXTENDED_TOPOLOGY:
- case 0x8000001D: /* Cache Topology Information */
- return TRUE;
- }
- return FALSE;
- }
- /**
- Fetch CPUID leaf/function via SEV-SNP CPUID table.
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in] EaxIn EAX input for cpuid instruction
- @param[in] EcxIn ECX input for cpuid instruction
- @param[in] Xcr0In XCR0 at time of cpuid instruction
- @param[in, out] Eax Pointer to store leaf's EAX value
- @param[in, out] Ebx Pointer to store leaf's EBX value
- @param[in, out] Ecx Pointer to store leaf's ECX value
- @param[in, out] Edx Pointer to store leaf's EDX value
- @param[in, out] Status Pointer to store status from VMGEXIT (always 0
- unless return value indicates failure)
- @param[in, out] Unsupported Pointer to store indication of unsupported
- VMGEXIT (always false unless return value
- indicates failure)
- @retval TRUE CPUID leaf fetch successfully.
- @retval FALSE Error occurred while fetching CPUID leaf. Callers
- should Status and Unsupported and handle
- accordingly if they indicate a more precise
- error condition.
- **/
- STATIC
- BOOLEAN
- GetCpuidFw (
- IN OUT GHCB *Ghcb,
- IN UINT32 EaxIn,
- IN UINT32 EcxIn,
- IN UINT64 XCr0,
- IN OUT UINT32 *Eax,
- IN OUT UINT32 *Ebx,
- IN OUT UINT32 *Ecx,
- IN OUT UINT32 *Edx,
- IN OUT UINT64 *Status,
- IN OUT BOOLEAN *Unsupported
- )
- {
- SEV_SNP_CPUID_INFO *CpuidInfo;
- BOOLEAN Found;
- UINT32 Idx;
- CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase);
- Found = FALSE;
- for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {
- SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];
- if (CpuidFn->EaxIn != EaxIn) {
- continue;
- }
- if (IsFunctionIndexed (CpuidFn->EaxIn) && (CpuidFn->EcxIn != EcxIn)) {
- continue;
- }
- *Eax = CpuidFn->Eax;
- *Ebx = CpuidFn->Ebx;
- *Ecx = CpuidFn->Ecx;
- *Edx = CpuidFn->Edx;
- Found = TRUE;
- break;
- }
- if (!Found) {
- *Eax = *Ebx = *Ecx = *Edx = 0;
- goto Out;
- }
- if (EaxIn == CPUID_VERSION_INFO) {
- IA32_CR4 Cr4;
- UINT32 Ebx2;
- UINT32 Edx2;
- if (!GetCpuidHyp (
- Ghcb,
- EaxIn,
- EcxIn,
- XCr0,
- NULL,
- &Ebx2,
- NULL,
- &Edx2,
- Status,
- Unsupported
- ))
- {
- return FALSE;
- }
- /* initial APIC ID */
- *Ebx = (*Ebx & 0x00FFFFFF) | (Ebx2 & 0xFF000000);
- /* APIC enabled bit */
- *Edx = (*Edx & ~BIT9) | (Edx2 & BIT9);
- /* OSXSAVE enabled bit */
- Cr4.UintN = AsmReadCr4 ();
- *Ecx = (Cr4.Bits.OSXSAVE) ? (*Ecx & ~BIT27) | (*Ecx & BIT27)
- : (*Ecx & ~BIT27);
- } else if (EaxIn == CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS) {
- IA32_CR4 Cr4;
- Cr4.UintN = AsmReadCr4 ();
- /* OSPKE enabled bit */
- *Ecx = (Cr4.Bits.PKE) ? (*Ecx | BIT4) : (*Ecx & ~BIT4);
- } else if (EaxIn == CPUID_EXTENDED_TOPOLOGY) {
- if (!GetCpuidHyp (
- Ghcb,
- EaxIn,
- EcxIn,
- XCr0,
- NULL,
- NULL,
- NULL,
- Edx,
- Status,
- Unsupported
- ))
- {
- return FALSE;
- }
- } else if ((EaxIn == CPUID_EXTENDED_STATE) && ((EcxIn == 0) || (EcxIn == 1))) {
- MSR_IA32_XSS_REGISTER XssMsr;
- BOOLEAN Compacted;
- UINT32 XSaveSize;
- XssMsr.Uint64 = 0;
- Compacted = FALSE;
- if (EcxIn == 1) {
- /*
- * The PPR and APM aren't clear on what size should be encoded in
- * 0xD:0x1:EBX when compaction is not enabled by either XSAVEC or
- * XSAVES, as these are generally fixed to 1 on real CPUs. Report
- * this undefined case as an error.
- */
- if (!(*Eax & (BIT3 | BIT1))) {
- /* (XSAVES | XSAVEC) */
- return FALSE;
- }
- Compacted = TRUE;
- XssMsr.Uint64 = AsmReadMsr64 (MSR_IA32_XSS);
- }
- if (!GetCpuidXSaveSize (
- XCr0 | XssMsr.Uint64,
- *Ebx,
- &XSaveSize,
- Compacted
- ))
- {
- return FALSE;
- }
- *Ebx = XSaveSize;
- } else if (EaxIn == 0x8000001E) {
- UINT32 Ebx2;
- UINT32 Ecx2;
- /* extended APIC ID */
- if (!GetCpuidHyp (
- Ghcb,
- EaxIn,
- EcxIn,
- XCr0,
- Eax,
- &Ebx2,
- &Ecx2,
- NULL,
- Status,
- Unsupported
- ))
- {
- return FALSE;
- }
- /* compute ID */
- *Ebx = (*Ebx & 0xFFFFFF00) | (Ebx2 & 0x000000FF);
- /* node ID */
- *Ecx = (*Ecx & 0xFFFFFF00) | (Ecx2 & 0x000000FF);
- }
- Out:
- *Status = 0;
- *Unsupported = FALSE;
- return TRUE;
- }
- /**
- Handle a CPUID event.
- Use VMGEXIT instruction or CPUID table to handle a CPUID event.
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in, out] Regs x64 processor context
- @param[in] InstructionData Instruction parsing context
- @retval 0 Event handled successfully
- @return New exception value to propagate
- **/
- STATIC
- UINT64
- CpuidExit (
- IN OUT GHCB *Ghcb,
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- BOOLEAN Unsupported;
- UINT64 Status;
- UINT32 EaxIn;
- UINT32 EcxIn;
- UINT64 XCr0;
- UINT32 Eax;
- UINT32 Ebx;
- UINT32 Ecx;
- UINT32 Edx;
- EaxIn = (UINT32)(UINTN)Regs->Rax;
- EcxIn = (UINT32)(UINTN)Regs->Rcx;
- if (EaxIn == CPUID_EXTENDED_STATE) {
- IA32_CR4 Cr4;
- Cr4.UintN = AsmReadCr4 ();
- Ghcb->SaveArea.XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;
- XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;
- }
- if (SnpEnabled ()) {
- if (!GetCpuidFw (
- Ghcb,
- EaxIn,
- EcxIn,
- XCr0,
- &Eax,
- &Ebx,
- &Ecx,
- &Edx,
- &Status,
- &Unsupported
- ))
- {
- goto CpuidFail;
- }
- } else {
- if (!GetCpuidHyp (
- Ghcb,
- EaxIn,
- EcxIn,
- XCr0,
- &Eax,
- &Ebx,
- &Ecx,
- &Edx,
- &Status,
- &Unsupported
- ))
- {
- goto CpuidFail;
- }
- }
- Regs->Rax = Eax;
- Regs->Rbx = Ebx;
- Regs->Rcx = Ecx;
- Regs->Rdx = Edx;
- return 0;
- CpuidFail:
- if (Unsupported) {
- return UnsupportedExit (Ghcb, Regs, InstructionData);
- }
- return Status;
- }
- /**
- Handle a RDPMC event.
- Use the VMGEXIT instruction to handle a RDPMC event.
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in, out] Regs x64 processor context
- @param[in] InstructionData Instruction parsing context
- @retval 0 Event handled successfully
- @return New exception value to propagate
- **/
- STATIC
- UINT64
- RdpmcExit (
- IN OUT GHCB *Ghcb,
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- UINT64 Status;
- Ghcb->SaveArea.Rcx = Regs->Rcx;
- VmgSetOffsetValid (Ghcb, GhcbRcx);
- Status = VmgExit (Ghcb, SVM_EXIT_RDPMC, 0, 0);
- if (Status != 0) {
- return Status;
- }
- if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||
- !VmgIsOffsetValid (Ghcb, GhcbRdx))
- {
- return UnsupportedExit (Ghcb, Regs, InstructionData);
- }
- Regs->Rax = Ghcb->SaveArea.Rax;
- Regs->Rdx = Ghcb->SaveArea.Rdx;
- return 0;
- }
- /**
- Handle a RDTSC event.
- Use the VMGEXIT instruction to handle a RDTSC event.
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in, out] Regs x64 processor context
- @param[in] InstructionData Instruction parsing context
- @retval 0 Event handled successfully
- @return New exception value to propagate
- **/
- STATIC
- UINT64
- RdtscExit (
- IN OUT GHCB *Ghcb,
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- UINT64 Status;
- Status = VmgExit (Ghcb, SVM_EXIT_RDTSC, 0, 0);
- if (Status != 0) {
- return Status;
- }
- if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||
- !VmgIsOffsetValid (Ghcb, GhcbRdx))
- {
- return UnsupportedExit (Ghcb, Regs, InstructionData);
- }
- Regs->Rax = Ghcb->SaveArea.Rax;
- Regs->Rdx = Ghcb->SaveArea.Rdx;
- return 0;
- }
- /**
- Handle a DR7 register write event.
- Use the VMGEXIT instruction to handle a DR7 write event.
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in, out] Regs x64 processor context
- @param[in] InstructionData Instruction parsing context
- @retval 0 Event handled successfully
- @return New exception value to propagate
- **/
- STATIC
- UINT64
- Dr7WriteExit (
- IN OUT GHCB *Ghcb,
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;
- SEV_ES_PER_CPU_DATA *SevEsData;
- UINT64 *Register;
- UINT64 Status;
- Ext = &InstructionData->Ext;
- SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);
- DecodeModRm (Regs, InstructionData);
- //
- // MOV DRn always treats MOD == 3 no matter how encoded
- //
- Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);
- //
- // Using a value of 0 for ExitInfo1 means RAX holds the value
- //
- Ghcb->SaveArea.Rax = *Register;
- VmgSetOffsetValid (Ghcb, GhcbRax);
- Status = VmgExit (Ghcb, SVM_EXIT_DR7_WRITE, 0, 0);
- if (Status != 0) {
- return Status;
- }
- SevEsData->Dr7 = *Register;
- SevEsData->Dr7Cached = 1;
- return 0;
- }
- /**
- Handle a DR7 register read event.
- Use the VMGEXIT instruction to handle a DR7 read event.
- @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
- Block
- @param[in, out] Regs x64 processor context
- @param[in] InstructionData Instruction parsing context
- @retval 0 Event handled successfully
- **/
- STATIC
- UINT64
- Dr7ReadExit (
- IN OUT GHCB *Ghcb,
- IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
- IN SEV_ES_INSTRUCTION_DATA *InstructionData
- )
- {
- SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;
- SEV_ES_PER_CPU_DATA *SevEsData;
- UINT64 *Register;
- Ext = &InstructionData->Ext;
- SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);
- DecodeModRm (Regs, InstructionData);
- //
- // MOV DRn always treats MOD == 3 no matter how encoded
- //
- Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);
- //
- // If there is a cached valued for DR7, return that. Otherwise return the
- // DR7 standard reset value of 0x400 (no debug breakpoints set).
- //
- *Register = (SevEsData->Dr7Cached == 1) ? SevEsData->Dr7 : 0x400;
- return 0;
- }
- /**
- Handle a #VC exception.
- Performs the necessary processing to handle a #VC exception.
- @param[in, out] Ghcb Pointer to the GHCB
- @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set
- as value to use on error.
- @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT
- @retval EFI_SUCCESS Exception handled
- @retval EFI_UNSUPPORTED #VC not supported, (new) exception value to
- propagate provided
- @retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to
- propagate provided
- **/
- EFI_STATUS
- EFIAPI
- InternalVmgExitHandleVc (
- IN OUT GHCB *Ghcb,
- IN OUT EFI_EXCEPTION_TYPE *ExceptionType,
- IN OUT EFI_SYSTEM_CONTEXT SystemContext
- )
- {
- EFI_SYSTEM_CONTEXT_X64 *Regs;
- NAE_EXIT NaeExit;
- SEV_ES_INSTRUCTION_DATA InstructionData;
- UINT64 ExitCode, Status;
- EFI_STATUS VcRet;
- BOOLEAN InterruptState;
- VcRet = EFI_SUCCESS;
- Regs = SystemContext.SystemContextX64;
- VmgInit (Ghcb, &InterruptState);
- ExitCode = Regs->ExceptionData;
- switch (ExitCode) {
- case SVM_EXIT_DR7_READ:
- NaeExit = Dr7ReadExit;
- break;
- case SVM_EXIT_DR7_WRITE:
- NaeExit = Dr7WriteExit;
- break;
- case SVM_EXIT_RDTSC:
- NaeExit = RdtscExit;
- break;
- case SVM_EXIT_RDPMC:
- NaeExit = RdpmcExit;
- break;
- case SVM_EXIT_CPUID:
- NaeExit = CpuidExit;
- break;
- case SVM_EXIT_INVD:
- NaeExit = InvdExit;
- break;
- case SVM_EXIT_IOIO_PROT:
- NaeExit = IoioExit;
- break;
- case SVM_EXIT_MSR:
- NaeExit = MsrExit;
- break;
- case SVM_EXIT_VMMCALL:
- NaeExit = VmmCallExit;
- break;
- case SVM_EXIT_RDTSCP:
- NaeExit = RdtscpExit;
- break;
- case SVM_EXIT_WBINVD:
- NaeExit = WbinvdExit;
- break;
- case SVM_EXIT_MONITOR:
- NaeExit = MonitorExit;
- break;
- case SVM_EXIT_MWAIT:
- NaeExit = MwaitExit;
- break;
- case SVM_EXIT_NPF:
- NaeExit = MmioExit;
- break;
- default:
- NaeExit = UnsupportedExit;
- }
- InitInstructionData (&InstructionData, Ghcb, Regs);
- Status = NaeExit (Ghcb, Regs, &InstructionData);
- if (Status == 0) {
- Regs->Rip += InstructionLength (&InstructionData);
- } else {
- GHCB_EVENT_INJECTION Event;
- Event.Uint64 = Status;
- if (Event.Elements.ErrorCodeValid != 0) {
- Regs->ExceptionData = Event.Elements.ErrorCode;
- } else {
- Regs->ExceptionData = 0;
- }
- *ExceptionType = Event.Elements.Vector;
- VcRet = EFI_PROTOCOL_ERROR;
- }
- VmgDone (Ghcb, InterruptState);
- return VcRet;
- }
- /**
- Routine to allow ASSERT from within #VC.
- @param[in, out] SevEsData Pointer to the per-CPU data
- **/
- VOID
- EFIAPI
- VmgExitIssueAssert (
- IN OUT SEV_ES_PER_CPU_DATA *SevEsData
- )
- {
- //
- // Progress will be halted, so set VcCount to allow for ASSERT output
- // to be seen.
- //
- SevEsData->VcCount = 0;
- ASSERT (FALSE);
- CpuDeadLoop ();
- }
|