]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/Library/CcExitLib/CcExitVeHandler.c
OvmfPkg/CcExitLib: Refactor TDX MmioExit
[mirror_edk2.git] / OvmfPkg / Library / CcExitLib / CcExitVeHandler.c
1 /** @file
2
3 Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
4
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <Library/BaseLib.h>
10 #include <Library/DebugLib.h>
11 #include "CcExitTd.h"
12 #include <Library/CcExitLib.h>
13 #include <Library/BaseMemoryLib.h>
14 #include <IndustryStandard/Tdx.h>
15 #include <IndustryStandard/InstructionParsing.h>
16 #include "CcInstruction.h"
17
18 #define TDX_MMIO_READ 0
19 #define TDX_MMIO_WRITE 1
20
21 typedef union {
22 struct {
23 UINT32 Eax;
24 UINT32 Edx;
25 } Regs;
26 UINT64 Val;
27 } MSR_DATA;
28
29 typedef union {
30 UINT8 Val;
31 struct {
32 UINT8 B : 1;
33 UINT8 X : 1;
34 UINT8 R : 1;
35 UINT8 W : 1;
36 } Bits;
37 } REX;
38
39 typedef union {
40 UINT8 Val;
41 struct {
42 UINT8 Rm : 3;
43 UINT8 Reg : 3;
44 UINT8 Mod : 2;
45 } Bits;
46 } MODRM;
47
48 typedef struct {
49 UINT64 Regs[4];
50 } CPUID_DATA;
51
52 /**
53 Handle an CPUID event.
54
55 Use the TDVMCALL instruction to handle cpuid #ve
56
57 @param[in, out] Regs x64 processor context
58 @param[in] Veinfo VE Info
59
60 @retval 0 Event handled successfully
61 @return New exception value to propagate
62 **/
63 STATIC
64 UINT64
65 EFIAPI
66 CpuIdExit (
67 IN EFI_SYSTEM_CONTEXT_X64 *Regs,
68 IN TDCALL_VEINFO_RETURN_DATA *Veinfo
69 )
70 {
71 CPUID_DATA CpuIdData;
72 UINT64 Status;
73
74 Status = TdVmCallCpuid (Regs->Rax, Regs->Rcx, &CpuIdData);
75
76 if (Status == 0) {
77 Regs->Rax = CpuIdData.Regs[0];
78 Regs->Rbx = CpuIdData.Regs[1];
79 Regs->Rcx = CpuIdData.Regs[2];
80 Regs->Rdx = CpuIdData.Regs[3];
81 }
82
83 return Status;
84 }
85
86 /**
87 Handle an IO event.
88
89 Use the TDVMCALL instruction to handle either an IO read or an IO write.
90
91 @param[in, out] Regs x64 processor context
92 @param[in] Veinfo VE Info
93
94 @retval 0 Event handled successfully
95 @return New exception value to propagate
96 **/
97 STATIC
98 UINT64
99 EFIAPI
100 IoExit (
101 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
102 IN TDCALL_VEINFO_RETURN_DATA *Veinfo
103 )
104 {
105 BOOLEAN Write;
106 UINTN Size;
107 UINTN Port;
108 UINT64 Val;
109 UINT64 RepCnt;
110 UINT64 Status;
111
112 Val = 0;
113 Write = Veinfo->ExitQualification.Io.Direction ? FALSE : TRUE;
114 Size = Veinfo->ExitQualification.Io.Size + 1;
115 Port = Veinfo->ExitQualification.Io.Port;
116
117 if (Veinfo->ExitQualification.Io.String) {
118 //
119 // If REP is set, get rep-cnt from Rcx
120 //
121 RepCnt = Veinfo->ExitQualification.Io.Rep ? Regs->Rcx : 1;
122
123 while (RepCnt) {
124 Val = 0;
125 if (Write == TRUE) {
126 CopyMem (&Val, (VOID *)Regs->Rsi, Size);
127 Regs->Rsi += Size;
128 }
129
130 Status = TdVmCall (EXIT_REASON_IO_INSTRUCTION, Size, Write, Port, Val, (Write ? NULL : &Val));
131 if (Status != 0) {
132 break;
133 }
134
135 if (Write == FALSE) {
136 CopyMem ((VOID *)Regs->Rdi, &Val, Size);
137 Regs->Rdi += Size;
138 }
139
140 if (Veinfo->ExitQualification.Io.Rep) {
141 Regs->Rcx -= 1;
142 }
143
144 RepCnt -= 1;
145 }
146 } else {
147 if (Write == TRUE) {
148 CopyMem (&Val, (VOID *)&Regs->Rax, Size);
149 }
150
151 Status = TdVmCall (EXIT_REASON_IO_INSTRUCTION, Size, Write, Port, Val, (Write ? NULL : &Val));
152 if ((Status == 0) && (Write == FALSE)) {
153 CopyMem ((VOID *)&Regs->Rax, &Val, Size);
154 }
155 }
156
157 return Status;
158 }
159
160 /**
161 Handle an READ MSR event.
162
163 Use the TDVMCALL instruction to handle msr read
164
165 @param[in, out] Regs x64 processor context
166 @param[in] Veinfo VE Info
167
168 @retval 0 Event handled successfully
169 @return New exception value to propagate
170 **/
171 STATIC
172 UINT64
173 ReadMsrExit (
174 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
175 IN TDCALL_VEINFO_RETURN_DATA *Veinfo
176 )
177 {
178 MSR_DATA Data;
179 UINT64 Status;
180
181 Status = TdVmCall (EXIT_REASON_MSR_READ, Regs->Rcx, 0, 0, 0, &Data);
182 if (Status == 0) {
183 Regs->Rax = Data.Regs.Eax;
184 Regs->Rdx = Data.Regs.Edx;
185 }
186
187 return Status;
188 }
189
190 /**
191 Handle an WRITE MSR event.
192
193 Use the TDVMCALL instruction to handle msr write
194
195 @param[in, out] Regs x64 processor context
196 @param[in] Veinfo VE Info
197
198 @retval 0 Event handled successfully
199 @return New exception value to propagate
200 **/
201 STATIC
202 UINT64
203 WriteMsrExit (
204 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
205 IN TDCALL_VEINFO_RETURN_DATA *Veinfo
206 )
207 {
208 UINT64 Status;
209 MSR_DATA Data;
210
211 Data.Regs.Eax = (UINT32)Regs->Rax;
212 Data.Regs.Edx = (UINT32)Regs->Rdx;
213
214 Status = TdVmCall (EXIT_REASON_MSR_WRITE, Regs->Rcx, Data.Val, 0, 0, NULL);
215
216 return Status;
217 }
218
219 STATIC
220 VOID
221 EFIAPI
222 TdxDecodeInstruction (
223 IN UINT8 *Rip,
224 IN UINT32 Length
225 )
226 {
227 UINTN i;
228
229 DEBUG ((DEBUG_INFO, "TDX: #TD[EPT] instruction (%p):", Rip));
230 for (i = 0; i < MIN (15, Length); i++) {
231 DEBUG ((DEBUG_INFO, "%02x ", Rip[i]));
232 }
233
234 DEBUG ((DEBUG_INFO, "\n"));
235 }
236
237 #define TDX_DECODER_BUG_ON(x) \
238 if ((x)) { \
239 TdxDecodeInstruction(Rip); \
240 TdVmCall(TDVMCALL_HALT, 0, 0, 0, 0, 0); \
241 CpuDeadLoop (); \
242 }
243
244 /**
245 * Tdx MMIO access via TdVmcall.
246 *
247 * @param MmioSize Size of the MMIO access
248 * @param ReadOrWrite Read or write operation
249 * @param GuestPA Guest physical address
250 * @param Val Pointer to the value which is read or written
251
252 * @retval EFI_SUCCESS Successfully access the mmio
253 * @retval Others Other errors as indicated
254 */
255 STATIC
256 EFI_STATUS
257 TdxMmioReadWrite (
258 IN UINT32 MmioSize,
259 IN UINT32 ReadOrWrite,
260 IN UINT64 GuestPA,
261 IN UINT64 *Val
262 )
263 {
264 UINT64 TdStatus;
265
266 if ((MmioSize != 1) && (MmioSize != 2) && (MmioSize != 4) && (MmioSize != 8)) {
267 DEBUG ((DEBUG_ERROR, "%a: Invalid MmioSize - %d\n", __FUNCTION__, MmioSize));
268 return EFI_INVALID_PARAMETER;
269 }
270
271 if (Val == NULL) {
272 return EFI_INVALID_PARAMETER;
273 }
274
275 TdStatus = 0;
276 if (ReadOrWrite == TDX_MMIO_READ) {
277 TdStatus = TdVmCall (TDVMCALL_MMIO, MmioSize, TDX_MMIO_READ, GuestPA, 0, Val);
278 } else if (ReadOrWrite == TDX_MMIO_WRITE) {
279 TdStatus = TdVmCall (TDVMCALL_MMIO, MmioSize, TDX_MMIO_WRITE, GuestPA, *Val, 0);
280 } else {
281 return EFI_INVALID_PARAMETER;
282 }
283
284 if (TdStatus != 0) {
285 DEBUG ((DEBUG_ERROR, "%a: TdVmcall failed with %llx\n", __FUNCTION__, TdStatus));
286 return EFI_ABORTED;
287 }
288
289 return EFI_SUCCESS;
290 }
291
292 typedef struct {
293 UINT8 OpCode;
294 UINT32 Bytes;
295 EFI_PHYSICAL_ADDRESS Address;
296 UINT64 Val;
297 UINT64 *Register;
298 UINT32 ReadOrWrite;
299 } MMIO_EXIT_PARSED_INSTRUCTION;
300
301 /**
302 * Parse the MMIO instructions.
303 *
304 * @param Regs Pointer to the EFI_SYSTEM_CONTEXT_X64 which includes the instructions
305 * @param InstructionData Pointer to the CC_INSTRUCTION_DATA
306 * @param ParsedInstruction Pointer to the parsed instruction data
307 *
308 * @retval EFI_SUCCESS Successfully parsed the instructions
309 * @retval Others Other error as indicated
310 */
311 STATIC
312 EFI_STATUS
313 ParseMmioExitInstructions (
314 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
315 IN OUT CC_INSTRUCTION_DATA *InstructionData,
316 OUT MMIO_EXIT_PARSED_INSTRUCTION *ParsedInstruction
317 )
318 {
319 EFI_STATUS Status;
320 UINT8 OpCode;
321 UINT8 SignByte;
322 UINT32 Bytes;
323 EFI_PHYSICAL_ADDRESS Address;
324 UINT64 Val;
325 UINT64 *Register;
326 UINT32 ReadOrWrite;
327
328 Address = 0;
329 Bytes = 0;
330 Register = NULL;
331 Status = EFI_SUCCESS;
332 Val = 0;
333
334 Status = CcInitInstructionData (InstructionData, NULL, Regs);
335 if (EFI_ERROR (Status)) {
336 DEBUG ((DEBUG_ERROR, "%a: Initialize InstructionData failed! (%r)\n", __FUNCTION__, Status));
337 return Status;
338 }
339
340 OpCode = *(InstructionData->OpCodes);
341 if (OpCode == TWO_BYTE_OPCODE_ESCAPE) {
342 OpCode = *(InstructionData->OpCodes + 1);
343 }
344
345 switch (OpCode) {
346 //
347 // MMIO write (MOV reg/memX, regX)
348 //
349 case 0x88:
350 Bytes = 1;
351 //
352 // fall through
353 //
354 case 0x89:
355 CcDecodeModRm (Regs, InstructionData);
356 Bytes = ((Bytes != 0) ? Bytes :
357 (InstructionData->DataSize == Size16Bits) ? 2 :
358 (InstructionData->DataSize == Size32Bits) ? 4 :
359 (InstructionData->DataSize == Size64Bits) ? 8 :
360 0);
361
362 if (InstructionData->Ext.ModRm.Mod == 3) {
363 DEBUG ((DEBUG_ERROR, "%a: Parse Ext.ModRm.Mod error! (OpCode: 0x%x)\n", __FUNCTION__, OpCode));
364 return EFI_UNSUPPORTED;
365 }
366
367 Address = InstructionData->Ext.RmData;
368 Val = InstructionData->Ext.RegData;
369 ReadOrWrite = TDX_MMIO_WRITE;
370
371 break;
372
373 //
374 // MMIO write (MOV moffsetX, aX)
375 //
376 case 0xA2:
377 Bytes = 1;
378 //
379 // fall through
380 //
381 case 0xA3:
382 Bytes = ((Bytes != 0) ? Bytes :
383 (InstructionData->DataSize == Size16Bits) ? 2 :
384 (InstructionData->DataSize == Size32Bits) ? 4 :
385 (InstructionData->DataSize == Size64Bits) ? 8 :
386 0);
387
388 InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);
389 InstructionData->End += InstructionData->ImmediateSize;
390 CopyMem (&Address, InstructionData->Immediate, InstructionData->ImmediateSize);
391
392 Val = Regs->Rax;
393 ReadOrWrite = TDX_MMIO_WRITE;
394 break;
395
396 //
397 // MMIO write (MOV reg/memX, immX)
398 //
399 case 0xC6:
400 Bytes = 1;
401 //
402 // fall through
403 //
404 case 0xC7:
405 CcDecodeModRm (Regs, InstructionData);
406 Bytes = ((Bytes != 0) ? Bytes :
407 (InstructionData->DataSize == Size16Bits) ? 2 :
408 (InstructionData->DataSize == Size32Bits) ? 4 :
409 (InstructionData->DataSize == Size64Bits) ? 8 :
410 0);
411
412 InstructionData->ImmediateSize = Bytes;
413 InstructionData->End += Bytes;
414
415 Val = 0;
416 CopyMem (&Val, InstructionData->Immediate, InstructionData->ImmediateSize);
417
418 Address = InstructionData->Ext.RmData;
419 ReadOrWrite = TDX_MMIO_WRITE;
420
421 break;
422
423 //
424 // MMIO read (MOV regX, reg/memX)
425 //
426 case 0x8A:
427 Bytes = 1;
428 //
429 // fall through
430 //
431 case 0x8B:
432 CcDecodeModRm (Regs, InstructionData);
433 Bytes = ((Bytes != 0) ? Bytes :
434 (InstructionData->DataSize == Size16Bits) ? 2 :
435 (InstructionData->DataSize == Size32Bits) ? 4 :
436 (InstructionData->DataSize == Size64Bits) ? 8 :
437 0);
438 if (InstructionData->Ext.ModRm.Mod == 3) {
439 //
440 // NPF on two register operands???
441 //
442 DEBUG ((DEBUG_ERROR, "%a: Parse Ext.ModRm.Mod error! (OpCode: 0x%x)\n", __FUNCTION__, OpCode));
443 return EFI_UNSUPPORTED;
444 }
445
446 Address = InstructionData->Ext.RmData;
447 ReadOrWrite = TDX_MMIO_READ;
448
449 Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
450 if (Register == NULL) {
451 return EFI_ABORTED;
452 }
453
454 if (Bytes == 4) {
455 //
456 // Zero-extend for 32-bit operation
457 //
458 *Register = 0;
459 }
460
461 break;
462
463 //
464 // MMIO read (MOV aX, moffsetX)
465 //
466 case 0xA0:
467 Bytes = 1;
468 //
469 // fall through
470 //
471 case 0xA1:
472 Bytes = ((Bytes != 0) ? Bytes :
473 (InstructionData->DataSize == Size16Bits) ? 2 :
474 (InstructionData->DataSize == Size32Bits) ? 4 :
475 (InstructionData->DataSize == Size64Bits) ? 8 :
476 0);
477
478 InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);
479 InstructionData->End += InstructionData->ImmediateSize;
480
481 Address = 0;
482 CopyMem (
483 &Address,
484 InstructionData->Immediate,
485 InstructionData->ImmediateSize
486 );
487
488 if (Bytes == 4) {
489 //
490 // Zero-extend for 32-bit operation
491 //
492 Regs->Rax = 0;
493 }
494
495 Register = &Regs->Rax;
496 ReadOrWrite = TDX_MMIO_READ;
497
498 break;
499
500 //
501 // MMIO read w/ zero-extension ((MOVZX regX, reg/memX)
502 //
503 case 0xB6:
504 Bytes = 1;
505 //
506 // fall through
507 //
508 case 0xB7:
509 CcDecodeModRm (Regs, InstructionData);
510 Bytes = (Bytes != 0) ? Bytes : 2;
511 Address = InstructionData->Ext.RmData;
512
513 Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
514 if (Register == NULL) {
515 return EFI_ABORTED;
516 }
517
518 SetMem (Register, (UINTN)(1 << InstructionData->DataSize), 0);
519
520 ReadOrWrite = TDX_MMIO_READ;
521
522 break;
523
524 //
525 // MMIO read w/ sign-extension (MOVSX regX, reg/memX)
526 //
527 case 0xBE:
528 Bytes = 1;
529 //
530 // fall through
531 //
532 case 0xBF:
533 CcDecodeModRm (Regs, InstructionData);
534 Bytes = (Bytes != 0) ? Bytes : 2;
535
536 Address = InstructionData->Ext.RmData;
537
538 if (Bytes == 1) {
539 UINT8 *Data;
540 Data = (UINT8 *)&Val;
541 SignByte = ((*Data & BIT7) != 0) ? 0xFF : 0x00;
542 } else {
543 UINT16 *Data;
544 Data = (UINT16 *)&Val;
545 SignByte = ((*Data & BIT15) != 0) ? 0xFF : 0x00;
546 }
547
548 Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
549 if (Register == NULL) {
550 return EFI_ABORTED;
551 }
552
553 SetMem (Register, (UINTN)(1 << InstructionData->DataSize), SignByte);
554
555 ReadOrWrite = TDX_MMIO_READ;
556
557 break;
558
559 default:
560 DEBUG ((DEBUG_ERROR, "%a: Invalid MMIO opcode (%x)\n", __FUNCTION__, OpCode));
561 Status = EFI_UNSUPPORTED;
562 }
563
564 if (!EFI_ERROR (Status)) {
565 ParsedInstruction->OpCode = OpCode;
566 ParsedInstruction->Address = Address;
567 ParsedInstruction->Bytes = Bytes;
568 ParsedInstruction->Register = Register;
569 ParsedInstruction->Val = Val;
570 ParsedInstruction->ReadOrWrite = ReadOrWrite;
571 }
572
573 return Status;
574 }
575
576 /**
577 Handle an MMIO event.
578
579 Use the TDVMCALL instruction to handle either an mmio read or an mmio write.
580
581 @param[in, out] Regs x64 processor context
582 @param[in] Veinfo VE Info
583
584 @retval 0 Event handled successfully
585 **/
586 STATIC
587 UINT64
588 EFIAPI
589 MmioExit (
590 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,
591 IN TDCALL_VEINFO_RETURN_DATA *Veinfo
592 )
593 {
594 UINT64 TdStatus;
595 EFI_STATUS Status;
596 TD_RETURN_DATA TdReturnData;
597 UINT8 Gpaw;
598 UINT64 Val;
599 UINT64 TdSharedPageMask;
600 CC_INSTRUCTION_DATA InstructionData;
601 MMIO_EXIT_PARSED_INSTRUCTION ParsedInstruction;
602
603 TdStatus = TdCall (TDCALL_TDINFO, 0, 0, 0, &TdReturnData);
604 if (TdStatus == TDX_EXIT_REASON_SUCCESS) {
605 Gpaw = (UINT8)(TdReturnData.TdInfo.Gpaw & 0x3f);
606 TdSharedPageMask = 1ULL << (Gpaw - 1);
607 } else {
608 DEBUG ((DEBUG_ERROR, "%a: TDCALL failed with status=%llx\n", __FUNCTION__, TdStatus));
609 goto FatalError;
610 }
611
612 if ((Veinfo->GuestPA & TdSharedPageMask) == 0) {
613 DEBUG ((DEBUG_ERROR, "%a: EPT-violation #VE on private memory is not allowed!", __FUNCTION__));
614 goto FatalError;
615 }
616
617 Status = ParseMmioExitInstructions (Regs, &InstructionData, &ParsedInstruction);
618 if (EFI_ERROR (Status)) {
619 goto FatalError;
620 }
621
622 if (Veinfo->GuestPA != (ParsedInstruction.Address | TdSharedPageMask)) {
623 DEBUG ((
624 DEBUG_ERROR,
625 "%a: Address is not correct! (%d: 0x%llx != 0x%llx)\n",
626 __FUNCTION__,
627 ParsedInstruction.OpCode,
628 Veinfo->GuestPA,
629 ParsedInstruction.Address
630 ));
631 goto FatalError;
632 }
633
634 if (ParsedInstruction.ReadOrWrite == TDX_MMIO_WRITE ) {
635 Status = TdxMmioReadWrite (ParsedInstruction.Bytes, TDX_MMIO_WRITE, Veinfo->GuestPA, &ParsedInstruction.Val);
636 } else if (ParsedInstruction.ReadOrWrite == TDX_MMIO_READ) {
637 Val = 0;
638 Status = TdxMmioReadWrite (ParsedInstruction.Bytes, TDX_MMIO_READ, Veinfo->GuestPA, &Val);
639 if (!EFI_ERROR (Status)) {
640 CopyMem (ParsedInstruction.Register, &Val, ParsedInstruction.Bytes);
641 }
642 } else {
643 goto FatalError;
644 }
645
646 if (EFI_ERROR (Status)) {
647 goto FatalError;
648 }
649
650 //
651 // We change instruction length to reflect true size so handler can
652 // bump rip
653 //
654 Veinfo->ExitInstructionLength = (UINT32)(CcInstructionLength (&InstructionData));
655 TdxDecodeInstruction ((UINT8 *)Regs->Rip, Veinfo->ExitInstructionLength);
656
657 return 0;
658
659 FatalError:
660 TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
661 CpuDeadLoop ();
662 return 0;
663 }
664
665 /**
666 Handle a #VE exception.
667
668 Performs the necessary processing to handle a #VE exception.
669
670 @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set
671 as value to use on error.
672 @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT
673
674 @retval EFI_SUCCESS Exception handled
675 @retval EFI_UNSUPPORTED #VE not supported, (new) exception value to
676 propagate provided
677 @retval EFI_PROTOCOL_ERROR #VE handling failed, (new) exception value to
678 propagate provided
679
680 **/
681 EFI_STATUS
682 EFIAPI
683 CcExitHandleVe (
684 IN OUT EFI_EXCEPTION_TYPE *ExceptionType,
685 IN OUT EFI_SYSTEM_CONTEXT SystemContext
686 )
687 {
688 UINT64 Status;
689 TD_RETURN_DATA ReturnData;
690 EFI_SYSTEM_CONTEXT_X64 *Regs;
691
692 Regs = SystemContext.SystemContextX64;
693 Status = TdCall (TDCALL_TDGETVEINFO, 0, 0, 0, &ReturnData);
694 ASSERT (Status == 0);
695 if (Status != 0) {
696 DEBUG ((DEBUG_ERROR, "#VE happened. TDGETVEINFO failed with Status = 0x%llx\n", Status));
697 TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
698 CpuDeadLoop ();
699 }
700
701 switch (ReturnData.VeInfo.ExitReason) {
702 case EXIT_REASON_CPUID:
703 Status = CpuIdExit (Regs, &ReturnData.VeInfo);
704 DEBUG ((
705 DEBUG_VERBOSE,
706 "CPUID #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",
707 ReturnData.VeInfo.ExitReason,
708 ReturnData.VeInfo.ExitQualification.Val
709 ));
710 break;
711
712 case EXIT_REASON_HLT:
713 Status = TdVmCall (EXIT_REASON_HLT, 0, 0, 0, 0, 0);
714 break;
715
716 case EXIT_REASON_IO_INSTRUCTION:
717 Status = IoExit (Regs, &ReturnData.VeInfo);
718 DEBUG ((
719 DEBUG_VERBOSE,
720 "IO_Instruction #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",
721 ReturnData.VeInfo.ExitReason,
722 ReturnData.VeInfo.ExitQualification.Val
723 ));
724 break;
725
726 case EXIT_REASON_MSR_READ:
727 Status = ReadMsrExit (Regs, &ReturnData.VeInfo);
728 DEBUG ((
729 DEBUG_VERBOSE,
730 "RDMSR #VE happened, ExitReasion is %d, ExitQualification = 0x%x. Regs->Rcx=0x%llx, Status = 0x%llx\n",
731 ReturnData.VeInfo.ExitReason,
732 ReturnData.VeInfo.ExitQualification.Val,
733 Regs->Rcx,
734 Status
735 ));
736 break;
737
738 case EXIT_REASON_MSR_WRITE:
739 Status = WriteMsrExit (Regs, &ReturnData.VeInfo);
740 DEBUG ((
741 DEBUG_VERBOSE,
742 "WRMSR #VE happened, ExitReasion is %d, ExitQualification = 0x%x. Regs->Rcx=0x%llx, Status = 0x%llx\n",
743 ReturnData.VeInfo.ExitReason,
744 ReturnData.VeInfo.ExitQualification.Val,
745 Regs->Rcx,
746 Status
747 ));
748 break;
749
750 case EXIT_REASON_EPT_VIOLATION:
751 Status = MmioExit (Regs, &ReturnData.VeInfo);
752 DEBUG ((
753 DEBUG_VERBOSE,
754 "MMIO #VE happened, ExitReasion is %d, ExitQualification = 0x%x.\n",
755 ReturnData.VeInfo.ExitReason,
756 ReturnData.VeInfo.ExitQualification.Val
757 ));
758 break;
759
760 case EXIT_REASON_VMCALL:
761 case EXIT_REASON_MWAIT_INSTRUCTION:
762 case EXIT_REASON_MONITOR_INSTRUCTION:
763 case EXIT_REASON_WBINVD:
764 case EXIT_REASON_RDPMC:
765 case EXIT_REASON_INVD:
766 /* Handle as nops. */
767 break;
768
769 default:
770 DEBUG ((
771 DEBUG_ERROR,
772 "Unsupported #VE happened, ExitReason is %d, ExitQualification = 0x%x.\n",
773 ReturnData.VeInfo.ExitReason,
774 ReturnData.VeInfo.ExitQualification.Val
775 ));
776
777 ASSERT (FALSE);
778 CpuDeadLoop ();
779 }
780
781 if (Status) {
782 DEBUG ((
783 DEBUG_ERROR,
784 "#VE Error (0x%llx) returned from host, ExitReason is %d, ExitQualification = 0x%x.\n",
785 Status,
786 ReturnData.VeInfo.ExitReason,
787 ReturnData.VeInfo.ExitQualification.Val
788 ));
789
790 TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
791 CpuDeadLoop ();
792 }
793
794 SystemContext.SystemContextX64->Rip += ReturnData.VeInfo.ExitInstructionLength;
795 return EFI_SUCCESS;
796 }