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
,
207 ASSERT (Reg
!= NULL
);
213 Update the instruction parsing context for displacement bytes.
215 @param[in, out] InstructionData Instruction parsing context
216 @param[in] Size The instruction displacement size
221 UpdateForDisplacement (
222 IN OUT SEV_ES_INSTRUCTION_DATA
*InstructionData
,
226 InstructionData
->DisplacementSize
= Size
;
227 InstructionData
->Immediate
+= Size
;
228 InstructionData
->End
+= Size
;
232 Determine if an instruction address if RIP relative.
234 Examine the instruction parsing context to determine if the address offset
235 is relative to the instruction pointer.
237 @param[in] InstructionData Instruction parsing context
239 @retval TRUE Instruction addressing is RIP relative
240 @retval FALSE Instruction addressing is not RIP relative
246 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
249 SEV_ES_INSTRUCTION_OPCODE_EXT
*Ext
;
251 Ext
= &InstructionData
->Ext
;
253 return ((InstructionData
->Mode
== LongMode64Bit
) &&
254 (Ext
->ModRm
.Mod
== 0) &&
255 (Ext
->ModRm
.Rm
== 5) &&
256 (InstructionData
->SibPresent
== FALSE
));
260 Return the effective address of a memory operand.
262 Examine the instruction parsing context to obtain the effective memory
263 address of a memory operand.
265 @param[in] Regs x64 processor context
266 @param[in] InstructionData Instruction parsing context
268 @return The memory operand effective address
273 GetEffectiveMemoryAddress (
274 IN EFI_SYSTEM_CONTEXT_X64
*Regs
,
275 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
278 SEV_ES_INSTRUCTION_OPCODE_EXT
*Ext
;
279 UINT64 EffectiveAddress
;
281 Ext
= &InstructionData
->Ext
;
282 EffectiveAddress
= 0;
284 if (IsRipRelative (InstructionData
)) {
286 // RIP-relative displacement is a 32-bit signed value
290 RipRelative
= *(INT32
*)InstructionData
->Displacement
;
292 UpdateForDisplacement (InstructionData
, 4);
295 // Negative displacement is handled by standard UINT64 wrap-around.
297 return Regs
->Rip
+ (UINT64
)RipRelative
;
300 switch (Ext
->ModRm
.Mod
) {
302 UpdateForDisplacement (InstructionData
, 1);
303 EffectiveAddress
+= (UINT64
)(*(INT8
*)(InstructionData
->Displacement
));
306 switch (InstructionData
->AddrSize
) {
308 UpdateForDisplacement (InstructionData
, 2);
309 EffectiveAddress
+= (UINT64
)(*(INT16
*)(InstructionData
->Displacement
));
312 UpdateForDisplacement (InstructionData
, 4);
313 EffectiveAddress
+= (UINT64
)(*(INT32
*)(InstructionData
->Displacement
));
320 if (InstructionData
->SibPresent
) {
323 if (Ext
->Sib
.Index
!= 4) {
326 GetRegisterPointer (Regs
, Ext
->Sib
.Index
),
327 sizeof (Displacement
)
329 Displacement
*= (INT64
)(1 << Ext
->Sib
.Scale
);
332 // Negative displacement is handled by standard UINT64 wrap-around.
334 EffectiveAddress
+= (UINT64
)Displacement
;
337 if ((Ext
->Sib
.Base
!= 5) || Ext
->ModRm
.Mod
) {
338 EffectiveAddress
+= *GetRegisterPointer (Regs
, Ext
->Sib
.Base
);
340 UpdateForDisplacement (InstructionData
, 4);
341 EffectiveAddress
+= (UINT64
)(*(INT32
*)(InstructionData
->Displacement
));
344 EffectiveAddress
+= *GetRegisterPointer (Regs
, Ext
->ModRm
.Rm
);
347 return EffectiveAddress
;
353 Examine the instruction parsing context to decode a ModRM byte and the SIB
356 @param[in] Regs x64 processor context
357 @param[in, out] InstructionData Instruction parsing context
363 IN EFI_SYSTEM_CONTEXT_X64
*Regs
,
364 IN OUT SEV_ES_INSTRUCTION_DATA
*InstructionData
367 SEV_ES_INSTRUCTION_OPCODE_EXT
*Ext
;
368 INSTRUCTION_REX_PREFIX
*RexPrefix
;
369 INSTRUCTION_MODRM
*ModRm
;
370 INSTRUCTION_SIB
*Sib
;
372 RexPrefix
= &InstructionData
->RexPrefix
;
373 Ext
= &InstructionData
->Ext
;
374 ModRm
= &InstructionData
->ModRm
;
375 Sib
= &InstructionData
->Sib
;
377 InstructionData
->ModRmPresent
= TRUE
;
378 ModRm
->Uint8
= *(InstructionData
->End
);
380 InstructionData
->Displacement
++;
381 InstructionData
->Immediate
++;
382 InstructionData
->End
++;
384 Ext
->ModRm
.Mod
= ModRm
->Bits
.Mod
;
385 Ext
->ModRm
.Reg
= (RexPrefix
->Bits
.BitR
<< 3) | ModRm
->Bits
.Reg
;
386 Ext
->ModRm
.Rm
= (RexPrefix
->Bits
.BitB
<< 3) | ModRm
->Bits
.Rm
;
388 Ext
->RegData
= *GetRegisterPointer (Regs
, Ext
->ModRm
.Reg
);
390 if (Ext
->ModRm
.Mod
== 3) {
391 Ext
->RmData
= *GetRegisterPointer (Regs
, Ext
->ModRm
.Rm
);
393 if (ModRm
->Bits
.Rm
== 4) {
394 InstructionData
->SibPresent
= TRUE
;
395 Sib
->Uint8
= *(InstructionData
->End
);
397 InstructionData
->Displacement
++;
398 InstructionData
->Immediate
++;
399 InstructionData
->End
++;
401 Ext
->Sib
.Scale
= Sib
->Bits
.Scale
;
402 Ext
->Sib
.Index
= (RexPrefix
->Bits
.BitX
<< 3) | Sib
->Bits
.Index
;
403 Ext
->Sib
.Base
= (RexPrefix
->Bits
.BitB
<< 3) | Sib
->Bits
.Base
;
406 Ext
->RmData
= GetEffectiveMemoryAddress (Regs
, InstructionData
);
411 Decode instruction prefixes.
413 Parse the instruction data to track the instruction prefixes that have
416 @param[in] Regs x64 processor context
417 @param[in, out] InstructionData Instruction parsing context
423 IN EFI_SYSTEM_CONTEXT_X64
*Regs
,
424 IN OUT SEV_ES_INSTRUCTION_DATA
*InstructionData
427 SEV_ES_INSTRUCTION_MODE Mode
;
428 SEV_ES_INSTRUCTION_SIZE ModeDataSize
;
429 SEV_ES_INSTRUCTION_SIZE ModeAddrSize
;
433 // Always in 64-bit mode
435 Mode
= LongMode64Bit
;
436 ModeDataSize
= Size32Bits
;
437 ModeAddrSize
= Size64Bits
;
439 InstructionData
->Mode
= Mode
;
440 InstructionData
->DataSize
= ModeDataSize
;
441 InstructionData
->AddrSize
= ModeAddrSize
;
443 InstructionData
->Prefixes
= InstructionData
->Begin
;
445 Byte
= InstructionData
->Prefixes
;
446 for ( ; ; Byte
++, InstructionData
->PrefixSize
++) {
448 // Check the 0x40 to 0x4F range using an if statement here since some
449 // compilers don't like the "case 0x40 ... 0x4F:" syntax. This avoids
450 // 16 case statements below.
452 if ((*Byte
>= REX_PREFIX_START
) && (*Byte
<= REX_PREFIX_STOP
)) {
453 InstructionData
->RexPrefix
.Uint8
= *Byte
;
454 if ((*Byte
& REX_64BIT_OPERAND_SIZE_MASK
) != 0) {
455 InstructionData
->DataSize
= Size64Bits
;
462 case OVERRIDE_SEGMENT_CS
:
463 case OVERRIDE_SEGMENT_DS
:
464 case OVERRIDE_SEGMENT_ES
:
465 case OVERRIDE_SEGMENT_SS
:
466 if (Mode
!= LongMode64Bit
) {
467 InstructionData
->SegmentSpecified
= TRUE
;
468 InstructionData
->Segment
= (*Byte
>> 3) & 3;
473 case OVERRIDE_SEGMENT_FS
:
474 case OVERRIDE_SEGMENT_GS
:
475 InstructionData
->SegmentSpecified
= TRUE
;
476 InstructionData
->Segment
= *Byte
& 7;
479 case OVERRIDE_OPERAND_SIZE
:
480 if (InstructionData
->RexPrefix
.Uint8
== 0) {
481 InstructionData
->DataSize
=
482 (Mode
== LongMode64Bit
) ? Size16Bits
:
483 (Mode
== LongModeCompat32Bit
) ? Size16Bits
:
484 (Mode
== LongModeCompat16Bit
) ? Size32Bits
: 0;
489 case OVERRIDE_ADDRESS_SIZE
:
490 InstructionData
->AddrSize
=
491 (Mode
== LongMode64Bit
) ? Size32Bits
:
492 (Mode
== LongModeCompat32Bit
) ? Size16Bits
:
493 (Mode
== LongModeCompat16Bit
) ? Size32Bits
: 0;
500 InstructionData
->RepMode
= RepZ
;
504 InstructionData
->RepMode
= RepNZ
;
508 InstructionData
->OpCodes
= Byte
;
509 InstructionData
->OpCodeSize
= (*Byte
== TWO_BYTE_OPCODE_ESCAPE
) ? 2 : 1;
511 InstructionData
->End
= Byte
+ InstructionData
->OpCodeSize
;
512 InstructionData
->Displacement
= InstructionData
->End
;
513 InstructionData
->Immediate
= InstructionData
->End
;
520 Determine instruction length
522 Return the total length of the parsed instruction.
524 @param[in] InstructionData Instruction parsing context
526 @return Length of parsed instruction
532 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
535 return (UINT64
)(InstructionData
->End
- InstructionData
->Begin
);
539 Initialize the instruction parsing context.
541 Initialize the instruction parsing context, which includes decoding the
542 instruction prefixes.
544 @param[in, out] InstructionData Instruction parsing context
545 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication
547 @param[in] Regs x64 processor context
552 InitInstructionData (
553 IN OUT SEV_ES_INSTRUCTION_DATA
*InstructionData
,
555 IN EFI_SYSTEM_CONTEXT_X64
*Regs
558 SetMem (InstructionData
, sizeof (*InstructionData
), 0);
559 InstructionData
->Ghcb
= Ghcb
;
560 InstructionData
->Begin
= (UINT8
*)Regs
->Rip
;
561 InstructionData
->End
= (UINT8
*)Regs
->Rip
;
563 DecodePrefixes (Regs
, InstructionData
);
567 Report an unsupported event to the hypervisor
569 Use the VMGEXIT support to report an unsupported event to the hypervisor.
571 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication
573 @param[in] Regs x64 processor context
574 @param[in] InstructionData Instruction parsing context
576 @return New exception value to propagate
583 IN EFI_SYSTEM_CONTEXT_X64
*Regs
,
584 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
589 Status
= VmgExit (Ghcb
, SVM_EXIT_UNSUPPORTED
, Regs
->ExceptionData
, 0);
591 GHCB_EVENT_INJECTION Event
;
594 Event
.Elements
.Vector
= GP_EXCEPTION
;
595 Event
.Elements
.Type
= GHCB_EVENT_INJECTION_TYPE_EXCEPTION
;
596 Event
.Elements
.Valid
= 1;
598 Status
= Event
.Uint64
;
605 Validate that the MMIO memory access is not to encrypted memory.
607 Examine the pagetable entry for the memory specified. MMIO should not be
608 performed against encrypted memory. MMIO to the APIC page is always allowed.
610 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication Block
611 @param[in] MemoryAddress Memory address to validate
612 @param[in] MemoryLength Memory length to validate
614 @retval 0 Memory is not encrypted
615 @return New exception value to propogate
622 IN UINTN MemoryAddress
,
623 IN UINTN MemoryLength
626 MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State
;
627 GHCB_EVENT_INJECTION GpEvent
;
631 // Allow APIC accesses (which will have the encryption bit set during
632 // SEC and PEI phases).
634 Address
= MemoryAddress
& ~(SIZE_4KB
- 1);
635 if (Address
== GetLocalApicBaseAddress ()) {
639 State
= MemEncryptSevGetAddressRangeState (
644 if (State
== MemEncryptSevAddressRangeUnencrypted
) {
649 // Any state other than unencrypted is an error, issue a #GP.
653 "MMIO using encrypted memory: %lx\n",
654 (UINT64
)MemoryAddress
657 GpEvent
.Elements
.Vector
= GP_EXCEPTION
;
658 GpEvent
.Elements
.Type
= GHCB_EVENT_INJECTION_TYPE_EXCEPTION
;
659 GpEvent
.Elements
.Valid
= 1;
661 return GpEvent
.Uint64
;
665 Handle an MMIO event.
667 Use the VMGEXIT instruction to handle either an MMIO read or an MMIO write.
669 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
671 @param[in, out] Regs x64 processor context
672 @param[in, out] InstructionData Instruction parsing context
674 @retval 0 Event handled successfully
675 @return New exception value to propagate
682 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
683 IN OUT SEV_ES_INSTRUCTION_DATA
*InstructionData
686 UINT64 ExitInfo1
, ExitInfo2
, Status
;
689 UINT8 OpCode
, SignByte
;
694 OpCode
= *(InstructionData
->OpCodes
);
695 if (OpCode
== TWO_BYTE_OPCODE_ESCAPE
) {
696 OpCode
= *(InstructionData
->OpCodes
+ 1);
701 // MMIO write (MOV reg/memX, regX)
709 DecodeModRm (Regs
, InstructionData
);
710 Bytes
= ((Bytes
!= 0) ? Bytes
:
711 (InstructionData
->DataSize
== Size16Bits
) ? 2 :
712 (InstructionData
->DataSize
== Size32Bits
) ? 4 :
713 (InstructionData
->DataSize
== Size64Bits
) ? 8 :
716 if (InstructionData
->Ext
.ModRm
.Mod
== 3) {
718 // NPF on two register operands???
720 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
723 Status
= ValidateMmioMemory (Ghcb
, InstructionData
->Ext
.RmData
, Bytes
);
728 ExitInfo1
= InstructionData
->Ext
.RmData
;
730 CopyMem (Ghcb
->SharedBuffer
, &InstructionData
->Ext
.RegData
, Bytes
);
732 Ghcb
->SaveArea
.SwScratch
= (UINT64
)Ghcb
->SharedBuffer
;
733 VmgSetOffsetValid (Ghcb
, GhcbSwScratch
);
734 Status
= VmgExit (Ghcb
, SVM_EXIT_MMIO_WRITE
, ExitInfo1
, ExitInfo2
);
742 // MMIO write (MOV moffsetX, aX)
750 Bytes
= ((Bytes
!= 0) ? Bytes
:
751 (InstructionData
->DataSize
== Size16Bits
) ? 2 :
752 (InstructionData
->DataSize
== Size32Bits
) ? 4 :
753 (InstructionData
->DataSize
== Size64Bits
) ? 8 :
756 InstructionData
->ImmediateSize
= (UINTN
)(1 << InstructionData
->AddrSize
);
757 InstructionData
->End
+= InstructionData
->ImmediateSize
;
760 // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
761 // Use a STATIC_ASSERT to be certain the code is being built as X64.
764 sizeof (UINTN
) == sizeof (UINT64
),
765 "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
771 InstructionData
->Immediate
,
772 InstructionData
->ImmediateSize
775 Status
= ValidateMmioMemory (Ghcb
, Address
, Bytes
);
782 CopyMem (Ghcb
->SharedBuffer
, &Regs
->Rax
, Bytes
);
784 Ghcb
->SaveArea
.SwScratch
= (UINT64
)Ghcb
->SharedBuffer
;
785 VmgSetOffsetValid (Ghcb
, GhcbSwScratch
);
786 Status
= VmgExit (Ghcb
, SVM_EXIT_MMIO_WRITE
, ExitInfo1
, ExitInfo2
);
794 // MMIO write (MOV reg/memX, immX)
802 DecodeModRm (Regs
, InstructionData
);
803 Bytes
= ((Bytes
!= 0) ? Bytes
:
804 (InstructionData
->DataSize
== Size16Bits
) ? 2 :
805 (InstructionData
->DataSize
== Size32Bits
) ? 4 :
808 InstructionData
->ImmediateSize
= Bytes
;
809 InstructionData
->End
+= Bytes
;
811 Status
= ValidateMmioMemory (Ghcb
, InstructionData
->Ext
.RmData
, Bytes
);
816 ExitInfo1
= InstructionData
->Ext
.RmData
;
818 CopyMem (Ghcb
->SharedBuffer
, InstructionData
->Immediate
, Bytes
);
820 Ghcb
->SaveArea
.SwScratch
= (UINT64
)Ghcb
->SharedBuffer
;
821 VmgSetOffsetValid (Ghcb
, GhcbSwScratch
);
822 Status
= VmgExit (Ghcb
, SVM_EXIT_MMIO_WRITE
, ExitInfo1
, ExitInfo2
);
830 // MMIO read (MOV regX, reg/memX)
838 DecodeModRm (Regs
, InstructionData
);
839 Bytes
= ((Bytes
!= 0) ? Bytes
:
840 (InstructionData
->DataSize
== Size16Bits
) ? 2 :
841 (InstructionData
->DataSize
== Size32Bits
) ? 4 :
842 (InstructionData
->DataSize
== Size64Bits
) ? 8 :
844 if (InstructionData
->Ext
.ModRm
.Mod
== 3) {
846 // NPF on two register operands???
848 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
851 Status
= ValidateMmioMemory (Ghcb
, InstructionData
->Ext
.RmData
, Bytes
);
856 ExitInfo1
= InstructionData
->Ext
.RmData
;
859 Ghcb
->SaveArea
.SwScratch
= (UINT64
)Ghcb
->SharedBuffer
;
860 VmgSetOffsetValid (Ghcb
, GhcbSwScratch
);
861 Status
= VmgExit (Ghcb
, SVM_EXIT_MMIO_READ
, ExitInfo1
, ExitInfo2
);
866 Register
= GetRegisterPointer (Regs
, InstructionData
->Ext
.ModRm
.Reg
);
869 // Zero-extend for 32-bit operation
874 CopyMem (Register
, Ghcb
->SharedBuffer
, Bytes
);
878 // MMIO read (MOV aX, moffsetX)
886 Bytes
= ((Bytes
!= 0) ? Bytes
:
887 (InstructionData
->DataSize
== Size16Bits
) ? 2 :
888 (InstructionData
->DataSize
== Size32Bits
) ? 4 :
889 (InstructionData
->DataSize
== Size64Bits
) ? 8 :
892 InstructionData
->ImmediateSize
= (UINTN
)(1 << InstructionData
->AddrSize
);
893 InstructionData
->End
+= InstructionData
->ImmediateSize
;
896 // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
897 // Use a STATIC_ASSERT to be certain the code is being built as X64.
900 sizeof (UINTN
) == sizeof (UINT64
),
901 "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
907 InstructionData
->Immediate
,
908 InstructionData
->ImmediateSize
911 Status
= ValidateMmioMemory (Ghcb
, Address
, Bytes
);
919 Ghcb
->SaveArea
.SwScratch
= (UINT64
)Ghcb
->SharedBuffer
;
920 VmgSetOffsetValid (Ghcb
, GhcbSwScratch
);
921 Status
= VmgExit (Ghcb
, SVM_EXIT_MMIO_READ
, ExitInfo1
, ExitInfo2
);
928 // Zero-extend for 32-bit operation
933 CopyMem (&Regs
->Rax
, Ghcb
->SharedBuffer
, Bytes
);
937 // MMIO read w/ zero-extension ((MOVZX regX, reg/memX)
945 DecodeModRm (Regs
, InstructionData
);
946 Bytes
= (Bytes
!= 0) ? Bytes
: 2;
948 Status
= ValidateMmioMemory (Ghcb
, InstructionData
->Ext
.RmData
, Bytes
);
953 ExitInfo1
= InstructionData
->Ext
.RmData
;
956 Ghcb
->SaveArea
.SwScratch
= (UINT64
)Ghcb
->SharedBuffer
;
957 VmgSetOffsetValid (Ghcb
, GhcbSwScratch
);
958 Status
= VmgExit (Ghcb
, SVM_EXIT_MMIO_READ
, ExitInfo1
, ExitInfo2
);
963 Register
= GetRegisterPointer (Regs
, InstructionData
->Ext
.ModRm
.Reg
);
964 SetMem (Register
, (UINTN
)(1 << InstructionData
->DataSize
), 0);
965 CopyMem (Register
, Ghcb
->SharedBuffer
, Bytes
);
969 // MMIO read w/ sign-extension (MOVSX regX, reg/memX)
977 DecodeModRm (Regs
, InstructionData
);
978 Bytes
= (Bytes
!= 0) ? Bytes
: 2;
980 Status
= ValidateMmioMemory (Ghcb
, InstructionData
->Ext
.RmData
, Bytes
);
985 ExitInfo1
= InstructionData
->Ext
.RmData
;
988 Ghcb
->SaveArea
.SwScratch
= (UINT64
)Ghcb
->SharedBuffer
;
989 VmgSetOffsetValid (Ghcb
, GhcbSwScratch
);
990 Status
= VmgExit (Ghcb
, SVM_EXIT_MMIO_READ
, ExitInfo1
, ExitInfo2
);
998 Data
= (UINT8
*)Ghcb
->SharedBuffer
;
999 SignByte
= ((*Data
& BIT7
) != 0) ? 0xFF : 0x00;
1003 Data
= (UINT16
*)Ghcb
->SharedBuffer
;
1004 SignByte
= ((*Data
& BIT15
) != 0) ? 0xFF : 0x00;
1007 Register
= GetRegisterPointer (Regs
, InstructionData
->Ext
.ModRm
.Reg
);
1008 SetMem (Register
, (UINTN
)(1 << InstructionData
->DataSize
), SignByte
);
1009 CopyMem (Register
, Ghcb
->SharedBuffer
, Bytes
);
1013 DEBUG ((DEBUG_ERROR
, "Invalid MMIO opcode (%x)\n", OpCode
));
1014 Status
= GP_EXCEPTION
;
1022 Handle a MWAIT event.
1024 Use the VMGEXIT instruction to handle a MWAIT event.
1026 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1028 @param[in, out] Regs x64 processor context
1029 @param[in] InstructionData Instruction parsing context
1031 @retval 0 Event handled successfully
1032 @return New exception value to propagate
1039 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1040 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1043 DecodeModRm (Regs
, InstructionData
);
1045 Ghcb
->SaveArea
.Rax
= Regs
->Rax
;
1046 VmgSetOffsetValid (Ghcb
, GhcbRax
);
1047 Ghcb
->SaveArea
.Rcx
= Regs
->Rcx
;
1048 VmgSetOffsetValid (Ghcb
, GhcbRcx
);
1050 return VmgExit (Ghcb
, SVM_EXIT_MWAIT
, 0, 0);
1054 Handle a MONITOR event.
1056 Use the VMGEXIT instruction to handle a MONITOR event.
1058 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1060 @param[in, out] Regs x64 processor context
1061 @param[in] InstructionData Instruction parsing context
1063 @retval 0 Event handled successfully
1064 @return New exception value to propagate
1071 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1072 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1075 DecodeModRm (Regs
, InstructionData
);
1077 Ghcb
->SaveArea
.Rax
= Regs
->Rax
; // Identity mapped, so VA = PA
1078 VmgSetOffsetValid (Ghcb
, GhcbRax
);
1079 Ghcb
->SaveArea
.Rcx
= Regs
->Rcx
;
1080 VmgSetOffsetValid (Ghcb
, GhcbRcx
);
1081 Ghcb
->SaveArea
.Rdx
= Regs
->Rdx
;
1082 VmgSetOffsetValid (Ghcb
, GhcbRdx
);
1084 return VmgExit (Ghcb
, SVM_EXIT_MONITOR
, 0, 0);
1088 Handle a WBINVD event.
1090 Use the VMGEXIT instruction to handle a WBINVD event.
1092 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1094 @param[in, out] Regs x64 processor context
1095 @param[in] InstructionData Instruction parsing context
1097 @retval 0 Event handled successfully
1098 @return New exception value to propagate
1105 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1106 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1109 return VmgExit (Ghcb
, SVM_EXIT_WBINVD
, 0, 0);
1113 Handle a RDTSCP event.
1115 Use the VMGEXIT instruction to handle a RDTSCP event.
1117 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1119 @param[in, out] Regs x64 processor context
1120 @param[in] InstructionData Instruction parsing context
1122 @retval 0 Event handled successfully
1123 @return New exception value to propagate
1130 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1131 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1136 DecodeModRm (Regs
, InstructionData
);
1138 Status
= VmgExit (Ghcb
, SVM_EXIT_RDTSCP
, 0, 0);
1143 if (!VmgIsOffsetValid (Ghcb
, GhcbRax
) ||
1144 !VmgIsOffsetValid (Ghcb
, GhcbRcx
) ||
1145 !VmgIsOffsetValid (Ghcb
, GhcbRdx
))
1147 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1150 Regs
->Rax
= Ghcb
->SaveArea
.Rax
;
1151 Regs
->Rcx
= Ghcb
->SaveArea
.Rcx
;
1152 Regs
->Rdx
= Ghcb
->SaveArea
.Rdx
;
1158 Handle a VMMCALL event.
1160 Use the VMGEXIT instruction to handle a VMMCALL event.
1162 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1164 @param[in, out] Regs x64 processor context
1165 @param[in] InstructionData Instruction parsing context
1167 @retval 0 Event handled successfully
1168 @return New exception value to propagate
1175 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1176 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1181 DecodeModRm (Regs
, InstructionData
);
1183 Ghcb
->SaveArea
.Rax
= Regs
->Rax
;
1184 VmgSetOffsetValid (Ghcb
, GhcbRax
);
1185 Ghcb
->SaveArea
.Cpl
= (UINT8
)(Regs
->Cs
& 0x3);
1186 VmgSetOffsetValid (Ghcb
, GhcbCpl
);
1188 Status
= VmgExit (Ghcb
, SVM_EXIT_VMMCALL
, 0, 0);
1193 if (!VmgIsOffsetValid (Ghcb
, GhcbRax
)) {
1194 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1197 Regs
->Rax
= Ghcb
->SaveArea
.Rax
;
1203 Handle an MSR event.
1205 Use the VMGEXIT instruction to handle either a RDMSR or WRMSR event.
1207 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1209 @param[in, out] Regs x64 processor context
1210 @param[in] InstructionData Instruction parsing context
1212 @retval 0 Event handled successfully
1213 @return New exception value to propagate
1220 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1221 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1224 UINT64 ExitInfo1
, Status
;
1228 switch (*(InstructionData
->OpCodes
+ 1)) {
1231 Ghcb
->SaveArea
.Rax
= Regs
->Rax
;
1232 VmgSetOffsetValid (Ghcb
, GhcbRax
);
1233 Ghcb
->SaveArea
.Rdx
= Regs
->Rdx
;
1234 VmgSetOffsetValid (Ghcb
, GhcbRdx
);
1239 Ghcb
->SaveArea
.Rcx
= Regs
->Rcx
;
1240 VmgSetOffsetValid (Ghcb
, GhcbRcx
);
1243 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1246 Status
= VmgExit (Ghcb
, SVM_EXIT_MSR
, ExitInfo1
, 0);
1251 if (ExitInfo1
== 0) {
1252 if (!VmgIsOffsetValid (Ghcb
, GhcbRax
) ||
1253 !VmgIsOffsetValid (Ghcb
, GhcbRdx
))
1255 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1258 Regs
->Rax
= Ghcb
->SaveArea
.Rax
;
1259 Regs
->Rdx
= Ghcb
->SaveArea
.Rdx
;
1266 Build the IOIO event information.
1268 The IOIO event information identifies the type of IO operation to be performed
1269 by the hypervisor. Build this information based on the instruction data.
1271 @param[in] Regs x64 processor context
1272 @param[in, out] InstructionData Instruction parsing context
1274 @return IOIO event information value
1280 IN EFI_SYSTEM_CONTEXT_X64
*Regs
,
1281 IN OUT SEV_ES_INSTRUCTION_DATA
*InstructionData
1288 switch (*(InstructionData
->OpCodes
)) {
1294 ExitInfo
|= IOIO_TYPE_INS
;
1295 ExitInfo
|= IOIO_SEG_ES
;
1296 ExitInfo
|= ((Regs
->Rdx
& 0xffff) << 16);
1304 ExitInfo
|= IOIO_TYPE_OUTS
;
1305 ExitInfo
|= IOIO_SEG_DS
;
1306 ExitInfo
|= ((Regs
->Rdx
& 0xffff) << 16);
1310 // IN immediate opcodes
1314 InstructionData
->ImmediateSize
= 1;
1315 InstructionData
->End
++;
1316 ExitInfo
|= IOIO_TYPE_IN
;
1317 ExitInfo
|= ((*(InstructionData
->OpCodes
+ 1)) << 16);
1321 // OUT immediate opcodes
1325 InstructionData
->ImmediateSize
= 1;
1326 InstructionData
->End
++;
1327 ExitInfo
|= IOIO_TYPE_OUT
;
1328 ExitInfo
|= ((*(InstructionData
->OpCodes
+ 1)) << 16) | IOIO_TYPE_OUT
;
1332 // IN register opcodes
1336 ExitInfo
|= IOIO_TYPE_IN
;
1337 ExitInfo
|= ((Regs
->Rdx
& 0xffff) << 16);
1341 // OUT register opcodes
1345 ExitInfo
|= IOIO_TYPE_OUT
;
1346 ExitInfo
|= ((Regs
->Rdx
& 0xffff) << 16);
1353 switch (*(InstructionData
->OpCodes
)) {
1355 // Single-byte opcodes
1363 ExitInfo
|= IOIO_DATA_8
;
1367 // Length determined by instruction parsing
1370 ExitInfo
|= (InstructionData
->DataSize
== Size16Bits
) ? IOIO_DATA_16
1374 switch (InstructionData
->AddrSize
) {
1376 ExitInfo
|= IOIO_ADDR_16
;
1380 ExitInfo
|= IOIO_ADDR_32
;
1384 ExitInfo
|= IOIO_ADDR_64
;
1391 if (InstructionData
->RepMode
!= 0) {
1392 ExitInfo
|= IOIO_REP
;
1399 Handle an IOIO event.
1401 Use the VMGEXIT instruction to handle an IOIO event.
1403 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1405 @param[in, out] Regs x64 processor context
1406 @param[in] InstructionData Instruction parsing context
1408 @retval 0 Event handled successfully
1409 @return New exception value to propagate
1416 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1417 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1420 UINT64 ExitInfo1
, ExitInfo2
, Status
;
1423 ExitInfo1
= IoioExitInfo (Regs
, InstructionData
);
1424 if (ExitInfo1
== 0) {
1425 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1428 IsString
= ((ExitInfo1
& IOIO_TYPE_STR
) != 0) ? TRUE
: FALSE
;
1430 UINTN IoBytes
, VmgExitBytes
;
1431 UINTN GhcbCount
, OpCount
;
1435 IoBytes
= IOIO_DATA_BYTES (ExitInfo1
);
1436 GhcbCount
= sizeof (Ghcb
->SharedBuffer
) / IoBytes
;
1438 OpCount
= ((ExitInfo1
& IOIO_REP
) != 0) ? Regs
->Rcx
: 1;
1439 while (OpCount
!= 0) {
1440 ExitInfo2
= MIN (OpCount
, GhcbCount
);
1441 VmgExitBytes
= ExitInfo2
* IoBytes
;
1443 if ((ExitInfo1
& IOIO_TYPE_IN
) == 0) {
1444 CopyMem (Ghcb
->SharedBuffer
, (VOID
*)Regs
->Rsi
, VmgExitBytes
);
1445 Regs
->Rsi
+= VmgExitBytes
;
1448 Ghcb
->SaveArea
.SwScratch
= (UINT64
)Ghcb
->SharedBuffer
;
1449 VmgSetOffsetValid (Ghcb
, GhcbSwScratch
);
1450 Status
= VmgExit (Ghcb
, SVM_EXIT_IOIO_PROT
, ExitInfo1
, ExitInfo2
);
1455 if ((ExitInfo1
& IOIO_TYPE_IN
) != 0) {
1456 CopyMem ((VOID
*)Regs
->Rdi
, Ghcb
->SharedBuffer
, VmgExitBytes
);
1457 Regs
->Rdi
+= VmgExitBytes
;
1460 if ((ExitInfo1
& IOIO_REP
) != 0) {
1461 Regs
->Rcx
-= ExitInfo2
;
1464 OpCount
-= ExitInfo2
;
1467 if ((ExitInfo1
& IOIO_TYPE_IN
) != 0) {
1468 Ghcb
->SaveArea
.Rax
= 0;
1470 CopyMem (&Ghcb
->SaveArea
.Rax
, &Regs
->Rax
, IOIO_DATA_BYTES (ExitInfo1
));
1473 VmgSetOffsetValid (Ghcb
, GhcbRax
);
1475 Status
= VmgExit (Ghcb
, SVM_EXIT_IOIO_PROT
, ExitInfo1
, 0);
1480 if ((ExitInfo1
& IOIO_TYPE_IN
) != 0) {
1481 if (!VmgIsOffsetValid (Ghcb
, GhcbRax
)) {
1482 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1485 CopyMem (&Regs
->Rax
, &Ghcb
->SaveArea
.Rax
, IOIO_DATA_BYTES (ExitInfo1
));
1493 Handle a INVD event.
1495 Use the VMGEXIT instruction to handle a INVD event.
1497 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1499 @param[in, out] Regs x64 processor context
1500 @param[in] InstructionData Instruction parsing context
1502 @retval 0 Event handled successfully
1503 @return New exception value to propagate
1510 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1511 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1514 return VmgExit (Ghcb
, SVM_EXIT_INVD
, 0, 0);
1518 Handle a CPUID event.
1520 Use the VMGEXIT instruction to handle a CPUID event.
1522 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1524 @param[in, out] Regs x64 processor context
1525 @param[in] InstructionData Instruction parsing context
1527 @retval 0 Event handled successfully
1528 @return New exception value to propagate
1535 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1536 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1541 Ghcb
->SaveArea
.Rax
= Regs
->Rax
;
1542 VmgSetOffsetValid (Ghcb
, GhcbRax
);
1543 Ghcb
->SaveArea
.Rcx
= Regs
->Rcx
;
1544 VmgSetOffsetValid (Ghcb
, GhcbRcx
);
1545 if (Regs
->Rax
== CPUID_EXTENDED_STATE
) {
1548 Cr4
.UintN
= AsmReadCr4 ();
1549 Ghcb
->SaveArea
.XCr0
= (Cr4
.Bits
.OSXSAVE
== 1) ? AsmXGetBv (0) : 1;
1550 VmgSetOffsetValid (Ghcb
, GhcbXCr0
);
1553 Status
= VmgExit (Ghcb
, SVM_EXIT_CPUID
, 0, 0);
1558 if (!VmgIsOffsetValid (Ghcb
, GhcbRax
) ||
1559 !VmgIsOffsetValid (Ghcb
, GhcbRbx
) ||
1560 !VmgIsOffsetValid (Ghcb
, GhcbRcx
) ||
1561 !VmgIsOffsetValid (Ghcb
, GhcbRdx
))
1563 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1566 Regs
->Rax
= Ghcb
->SaveArea
.Rax
;
1567 Regs
->Rbx
= Ghcb
->SaveArea
.Rbx
;
1568 Regs
->Rcx
= Ghcb
->SaveArea
.Rcx
;
1569 Regs
->Rdx
= Ghcb
->SaveArea
.Rdx
;
1575 Handle a RDPMC event.
1577 Use the VMGEXIT instruction to handle a RDPMC event.
1579 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1581 @param[in, out] Regs x64 processor context
1582 @param[in] InstructionData Instruction parsing context
1584 @retval 0 Event handled successfully
1585 @return New exception value to propagate
1592 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1593 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1598 Ghcb
->SaveArea
.Rcx
= Regs
->Rcx
;
1599 VmgSetOffsetValid (Ghcb
, GhcbRcx
);
1601 Status
= VmgExit (Ghcb
, SVM_EXIT_RDPMC
, 0, 0);
1606 if (!VmgIsOffsetValid (Ghcb
, GhcbRax
) ||
1607 !VmgIsOffsetValid (Ghcb
, GhcbRdx
))
1609 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1612 Regs
->Rax
= Ghcb
->SaveArea
.Rax
;
1613 Regs
->Rdx
= Ghcb
->SaveArea
.Rdx
;
1619 Handle a RDTSC event.
1621 Use the VMGEXIT instruction to handle a RDTSC event.
1623 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1625 @param[in, out] Regs x64 processor context
1626 @param[in] InstructionData Instruction parsing context
1628 @retval 0 Event handled successfully
1629 @return New exception value to propagate
1636 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1637 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1642 Status
= VmgExit (Ghcb
, SVM_EXIT_RDTSC
, 0, 0);
1647 if (!VmgIsOffsetValid (Ghcb
, GhcbRax
) ||
1648 !VmgIsOffsetValid (Ghcb
, GhcbRdx
))
1650 return UnsupportedExit (Ghcb
, Regs
, InstructionData
);
1653 Regs
->Rax
= Ghcb
->SaveArea
.Rax
;
1654 Regs
->Rdx
= Ghcb
->SaveArea
.Rdx
;
1660 Handle a DR7 register write event.
1662 Use the VMGEXIT instruction to handle a DR7 write event.
1664 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1666 @param[in, out] Regs x64 processor context
1667 @param[in] InstructionData Instruction parsing context
1669 @retval 0 Event handled successfully
1670 @return New exception value to propagate
1677 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1678 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1681 SEV_ES_INSTRUCTION_OPCODE_EXT
*Ext
;
1682 SEV_ES_PER_CPU_DATA
*SevEsData
;
1686 Ext
= &InstructionData
->Ext
;
1687 SevEsData
= (SEV_ES_PER_CPU_DATA
*)(Ghcb
+ 1);
1689 DecodeModRm (Regs
, InstructionData
);
1692 // MOV DRn always treats MOD == 3 no matter how encoded
1694 Register
= GetRegisterPointer (Regs
, Ext
->ModRm
.Rm
);
1697 // Using a value of 0 for ExitInfo1 means RAX holds the value
1699 Ghcb
->SaveArea
.Rax
= *Register
;
1700 VmgSetOffsetValid (Ghcb
, GhcbRax
);
1702 Status
= VmgExit (Ghcb
, SVM_EXIT_DR7_WRITE
, 0, 0);
1707 SevEsData
->Dr7
= *Register
;
1708 SevEsData
->Dr7Cached
= 1;
1714 Handle a DR7 register read event.
1716 Use the VMGEXIT instruction to handle a DR7 read event.
1718 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1720 @param[in, out] Regs x64 processor context
1721 @param[in] InstructionData Instruction parsing context
1723 @retval 0 Event handled successfully
1730 IN OUT EFI_SYSTEM_CONTEXT_X64
*Regs
,
1731 IN SEV_ES_INSTRUCTION_DATA
*InstructionData
1734 SEV_ES_INSTRUCTION_OPCODE_EXT
*Ext
;
1735 SEV_ES_PER_CPU_DATA
*SevEsData
;
1738 Ext
= &InstructionData
->Ext
;
1739 SevEsData
= (SEV_ES_PER_CPU_DATA
*)(Ghcb
+ 1);
1741 DecodeModRm (Regs
, InstructionData
);
1744 // MOV DRn always treats MOD == 3 no matter how encoded
1746 Register
= GetRegisterPointer (Regs
, Ext
->ModRm
.Rm
);
1749 // If there is a cached valued for DR7, return that. Otherwise return the
1750 // DR7 standard reset value of 0x400 (no debug breakpoints set).
1752 *Register
= (SevEsData
->Dr7Cached
== 1) ? SevEsData
->Dr7
: 0x400;
1758 Handle a #VC exception.
1760 Performs the necessary processing to handle a #VC exception.
1762 @param[in, out] Ghcb Pointer to the GHCB
1763 @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set
1764 as value to use on error.
1765 @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT
1767 @retval EFI_SUCCESS Exception handled
1768 @retval EFI_UNSUPPORTED #VC not supported, (new) exception value to
1770 @retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to
1776 InternalVmgExitHandleVc (
1778 IN OUT EFI_EXCEPTION_TYPE
*ExceptionType
,
1779 IN OUT EFI_SYSTEM_CONTEXT SystemContext
1782 EFI_SYSTEM_CONTEXT_X64
*Regs
;
1784 SEV_ES_INSTRUCTION_DATA InstructionData
;
1785 UINT64 ExitCode
, Status
;
1787 BOOLEAN InterruptState
;
1789 VcRet
= EFI_SUCCESS
;
1791 Regs
= SystemContext
.SystemContextX64
;
1793 VmgInit (Ghcb
, &InterruptState
);
1795 ExitCode
= Regs
->ExceptionData
;
1797 case SVM_EXIT_DR7_READ
:
1798 NaeExit
= Dr7ReadExit
;
1801 case SVM_EXIT_DR7_WRITE
:
1802 NaeExit
= Dr7WriteExit
;
1805 case SVM_EXIT_RDTSC
:
1806 NaeExit
= RdtscExit
;
1809 case SVM_EXIT_RDPMC
:
1810 NaeExit
= RdpmcExit
;
1813 case SVM_EXIT_CPUID
:
1814 NaeExit
= CpuidExit
;
1821 case SVM_EXIT_IOIO_PROT
:
1829 case SVM_EXIT_VMMCALL
:
1830 NaeExit
= VmmCallExit
;
1833 case SVM_EXIT_RDTSCP
:
1834 NaeExit
= RdtscpExit
;
1837 case SVM_EXIT_WBINVD
:
1838 NaeExit
= WbinvdExit
;
1841 case SVM_EXIT_MONITOR
:
1842 NaeExit
= MonitorExit
;
1845 case SVM_EXIT_MWAIT
:
1846 NaeExit
= MwaitExit
;
1854 NaeExit
= UnsupportedExit
;
1857 InitInstructionData (&InstructionData
, Ghcb
, Regs
);
1859 Status
= NaeExit (Ghcb
, Regs
, &InstructionData
);
1861 Regs
->Rip
+= InstructionLength (&InstructionData
);
1863 GHCB_EVENT_INJECTION Event
;
1865 Event
.Uint64
= Status
;
1866 if (Event
.Elements
.ErrorCodeValid
!= 0) {
1867 Regs
->ExceptionData
= Event
.Elements
.ErrorCode
;
1869 Regs
->ExceptionData
= 0;
1872 *ExceptionType
= Event
.Elements
.Vector
;
1874 VcRet
= EFI_PROTOCOL_ERROR
;
1877 VmgDone (Ghcb
, InterruptState
);
1883 Routine to allow ASSERT from within #VC.
1885 @param[in, out] SevEsData Pointer to the per-CPU data
1890 VmgExitIssueAssert (
1891 IN OUT SEV_ES_PER_CPU_DATA
*SevEsData
1895 // Progress will be halted, so set VcCount to allow for ASSERT output
1898 SevEsData
->VcCount
= 0;