]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
OvmfPkg/VmgExitLib: Add support for VMMCALL NAE events
[mirror_edk2.git] / OvmfPkg / Library / VmgExitLib / VmgExitVcHandler.c
1 /** @file
2 X64 #VC Exception Handler functon.
3
4 Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <Base.h>
10 #include <Uefi.h>
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/VmgExitLib.h>
13 #include <Register/Amd/Msr.h>
14 #include <Register/Intel/Cpuid.h>
15 #include <IndustryStandard/InstructionParsing.h>
16
17 //
18 // Instruction execution mode definition
19 //
20 typedef enum {
21 LongMode64Bit = 0,
22 LongModeCompat32Bit,
23 LongModeCompat16Bit,
24 } SEV_ES_INSTRUCTION_MODE;
25
26 //
27 // Instruction size definition (for operand and address)
28 //
29 typedef enum {
30 Size8Bits = 0,
31 Size16Bits,
32 Size32Bits,
33 Size64Bits,
34 } SEV_ES_INSTRUCTION_SIZE;
35
36 //
37 // Intruction segment definition
38 //
39 typedef enum {
40 SegmentEs = 0,
41 SegmentCs,
42 SegmentSs,
43 SegmentDs,
44 SegmentFs,
45 SegmentGs,
46 } SEV_ES_INSTRUCTION_SEGMENT;
47
48 //
49 // Instruction rep function definition
50 //
51 typedef enum {
52 RepNone = 0,
53 RepZ,
54 RepNZ,
55 } SEV_ES_INSTRUCTION_REP;
56
57 typedef struct {
58 UINT8 Rm;
59 UINT8 Reg;
60 UINT8 Mod;
61 } SEV_ES_INSTRUCTION_MODRM_EXT;
62
63 typedef struct {
64 UINT8 Base;
65 UINT8 Index;
66 UINT8 Scale;
67 } SEV_ES_INSTRUCTION_SIB_EXT;
68
69 //
70 // Instruction opcode definition
71 //
72 typedef struct {
73 SEV_ES_INSTRUCTION_MODRM_EXT ModRm;
74
75 SEV_ES_INSTRUCTION_SIB_EXT Sib;
76
77 UINTN RegData;
78 UINTN RmData;
79 } SEV_ES_INSTRUCTION_OPCODE_EXT;
80
81 //
82 // Instruction parsing context definition
83 //
84 typedef struct {
85 GHCB *Ghcb;
86
87 SEV_ES_INSTRUCTION_MODE Mode;
88 SEV_ES_INSTRUCTION_SIZE DataSize;
89 SEV_ES_INSTRUCTION_SIZE AddrSize;
90 BOOLEAN SegmentSpecified;
91 SEV_ES_INSTRUCTION_SEGMENT Segment;
92 SEV_ES_INSTRUCTION_REP RepMode;
93
94 UINT8 *Begin;
95 UINT8 *End;
96
97 UINT8 *Prefixes;
98 UINT8 *OpCodes;
99 UINT8 *Displacement;
100 UINT8 *Immediate;
101
102 INSTRUCTION_REX_PREFIX RexPrefix;
103
104 BOOLEAN ModRmPresent;
105 INSTRUCTION_MODRM ModRm;
106
107 BOOLEAN SibPresent;
108 INSTRUCTION_SIB Sib;
109
110 UINTN PrefixSize;
111 UINTN OpCodeSize;
112 UINTN DisplacementSize;
113 UINTN ImmediateSize;
114
115 SEV_ES_INSTRUCTION_OPCODE_EXT Ext;
116 } SEV_ES_INSTRUCTION_DATA;
117
118 //
119 // Non-automatic Exit function prototype
120 //
121 typedef
122 UINT64
123 (*NAE_EXIT) (
124 GHCB *Ghcb,
125 EFI_SYSTEM_CONTEXT_X64 *Regs,
126 SEV_ES_INSTRUCTION_DATA *InstructionData
127 );
128
129
130 /**
131 Checks the GHCB to determine if the specified register has been marked valid.
132
133 The ValidBitmap area represents the areas of the GHCB that have been marked
134 valid. Return an indication of whether the area of the GHCB that holds the
135 specified register has been marked valid.
136
137 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication Block
138 @param[in] Reg Offset in the GHCB of the register to check
139
140 @retval TRUE Register has been marked vald in the GHCB
141 @retval FALSE Register has not been marked valid in the GHCB
142
143 **/
144 STATIC
145 BOOLEAN
146 GhcbIsRegValid (
147 IN GHCB *Ghcb,
148 IN GHCB_REGISTER Reg
149 )
150 {
151 UINT32 RegIndex;
152 UINT32 RegBit;
153
154 RegIndex = Reg / 8;
155 RegBit = Reg & 0x07;
156
157 return ((Ghcb->SaveArea.ValidBitmap[RegIndex] & (1 << RegBit)) != 0);
158 }
159
160 /**
161 Marks a register as valid in the GHCB.
162
163 The ValidBitmap area represents the areas of the GHCB that have been marked
164 valid. Set the area of the GHCB that holds the specified register as valid.
165
166 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication Block
167 @param[in] Reg Offset in the GHCB of the register to mark valid
168
169 **/
170 STATIC
171 VOID
172 GhcbSetRegValid (
173 IN OUT GHCB *Ghcb,
174 IN GHCB_REGISTER Reg
175 )
176 {
177 UINT32 RegIndex;
178 UINT32 RegBit;
179
180 RegIndex = Reg / 8;
181 RegBit = Reg & 0x07;
182
183 Ghcb->SaveArea.ValidBitmap[RegIndex] |= (1 << RegBit);
184 }
185
186 /**
187 Return a pointer to the contents of the specified register.
188
189 Based upon the input register, return a pointer to the registers contents
190 in the x86 processor context.
191
192 @param[in] Regs x64 processor context
193 @param[in] Register Register to obtain pointer for
194
195 @return Pointer to the contents of the requested register
196
197 **/
198 STATIC
199 UINT64 *
200 GetRegisterPointer (
201 IN EFI_SYSTEM_CONTEXT_X64 *Regs,
202 IN UINT8 Register
203 )
204 {
205 UINT64 *Reg;
206
207 switch (Register) {
208 case 0:
209 Reg = &Regs->Rax;
210 break;
211 case 1:
212 Reg = &Regs->Rcx;
213 break;
214 case 2:
215 Reg = &Regs->Rdx;
216 break;
217 case 3:
218 Reg = &Regs->Rbx;
219 break;
220 case 4:
221 Reg = &Regs->Rsp;
222 break;
223 case 5:
224 Reg = &Regs->Rbp;
225 break;
226 case 6:
227 Reg = &Regs->Rsi;
228 break;
229 case 7:
230 Reg = &Regs->Rdi;
231 break;
232 case 8:
233 Reg = &Regs->R8;
234 break;
235 case 9:
236 Reg = &Regs->R9;
237 break;
238 case 10:
239 Reg = &Regs->R10;
240 break;
241 case 11:
242 Reg = &Regs->R11;
243 break;
244 case 12:
245 Reg = &Regs->R12;
246 break;
247 case 13:
248 Reg = &Regs->R13;
249 break;
250 case 14:
251 Reg = &Regs->R14;
252 break;
253 case 15:
254 Reg = &Regs->R15;
255 break;
256 default:
257 Reg = NULL;
258 }
259 ASSERT (Reg != NULL);
260
261 return Reg;
262 }
263
264 /**
265 Update the instruction parsing context for displacement bytes.
266
267 @param[in, out] InstructionData Instruction parsing context
268 @param[in] Size The instruction displacement size
269
270 **/
271 STATIC
272 VOID
273 UpdateForDisplacement (
274 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,
275 IN UINTN Size
276 )
277 {
278 InstructionData->DisplacementSize = Size;
279 InstructionData->Immediate += Size;
280 InstructionData->End += Size;
281 }
282
283 /**
284 Determine if an instruction address if RIP relative.
285
286 Examine the instruction parsing context to determine if the address offset
287 is relative to the instruction pointer.
288
289 @param[in] InstructionData Instruction parsing context
290
291 @retval TRUE Instruction addressing is RIP relative
292 @retval FALSE Instruction addressing is not RIP relative
293
294 **/
295 STATIC
296 BOOLEAN
297 IsRipRelative (
298 IN SEV_ES_INSTRUCTION_DATA *InstructionData
299 )
300 {
301 SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;
302
303 Ext = &InstructionData->Ext;
304
305 return ((InstructionData->Mode == LongMode64Bit) &&
306 (Ext->ModRm.Mod == 0) &&
307 (Ext->ModRm.Rm == 5) &&
308 (InstructionData->SibPresent == FALSE));
309 }
310
311 /**
312 Return the effective address of a memory operand.
313
314 Examine the instruction parsing context to obtain the effective memory
315 address of a memory operand.
316
317 @param[in] Regs x64 processor context
318 @param[in] InstructionData Instruction parsing context
319
320 @return The memory operand effective address
321
322 **/
323 STATIC
324 UINT64
325 GetEffectiveMemoryAddress (
326 IN EFI_SYSTEM_CONTEXT_X64 *Regs,
327 IN SEV_ES_INSTRUCTION_DATA *InstructionData
328 )
329 {
330 SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;
331 UINT64 EffectiveAddress;
332
333 Ext = &InstructionData->Ext;
334 EffectiveAddress = 0;
335
336 if (IsRipRelative (InstructionData)) {
337 //
338 // RIP-relative displacement is a 32-bit signed value
339 //
340 INT32 RipRelative;
341
342 RipRelative = *(INT32 *) InstructionData->Displacement;
343
344 UpdateForDisplacement (InstructionData, 4);
345
346 //
347 // Negative displacement is handled by standard UINT64 wrap-around.
348 //
349 return Regs->Rip + (UINT64) RipRelative;
350 }
351
352 switch (Ext->ModRm.Mod) {
353 case 1:
354 UpdateForDisplacement (InstructionData, 1);
355 EffectiveAddress += (UINT64) (*(INT8 *) (InstructionData->Displacement));
356 break;
357 case 2:
358 switch (InstructionData->AddrSize) {
359 case Size16Bits:
360 UpdateForDisplacement (InstructionData, 2);
361 EffectiveAddress += (UINT64) (*(INT16 *) (InstructionData->Displacement));
362 break;
363 default:
364 UpdateForDisplacement (InstructionData, 4);
365 EffectiveAddress += (UINT64) (*(INT32 *) (InstructionData->Displacement));
366 break;
367 }
368 break;
369 }
370
371 if (InstructionData->SibPresent) {
372 INT64 Displacement;
373
374 if (Ext->Sib.Index != 4) {
375 CopyMem (
376 &Displacement,
377 GetRegisterPointer (Regs, Ext->Sib.Index),
378 sizeof (Displacement)
379 );
380 Displacement *= (INT64)(1 << Ext->Sib.Scale);
381
382 //
383 // Negative displacement is handled by standard UINT64 wrap-around.
384 //
385 EffectiveAddress += (UINT64) Displacement;
386 }
387
388 if ((Ext->Sib.Base != 5) || Ext->ModRm.Mod) {
389 EffectiveAddress += *GetRegisterPointer (Regs, Ext->Sib.Base);
390 } else {
391 UpdateForDisplacement (InstructionData, 4);
392 EffectiveAddress += (UINT64) (*(INT32 *) (InstructionData->Displacement));
393 }
394 } else {
395 EffectiveAddress += *GetRegisterPointer (Regs, Ext->ModRm.Rm);
396 }
397
398 return EffectiveAddress;
399 }
400
401 /**
402 Decode a ModRM byte.
403
404 Examine the instruction parsing context to decode a ModRM byte and the SIB
405 byte, if present.
406
407 @param[in] Regs x64 processor context
408 @param[in, out] InstructionData Instruction parsing context
409
410 **/
411 STATIC
412 VOID
413 DecodeModRm (
414 IN EFI_SYSTEM_CONTEXT_X64 *Regs,
415 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData
416 )
417 {
418 SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;
419 INSTRUCTION_REX_PREFIX *RexPrefix;
420 INSTRUCTION_MODRM *ModRm;
421 INSTRUCTION_SIB *Sib;
422
423 RexPrefix = &InstructionData->RexPrefix;
424 Ext = &InstructionData->Ext;
425 ModRm = &InstructionData->ModRm;
426 Sib = &InstructionData->Sib;
427
428 InstructionData->ModRmPresent = TRUE;
429 ModRm->Uint8 = *(InstructionData->End);
430
431 InstructionData->Displacement++;
432 InstructionData->Immediate++;
433 InstructionData->End++;
434
435 Ext->ModRm.Mod = ModRm->Bits.Mod;
436 Ext->ModRm.Reg = (RexPrefix->Bits.BitR << 3) | ModRm->Bits.Reg;
437 Ext->ModRm.Rm = (RexPrefix->Bits.BitB << 3) | ModRm->Bits.Rm;
438
439 Ext->RegData = *GetRegisterPointer (Regs, Ext->ModRm.Reg);
440
441 if (Ext->ModRm.Mod == 3) {
442 Ext->RmData = *GetRegisterPointer (Regs, Ext->ModRm.Rm);
443 } else {
444 if (ModRm->Bits.Rm == 4) {
445 InstructionData->SibPresent = TRUE;
446 Sib->Uint8 = *(InstructionData->End);
447
448 InstructionData->Displacement++;
449 InstructionData->Immediate++;
450 InstructionData->End++;
451
452 Ext->Sib.Scale = Sib->Bits.Scale;
453 Ext->Sib.Index = (RexPrefix->Bits.BitX << 3) | Sib->Bits.Index;
454 Ext->Sib.Base = (RexPrefix->Bits.BitB << 3) | Sib->Bits.Base;
455 }
456
457 Ext->RmData = GetEffectiveMemoryAddress (Regs, InstructionData);
458 }
459 }
460
461 /**
462 Decode instruction prefixes.
463
464 Parse the instruction data to track the instruction prefixes that have
465 been used.
466
467 @param[in] Regs x64 processor context
468 @param[in, out] InstructionData Instruction parsing context
469
470 **/
471 STATIC
472 VOID
473 DecodePrefixes (
474 IN EFI_SYSTEM_CONTEXT_X64 *Regs,
475 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData
476 )
477 {
478 SEV_ES_INSTRUCTION_MODE Mode;
479 SEV_ES_INSTRUCTION_SIZE ModeDataSize;
480 SEV_ES_INSTRUCTION_SIZE ModeAddrSize;
481 UINT8 *Byte;
482
483 //
484 // Always in 64-bit mode
485 //
486 Mode = LongMode64Bit;
487 ModeDataSize = Size32Bits;
488 ModeAddrSize = Size64Bits;
489
490 InstructionData->Mode = Mode;
491 InstructionData->DataSize = ModeDataSize;
492 InstructionData->AddrSize = ModeAddrSize;
493
494 InstructionData->Prefixes = InstructionData->Begin;
495
496 Byte = InstructionData->Prefixes;
497 for ( ; ; Byte++, InstructionData->PrefixSize++) {
498 //
499 // Check the 0x40 to 0x4F range using an if statement here since some
500 // compilers don't like the "case 0x40 ... 0x4F:" syntax. This avoids
501 // 16 case statements below.
502 //
503 if ((*Byte >= REX_PREFIX_START) && (*Byte <= REX_PREFIX_STOP)) {
504 InstructionData->RexPrefix.Uint8 = *Byte;
505 if ((*Byte & REX_64BIT_OPERAND_SIZE_MASK) != 0) {
506 InstructionData->DataSize = Size64Bits;
507 }
508 continue;
509 }
510
511 switch (*Byte) {
512 case OVERRIDE_SEGMENT_CS:
513 case OVERRIDE_SEGMENT_DS:
514 case OVERRIDE_SEGMENT_ES:
515 case OVERRIDE_SEGMENT_SS:
516 if (Mode != LongMode64Bit) {
517 InstructionData->SegmentSpecified = TRUE;
518 InstructionData->Segment = (*Byte >> 3) & 3;
519 }
520 break;
521
522 case OVERRIDE_SEGMENT_FS:
523 case OVERRIDE_SEGMENT_GS:
524 InstructionData->SegmentSpecified = TRUE;
525 InstructionData->Segment = *Byte & 7;
526 break;
527
528 case OVERRIDE_OPERAND_SIZE:
529 if (InstructionData->RexPrefix.Uint8 == 0) {
530 InstructionData->DataSize =
531 (Mode == LongMode64Bit) ? Size16Bits :
532 (Mode == LongModeCompat32Bit) ? Size16Bits :
533 (Mode == LongModeCompat16Bit) ? Size32Bits : 0;
534 }
535 break;
536
537 case OVERRIDE_ADDRESS_SIZE:
538 InstructionData->AddrSize =
539 (Mode == LongMode64Bit) ? Size32Bits :
540 (Mode == LongModeCompat32Bit) ? Size16Bits :
541 (Mode == LongModeCompat16Bit) ? Size32Bits : 0;
542 break;
543
544 case LOCK_PREFIX:
545 break;
546
547 case REPZ_PREFIX:
548 InstructionData->RepMode = RepZ;
549 break;
550
551 case REPNZ_PREFIX:
552 InstructionData->RepMode = RepNZ;
553 break;
554
555 default:
556 InstructionData->OpCodes = Byte;
557 InstructionData->OpCodeSize = (*Byte == TWO_BYTE_OPCODE_ESCAPE) ? 2 : 1;
558
559 InstructionData->End = Byte + InstructionData->OpCodeSize;
560 InstructionData->Displacement = InstructionData->End;
561 InstructionData->Immediate = InstructionData->End;
562 return;
563 }
564 }
565 }
566
567 /**
568 Determine instruction length
569
570 Return the total length of the parsed instruction.
571
572 @param[in] InstructionData Instruction parsing context
573
574 @return Length of parsed instruction
575
576 **/
577 STATIC
578 UINT64
579 InstructionLength (
580 IN SEV_ES_INSTRUCTION_DATA *InstructionData
581 )
582 {
583 return (UINT64) (InstructionData->End - InstructionData->Begin);
584 }
585
586 /**
587 Initialize the instruction parsing context.
588
589 Initialize the instruction parsing context, which includes decoding the
590 instruction prefixes.
591
592 @param[in, out] InstructionData Instruction parsing context
593 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication
594 Block
595 @param[in] Regs x64 processor context
596
597 **/
598 STATIC
599 VOID
600 InitInstructionData (
601 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,
602 IN GHCB *Ghcb,
603 IN EFI_SYSTEM_CONTEXT_X64 *Regs
604 )
605 {
606 SetMem (InstructionData, sizeof (*InstructionData), 0);
607 InstructionData->Ghcb = Ghcb;
608 InstructionData->Begin = (UINT8 *) Regs->Rip;
609 InstructionData->End = (UINT8 *) Regs->Rip;
610
611 DecodePrefixes (Regs, InstructionData);
612 }
613
614 /**
615 Report an unsupported event to the hypervisor
616
617 Use the VMGEXIT support to report an unsupported event to the hypervisor.
618
619 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication
620 Block
621 @param[in] Regs x64 processor context
622 @param[in] InstructionData Instruction parsing context
623
624 @return New exception value to propagate
625
626 **/
627 STATIC
628 UINT64
629 UnsupportedExit (
630 IN GHCB *Ghcb,
631 IN EFI_SYSTEM_CONTEXT_X64 *Regs,
632 IN SEV_ES_INSTRUCTION_DATA *InstructionData
633 )
634 {
635 UINT64 Status;
636
637 Status = VmgExit (Ghcb, SVM_EXIT_UNSUPPORTED, Regs->ExceptionData, 0);
638 if (Status == 0) {
639 GHCB_EVENT_INJECTION Event;
640
641 Event.Uint64 = 0;
642 Event.Elements.Vector = GP_EXCEPTION;
643 Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;
644 Event.Elements.Valid = 1;
645
646 Status = Event.Uint64;
647 }
648
649 return Status;
650 }
651
652 /**
653 Handle an MMIO event.
654
655 Use the VMGEXIT instruction to handle either an MMIO read or an MMIO write.
656
657 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
658 Block
659 @param[in, out] Regs x64 processor context
660 @param[in, out] InstructionData Instruction parsing context
661
662 @retval 0 Event handled successfully
663 @return New exception value to propagate
664
665 **/
666 STATIC
667 UINT64
668 MmioExit (
669 IN OUT GHCB *Ghcb,
670 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
671 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData
672 )
673 {
674 UINT64 ExitInfo1, ExitInfo2, Status;
675 UINTN Bytes;
676 UINT64 *Register;
677 UINT8 OpCode, SignByte;
678
679 Bytes = 0;
680
681 OpCode = *(InstructionData->OpCodes);
682 if (OpCode == TWO_BYTE_OPCODE_ESCAPE) {
683 OpCode = *(InstructionData->OpCodes + 1);
684 }
685
686 switch (OpCode) {
687 //
688 // MMIO write (MOV reg/memX, regX)
689 //
690 case 0x88:
691 Bytes = 1;
692 //
693 // fall through
694 //
695 case 0x89:
696 DecodeModRm (Regs, InstructionData);
697 Bytes = ((Bytes != 0) ? Bytes :
698 (InstructionData->DataSize == Size16Bits) ? 2 :
699 (InstructionData->DataSize == Size32Bits) ? 4 :
700 (InstructionData->DataSize == Size64Bits) ? 8 :
701 0);
702
703 if (InstructionData->Ext.ModRm.Mod == 3) {
704 //
705 // NPF on two register operands???
706 //
707 return UnsupportedExit (Ghcb, Regs, InstructionData);
708 }
709
710 ExitInfo1 = InstructionData->Ext.RmData;
711 ExitInfo2 = Bytes;
712 CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes);
713
714 Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
715 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
716 if (Status != 0) {
717 return Status;
718 }
719 break;
720
721 //
722 // MMIO write (MOV reg/memX, immX)
723 //
724 case 0xC6:
725 Bytes = 1;
726 //
727 // fall through
728 //
729 case 0xC7:
730 DecodeModRm (Regs, InstructionData);
731 Bytes = ((Bytes != 0) ? Bytes :
732 (InstructionData->DataSize == Size16Bits) ? 2 :
733 (InstructionData->DataSize == Size32Bits) ? 4 :
734 0);
735
736 InstructionData->ImmediateSize = Bytes;
737 InstructionData->End += Bytes;
738
739 ExitInfo1 = InstructionData->Ext.RmData;
740 ExitInfo2 = Bytes;
741 CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, Bytes);
742
743 Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
744 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
745 if (Status != 0) {
746 return Status;
747 }
748 break;
749
750 //
751 // MMIO read (MOV regX, reg/memX)
752 //
753 case 0x8A:
754 Bytes = 1;
755 //
756 // fall through
757 //
758 case 0x8B:
759 DecodeModRm (Regs, InstructionData);
760 Bytes = ((Bytes != 0) ? Bytes :
761 (InstructionData->DataSize == Size16Bits) ? 2 :
762 (InstructionData->DataSize == Size32Bits) ? 4 :
763 (InstructionData->DataSize == Size64Bits) ? 8 :
764 0);
765 if (InstructionData->Ext.ModRm.Mod == 3) {
766 //
767 // NPF on two register operands???
768 //
769 return UnsupportedExit (Ghcb, Regs, InstructionData);
770 }
771
772 ExitInfo1 = InstructionData->Ext.RmData;
773 ExitInfo2 = Bytes;
774
775 Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
776 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
777 if (Status != 0) {
778 return Status;
779 }
780
781 Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
782 if (Bytes == 4) {
783 //
784 // Zero-extend for 32-bit operation
785 //
786 *Register = 0;
787 }
788 CopyMem (Register, Ghcb->SharedBuffer, Bytes);
789 break;
790
791 //
792 // MMIO read w/ zero-extension ((MOVZX regX, reg/memX)
793 //
794 case 0xB6:
795 Bytes = 1;
796 //
797 // fall through
798 //
799 case 0xB7:
800 Bytes = (Bytes != 0) ? Bytes : 2;
801
802 ExitInfo1 = InstructionData->Ext.RmData;
803 ExitInfo2 = Bytes;
804
805 Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
806 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
807 if (Status != 0) {
808 return Status;
809 }
810
811 Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
812 SetMem (Register, InstructionData->DataSize, 0);
813 CopyMem (Register, Ghcb->SharedBuffer, Bytes);
814 break;
815
816 //
817 // MMIO read w/ sign-extension (MOVSX regX, reg/memX)
818 //
819 case 0xBE:
820 Bytes = 1;
821 //
822 // fall through
823 //
824 case 0xBF:
825 Bytes = (Bytes != 0) ? Bytes : 2;
826
827 ExitInfo1 = InstructionData->Ext.RmData;
828 ExitInfo2 = Bytes;
829
830 Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
831 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
832 if (Status != 0) {
833 return Status;
834 }
835
836 if (Bytes == 1) {
837 UINT8 *Data;
838
839 Data = (UINT8 *) Ghcb->SharedBuffer;
840 SignByte = ((*Data & BIT7) != 0) ? 0xFF : 0x00;
841 } else {
842 UINT16 *Data;
843
844 Data = (UINT16 *) Ghcb->SharedBuffer;
845 SignByte = ((*Data & BIT15) != 0) ? 0xFF : 0x00;
846 }
847
848 Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
849 SetMem (Register, InstructionData->DataSize, SignByte);
850 CopyMem (Register, Ghcb->SharedBuffer, Bytes);
851 break;
852
853 default:
854 Status = GP_EXCEPTION;
855 ASSERT (FALSE);
856 }
857
858 return Status;
859 }
860
861 /**
862 Handle a WBINVD event.
863
864 Use the VMGEXIT instruction to handle a WBINVD event.
865
866 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
867 Block
868 @param[in, out] Regs x64 processor context
869 @param[in] InstructionData Instruction parsing context
870
871 @retval 0 Event handled successfully
872 @return New exception value to propagate
873
874 **/
875 STATIC
876 UINT64
877 WbinvdExit (
878 IN OUT GHCB *Ghcb,
879 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
880 IN SEV_ES_INSTRUCTION_DATA *InstructionData
881 )
882 {
883 return VmgExit (Ghcb, SVM_EXIT_WBINVD, 0, 0);
884 }
885
886 /**
887 Handle a VMMCALL event.
888
889 Use the VMGEXIT instruction to handle a VMMCALL event.
890
891 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
892 Block
893 @param[in, out] Regs x64 processor context
894 @param[in] InstructionData Instruction parsing context
895
896 @retval 0 Event handled successfully
897 @return New exception value to propagate
898
899 **/
900 STATIC
901 UINT64
902 VmmCallExit (
903 IN OUT GHCB *Ghcb,
904 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
905 IN SEV_ES_INSTRUCTION_DATA *InstructionData
906 )
907 {
908 UINT64 Status;
909
910 DecodeModRm (Regs, InstructionData);
911
912 Ghcb->SaveArea.Rax = Regs->Rax;
913 GhcbSetRegValid (Ghcb, GhcbRax);
914 Ghcb->SaveArea.Cpl = (UINT8) (Regs->Cs & 0x3);
915 GhcbSetRegValid (Ghcb, GhcbCpl);
916
917 Status = VmgExit (Ghcb, SVM_EXIT_VMMCALL, 0, 0);
918 if (Status != 0) {
919 return Status;
920 }
921
922 if (!GhcbIsRegValid (Ghcb, GhcbRax)) {
923 return UnsupportedExit (Ghcb, Regs, InstructionData);
924 }
925 Regs->Rax = Ghcb->SaveArea.Rax;
926
927 return 0;
928 }
929
930 /**
931 Handle an MSR event.
932
933 Use the VMGEXIT instruction to handle either a RDMSR or WRMSR event.
934
935 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
936 Block
937 @param[in, out] Regs x64 processor context
938 @param[in] InstructionData Instruction parsing context
939
940 @retval 0 Event handled successfully
941 @return New exception value to propagate
942
943 **/
944 STATIC
945 UINT64
946 MsrExit (
947 IN OUT GHCB *Ghcb,
948 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
949 IN SEV_ES_INSTRUCTION_DATA *InstructionData
950 )
951 {
952 UINT64 ExitInfo1, Status;
953
954 ExitInfo1 = 0;
955
956 switch (*(InstructionData->OpCodes + 1)) {
957 case 0x30: // WRMSR
958 ExitInfo1 = 1;
959 Ghcb->SaveArea.Rax = Regs->Rax;
960 GhcbSetRegValid (Ghcb, GhcbRax);
961 Ghcb->SaveArea.Rdx = Regs->Rdx;
962 GhcbSetRegValid (Ghcb, GhcbRdx);
963 //
964 // fall through
965 //
966 case 0x32: // RDMSR
967 Ghcb->SaveArea.Rcx = Regs->Rcx;
968 GhcbSetRegValid (Ghcb, GhcbRcx);
969 break;
970 default:
971 return UnsupportedExit (Ghcb, Regs, InstructionData);
972 }
973
974 Status = VmgExit (Ghcb, SVM_EXIT_MSR, ExitInfo1, 0);
975 if (Status != 0) {
976 return Status;
977 }
978
979 if (ExitInfo1 == 0) {
980 if (!GhcbIsRegValid (Ghcb, GhcbRax) ||
981 !GhcbIsRegValid (Ghcb, GhcbRdx)) {
982 return UnsupportedExit (Ghcb, Regs, InstructionData);
983 }
984 Regs->Rax = Ghcb->SaveArea.Rax;
985 Regs->Rdx = Ghcb->SaveArea.Rdx;
986 }
987
988 return 0;
989 }
990
991 /**
992 Build the IOIO event information.
993
994 The IOIO event information identifies the type of IO operation to be performed
995 by the hypervisor. Build this information based on the instruction data.
996
997 @param[in] Regs x64 processor context
998 @param[in, out] InstructionData Instruction parsing context
999
1000 @return IOIO event information value
1001
1002 **/
1003 STATIC
1004 UINT64
1005 IoioExitInfo (
1006 IN EFI_SYSTEM_CONTEXT_X64 *Regs,
1007 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData
1008 )
1009 {
1010 UINT64 ExitInfo;
1011
1012 ExitInfo = 0;
1013
1014 switch (*(InstructionData->OpCodes)) {
1015 //
1016 // INS opcodes
1017 //
1018 case 0x6C:
1019 case 0x6D:
1020 ExitInfo |= IOIO_TYPE_INS;
1021 ExitInfo |= IOIO_SEG_ES;
1022 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
1023 break;
1024
1025 //
1026 // OUTS opcodes
1027 //
1028 case 0x6E:
1029 case 0x6F:
1030 ExitInfo |= IOIO_TYPE_OUTS;
1031 ExitInfo |= IOIO_SEG_DS;
1032 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
1033 break;
1034
1035 //
1036 // IN immediate opcodes
1037 //
1038 case 0xE4:
1039 case 0xE5:
1040 InstructionData->ImmediateSize = 1;
1041 InstructionData->End++;
1042 ExitInfo |= IOIO_TYPE_IN;
1043 ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16);
1044 break;
1045
1046 //
1047 // OUT immediate opcodes
1048 //
1049 case 0xE6:
1050 case 0xE7:
1051 InstructionData->ImmediateSize = 1;
1052 InstructionData->End++;
1053 ExitInfo |= IOIO_TYPE_OUT;
1054 ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT;
1055 break;
1056
1057 //
1058 // IN register opcodes
1059 //
1060 case 0xEC:
1061 case 0xED:
1062 ExitInfo |= IOIO_TYPE_IN;
1063 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
1064 break;
1065
1066 //
1067 // OUT register opcodes
1068 //
1069 case 0xEE:
1070 case 0xEF:
1071 ExitInfo |= IOIO_TYPE_OUT;
1072 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
1073 break;
1074
1075 default:
1076 return 0;
1077 }
1078
1079 switch (*(InstructionData->OpCodes)) {
1080 //
1081 // Single-byte opcodes
1082 //
1083 case 0x6C:
1084 case 0x6E:
1085 case 0xE4:
1086 case 0xE6:
1087 case 0xEC:
1088 case 0xEE:
1089 ExitInfo |= IOIO_DATA_8;
1090 break;
1091
1092 //
1093 // Length determined by instruction parsing
1094 //
1095 default:
1096 ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
1097 : IOIO_DATA_32;
1098 }
1099
1100 switch (InstructionData->AddrSize) {
1101 case Size16Bits:
1102 ExitInfo |= IOIO_ADDR_16;
1103 break;
1104
1105 case Size32Bits:
1106 ExitInfo |= IOIO_ADDR_32;
1107 break;
1108
1109 case Size64Bits:
1110 ExitInfo |= IOIO_ADDR_64;
1111 break;
1112
1113 default:
1114 break;
1115 }
1116
1117 if (InstructionData->RepMode != 0) {
1118 ExitInfo |= IOIO_REP;
1119 }
1120
1121 return ExitInfo;
1122 }
1123
1124 /**
1125 Handle an IOIO event.
1126
1127 Use the VMGEXIT instruction to handle an IOIO event.
1128
1129 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1130 Block
1131 @param[in, out] Regs x64 processor context
1132 @param[in] InstructionData Instruction parsing context
1133
1134 @retval 0 Event handled successfully
1135 @return New exception value to propagate
1136
1137 **/
1138 STATIC
1139 UINT64
1140 IoioExit (
1141 IN OUT GHCB *Ghcb,
1142 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
1143 IN SEV_ES_INSTRUCTION_DATA *InstructionData
1144 )
1145 {
1146 UINT64 ExitInfo1, ExitInfo2, Status;
1147 BOOLEAN IsString;
1148
1149 ExitInfo1 = IoioExitInfo (Regs, InstructionData);
1150 if (ExitInfo1 == 0) {
1151 return UnsupportedExit (Ghcb, Regs, InstructionData);
1152 }
1153
1154 IsString = ((ExitInfo1 & IOIO_TYPE_STR) != 0) ? TRUE : FALSE;
1155 if (IsString) {
1156 UINTN IoBytes, VmgExitBytes;
1157 UINTN GhcbCount, OpCount;
1158
1159 Status = 0;
1160
1161 IoBytes = IOIO_DATA_BYTES (ExitInfo1);
1162 GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes;
1163
1164 OpCount = ((ExitInfo1 & IOIO_REP) != 0) ? Regs->Rcx : 1;
1165 while (OpCount != 0) {
1166 ExitInfo2 = MIN (OpCount, GhcbCount);
1167 VmgExitBytes = ExitInfo2 * IoBytes;
1168
1169 if ((ExitInfo1 & IOIO_TYPE_IN) == 0) {
1170 CopyMem (Ghcb->SharedBuffer, (VOID *) Regs->Rsi, VmgExitBytes);
1171 Regs->Rsi += VmgExitBytes;
1172 }
1173
1174 Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;
1175 Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2);
1176 if (Status != 0) {
1177 return Status;
1178 }
1179
1180 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
1181 CopyMem ((VOID *) Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes);
1182 Regs->Rdi += VmgExitBytes;
1183 }
1184
1185 if ((ExitInfo1 & IOIO_REP) != 0) {
1186 Regs->Rcx -= ExitInfo2;
1187 }
1188
1189 OpCount -= ExitInfo2;
1190 }
1191 } else {
1192 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
1193 Ghcb->SaveArea.Rax = 0;
1194 } else {
1195 CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));
1196 }
1197 GhcbSetRegValid (Ghcb, GhcbRax);
1198
1199 Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);
1200 if (Status != 0) {
1201 return Status;
1202 }
1203
1204 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
1205 if (!GhcbIsRegValid (Ghcb, GhcbRax)) {
1206 return UnsupportedExit (Ghcb, Regs, InstructionData);
1207 }
1208 CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));
1209 }
1210 }
1211
1212 return 0;
1213 }
1214
1215 /**
1216 Handle a INVD event.
1217
1218 Use the VMGEXIT instruction to handle a INVD event.
1219
1220 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1221 Block
1222 @param[in, out] Regs x64 processor context
1223 @param[in] InstructionData Instruction parsing context
1224
1225 @retval 0 Event handled successfully
1226 @return New exception value to propagate
1227
1228 **/
1229 STATIC
1230 UINT64
1231 InvdExit (
1232 IN OUT GHCB *Ghcb,
1233 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
1234 IN SEV_ES_INSTRUCTION_DATA *InstructionData
1235 )
1236 {
1237 return VmgExit (Ghcb, SVM_EXIT_INVD, 0, 0);
1238 }
1239
1240 /**
1241 Handle a CPUID event.
1242
1243 Use the VMGEXIT instruction to handle a CPUID event.
1244
1245 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1246 Block
1247 @param[in, out] Regs x64 processor context
1248 @param[in] InstructionData Instruction parsing context
1249
1250 @retval 0 Event handled successfully
1251 @return New exception value to propagate
1252
1253 **/
1254 STATIC
1255 UINT64
1256 CpuidExit (
1257 IN OUT GHCB *Ghcb,
1258 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
1259 IN SEV_ES_INSTRUCTION_DATA *InstructionData
1260 )
1261 {
1262 UINT64 Status;
1263
1264 Ghcb->SaveArea.Rax = Regs->Rax;
1265 GhcbSetRegValid (Ghcb, GhcbRax);
1266 Ghcb->SaveArea.Rcx = Regs->Rcx;
1267 GhcbSetRegValid (Ghcb, GhcbRcx);
1268 if (Regs->Rax == CPUID_EXTENDED_STATE) {
1269 IA32_CR4 Cr4;
1270
1271 Cr4.UintN = AsmReadCr4 ();
1272 Ghcb->SaveArea.XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;
1273 GhcbSetRegValid (Ghcb, GhcbXCr0);
1274 }
1275
1276 Status = VmgExit (Ghcb, SVM_EXIT_CPUID, 0, 0);
1277 if (Status != 0) {
1278 return Status;
1279 }
1280
1281 if (!GhcbIsRegValid (Ghcb, GhcbRax) ||
1282 !GhcbIsRegValid (Ghcb, GhcbRbx) ||
1283 !GhcbIsRegValid (Ghcb, GhcbRcx) ||
1284 !GhcbIsRegValid (Ghcb, GhcbRdx)) {
1285 return UnsupportedExit (Ghcb, Regs, InstructionData);
1286 }
1287 Regs->Rax = Ghcb->SaveArea.Rax;
1288 Regs->Rbx = Ghcb->SaveArea.Rbx;
1289 Regs->Rcx = Ghcb->SaveArea.Rcx;
1290 Regs->Rdx = Ghcb->SaveArea.Rdx;
1291
1292 return 0;
1293 }
1294
1295 /**
1296 Handle a RDPMC event.
1297
1298 Use the VMGEXIT instruction to handle a RDPMC event.
1299
1300 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1301 Block
1302 @param[in, out] Regs x64 processor context
1303 @param[in] InstructionData Instruction parsing context
1304
1305 @retval 0 Event handled successfully
1306 @return New exception value to propagate
1307
1308 **/
1309 STATIC
1310 UINT64
1311 RdpmcExit (
1312 IN OUT GHCB *Ghcb,
1313 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
1314 IN SEV_ES_INSTRUCTION_DATA *InstructionData
1315 )
1316 {
1317 UINT64 Status;
1318
1319 Ghcb->SaveArea.Rcx = Regs->Rcx;
1320 GhcbSetRegValid (Ghcb, GhcbRcx);
1321
1322 Status = VmgExit (Ghcb, SVM_EXIT_RDPMC, 0, 0);
1323 if (Status != 0) {
1324 return Status;
1325 }
1326
1327 if (!GhcbIsRegValid (Ghcb, GhcbRax) ||
1328 !GhcbIsRegValid (Ghcb, GhcbRdx)) {
1329 return UnsupportedExit (Ghcb, Regs, InstructionData);
1330 }
1331 Regs->Rax = Ghcb->SaveArea.Rax;
1332 Regs->Rdx = Ghcb->SaveArea.Rdx;
1333
1334 return 0;
1335 }
1336
1337 /**
1338 Handle a RDTSC event.
1339
1340 Use the VMGEXIT instruction to handle a RDTSC event.
1341
1342 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication
1343 Block
1344 @param[in, out] Regs x64 processor context
1345 @param[in] InstructionData Instruction parsing context
1346
1347 @retval 0 Event handled successfully
1348 @return New exception value to propagate
1349
1350 **/
1351 STATIC
1352 UINT64
1353 RdtscExit (
1354 IN OUT GHCB *Ghcb,
1355 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
1356 IN SEV_ES_INSTRUCTION_DATA *InstructionData
1357 )
1358 {
1359 UINT64 Status;
1360
1361 Status = VmgExit (Ghcb, SVM_EXIT_RDTSC, 0, 0);
1362 if (Status != 0) {
1363 return Status;
1364 }
1365
1366 if (!GhcbIsRegValid (Ghcb, GhcbRax) ||
1367 !GhcbIsRegValid (Ghcb, GhcbRdx)) {
1368 return UnsupportedExit (Ghcb, Regs, InstructionData);
1369 }
1370 Regs->Rax = Ghcb->SaveArea.Rax;
1371 Regs->Rdx = Ghcb->SaveArea.Rdx;
1372
1373 return 0;
1374 }
1375
1376 /**
1377 Handle a #VC exception.
1378
1379 Performs the necessary processing to handle a #VC exception.
1380
1381 @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set
1382 as value to use on error.
1383 @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT
1384
1385 @retval EFI_SUCCESS Exception handled
1386 @retval EFI_UNSUPPORTED #VC not supported, (new) exception value to
1387 propagate provided
1388 @retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to
1389 propagate provided
1390
1391 **/
1392 EFI_STATUS
1393 EFIAPI
1394 VmgExitHandleVc (
1395 IN OUT EFI_EXCEPTION_TYPE *ExceptionType,
1396 IN OUT EFI_SYSTEM_CONTEXT SystemContext
1397 )
1398 {
1399 MSR_SEV_ES_GHCB_REGISTER Msr;
1400 EFI_SYSTEM_CONTEXT_X64 *Regs;
1401 GHCB *Ghcb;
1402 NAE_EXIT NaeExit;
1403 SEV_ES_INSTRUCTION_DATA InstructionData;
1404 UINT64 ExitCode, Status;
1405 EFI_STATUS VcRet;
1406
1407 VcRet = EFI_SUCCESS;
1408
1409 Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
1410 ASSERT (Msr.GhcbInfo.Function == 0);
1411 ASSERT (Msr.Ghcb != 0);
1412
1413 Regs = SystemContext.SystemContextX64;
1414 Ghcb = Msr.Ghcb;
1415
1416 VmgInit (Ghcb);
1417
1418 ExitCode = Regs->ExceptionData;
1419 switch (ExitCode) {
1420 case SVM_EXIT_RDTSC:
1421 NaeExit = RdtscExit;
1422 break;
1423
1424 case SVM_EXIT_RDPMC:
1425 NaeExit = RdpmcExit;
1426 break;
1427
1428 case SVM_EXIT_CPUID:
1429 NaeExit = CpuidExit;
1430 break;
1431
1432 case SVM_EXIT_INVD:
1433 NaeExit = InvdExit;
1434 break;
1435
1436 case SVM_EXIT_IOIO_PROT:
1437 NaeExit = IoioExit;
1438 break;
1439
1440 case SVM_EXIT_MSR:
1441 NaeExit = MsrExit;
1442 break;
1443
1444 case SVM_EXIT_VMMCALL:
1445 NaeExit = VmmCallExit;
1446 break;
1447
1448 case SVM_EXIT_WBINVD:
1449 NaeExit = WbinvdExit;
1450 break;
1451
1452 case SVM_EXIT_NPF:
1453 NaeExit = MmioExit;
1454 break;
1455
1456 default:
1457 NaeExit = UnsupportedExit;
1458 }
1459
1460 InitInstructionData (&InstructionData, Ghcb, Regs);
1461
1462 Status = NaeExit (Ghcb, Regs, &InstructionData);
1463 if (Status == 0) {
1464 Regs->Rip += InstructionLength (&InstructionData);
1465 } else {
1466 GHCB_EVENT_INJECTION Event;
1467
1468 Event.Uint64 = Status;
1469 if (Event.Elements.ErrorCodeValid != 0) {
1470 Regs->ExceptionData = Event.Elements.ErrorCode;
1471 } else {
1472 Regs->ExceptionData = 0;
1473 }
1474
1475 *ExceptionType = Event.Elements.Vector;
1476
1477 VcRet = EFI_PROTOCOL_ERROR;
1478 }
1479
1480 VmgDone (Ghcb);
1481
1482 return VcRet;
1483 }