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