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