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