]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
OvmfPkg/VmgExitLib: Support string IO for IOIO_PROT NAE events
[mirror_edk2.git] / OvmfPkg / Library / VmgExitLib / VmgExitVcHandler.c
CommitLineData
61bacc0f
TL
1/** @file\r
2 X64 #VC Exception Handler functon.\r
3\r
4 Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include <Base.h>\r
10#include <Uefi.h>\r
11#include <Library/BaseMemoryLib.h>\r
12#include <Library/VmgExitLib.h>\r
13#include <Register/Amd/Msr.h>\r
fb040cce
TL
14#include <IndustryStandard/InstructionParsing.h>\r
15\r
16//\r
17// Instruction execution mode definition\r
18//\r
19typedef enum {\r
20 LongMode64Bit = 0,\r
21 LongModeCompat32Bit,\r
22 LongModeCompat16Bit,\r
23} SEV_ES_INSTRUCTION_MODE;\r
24\r
25//\r
26// Instruction size definition (for operand and address)\r
27//\r
28typedef enum {\r
29 Size8Bits = 0,\r
30 Size16Bits,\r
31 Size32Bits,\r
32 Size64Bits,\r
33} SEV_ES_INSTRUCTION_SIZE;\r
34\r
35//\r
36// Intruction segment definition\r
37//\r
38typedef enum {\r
39 SegmentEs = 0,\r
40 SegmentCs,\r
41 SegmentSs,\r
42 SegmentDs,\r
43 SegmentFs,\r
44 SegmentGs,\r
45} SEV_ES_INSTRUCTION_SEGMENT;\r
46\r
47//\r
48// Instruction rep function definition\r
49//\r
50typedef enum {\r
51 RepNone = 0,\r
52 RepZ,\r
53 RepNZ,\r
54} SEV_ES_INSTRUCTION_REP;\r
55\r
56typedef struct {\r
57 UINT8 Rm;\r
58 UINT8 Reg;\r
59 UINT8 Mod;\r
60} SEV_ES_INSTRUCTION_MODRM_EXT;\r
61\r
62typedef struct {\r
63 UINT8 Base;\r
64 UINT8 Index;\r
65 UINT8 Scale;\r
66} SEV_ES_INSTRUCTION_SIB_EXT;\r
67\r
68//\r
69// Instruction opcode definition\r
70//\r
71typedef struct {\r
72 SEV_ES_INSTRUCTION_MODRM_EXT ModRm;\r
73\r
74 SEV_ES_INSTRUCTION_SIB_EXT Sib;\r
75\r
76 UINTN RegData;\r
77 UINTN RmData;\r
78} SEV_ES_INSTRUCTION_OPCODE_EXT;\r
79\r
80//\r
81// Instruction parsing context definition\r
82//\r
83typedef struct {\r
84 GHCB *Ghcb;\r
85\r
86 SEV_ES_INSTRUCTION_MODE Mode;\r
87 SEV_ES_INSTRUCTION_SIZE DataSize;\r
88 SEV_ES_INSTRUCTION_SIZE AddrSize;\r
89 BOOLEAN SegmentSpecified;\r
90 SEV_ES_INSTRUCTION_SEGMENT Segment;\r
91 SEV_ES_INSTRUCTION_REP RepMode;\r
92\r
93 UINT8 *Begin;\r
94 UINT8 *End;\r
95\r
96 UINT8 *Prefixes;\r
97 UINT8 *OpCodes;\r
98 UINT8 *Displacement;\r
99 UINT8 *Immediate;\r
100\r
101 INSTRUCTION_REX_PREFIX RexPrefix;\r
102\r
103 BOOLEAN ModRmPresent;\r
104 INSTRUCTION_MODRM ModRm;\r
105\r
106 BOOLEAN SibPresent;\r
107 INSTRUCTION_SIB Sib;\r
108\r
109 UINTN PrefixSize;\r
110 UINTN OpCodeSize;\r
111 UINTN DisplacementSize;\r
112 UINTN ImmediateSize;\r
113\r
114 SEV_ES_INSTRUCTION_OPCODE_EXT Ext;\r
115} SEV_ES_INSTRUCTION_DATA;\r
116\r
117//\r
118// Non-automatic Exit function prototype\r
119//\r
120typedef\r
121UINT64\r
122(*NAE_EXIT) (\r
123 GHCB *Ghcb,\r
124 EFI_SYSTEM_CONTEXT_X64 *Regs,\r
125 SEV_ES_INSTRUCTION_DATA *InstructionData\r
126 );\r
127\r
128\r
129/**\r
130 Checks the GHCB to determine if the specified register has been marked valid.\r
131\r
132 The ValidBitmap area represents the areas of the GHCB that have been marked\r
133 valid. Return an indication of whether the area of the GHCB that holds the\r
134 specified register has been marked valid.\r
135\r
136 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication Block\r
137 @param[in] Reg Offset in the GHCB of the register to check\r
138\r
139 @retval TRUE Register has been marked vald in the GHCB\r
140 @retval FALSE Register has not been marked valid in the GHCB\r
141\r
142**/\r
143STATIC\r
144BOOLEAN\r
145GhcbIsRegValid (\r
146 IN GHCB *Ghcb,\r
147 IN GHCB_REGISTER Reg\r
148 )\r
149{\r
150 UINT32 RegIndex;\r
151 UINT32 RegBit;\r
152\r
153 RegIndex = Reg / 8;\r
154 RegBit = Reg & 0x07;\r
155\r
156 return ((Ghcb->SaveArea.ValidBitmap[RegIndex] & (1 << RegBit)) != 0);\r
157}\r
158\r
159/**\r
160 Marks a register as valid in the GHCB.\r
161\r
162 The ValidBitmap area represents the areas of the GHCB that have been marked\r
163 valid. Set the area of the GHCB that holds the specified register as valid.\r
164\r
165 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication Block\r
166 @param[in] Reg Offset in the GHCB of the register to mark valid\r
167\r
168**/\r
169STATIC\r
170VOID\r
171GhcbSetRegValid (\r
172 IN OUT GHCB *Ghcb,\r
173 IN GHCB_REGISTER Reg\r
174 )\r
175{\r
176 UINT32 RegIndex;\r
177 UINT32 RegBit;\r
178\r
179 RegIndex = Reg / 8;\r
180 RegBit = Reg & 0x07;\r
181\r
182 Ghcb->SaveArea.ValidBitmap[RegIndex] |= (1 << RegBit);\r
183}\r
184\r
185/**\r
186 Decode instruction prefixes.\r
187\r
188 Parse the instruction data to track the instruction prefixes that have\r
189 been used.\r
190\r
191 @param[in] Regs x64 processor context\r
192 @param[in, out] InstructionData Instruction parsing context\r
193\r
194**/\r
195STATIC\r
196VOID\r
197DecodePrefixes (\r
198 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
199 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
200 )\r
201{\r
202 SEV_ES_INSTRUCTION_MODE Mode;\r
203 SEV_ES_INSTRUCTION_SIZE ModeDataSize;\r
204 SEV_ES_INSTRUCTION_SIZE ModeAddrSize;\r
205 UINT8 *Byte;\r
206\r
207 //\r
208 // Always in 64-bit mode\r
209 //\r
210 Mode = LongMode64Bit;\r
211 ModeDataSize = Size32Bits;\r
212 ModeAddrSize = Size64Bits;\r
213\r
214 InstructionData->Mode = Mode;\r
215 InstructionData->DataSize = ModeDataSize;\r
216 InstructionData->AddrSize = ModeAddrSize;\r
217\r
218 InstructionData->Prefixes = InstructionData->Begin;\r
219\r
220 Byte = InstructionData->Prefixes;\r
221 for ( ; ; Byte++, InstructionData->PrefixSize++) {\r
222 //\r
223 // Check the 0x40 to 0x4F range using an if statement here since some\r
224 // compilers don't like the "case 0x40 ... 0x4F:" syntax. This avoids\r
225 // 16 case statements below.\r
226 //\r
227 if ((*Byte >= REX_PREFIX_START) && (*Byte <= REX_PREFIX_STOP)) {\r
228 InstructionData->RexPrefix.Uint8 = *Byte;\r
229 if ((*Byte & REX_64BIT_OPERAND_SIZE_MASK) != 0) {\r
230 InstructionData->DataSize = Size64Bits;\r
231 }\r
232 continue;\r
233 }\r
234\r
235 switch (*Byte) {\r
236 case OVERRIDE_SEGMENT_CS:\r
237 case OVERRIDE_SEGMENT_DS:\r
238 case OVERRIDE_SEGMENT_ES:\r
239 case OVERRIDE_SEGMENT_SS:\r
240 if (Mode != LongMode64Bit) {\r
241 InstructionData->SegmentSpecified = TRUE;\r
242 InstructionData->Segment = (*Byte >> 3) & 3;\r
243 }\r
244 break;\r
245\r
246 case OVERRIDE_SEGMENT_FS:\r
247 case OVERRIDE_SEGMENT_GS:\r
248 InstructionData->SegmentSpecified = TRUE;\r
249 InstructionData->Segment = *Byte & 7;\r
250 break;\r
251\r
252 case OVERRIDE_OPERAND_SIZE:\r
253 if (InstructionData->RexPrefix.Uint8 == 0) {\r
254 InstructionData->DataSize =\r
255 (Mode == LongMode64Bit) ? Size16Bits :\r
256 (Mode == LongModeCompat32Bit) ? Size16Bits :\r
257 (Mode == LongModeCompat16Bit) ? Size32Bits : 0;\r
258 }\r
259 break;\r
260\r
261 case OVERRIDE_ADDRESS_SIZE:\r
262 InstructionData->AddrSize =\r
263 (Mode == LongMode64Bit) ? Size32Bits :\r
264 (Mode == LongModeCompat32Bit) ? Size16Bits :\r
265 (Mode == LongModeCompat16Bit) ? Size32Bits : 0;\r
266 break;\r
267\r
268 case LOCK_PREFIX:\r
269 break;\r
270\r
271 case REPZ_PREFIX:\r
272 InstructionData->RepMode = RepZ;\r
273 break;\r
274\r
275 case REPNZ_PREFIX:\r
276 InstructionData->RepMode = RepNZ;\r
277 break;\r
278\r
279 default:\r
280 InstructionData->OpCodes = Byte;\r
281 InstructionData->OpCodeSize = (*Byte == TWO_BYTE_OPCODE_ESCAPE) ? 2 : 1;\r
282\r
283 InstructionData->End = Byte + InstructionData->OpCodeSize;\r
284 InstructionData->Displacement = InstructionData->End;\r
285 InstructionData->Immediate = InstructionData->End;\r
286 return;\r
287 }\r
288 }\r
289}\r
290\r
291/**\r
292 Determine instruction length\r
293\r
294 Return the total length of the parsed instruction.\r
295\r
296 @param[in] InstructionData Instruction parsing context\r
297\r
298 @return Length of parsed instruction\r
299\r
300**/\r
301STATIC\r
302UINT64\r
303InstructionLength (\r
304 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
305 )\r
306{\r
307 return (UINT64) (InstructionData->End - InstructionData->Begin);\r
308}\r
309\r
310/**\r
311 Initialize the instruction parsing context.\r
312\r
313 Initialize the instruction parsing context, which includes decoding the\r
314 instruction prefixes.\r
315\r
316 @param[in, out] InstructionData Instruction parsing context\r
317 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication\r
318 Block\r
319 @param[in] Regs x64 processor context\r
320\r
321**/\r
322STATIC\r
323VOID\r
324InitInstructionData (\r
325 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,\r
326 IN GHCB *Ghcb,\r
327 IN EFI_SYSTEM_CONTEXT_X64 *Regs\r
328 )\r
329{\r
330 SetMem (InstructionData, sizeof (*InstructionData), 0);\r
331 InstructionData->Ghcb = Ghcb;\r
332 InstructionData->Begin = (UINT8 *) Regs->Rip;\r
333 InstructionData->End = (UINT8 *) Regs->Rip;\r
334\r
335 DecodePrefixes (Regs, InstructionData);\r
336}\r
337\r
338/**\r
339 Report an unsupported event to the hypervisor\r
340\r
341 Use the VMGEXIT support to report an unsupported event to the hypervisor.\r
342\r
343 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication\r
344 Block\r
345 @param[in] Regs x64 processor context\r
346 @param[in] InstructionData Instruction parsing context\r
347\r
348 @return New exception value to propagate\r
349\r
350**/\r
351STATIC\r
352UINT64\r
353UnsupportedExit (\r
354 IN GHCB *Ghcb,\r
355 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
356 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
357 )\r
358{\r
359 UINT64 Status;\r
360\r
361 Status = VmgExit (Ghcb, SVM_EXIT_UNSUPPORTED, Regs->ExceptionData, 0);\r
362 if (Status == 0) {\r
363 GHCB_EVENT_INJECTION Event;\r
364\r
365 Event.Uint64 = 0;\r
366 Event.Elements.Vector = GP_EXCEPTION;\r
367 Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;\r
368 Event.Elements.Valid = 1;\r
369\r
370 Status = Event.Uint64;\r
371 }\r
372\r
373 return Status;\r
374}\r
375\r
376/**\r
377 Build the IOIO event information.\r
378\r
379 The IOIO event information identifies the type of IO operation to be performed\r
380 by the hypervisor. Build this information based on the instruction data.\r
381\r
382 @param[in] Regs x64 processor context\r
383 @param[in, out] InstructionData Instruction parsing context\r
384\r
385 @return IOIO event information value\r
386\r
387**/\r
388STATIC\r
389UINT64\r
390IoioExitInfo (\r
391 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
392 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
393 )\r
394{\r
395 UINT64 ExitInfo;\r
396\r
397 ExitInfo = 0;\r
398\r
399 switch (*(InstructionData->OpCodes)) {\r
0020157a
TL
400 //\r
401 // INS opcodes\r
402 //\r
403 case 0x6C:\r
404 case 0x6D:\r
405 ExitInfo |= IOIO_TYPE_INS;\r
406 ExitInfo |= IOIO_SEG_ES;\r
407 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
408 break;\r
409\r
410 //\r
411 // OUTS opcodes\r
412 //\r
413 case 0x6E:\r
414 case 0x6F:\r
415 ExitInfo |= IOIO_TYPE_OUTS;\r
416 ExitInfo |= IOIO_SEG_DS;\r
417 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
418 break;\r
419\r
fb040cce
TL
420 //\r
421 // IN immediate opcodes\r
422 //\r
423 case 0xE4:\r
424 case 0xE5:\r
425 InstructionData->ImmediateSize = 1;\r
426 InstructionData->End++;\r
427 ExitInfo |= IOIO_TYPE_IN;\r
428 ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16);\r
429 break;\r
430\r
431 //\r
432 // OUT immediate opcodes\r
433 //\r
434 case 0xE6:\r
435 case 0xE7:\r
436 InstructionData->ImmediateSize = 1;\r
437 InstructionData->End++;\r
438 ExitInfo |= IOIO_TYPE_OUT;\r
439 ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT;\r
440 break;\r
441\r
442 //\r
443 // IN register opcodes\r
444 //\r
445 case 0xEC:\r
446 case 0xED:\r
447 ExitInfo |= IOIO_TYPE_IN;\r
448 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
449 break;\r
450\r
451 //\r
452 // OUT register opcodes\r
453 //\r
454 case 0xEE:\r
455 case 0xEF:\r
456 ExitInfo |= IOIO_TYPE_OUT;\r
457 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
458 break;\r
459\r
460 default:\r
461 return 0;\r
462 }\r
463\r
464 switch (*(InstructionData->OpCodes)) {\r
465 //\r
466 // Single-byte opcodes\r
467 //\r
0020157a
TL
468 case 0x6C:\r
469 case 0x6E:\r
fb040cce
TL
470 case 0xE4:\r
471 case 0xE6:\r
472 case 0xEC:\r
473 case 0xEE:\r
474 ExitInfo |= IOIO_DATA_8;\r
475 break;\r
476\r
477 //\r
478 // Length determined by instruction parsing\r
479 //\r
480 default:\r
481 ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16\r
482 : IOIO_DATA_32;\r
483 }\r
484\r
485 switch (InstructionData->AddrSize) {\r
486 case Size16Bits:\r
487 ExitInfo |= IOIO_ADDR_16;\r
488 break;\r
489\r
490 case Size32Bits:\r
491 ExitInfo |= IOIO_ADDR_32;\r
492 break;\r
493\r
494 case Size64Bits:\r
495 ExitInfo |= IOIO_ADDR_64;\r
496 break;\r
497\r
498 default:\r
499 break;\r
500 }\r
501\r
502 if (InstructionData->RepMode != 0) {\r
503 ExitInfo |= IOIO_REP;\r
504 }\r
505\r
506 return ExitInfo;\r
507}\r
508\r
509/**\r
510 Handle an IOIO event.\r
511\r
512 Use the VMGEXIT instruction to handle an IOIO event.\r
513\r
514 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
515 Block\r
516 @param[in, out] Regs x64 processor context\r
517 @param[in] InstructionData Instruction parsing context\r
518\r
519 @retval 0 Event handled successfully\r
520 @return New exception value to propagate\r
521\r
522**/\r
523STATIC\r
524UINT64\r
525IoioExit (\r
526 IN OUT GHCB *Ghcb,\r
527 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
528 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
529 )\r
530{\r
0020157a
TL
531 UINT64 ExitInfo1, ExitInfo2, Status;\r
532 BOOLEAN IsString;\r
fb040cce
TL
533\r
534 ExitInfo1 = IoioExitInfo (Regs, InstructionData);\r
535 if (ExitInfo1 == 0) {\r
536 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
537 }\r
538\r
0020157a
TL
539 IsString = ((ExitInfo1 & IOIO_TYPE_STR) != 0) ? TRUE : FALSE;\r
540 if (IsString) {\r
541 UINTN IoBytes, VmgExitBytes;\r
542 UINTN GhcbCount, OpCount;\r
543\r
544 Status = 0;\r
545\r
546 IoBytes = IOIO_DATA_BYTES (ExitInfo1);\r
547 GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes;\r
548\r
549 OpCount = ((ExitInfo1 & IOIO_REP) != 0) ? Regs->Rcx : 1;\r
550 while (OpCount != 0) {\r
551 ExitInfo2 = MIN (OpCount, GhcbCount);\r
552 VmgExitBytes = ExitInfo2 * IoBytes;\r
553\r
554 if ((ExitInfo1 & IOIO_TYPE_IN) == 0) {\r
555 CopyMem (Ghcb->SharedBuffer, (VOID *) Regs->Rsi, VmgExitBytes);\r
556 Regs->Rsi += VmgExitBytes;\r
557 }\r
558\r
559 Ghcb->SaveArea.SwScratch = (UINT64) Ghcb->SharedBuffer;\r
560 Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2);\r
561 if (Status != 0) {\r
562 return Status;\r
563 }\r
564\r
565 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
566 CopyMem ((VOID *) Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes);\r
567 Regs->Rdi += VmgExitBytes;\r
568 }\r
569\r
570 if ((ExitInfo1 & IOIO_REP) != 0) {\r
571 Regs->Rcx -= ExitInfo2;\r
572 }\r
573\r
574 OpCount -= ExitInfo2;\r
575 }\r
fb040cce 576 } else {\r
0020157a
TL
577 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
578 Ghcb->SaveArea.Rax = 0;\r
579 } else {\r
580 CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));\r
581 }\r
582 GhcbSetRegValid (Ghcb, GhcbRax);\r
fb040cce 583\r
0020157a
TL
584 Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);\r
585 if (Status != 0) {\r
586 return Status;\r
587 }\r
fb040cce 588\r
0020157a
TL
589 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
590 if (!GhcbIsRegValid (Ghcb, GhcbRax)) {\r
591 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
592 }\r
593 CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));\r
fb040cce 594 }\r
fb040cce
TL
595 }\r
596\r
597 return 0;\r
598}\r
61bacc0f
TL
599\r
600/**\r
601 Handle a #VC exception.\r
602\r
603 Performs the necessary processing to handle a #VC exception.\r
604\r
605 @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set\r
606 as value to use on error.\r
607 @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT\r
608\r
609 @retval EFI_SUCCESS Exception handled\r
610 @retval EFI_UNSUPPORTED #VC not supported, (new) exception value to\r
611 propagate provided\r
612 @retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to\r
613 propagate provided\r
614\r
615**/\r
616EFI_STATUS\r
617EFIAPI\r
618VmgExitHandleVc (\r
619 IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
620 IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
621 )\r
622{\r
623 MSR_SEV_ES_GHCB_REGISTER Msr;\r
624 EFI_SYSTEM_CONTEXT_X64 *Regs;\r
625 GHCB *Ghcb;\r
fb040cce
TL
626 NAE_EXIT NaeExit;\r
627 SEV_ES_INSTRUCTION_DATA InstructionData;\r
61bacc0f
TL
628 UINT64 ExitCode, Status;\r
629 EFI_STATUS VcRet;\r
630\r
631 VcRet = EFI_SUCCESS;\r
632\r
633 Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);\r
634 ASSERT (Msr.GhcbInfo.Function == 0);\r
635 ASSERT (Msr.Ghcb != 0);\r
636\r
637 Regs = SystemContext.SystemContextX64;\r
638 Ghcb = Msr.Ghcb;\r
639\r
640 VmgInit (Ghcb);\r
641\r
642 ExitCode = Regs->ExceptionData;\r
643 switch (ExitCode) {\r
fb040cce
TL
644 case SVM_EXIT_IOIO_PROT:\r
645 NaeExit = IoioExit;\r
646 break;\r
647\r
61bacc0f 648 default:\r
fb040cce
TL
649 NaeExit = UnsupportedExit;\r
650 }\r
61bacc0f 651\r
fb040cce
TL
652 InitInstructionData (&InstructionData, Ghcb, Regs);\r
653\r
654 Status = NaeExit (Ghcb, Regs, &InstructionData);\r
655 if (Status == 0) {\r
656 Regs->Rip += InstructionLength (&InstructionData);\r
657 } else {\r
658 GHCB_EVENT_INJECTION Event;\r
61bacc0f 659\r
fb040cce
TL
660 Event.Uint64 = Status;\r
661 if (Event.Elements.ErrorCodeValid != 0) {\r
662 Regs->ExceptionData = Event.Elements.ErrorCode;\r
663 } else {\r
664 Regs->ExceptionData = 0;\r
61bacc0f
TL
665 }\r
666\r
fb040cce
TL
667 *ExceptionType = Event.Elements.Vector;\r
668\r
61bacc0f
TL
669 VcRet = EFI_PROTOCOL_ERROR;\r
670 }\r
671\r
672 VmgDone (Ghcb);\r
673\r
674 return VcRet;\r
675}\r