2 X64 #VC Exception Handler functon.
4 Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/LocalApicLib.h>
13 #include <Library/MemEncryptSevLib.h>
14 #include <Library/VmgExitLib.h>
15 #include <Register/Amd/Msr.h>
16 #include <Register/Intel/Cpuid.h>
17 #include <IndustryStandard/InstructionParsing.h>
19 #include "VmgExitVcHandler.h"
22 // Instruction execution mode definition
28 } SEV_ES_INSTRUCTION_MODE
;
31 // Instruction size definition (for operand and address)
38 } SEV_ES_INSTRUCTION_SIZE
;
41 // Intruction segment definition
50 } SEV_ES_INSTRUCTION_SEGMENT
;
53 // Instruction rep function definition
59 } SEV_ES_INSTRUCTION_REP
;
65 } SEV_ES_INSTRUCTION_MODRM_EXT
;
71 } SEV_ES_INSTRUCTION_SIB_EXT
;
74 // Instruction opcode definition
77 SEV_ES_INSTRUCTION_MODRM_EXT ModRm
;
79 SEV_ES_INSTRUCTION_SIB_EXT Sib
;
83 } SEV_ES_INSTRUCTION_OPCODE_EXT
;
86 // Instruction parsing context definition
91 SEV_ES_INSTRUCTION_MODE Mode
;
92 SEV_ES_INSTRUCTION_SIZE DataSize
;
93 SEV_ES_INSTRUCTION_SIZE AddrSize
;
94 BOOLEAN SegmentSpecified
;
95 SEV_ES_INSTRUCTION_SEGMENT Segment
;
96 SEV_ES_INSTRUCTION_REP RepMode
;
106 INSTRUCTION_REX_PREFIX RexPrefix
;
108 BOOLEAN ModRmPresent
;
109 INSTRUCTION_MODRM ModRm
;
116 UINTN DisplacementSize
;
119 SEV_ES_INSTRUCTION_OPCODE_EXT Ext
;
120 } SEV_ES_INSTRUCTION_DATA
;
123 // Non-automatic Exit function prototype
129 EFI_SYSTEM_CONTEXT_X64
*Regs
,
130 SEV_ES_INSTRUCTION_DATA
*InstructionData
134 Return a pointer to the contents of the specified register.
136 Based upon the input register, return a pointer to the registers contents
137 in the x86 processor context.
139 @param[in] Regs x64 processor context
140 @param[in] Register Register to obtain pointer for
142 @return Pointer to the contents of the requested register
148 IN EFI_SYSTEM_CONTEXT_X64
*Regs
,
206 ASSERT (Reg
!= NULL
);
212 Update the instruction parsing context for displacement bytes.
214 @param[in, out] InstructionData Instruction parsing context
215 @param[in] Size The instruction displacement size
220 UpdateForDisplacement (
221 IN OUT SEV_ES_INSTRUCTION_DATA
*InstructionData
,
225 InstructionData
->DisplacementSize
= Size
;
226 InstructionData
->Immediate
+= Size
;
227 InstructionData
->End
+= Size
;
231 Determine if an instruction address if RIP relative.
233 Examine the instruction parsing context to determine if the address offset
234 is relative to the instruction pointer.
236 @param[in] InstructionData Instruction parsing context
238 @retval TRUE Instruction addressing is RIP relative
239 @retval FALSE Instruction addressing is not RIP relative
245 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
248 SEV_ES_INSTRUCTION_OPCODE_EXT
*Ext
;
250 Ext
= &InstructionData
->Ext
;
252 return ((InstructionData
->Mode
== LongMode64Bit
) &&
253 (Ext
->ModRm
.Mod
== 0) &&
254 (Ext
->ModRm
.Rm
== 5) &&
255 (InstructionData
->SibPresent
== FALSE
));
259 Return the effective address of a memory operand.
261 Examine the instruction parsing context to obtain the effective memory
262 address of a memory operand.
264 @param[in] Regs x64 processor context
265 @param[in] InstructionData Instruction parsing context
267 @return The memory operand effective address
272 GetEffectiveMemoryAddress (
273 IN EFI_SYSTEM_CONTEXT_X64
*Regs
,
274 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
277 SEV_ES_INSTRUCTION_OPCODE_EXT
*Ext
;
278 UINT64 EffectiveAddress
;
280 Ext
= &InstructionData
->Ext
;
281 EffectiveAddress
= 0;
283 if (IsRipRelative (InstructionData
)) {
285 // RIP-relative displacement is a 32-bit signed value
289 RipRelative
= *(INT32
*) InstructionData
->Displacement
;
291 UpdateForDisplacement (InstructionData
, 4);
294 // Negative displacement is handled by standard UINT64 wrap-around.
296 return Regs
->Rip
+ (UINT64
) RipRelative
;
299 switch (Ext
->ModRm
.Mod
) {
301 UpdateForDisplacement (InstructionData
, 1);
302 EffectiveAddress
+= (UINT64
) (*(INT8
*) (InstructionData
->Displacement
));
305 switch (InstructionData
->AddrSize
) {
307 UpdateForDisplacement (InstructionData
, 2);
308 EffectiveAddress
+= (UINT64
) (*(INT16
*) (InstructionData
->Displacement
));
311 UpdateForDisplacement (InstructionData
, 4);
312 EffectiveAddress
+= (UINT64
) (*(INT32
*) (InstructionData
->Displacement
));
318 if (InstructionData
->SibPresent
) {
321 if (Ext
->Sib
.Index
!= 4) {
324 GetRegisterPointer (Regs
, Ext
->Sib
.Index
),
325 sizeof (Displacement
)
327 Displacement
*= (INT64
)(1 << Ext
->Sib
.Scale
);
330 // Negative displacement is handled by standard UINT64 wrap-around.
332 EffectiveAddress
+= (UINT64
) Displacement
;
335 if ((Ext
->Sib
.Base
!= 5) || Ext
->ModRm
.Mod
) {
336 EffectiveAddress
+= *GetRegisterPointer (Regs
, Ext
->Sib
.Base
);
338 UpdateForDisplacement (InstructionData
, 4);
339 EffectiveAddress
+= (UINT64
) (*(INT32
*) (InstructionData
->Displacement
));
342 EffectiveAddress
+= *GetRegisterPointer (Regs
, Ext
->ModRm
.Rm
);
345 return EffectiveAddress
;
351 Examine the instruction parsing context to decode a ModRM byte and the SIB
354 @param[in] Regs x64 processor context
355 @param[in, out] InstructionData Instruction parsing context
361 IN EFI_SYSTEM_CONTEXT_X64
*Regs
,
362 IN OUT SEV_ES_INSTRUCTION_DATA
*InstructionData
365 SEV_ES_INSTRUCTION_OPCODE_EXT
*Ext
;
366 INSTRUCTION_REX_PREFIX
*RexPrefix
;
367 INSTRUCTION_MODRM
*ModRm
;
368 INSTRUCTION_SIB
*Sib
;
370 RexPrefix
= &InstructionData
->RexPrefix
;
371 Ext
= &InstructionData
->Ext
;
372 ModRm
= &InstructionData
->ModRm
;
373 Sib
= &InstructionData
->Sib
;
375 InstructionData
->ModRmPresent
= TRUE
;
376 ModRm
->Uint8
= *(InstructionData
->End
);
378 InstructionData
->Displacement
++;
379 InstructionData
->Immediate
++;
380 InstructionData
->End
++;
382 Ext
->ModRm
.Mod
= ModRm
->Bits
.Mod
;
383 Ext
->ModRm
.Reg
= (RexPrefix
->Bits
.BitR
<< 3) | ModRm
->Bits
.Reg
;
384 Ext
->ModRm
.Rm
= (RexPrefix
->Bits
.BitB
<< 3) | ModRm
->Bits
.Rm
;
386 Ext
->RegData
= *GetRegisterPointer (Regs
, Ext
->ModRm
.Reg
);
388 if (Ext
->ModRm
.Mod
== 3) {
389 Ext
->RmData
= *GetRegisterPointer (Regs
, Ext
->ModRm
.Rm
);
391 if (ModRm
->Bits
.Rm
== 4) {
392 InstructionData
->SibPresent
= TRUE
;
393 Sib
->Uint8
= *(InstructionData
->End
);
395 InstructionData
->Displacement
++;
396 InstructionData
->Immediate
++;
397 InstructionData
->End
++;
399 Ext
->Sib
.Scale
= Sib
->Bits
.Scale
;
400 Ext
->Sib
.Index
= (RexPrefix
->Bits
.BitX
<< 3) | Sib
->Bits
.Index
;
401 Ext
->Sib
.Base
= (RexPrefix
->Bits
.BitB
<< 3) | Sib
->Bits
.Base
;
404 Ext
->RmData
= GetEffectiveMemoryAddress (Regs
, InstructionData
);
409 Decode instruction prefixes.
411 Parse the instruction data to track the instruction prefixes that have
414 @param[in] Regs x64 processor context
415 @param[in, out] InstructionData Instruction parsing context
421 IN EFI_SYSTEM_CONTEXT_X64
*Regs
,
422 IN OUT SEV_ES_INSTRUCTION_DATA
*InstructionData
425 SEV_ES_INSTRUCTION_MODE Mode
;
426 SEV_ES_INSTRUCTION_SIZE ModeDataSize
;
427 SEV_ES_INSTRUCTION_SIZE ModeAddrSize
;
431 // Always in 64-bit mode
433 Mode
= LongMode64Bit
;
434 ModeDataSize
= Size32Bits
;
435 ModeAddrSize
= Size64Bits
;
437 InstructionData
->Mode
= Mode
;
438 InstructionData
->DataSize
= ModeDataSize
;
439 InstructionData
->AddrSize
= ModeAddrSize
;
441 InstructionData
->Prefixes
= InstructionData
->Begin
;
443 Byte
= InstructionData
->Prefixes
;
444 for ( ; ; Byte
++, InstructionData
->PrefixSize
++) {
446 // Check the 0x40 to 0x4F range using an if statement here since some
447 // compilers don't like the "case 0x40 ... 0x4F:" syntax. This avoids
448 // 16 case statements below.
450 if ((*Byte
>= REX_PREFIX_START
) && (*Byte
<= REX_PREFIX_STOP
)) {
451 InstructionData
->RexPrefix
.Uint8
= *Byte
;
452 if ((*Byte
& REX_64BIT_OPERAND_SIZE_MASK
) != 0) {
453 InstructionData
->DataSize
= Size64Bits
;
459 case OVERRIDE_SEGMENT_CS
:
460 case OVERRIDE_SEGMENT_DS
:
461 case OVERRIDE_SEGMENT_ES
:
462 case OVERRIDE_SEGMENT_SS
:
463 if (Mode
!= LongMode64Bit
) {
464 InstructionData
->SegmentSpecified
= TRUE
;
465 InstructionData
->Segment
= (*Byte
>> 3) & 3;
469 case OVERRIDE_SEGMENT_FS
:
470 case OVERRIDE_SEGMENT_GS
:
471 InstructionData
->SegmentSpecified
= TRUE
;
472 InstructionData
->Segment
= *Byte
& 7;
475 case OVERRIDE_OPERAND_SIZE
:
476 if (InstructionData
->RexPrefix
.Uint8
== 0) {
477 InstructionData
->DataSize
=
478 (Mode
== LongMode64Bit
) ? Size16Bits
:
479 (Mode
== LongModeCompat32Bit
) ? Size16Bits
:
480 (Mode
== LongModeCompat16Bit
) ? Size32Bits
: 0;
484 case OVERRIDE_ADDRESS_SIZE
:
485 InstructionData
->AddrSize
=
486 (Mode
== LongMode64Bit
) ? Size32Bits
:
487 (Mode
== LongModeCompat32Bit
) ? Size16Bits
:
488 (Mode
== LongModeCompat16Bit
) ? Size32Bits
: 0;
495 InstructionData
->RepMode
= RepZ
;
499 InstructionData
->RepMode
= RepNZ
;
503 InstructionData
->OpCodes
= Byte
;
504 InstructionData
->OpCodeSize
= (*Byte
== TWO_BYTE_OPCODE_ESCAPE
) ? 2 : 1;
506 InstructionData
->End
= Byte
+ InstructionData
->OpCodeSize
;
507 InstructionData
->Displacement
= InstructionData
->End
;
508 InstructionData
->Immediate
= InstructionData
->End
;
515 Determine instruction length
517 Return the total length of the parsed instruction.
519 @param[in] InstructionData Instruction parsing context
521 @return Length of parsed instruction
527 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
530 return (UINT64
) (InstructionData
->End
- InstructionData
->Begin
);
534 Initialize the instruction parsing context.
536 Initialize the instruction parsing context, which includes decoding the
537 instruction prefixes.
539 @param[in, out] InstructionData Instruction parsing context
540 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication
542 @param[in] Regs x64 processor context
547 InitInstructionData (
548 IN OUT SEV_ES_INSTRUCTION_DATA
*InstructionData
,
550 IN EFI_SYSTEM_CONTEXT_X64
*Regs
553 SetMem (InstructionData
, sizeof (*InstructionData
), 0);
554 InstructionData
->Ghcb
= Ghcb
;
555 InstructionData
->Begin
= (UINT8
*) Regs
->Rip
;
556 InstructionData
->End
= (UINT8
*) Regs
->Rip
;
558 DecodePrefixes (Regs
, InstructionData
);
562 Report an unsupported event to the hypervisor
564 Use the VMGEXIT support to report an unsupported event to the hypervisor.
566 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication
568 @param[in] Regs x64 processor context
569 @param[in] InstructionData Instruction parsing context
571 @return New exception value to propagate
578 IN EFI_SYSTEM_CONTEXT_X64
*Regs
,
579 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
584 Status
= VmgExit (Ghcb
, SVM_EXIT_UNSUPPORTED
, Regs
->ExceptionData
, 0);
586 GHCB_EVENT_INJECTION Event
;
589 Event
.Elements
.Vector
= GP_EXCEPTION
;
590 Event
.Elements
.Type
= GHCB_EVENT_INJECTION_TYPE_EXCEPTION
;
591 Event
.Elements
.Valid
= 1;
593 Status
= Event
.Uint64
;
600 Validate that the MMIO memory access is not to encrypted memory.
602 Examine the pagetable entry for the memory specified. MMIO should not be
603 performed against encrypted memory. MMIO to the APIC page is always allowed.
605 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication Block
606 @param[in] MemoryAddress Memory address to validate
607 @param[in] MemoryLength Memory length to validate
609 @retval 0 Memory is not encrypted
610 @return New exception value to propogate
617 IN UINTN MemoryAddress
,
618 IN UINTN MemoryLength
621 MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State
;
622 GHCB_EVENT_INJECTION GpEvent
;
626 // Allow APIC accesses (which will have the encryption bit set during
627 // SEC and PEI phases).
629 Address
= MemoryAddress
& ~(SIZE_4KB
- 1);
630 if (Address
== GetLocalApicBaseAddress ()) {
634 State
= MemEncryptSevGetAddressRangeState (
639 if (State
== MemEncryptSevAddressRangeUnencrypted
) {
644 // Any state other than unencrypted is an error, issue a #GP.
647 "MMIO using encrypted memory: %lx\n",
648 (UINT64
) MemoryAddress
));
650 GpEvent
.Elements
.Vector
= GP_EXCEPTION
;
651 GpEvent
.Elements
.Type
= GHCB_EVENT_INJECTION_TYPE_EXCEPTION
;
652 GpEvent
.Elements
.Valid
= 1;
654 return GpEvent
.Uint64
;
658 Handle an MMIO event.
660 Use the VMGEXIT instruction to handle either an MMIO read or an MMIO write.
662 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
664 @param[in, out] Regs x64 processor context
665 @param[in, out] InstructionData Instruction parsing context
667 @retval 0 Event handled successfully
668 @return New exception value to propagate
675 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
676 IN OUT SEV_ES_INSTRUCTION_DATA
*InstructionData
679 UINT64 ExitInfo1
, ExitInfo2
, Status
;
682 UINT8 OpCode
, SignByte
;
687 OpCode
= *(InstructionData
->OpCodes
);
688 if (OpCode
== TWO_BYTE_OPCODE_ESCAPE
) {
689 OpCode
= *(InstructionData
->OpCodes
+ 1);
694 // MMIO write (MOV reg/memX, regX)
702 DecodeModRm (Regs
, InstructionData
);
703 Bytes
= ((Bytes
!= 0) ? Bytes
:
704 (InstructionData
->DataSize
== Size16Bits
) ? 2 :
705 (InstructionData
->DataSize
== Size32Bits
) ? 4 :
706 (InstructionData
->DataSize
== Size64Bits
) ? 8 :
709 if (InstructionData
->Ext
.ModRm
.Mod
== 3) {
711 // NPF on two register operands???
713 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
716 Status
= ValidateMmioMemory (Ghcb
, InstructionData
->Ext
.RmData
, Bytes
);
721 ExitInfo1
= InstructionData
->Ext
.RmData
;
723 CopyMem (Ghcb
->SharedBuffer
, &InstructionData
->Ext
.RegData
, Bytes
);
725 Ghcb
->SaveArea
.SwScratch
= (UINT64
) Ghcb
->SharedBuffer
;
726 VmgSetOffsetValid (Ghcb
, GhcbSwScratch
);
727 Status
= VmgExit (Ghcb
, SVM_EXIT_MMIO_WRITE
, ExitInfo1
, ExitInfo2
);
734 // MMIO write (MOV moffsetX, aX)
742 Bytes
= ((Bytes
!= 0) ? Bytes
:
743 (InstructionData
->DataSize
== Size16Bits
) ? 2 :
744 (InstructionData
->DataSize
== Size32Bits
) ? 4 :
745 (InstructionData
->DataSize
== Size64Bits
) ? 8 :
748 InstructionData
->ImmediateSize
= (UINTN
) (1 << InstructionData
->AddrSize
);
749 InstructionData
->End
+= InstructionData
->ImmediateSize
;
752 // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
753 // Use a STATIC_ASSERT to be certain the code is being built as X64.
756 sizeof (UINTN
) == sizeof (UINT64
),
757 "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
763 InstructionData
->Immediate
,
764 InstructionData
->ImmediateSize
767 Status
= ValidateMmioMemory (Ghcb
, Address
, Bytes
);
774 CopyMem (Ghcb
->SharedBuffer
, &Regs
->Rax
, Bytes
);
776 Ghcb
->SaveArea
.SwScratch
= (UINT64
) Ghcb
->SharedBuffer
;
777 VmgSetOffsetValid (Ghcb
, GhcbSwScratch
);
778 Status
= VmgExit (Ghcb
, SVM_EXIT_MMIO_WRITE
, ExitInfo1
, ExitInfo2
);
785 // MMIO write (MOV reg/memX, immX)
793 DecodeModRm (Regs
, InstructionData
);
794 Bytes
= ((Bytes
!= 0) ? Bytes
:
795 (InstructionData
->DataSize
== Size16Bits
) ? 2 :
796 (InstructionData
->DataSize
== Size32Bits
) ? 4 :
799 InstructionData
->ImmediateSize
= Bytes
;
800 InstructionData
->End
+= Bytes
;
802 Status
= ValidateMmioMemory (Ghcb
, InstructionData
->Ext
.RmData
, Bytes
);
807 ExitInfo1
= InstructionData
->Ext
.RmData
;
809 CopyMem (Ghcb
->SharedBuffer
, InstructionData
->Immediate
, Bytes
);
811 Ghcb
->SaveArea
.SwScratch
= (UINT64
) Ghcb
->SharedBuffer
;
812 VmgSetOffsetValid (Ghcb
, GhcbSwScratch
);
813 Status
= VmgExit (Ghcb
, SVM_EXIT_MMIO_WRITE
, ExitInfo1
, ExitInfo2
);
820 // MMIO read (MOV regX, reg/memX)
828 DecodeModRm (Regs
, InstructionData
);
829 Bytes
= ((Bytes
!= 0) ? Bytes
:
830 (InstructionData
->DataSize
== Size16Bits
) ? 2 :
831 (InstructionData
->DataSize
== Size32Bits
) ? 4 :
832 (InstructionData
->DataSize
== Size64Bits
) ? 8 :
834 if (InstructionData
->Ext
.ModRm
.Mod
== 3) {
836 // NPF on two register operands???
838 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
841 Status
= ValidateMmioMemory (Ghcb
, InstructionData
->Ext
.RmData
, Bytes
);
846 ExitInfo1
= InstructionData
->Ext
.RmData
;
849 Ghcb
->SaveArea
.SwScratch
= (UINT64
) Ghcb
->SharedBuffer
;
850 VmgSetOffsetValid (Ghcb
, GhcbSwScratch
);
851 Status
= VmgExit (Ghcb
, SVM_EXIT_MMIO_READ
, ExitInfo1
, ExitInfo2
);
856 Register
= GetRegisterPointer (Regs
, InstructionData
->Ext
.ModRm
.Reg
);
859 // Zero-extend for 32-bit operation
863 CopyMem (Register
, Ghcb
->SharedBuffer
, Bytes
);
867 // MMIO read (MOV aX, moffsetX)
875 Bytes
= ((Bytes
!= 0) ? Bytes
:
876 (InstructionData
->DataSize
== Size16Bits
) ? 2 :
877 (InstructionData
->DataSize
== Size32Bits
) ? 4 :
878 (InstructionData
->DataSize
== Size64Bits
) ? 8 :
881 InstructionData
->ImmediateSize
= (UINTN
) (1 << InstructionData
->AddrSize
);
882 InstructionData
->End
+= InstructionData
->ImmediateSize
;
885 // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
886 // Use a STATIC_ASSERT to be certain the code is being built as X64.
889 sizeof (UINTN
) == sizeof (UINT64
),
890 "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
896 InstructionData
->Immediate
,
897 InstructionData
->ImmediateSize
900 Status
= ValidateMmioMemory (Ghcb
, Address
, Bytes
);
908 Ghcb
->SaveArea
.SwScratch
= (UINT64
) Ghcb
->SharedBuffer
;
909 VmgSetOffsetValid (Ghcb
, GhcbSwScratch
);
910 Status
= VmgExit (Ghcb
, SVM_EXIT_MMIO_READ
, ExitInfo1
, ExitInfo2
);
917 // Zero-extend for 32-bit operation
921 CopyMem (&Regs
->Rax
, Ghcb
->SharedBuffer
, Bytes
);
925 // MMIO read w/ zero-extension ((MOVZX regX, reg/memX)
933 DecodeModRm (Regs
, InstructionData
);
934 Bytes
= (Bytes
!= 0) ? Bytes
: 2;
936 Status
= ValidateMmioMemory (Ghcb
, InstructionData
->Ext
.RmData
, Bytes
);
941 ExitInfo1
= InstructionData
->Ext
.RmData
;
944 Ghcb
->SaveArea
.SwScratch
= (UINT64
) Ghcb
->SharedBuffer
;
945 VmgSetOffsetValid (Ghcb
, GhcbSwScratch
);
946 Status
= VmgExit (Ghcb
, SVM_EXIT_MMIO_READ
, ExitInfo1
, ExitInfo2
);
951 Register
= GetRegisterPointer (Regs
, InstructionData
->Ext
.ModRm
.Reg
);
952 SetMem (Register
, (UINTN
) (1 << InstructionData
->DataSize
), 0);
953 CopyMem (Register
, Ghcb
->SharedBuffer
, Bytes
);
957 // MMIO read w/ sign-extension (MOVSX regX, reg/memX)
965 DecodeModRm (Regs
, InstructionData
);
966 Bytes
= (Bytes
!= 0) ? Bytes
: 2;
968 Status
= ValidateMmioMemory (Ghcb
, InstructionData
->Ext
.RmData
, Bytes
);
973 ExitInfo1
= InstructionData
->Ext
.RmData
;
976 Ghcb
->SaveArea
.SwScratch
= (UINT64
) Ghcb
->SharedBuffer
;
977 VmgSetOffsetValid (Ghcb
, GhcbSwScratch
);
978 Status
= VmgExit (Ghcb
, SVM_EXIT_MMIO_READ
, ExitInfo1
, ExitInfo2
);
986 Data
= (UINT8
*) Ghcb
->SharedBuffer
;
987 SignByte
= ((*Data
& BIT7
) != 0) ? 0xFF : 0x00;
991 Data
= (UINT16
*) Ghcb
->SharedBuffer
;
992 SignByte
= ((*Data
& BIT15
) != 0) ? 0xFF : 0x00;
995 Register
= GetRegisterPointer (Regs
, InstructionData
->Ext
.ModRm
.Reg
);
996 SetMem (Register
, (UINTN
) (1 << InstructionData
->DataSize
), SignByte
);
997 CopyMem (Register
, Ghcb
->SharedBuffer
, Bytes
);
1001 DEBUG ((DEBUG_ERROR
, "Invalid MMIO opcode (%x)\n", OpCode
));
1002 Status
= GP_EXCEPTION
;
1010 Handle a MWAIT event.
1012 Use the VMGEXIT instruction to handle a MWAIT event.
1014 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1016 @param[in, out] Regs x64 processor context
1017 @param[in] InstructionData Instruction parsing context
1019 @retval 0 Event handled successfully
1020 @return New exception value to propagate
1027 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1028 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1031 DecodeModRm (Regs
, InstructionData
);
1033 Ghcb
->SaveArea
.Rax
= Regs
->Rax
;
1034 VmgSetOffsetValid (Ghcb
, GhcbRax
);
1035 Ghcb
->SaveArea
.Rcx
= Regs
->Rcx
;
1036 VmgSetOffsetValid (Ghcb
, GhcbRcx
);
1038 return VmgExit (Ghcb
, SVM_EXIT_MWAIT
, 0, 0);
1042 Handle a MONITOR event.
1044 Use the VMGEXIT instruction to handle a MONITOR event.
1046 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1048 @param[in, out] Regs x64 processor context
1049 @param[in] InstructionData Instruction parsing context
1051 @retval 0 Event handled successfully
1052 @return New exception value to propagate
1059 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1060 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1063 DecodeModRm (Regs
, InstructionData
);
1065 Ghcb
->SaveArea
.Rax
= Regs
->Rax
; // Identity mapped, so VA = PA
1066 VmgSetOffsetValid (Ghcb
, GhcbRax
);
1067 Ghcb
->SaveArea
.Rcx
= Regs
->Rcx
;
1068 VmgSetOffsetValid (Ghcb
, GhcbRcx
);
1069 Ghcb
->SaveArea
.Rdx
= Regs
->Rdx
;
1070 VmgSetOffsetValid (Ghcb
, GhcbRdx
);
1072 return VmgExit (Ghcb
, SVM_EXIT_MONITOR
, 0, 0);
1076 Handle a WBINVD event.
1078 Use the VMGEXIT instruction to handle a WBINVD event.
1080 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1082 @param[in, out] Regs x64 processor context
1083 @param[in] InstructionData Instruction parsing context
1085 @retval 0 Event handled successfully
1086 @return New exception value to propagate
1093 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1094 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1097 return VmgExit (Ghcb
, SVM_EXIT_WBINVD
, 0, 0);
1101 Handle a RDTSCP event.
1103 Use the VMGEXIT instruction to handle a RDTSCP event.
1105 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1107 @param[in, out] Regs x64 processor context
1108 @param[in] InstructionData Instruction parsing context
1110 @retval 0 Event handled successfully
1111 @return New exception value to propagate
1118 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1119 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1124 DecodeModRm (Regs
, InstructionData
);
1126 Status
= VmgExit (Ghcb
, SVM_EXIT_RDTSCP
, 0, 0);
1131 if (!VmgIsOffsetValid (Ghcb
, GhcbRax
) ||
1132 !VmgIsOffsetValid (Ghcb
, GhcbRcx
) ||
1133 !VmgIsOffsetValid (Ghcb
, GhcbRdx
)) {
1134 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1136 Regs
->Rax
= Ghcb
->SaveArea
.Rax
;
1137 Regs
->Rcx
= Ghcb
->SaveArea
.Rcx
;
1138 Regs
->Rdx
= Ghcb
->SaveArea
.Rdx
;
1144 Handle a VMMCALL event.
1146 Use the VMGEXIT instruction to handle a VMMCALL event.
1148 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1150 @param[in, out] Regs x64 processor context
1151 @param[in] InstructionData Instruction parsing context
1153 @retval 0 Event handled successfully
1154 @return New exception value to propagate
1161 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1162 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1167 DecodeModRm (Regs
, InstructionData
);
1169 Ghcb
->SaveArea
.Rax
= Regs
->Rax
;
1170 VmgSetOffsetValid (Ghcb
, GhcbRax
);
1171 Ghcb
->SaveArea
.Cpl
= (UINT8
) (Regs
->Cs
& 0x3);
1172 VmgSetOffsetValid (Ghcb
, GhcbCpl
);
1174 Status
= VmgExit (Ghcb
, SVM_EXIT_VMMCALL
, 0, 0);
1179 if (!VmgIsOffsetValid (Ghcb
, GhcbRax
)) {
1180 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1182 Regs
->Rax
= Ghcb
->SaveArea
.Rax
;
1188 Handle an MSR event.
1190 Use the VMGEXIT instruction to handle either a RDMSR or WRMSR event.
1192 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1194 @param[in, out] Regs x64 processor context
1195 @param[in] InstructionData Instruction parsing context
1197 @retval 0 Event handled successfully
1198 @return New exception value to propagate
1205 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1206 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1209 UINT64 ExitInfo1
, Status
;
1213 switch (*(InstructionData
->OpCodes
+ 1)) {
1216 Ghcb
->SaveArea
.Rax
= Regs
->Rax
;
1217 VmgSetOffsetValid (Ghcb
, GhcbRax
);
1218 Ghcb
->SaveArea
.Rdx
= Regs
->Rdx
;
1219 VmgSetOffsetValid (Ghcb
, GhcbRdx
);
1224 Ghcb
->SaveArea
.Rcx
= Regs
->Rcx
;
1225 VmgSetOffsetValid (Ghcb
, GhcbRcx
);
1228 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1231 Status
= VmgExit (Ghcb
, SVM_EXIT_MSR
, ExitInfo1
, 0);
1236 if (ExitInfo1
== 0) {
1237 if (!VmgIsOffsetValid (Ghcb
, GhcbRax
) ||
1238 !VmgIsOffsetValid (Ghcb
, GhcbRdx
)) {
1239 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1241 Regs
->Rax
= Ghcb
->SaveArea
.Rax
;
1242 Regs
->Rdx
= Ghcb
->SaveArea
.Rdx
;
1249 Build the IOIO event information.
1251 The IOIO event information identifies the type of IO operation to be performed
1252 by the hypervisor. Build this information based on the instruction data.
1254 @param[in] Regs x64 processor context
1255 @param[in, out] InstructionData Instruction parsing context
1257 @return IOIO event information value
1263 IN EFI_SYSTEM_CONTEXT_X64
*Regs
,
1264 IN OUT SEV_ES_INSTRUCTION_DATA
*InstructionData
1271 switch (*(InstructionData
->OpCodes
)) {
1277 ExitInfo
|= IOIO_TYPE_INS
;
1278 ExitInfo
|= IOIO_SEG_ES
;
1279 ExitInfo
|= ((Regs
->Rdx
& 0xffff) << 16);
1287 ExitInfo
|= IOIO_TYPE_OUTS
;
1288 ExitInfo
|= IOIO_SEG_DS
;
1289 ExitInfo
|= ((Regs
->Rdx
& 0xffff) << 16);
1293 // IN immediate opcodes
1297 InstructionData
->ImmediateSize
= 1;
1298 InstructionData
->End
++;
1299 ExitInfo
|= IOIO_TYPE_IN
;
1300 ExitInfo
|= ((*(InstructionData
->OpCodes
+ 1)) << 16);
1304 // OUT immediate opcodes
1308 InstructionData
->ImmediateSize
= 1;
1309 InstructionData
->End
++;
1310 ExitInfo
|= IOIO_TYPE_OUT
;
1311 ExitInfo
|= ((*(InstructionData
->OpCodes
+ 1)) << 16) | IOIO_TYPE_OUT
;
1315 // IN register opcodes
1319 ExitInfo
|= IOIO_TYPE_IN
;
1320 ExitInfo
|= ((Regs
->Rdx
& 0xffff) << 16);
1324 // OUT register opcodes
1328 ExitInfo
|= IOIO_TYPE_OUT
;
1329 ExitInfo
|= ((Regs
->Rdx
& 0xffff) << 16);
1336 switch (*(InstructionData
->OpCodes
)) {
1338 // Single-byte opcodes
1346 ExitInfo
|= IOIO_DATA_8
;
1350 // Length determined by instruction parsing
1353 ExitInfo
|= (InstructionData
->DataSize
== Size16Bits
) ? IOIO_DATA_16
1357 switch (InstructionData
->AddrSize
) {
1359 ExitInfo
|= IOIO_ADDR_16
;
1363 ExitInfo
|= IOIO_ADDR_32
;
1367 ExitInfo
|= IOIO_ADDR_64
;
1374 if (InstructionData
->RepMode
!= 0) {
1375 ExitInfo
|= IOIO_REP
;
1382 Handle an IOIO event.
1384 Use the VMGEXIT instruction to handle an IOIO event.
1386 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1388 @param[in, out] Regs x64 processor context
1389 @param[in] InstructionData Instruction parsing context
1391 @retval 0 Event handled successfully
1392 @return New exception value to propagate
1399 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1400 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1403 UINT64 ExitInfo1
, ExitInfo2
, Status
;
1406 ExitInfo1
= IoioExitInfo (Regs
, InstructionData
);
1407 if (ExitInfo1
== 0) {
1408 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1411 IsString
= ((ExitInfo1
& IOIO_TYPE_STR
) != 0) ? TRUE
: FALSE
;
1413 UINTN IoBytes
, VmgExitBytes
;
1414 UINTN GhcbCount
, OpCount
;
1418 IoBytes
= IOIO_DATA_BYTES (ExitInfo1
);
1419 GhcbCount
= sizeof (Ghcb
->SharedBuffer
) / IoBytes
;
1421 OpCount
= ((ExitInfo1
& IOIO_REP
) != 0) ? Regs
->Rcx
: 1;
1422 while (OpCount
!= 0) {
1423 ExitInfo2
= MIN (OpCount
, GhcbCount
);
1424 VmgExitBytes
= ExitInfo2
* IoBytes
;
1426 if ((ExitInfo1
& IOIO_TYPE_IN
) == 0) {
1427 CopyMem (Ghcb
->SharedBuffer
, (VOID
*) Regs
->Rsi
, VmgExitBytes
);
1428 Regs
->Rsi
+= VmgExitBytes
;
1431 Ghcb
->SaveArea
.SwScratch
= (UINT64
) Ghcb
->SharedBuffer
;
1432 VmgSetOffsetValid (Ghcb
, GhcbSwScratch
);
1433 Status
= VmgExit (Ghcb
, SVM_EXIT_IOIO_PROT
, ExitInfo1
, ExitInfo2
);
1438 if ((ExitInfo1
& IOIO_TYPE_IN
) != 0) {
1439 CopyMem ((VOID
*) Regs
->Rdi
, Ghcb
->SharedBuffer
, VmgExitBytes
);
1440 Regs
->Rdi
+= VmgExitBytes
;
1443 if ((ExitInfo1
& IOIO_REP
) != 0) {
1444 Regs
->Rcx
-= ExitInfo2
;
1447 OpCount
-= ExitInfo2
;
1450 if ((ExitInfo1
& IOIO_TYPE_IN
) != 0) {
1451 Ghcb
->SaveArea
.Rax
= 0;
1453 CopyMem (&Ghcb
->SaveArea
.Rax
, &Regs
->Rax
, IOIO_DATA_BYTES (ExitInfo1
));
1455 VmgSetOffsetValid (Ghcb
, GhcbRax
);
1457 Status
= VmgExit (Ghcb
, SVM_EXIT_IOIO_PROT
, ExitInfo1
, 0);
1462 if ((ExitInfo1
& IOIO_TYPE_IN
) != 0) {
1463 if (!VmgIsOffsetValid (Ghcb
, GhcbRax
)) {
1464 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1466 CopyMem (&Regs
->Rax
, &Ghcb
->SaveArea
.Rax
, IOIO_DATA_BYTES (ExitInfo1
));
1474 Handle a INVD event.
1476 Use the VMGEXIT instruction to handle a INVD event.
1478 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1480 @param[in, out] Regs x64 processor context
1481 @param[in] InstructionData Instruction parsing context
1483 @retval 0 Event handled successfully
1484 @return New exception value to propagate
1491 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1492 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1495 return VmgExit (Ghcb
, SVM_EXIT_INVD
, 0, 0);
1499 Handle a CPUID event.
1501 Use the VMGEXIT instruction to handle a CPUID event.
1503 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1505 @param[in, out] Regs x64 processor context
1506 @param[in] InstructionData Instruction parsing context
1508 @retval 0 Event handled successfully
1509 @return New exception value to propagate
1516 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1517 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1522 Ghcb
->SaveArea
.Rax
= Regs
->Rax
;
1523 VmgSetOffsetValid (Ghcb
, GhcbRax
);
1524 Ghcb
->SaveArea
.Rcx
= Regs
->Rcx
;
1525 VmgSetOffsetValid (Ghcb
, GhcbRcx
);
1526 if (Regs
->Rax
== CPUID_EXTENDED_STATE
) {
1529 Cr4
.UintN
= AsmReadCr4 ();
1530 Ghcb
->SaveArea
.XCr0
= (Cr4
.Bits
.OSXSAVE
== 1) ? AsmXGetBv (0) : 1;
1531 VmgSetOffsetValid (Ghcb
, GhcbXCr0
);
1534 Status
= VmgExit (Ghcb
, SVM_EXIT_CPUID
, 0, 0);
1539 if (!VmgIsOffsetValid (Ghcb
, GhcbRax
) ||
1540 !VmgIsOffsetValid (Ghcb
, GhcbRbx
) ||
1541 !VmgIsOffsetValid (Ghcb
, GhcbRcx
) ||
1542 !VmgIsOffsetValid (Ghcb
, GhcbRdx
)) {
1543 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1545 Regs
->Rax
= Ghcb
->SaveArea
.Rax
;
1546 Regs
->Rbx
= Ghcb
->SaveArea
.Rbx
;
1547 Regs
->Rcx
= Ghcb
->SaveArea
.Rcx
;
1548 Regs
->Rdx
= Ghcb
->SaveArea
.Rdx
;
1554 Handle a RDPMC event.
1556 Use the VMGEXIT instruction to handle a RDPMC event.
1558 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1560 @param[in, out] Regs x64 processor context
1561 @param[in] InstructionData Instruction parsing context
1563 @retval 0 Event handled successfully
1564 @return New exception value to propagate
1571 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1572 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1577 Ghcb
->SaveArea
.Rcx
= Regs
->Rcx
;
1578 VmgSetOffsetValid (Ghcb
, GhcbRcx
);
1580 Status
= VmgExit (Ghcb
, SVM_EXIT_RDPMC
, 0, 0);
1585 if (!VmgIsOffsetValid (Ghcb
, GhcbRax
) ||
1586 !VmgIsOffsetValid (Ghcb
, GhcbRdx
)) {
1587 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1589 Regs
->Rax
= Ghcb
->SaveArea
.Rax
;
1590 Regs
->Rdx
= Ghcb
->SaveArea
.Rdx
;
1596 Handle a RDTSC event.
1598 Use the VMGEXIT instruction to handle a RDTSC event.
1600 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1602 @param[in, out] Regs x64 processor context
1603 @param[in] InstructionData Instruction parsing context
1605 @retval 0 Event handled successfully
1606 @return New exception value to propagate
1613 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1614 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1619 Status
= VmgExit (Ghcb
, SVM_EXIT_RDTSC
, 0, 0);
1624 if (!VmgIsOffsetValid (Ghcb
, GhcbRax
) ||
1625 !VmgIsOffsetValid (Ghcb
, GhcbRdx
)) {
1626 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1628 Regs
->Rax
= Ghcb
->SaveArea
.Rax
;
1629 Regs
->Rdx
= Ghcb
->SaveArea
.Rdx
;
1635 Handle a DR7 register write event.
1637 Use the VMGEXIT instruction to handle a DR7 write event.
1639 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1641 @param[in, out] Regs x64 processor context
1642 @param[in] InstructionData Instruction parsing context
1644 @retval 0 Event handled successfully
1645 @return New exception value to propagate
1652 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1653 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1656 SEV_ES_INSTRUCTION_OPCODE_EXT
*Ext
;
1657 SEV_ES_PER_CPU_DATA
*SevEsData
;
1661 Ext
= &InstructionData
->Ext
;
1662 SevEsData
= (SEV_ES_PER_CPU_DATA
*) (Ghcb
+ 1);
1664 DecodeModRm (Regs
, InstructionData
);
1667 // MOV DRn always treats MOD == 3 no matter how encoded
1669 Register
= GetRegisterPointer (Regs
, Ext
->ModRm
.Rm
);
1672 // Using a value of 0 for ExitInfo1 means RAX holds the value
1674 Ghcb
->SaveArea
.Rax
= *Register
;
1675 VmgSetOffsetValid (Ghcb
, GhcbRax
);
1677 Status
= VmgExit (Ghcb
, SVM_EXIT_DR7_WRITE
, 0, 0);
1682 SevEsData
->Dr7
= *Register
;
1683 SevEsData
->Dr7Cached
= 1;
1689 Handle a DR7 register read event.
1691 Use the VMGEXIT instruction to handle a DR7 read event.
1693 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1695 @param[in, out] Regs x64 processor context
1696 @param[in] InstructionData Instruction parsing context
1698 @retval 0 Event handled successfully
1705 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1706 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1709 SEV_ES_INSTRUCTION_OPCODE_EXT
*Ext
;
1710 SEV_ES_PER_CPU_DATA
*SevEsData
;
1713 Ext
= &InstructionData
->Ext
;
1714 SevEsData
= (SEV_ES_PER_CPU_DATA
*) (Ghcb
+ 1);
1716 DecodeModRm (Regs
, InstructionData
);
1719 // MOV DRn always treats MOD == 3 no matter how encoded
1721 Register
= GetRegisterPointer (Regs
, Ext
->ModRm
.Rm
);
1724 // If there is a cached valued for DR7, return that. Otherwise return the
1725 // DR7 standard reset value of 0x400 (no debug breakpoints set).
1727 *Register
= (SevEsData
->Dr7Cached
== 1) ? SevEsData
->Dr7
: 0x400;
1733 Handle a #VC exception.
1735 Performs the necessary processing to handle a #VC exception.
1737 @param[in, out] Ghcb Pointer to the GHCB
1738 @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set
1739 as value to use on error.
1740 @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT
1742 @retval EFI_SUCCESS Exception handled
1743 @retval EFI_UNSUPPORTED #VC not supported, (new) exception value to
1745 @retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to
1751 InternalVmgExitHandleVc (
1753 IN OUT EFI_EXCEPTION_TYPE
*ExceptionType
,
1754 IN OUT EFI_SYSTEM_CONTEXT SystemContext
1757 EFI_SYSTEM_CONTEXT_X64
*Regs
;
1759 SEV_ES_INSTRUCTION_DATA InstructionData
;
1760 UINT64 ExitCode
, Status
;
1762 BOOLEAN InterruptState
;
1764 VcRet
= EFI_SUCCESS
;
1766 Regs
= SystemContext
.SystemContextX64
;
1768 VmgInit (Ghcb
, &InterruptState
);
1770 ExitCode
= Regs
->ExceptionData
;
1772 case SVM_EXIT_DR7_READ
:
1773 NaeExit
= Dr7ReadExit
;
1776 case SVM_EXIT_DR7_WRITE
:
1777 NaeExit
= Dr7WriteExit
;
1780 case SVM_EXIT_RDTSC
:
1781 NaeExit
= RdtscExit
;
1784 case SVM_EXIT_RDPMC
:
1785 NaeExit
= RdpmcExit
;
1788 case SVM_EXIT_CPUID
:
1789 NaeExit
= CpuidExit
;
1796 case SVM_EXIT_IOIO_PROT
:
1804 case SVM_EXIT_VMMCALL
:
1805 NaeExit
= VmmCallExit
;
1808 case SVM_EXIT_RDTSCP
:
1809 NaeExit
= RdtscpExit
;
1812 case SVM_EXIT_WBINVD
:
1813 NaeExit
= WbinvdExit
;
1816 case SVM_EXIT_MONITOR
:
1817 NaeExit
= MonitorExit
;
1820 case SVM_EXIT_MWAIT
:
1821 NaeExit
= MwaitExit
;
1829 NaeExit
= UnsupportedExit
;
1832 InitInstructionData (&InstructionData
, Ghcb
, Regs
);
1834 Status
= NaeExit (Ghcb
, Regs
, &InstructionData
);
1836 Regs
->Rip
+= InstructionLength (&InstructionData
);
1838 GHCB_EVENT_INJECTION Event
;
1840 Event
.Uint64
= Status
;
1841 if (Event
.Elements
.ErrorCodeValid
!= 0) {
1842 Regs
->ExceptionData
= Event
.Elements
.ErrorCode
;
1844 Regs
->ExceptionData
= 0;
1847 *ExceptionType
= Event
.Elements
.Vector
;
1849 VcRet
= EFI_PROTOCOL_ERROR
;
1852 VmgDone (Ghcb
, InterruptState
);
1858 Routine to allow ASSERT from within #VC.
1860 @param[in, out] SevEsData Pointer to the per-CPU data
1865 VmgExitIssueAssert (
1866 IN OUT SEV_ES_PER_CPU_DATA
*SevEsData
1870 // Progress will be halted, so set VcCount to allow for ASSERT output
1873 SevEsData
->VcCount
= 0;