]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/CcExitLib/CcExitVcHandler.c
OvmfPkg/PeilessStartupLib: Find NCCFV in non-td guest
[mirror_edk2.git] / OvmfPkg / Library / CcExitLib / CcExitVcHandler.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
85b8eac5 12#include <Library/LocalApicLib.h>\r
5667dc43 13#include <Library/MemEncryptSevLib.h>\r
a89f558d 14#include <Library/CcExitLib.h>\r
61bacc0f 15#include <Register/Amd/Msr.h>\r
6587e08d 16#include <Register/Intel/Cpuid.h>\r
fb040cce
TL
17#include <IndustryStandard/InstructionParsing.h>\r
18\r
a89f558d 19#include "CcExitVcHandler.h"\r
5667dc43 20\r
fb040cce
TL
21//\r
22// Instruction execution mode definition\r
23//\r
24typedef enum {\r
ac0a286f 25 LongMode64Bit = 0,\r
fb040cce
TL
26 LongModeCompat32Bit,\r
27 LongModeCompat16Bit,\r
28} SEV_ES_INSTRUCTION_MODE;\r
29\r
30//\r
31// Instruction size definition (for operand and address)\r
32//\r
33typedef enum {\r
ac0a286f 34 Size8Bits = 0,\r
fb040cce
TL
35 Size16Bits,\r
36 Size32Bits,\r
37 Size64Bits,\r
38} SEV_ES_INSTRUCTION_SIZE;\r
39\r
40//\r
41// Intruction segment definition\r
42//\r
43typedef enum {\r
ac0a286f 44 SegmentEs = 0,\r
fb040cce
TL
45 SegmentCs,\r
46 SegmentSs,\r
47 SegmentDs,\r
48 SegmentFs,\r
49 SegmentGs,\r
50} SEV_ES_INSTRUCTION_SEGMENT;\r
51\r
52//\r
53// Instruction rep function definition\r
54//\r
55typedef enum {\r
ac0a286f 56 RepNone = 0,\r
fb040cce
TL
57 RepZ,\r
58 RepNZ,\r
59} SEV_ES_INSTRUCTION_REP;\r
60\r
61typedef struct {\r
ac0a286f
MK
62 UINT8 Rm;\r
63 UINT8 Reg;\r
64 UINT8 Mod;\r
fb040cce
TL
65} SEV_ES_INSTRUCTION_MODRM_EXT;\r
66\r
67typedef struct {\r
ac0a286f
MK
68 UINT8 Base;\r
69 UINT8 Index;\r
70 UINT8 Scale;\r
fb040cce
TL
71} SEV_ES_INSTRUCTION_SIB_EXT;\r
72\r
73//\r
74// Instruction opcode definition\r
75//\r
76typedef struct {\r
ac0a286f 77 SEV_ES_INSTRUCTION_MODRM_EXT ModRm;\r
fb040cce 78\r
ac0a286f 79 SEV_ES_INSTRUCTION_SIB_EXT Sib;\r
fb040cce 80\r
ac0a286f
MK
81 UINTN RegData;\r
82 UINTN RmData;\r
fb040cce
TL
83} SEV_ES_INSTRUCTION_OPCODE_EXT;\r
84\r
85//\r
86// Instruction parsing context definition\r
87//\r
88typedef struct {\r
ac0a286f 89 GHCB *Ghcb;\r
fb040cce 90\r
ac0a286f
MK
91 SEV_ES_INSTRUCTION_MODE Mode;\r
92 SEV_ES_INSTRUCTION_SIZE DataSize;\r
93 SEV_ES_INSTRUCTION_SIZE AddrSize;\r
94 BOOLEAN SegmentSpecified;\r
95 SEV_ES_INSTRUCTION_SEGMENT Segment;\r
96 SEV_ES_INSTRUCTION_REP RepMode;\r
fb040cce 97\r
ac0a286f
MK
98 UINT8 *Begin;\r
99 UINT8 *End;\r
fb040cce 100\r
ac0a286f
MK
101 UINT8 *Prefixes;\r
102 UINT8 *OpCodes;\r
103 UINT8 *Displacement;\r
104 UINT8 *Immediate;\r
fb040cce 105\r
ac0a286f 106 INSTRUCTION_REX_PREFIX RexPrefix;\r
fb040cce 107\r
ac0a286f
MK
108 BOOLEAN ModRmPresent;\r
109 INSTRUCTION_MODRM ModRm;\r
fb040cce 110\r
ac0a286f
MK
111 BOOLEAN SibPresent;\r
112 INSTRUCTION_SIB Sib;\r
fb040cce 113\r
ac0a286f
MK
114 UINTN PrefixSize;\r
115 UINTN OpCodeSize;\r
116 UINTN DisplacementSize;\r
117 UINTN ImmediateSize;\r
fb040cce 118\r
ac0a286f 119 SEV_ES_INSTRUCTION_OPCODE_EXT Ext;\r
fb040cce
TL
120} SEV_ES_INSTRUCTION_DATA;\r
121\r
122//\r
123// Non-automatic Exit function prototype\r
124//\r
125typedef\r
126UINT64\r
127(*NAE_EXIT) (\r
128 GHCB *Ghcb,\r
129 EFI_SYSTEM_CONTEXT_X64 *Regs,\r
130 SEV_ES_INSTRUCTION_DATA *InstructionData\r
131 );\r
132\r
d2b998fb
MR
133//\r
134// SEV-SNP Cpuid table entry/function\r
135//\r
136typedef PACKED struct {\r
137 UINT32 EaxIn;\r
138 UINT32 EcxIn;\r
139 UINT64 Unused;\r
140 UINT64 Unused2;\r
141 UINT32 Eax;\r
142 UINT32 Ebx;\r
143 UINT32 Ecx;\r
144 UINT32 Edx;\r
145 UINT64 Reserved;\r
146} SEV_SNP_CPUID_FUNCTION;\r
147\r
148//\r
149// SEV-SNP Cpuid page format\r
150//\r
151typedef PACKED struct {\r
152 UINT32 Count;\r
153 UINT32 Reserved1;\r
154 UINT64 Reserved2;\r
155 SEV_SNP_CPUID_FUNCTION function[0];\r
156} SEV_SNP_CPUID_INFO;\r
157\r
c45f678a
TL
158/**\r
159 Return a pointer to the contents of the specified register.\r
160\r
161 Based upon the input register, return a pointer to the registers contents\r
162 in the x86 processor context.\r
163\r
164 @param[in] Regs x64 processor context\r
165 @param[in] Register Register to obtain pointer for\r
166\r
167 @return Pointer to the contents of the requested register\r
168\r
169**/\r
170STATIC\r
171UINT64 *\r
172GetRegisterPointer (\r
ac0a286f
MK
173 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
174 IN UINT8 Register\r
c45f678a
TL
175 )\r
176{\r
ac0a286f 177 UINT64 *Reg;\r
c45f678a
TL
178\r
179 switch (Register) {\r
ac0a286f
MK
180 case 0:\r
181 Reg = &Regs->Rax;\r
182 break;\r
183 case 1:\r
184 Reg = &Regs->Rcx;\r
185 break;\r
186 case 2:\r
187 Reg = &Regs->Rdx;\r
188 break;\r
189 case 3:\r
190 Reg = &Regs->Rbx;\r
191 break;\r
192 case 4:\r
193 Reg = &Regs->Rsp;\r
194 break;\r
195 case 5:\r
196 Reg = &Regs->Rbp;\r
197 break;\r
198 case 6:\r
199 Reg = &Regs->Rsi;\r
200 break;\r
201 case 7:\r
202 Reg = &Regs->Rdi;\r
203 break;\r
204 case 8:\r
205 Reg = &Regs->R8;\r
206 break;\r
207 case 9:\r
208 Reg = &Regs->R9;\r
209 break;\r
210 case 10:\r
211 Reg = &Regs->R10;\r
212 break;\r
213 case 11:\r
214 Reg = &Regs->R11;\r
215 break;\r
216 case 12:\r
217 Reg = &Regs->R12;\r
218 break;\r
219 case 13:\r
220 Reg = &Regs->R13;\r
221 break;\r
222 case 14:\r
223 Reg = &Regs->R14;\r
224 break;\r
225 case 15:\r
226 Reg = &Regs->R15;\r
227 break;\r
228 default:\r
229 Reg = NULL;\r
c45f678a 230 }\r
ac0a286f 231\r
c45f678a
TL
232 ASSERT (Reg != NULL);\r
233\r
234 return Reg;\r
235}\r
236\r
237/**\r
238 Update the instruction parsing context for displacement bytes.\r
239\r
240 @param[in, out] InstructionData Instruction parsing context\r
241 @param[in] Size The instruction displacement size\r
242\r
243**/\r
244STATIC\r
245VOID\r
246UpdateForDisplacement (\r
247 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,\r
248 IN UINTN Size\r
249 )\r
250{\r
251 InstructionData->DisplacementSize = Size;\r
ac0a286f
MK
252 InstructionData->Immediate += Size;\r
253 InstructionData->End += Size;\r
c45f678a
TL
254}\r
255\r
256/**\r
257 Determine if an instruction address if RIP relative.\r
258\r
259 Examine the instruction parsing context to determine if the address offset\r
260 is relative to the instruction pointer.\r
261\r
262 @param[in] InstructionData Instruction parsing context\r
263\r
264 @retval TRUE Instruction addressing is RIP relative\r
265 @retval FALSE Instruction addressing is not RIP relative\r
266\r
267**/\r
268STATIC\r
269BOOLEAN\r
270IsRipRelative (\r
271 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
272 )\r
273{\r
274 SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
275\r
276 Ext = &InstructionData->Ext;\r
277\r
278 return ((InstructionData->Mode == LongMode64Bit) &&\r
279 (Ext->ModRm.Mod == 0) &&\r
280 (Ext->ModRm.Rm == 5) &&\r
281 (InstructionData->SibPresent == FALSE));\r
282}\r
283\r
284/**\r
285 Return the effective address of a memory operand.\r
286\r
287 Examine the instruction parsing context to obtain the effective memory\r
288 address of a memory operand.\r
289\r
290 @param[in] Regs x64 processor context\r
291 @param[in] InstructionData Instruction parsing context\r
292\r
293 @return The memory operand effective address\r
294\r
295**/\r
296STATIC\r
297UINT64\r
298GetEffectiveMemoryAddress (\r
299 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
300 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
301 )\r
302{\r
303 SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
304 UINT64 EffectiveAddress;\r
305\r
ac0a286f 306 Ext = &InstructionData->Ext;\r
c45f678a
TL
307 EffectiveAddress = 0;\r
308\r
309 if (IsRipRelative (InstructionData)) {\r
310 //\r
311 // RIP-relative displacement is a 32-bit signed value\r
312 //\r
ac0a286f 313 INT32 RipRelative;\r
c45f678a 314\r
ac0a286f 315 RipRelative = *(INT32 *)InstructionData->Displacement;\r
c45f678a
TL
316\r
317 UpdateForDisplacement (InstructionData, 4);\r
318\r
319 //\r
320 // Negative displacement is handled by standard UINT64 wrap-around.\r
321 //\r
ac0a286f 322 return Regs->Rip + (UINT64)RipRelative;\r
c45f678a
TL
323 }\r
324\r
325 switch (Ext->ModRm.Mod) {\r
ac0a286f
MK
326 case 1:\r
327 UpdateForDisplacement (InstructionData, 1);\r
328 EffectiveAddress += (UINT64)(*(INT8 *)(InstructionData->Displacement));\r
c45f678a 329 break;\r
ac0a286f
MK
330 case 2:\r
331 switch (InstructionData->AddrSize) {\r
332 case Size16Bits:\r
333 UpdateForDisplacement (InstructionData, 2);\r
334 EffectiveAddress += (UINT64)(*(INT16 *)(InstructionData->Displacement));\r
335 break;\r
336 default:\r
337 UpdateForDisplacement (InstructionData, 4);\r
338 EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement));\r
339 break;\r
340 }\r
341\r
c45f678a 342 break;\r
c45f678a
TL
343 }\r
344\r
345 if (InstructionData->SibPresent) {\r
346 INT64 Displacement;\r
347\r
348 if (Ext->Sib.Index != 4) {\r
349 CopyMem (\r
350 &Displacement,\r
351 GetRegisterPointer (Regs, Ext->Sib.Index),\r
352 sizeof (Displacement)\r
353 );\r
354 Displacement *= (INT64)(1 << Ext->Sib.Scale);\r
355\r
356 //\r
357 // Negative displacement is handled by standard UINT64 wrap-around.\r
358 //\r
ac0a286f 359 EffectiveAddress += (UINT64)Displacement;\r
c45f678a
TL
360 }\r
361\r
362 if ((Ext->Sib.Base != 5) || Ext->ModRm.Mod) {\r
363 EffectiveAddress += *GetRegisterPointer (Regs, Ext->Sib.Base);\r
364 } else {\r
365 UpdateForDisplacement (InstructionData, 4);\r
ac0a286f 366 EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement));\r
c45f678a
TL
367 }\r
368 } else {\r
369 EffectiveAddress += *GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
370 }\r
371\r
372 return EffectiveAddress;\r
373}\r
374\r
375/**\r
376 Decode a ModRM byte.\r
377\r
378 Examine the instruction parsing context to decode a ModRM byte and the SIB\r
379 byte, if present.\r
380\r
381 @param[in] Regs x64 processor context\r
382 @param[in, out] InstructionData Instruction parsing context\r
383\r
384**/\r
385STATIC\r
386VOID\r
387DecodeModRm (\r
388 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
389 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
390 )\r
391{\r
392 SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
393 INSTRUCTION_REX_PREFIX *RexPrefix;\r
394 INSTRUCTION_MODRM *ModRm;\r
395 INSTRUCTION_SIB *Sib;\r
396\r
397 RexPrefix = &InstructionData->RexPrefix;\r
ac0a286f
MK
398 Ext = &InstructionData->Ext;\r
399 ModRm = &InstructionData->ModRm;\r
400 Sib = &InstructionData->Sib;\r
c45f678a
TL
401\r
402 InstructionData->ModRmPresent = TRUE;\r
ac0a286f 403 ModRm->Uint8 = *(InstructionData->End);\r
c45f678a
TL
404\r
405 InstructionData->Displacement++;\r
406 InstructionData->Immediate++;\r
407 InstructionData->End++;\r
408\r
409 Ext->ModRm.Mod = ModRm->Bits.Mod;\r
410 Ext->ModRm.Reg = (RexPrefix->Bits.BitR << 3) | ModRm->Bits.Reg;\r
411 Ext->ModRm.Rm = (RexPrefix->Bits.BitB << 3) | ModRm->Bits.Rm;\r
412\r
413 Ext->RegData = *GetRegisterPointer (Regs, Ext->ModRm.Reg);\r
414\r
415 if (Ext->ModRm.Mod == 3) {\r
416 Ext->RmData = *GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
417 } else {\r
418 if (ModRm->Bits.Rm == 4) {\r
419 InstructionData->SibPresent = TRUE;\r
ac0a286f 420 Sib->Uint8 = *(InstructionData->End);\r
c45f678a
TL
421\r
422 InstructionData->Displacement++;\r
423 InstructionData->Immediate++;\r
424 InstructionData->End++;\r
425\r
426 Ext->Sib.Scale = Sib->Bits.Scale;\r
427 Ext->Sib.Index = (RexPrefix->Bits.BitX << 3) | Sib->Bits.Index;\r
428 Ext->Sib.Base = (RexPrefix->Bits.BitB << 3) | Sib->Bits.Base;\r
429 }\r
430\r
431 Ext->RmData = GetEffectiveMemoryAddress (Regs, InstructionData);\r
432 }\r
433}\r
434\r
fb040cce
TL
435/**\r
436 Decode instruction prefixes.\r
437\r
438 Parse the instruction data to track the instruction prefixes that have\r
439 been used.\r
440\r
441 @param[in] Regs x64 processor context\r
442 @param[in, out] InstructionData Instruction parsing context\r
443\r
444**/\r
445STATIC\r
446VOID\r
447DecodePrefixes (\r
448 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
449 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
450 )\r
451{\r
452 SEV_ES_INSTRUCTION_MODE Mode;\r
453 SEV_ES_INSTRUCTION_SIZE ModeDataSize;\r
454 SEV_ES_INSTRUCTION_SIZE ModeAddrSize;\r
455 UINT8 *Byte;\r
456\r
457 //\r
458 // Always in 64-bit mode\r
459 //\r
ac0a286f 460 Mode = LongMode64Bit;\r
fb040cce
TL
461 ModeDataSize = Size32Bits;\r
462 ModeAddrSize = Size64Bits;\r
463\r
ac0a286f 464 InstructionData->Mode = Mode;\r
fb040cce
TL
465 InstructionData->DataSize = ModeDataSize;\r
466 InstructionData->AddrSize = ModeAddrSize;\r
467\r
468 InstructionData->Prefixes = InstructionData->Begin;\r
469\r
470 Byte = InstructionData->Prefixes;\r
471 for ( ; ; Byte++, InstructionData->PrefixSize++) {\r
472 //\r
473 // Check the 0x40 to 0x4F range using an if statement here since some\r
474 // compilers don't like the "case 0x40 ... 0x4F:" syntax. This avoids\r
475 // 16 case statements below.\r
476 //\r
477 if ((*Byte >= REX_PREFIX_START) && (*Byte <= REX_PREFIX_STOP)) {\r
478 InstructionData->RexPrefix.Uint8 = *Byte;\r
479 if ((*Byte & REX_64BIT_OPERAND_SIZE_MASK) != 0) {\r
480 InstructionData->DataSize = Size64Bits;\r
481 }\r
ac0a286f 482\r
fb040cce
TL
483 continue;\r
484 }\r
485\r
486 switch (*Byte) {\r
ac0a286f
MK
487 case OVERRIDE_SEGMENT_CS:\r
488 case OVERRIDE_SEGMENT_DS:\r
489 case OVERRIDE_SEGMENT_ES:\r
490 case OVERRIDE_SEGMENT_SS:\r
491 if (Mode != LongMode64Bit) {\r
492 InstructionData->SegmentSpecified = TRUE;\r
493 InstructionData->Segment = (*Byte >> 3) & 3;\r
494 }\r
495\r
496 break;\r
497\r
498 case OVERRIDE_SEGMENT_FS:\r
499 case OVERRIDE_SEGMENT_GS:\r
fb040cce 500 InstructionData->SegmentSpecified = TRUE;\r
ac0a286f
MK
501 InstructionData->Segment = *Byte & 7;\r
502 break;\r
503\r
504 case OVERRIDE_OPERAND_SIZE:\r
505 if (InstructionData->RexPrefix.Uint8 == 0) {\r
506 InstructionData->DataSize =\r
507 (Mode == LongMode64Bit) ? Size16Bits :\r
508 (Mode == LongModeCompat32Bit) ? Size16Bits :\r
509 (Mode == LongModeCompat16Bit) ? Size32Bits : 0;\r
510 }\r
511\r
512 break;\r
513\r
514 case OVERRIDE_ADDRESS_SIZE:\r
515 InstructionData->AddrSize =\r
516 (Mode == LongMode64Bit) ? Size32Bits :\r
fb040cce
TL
517 (Mode == LongModeCompat32Bit) ? Size16Bits :\r
518 (Mode == LongModeCompat16Bit) ? Size32Bits : 0;\r
ac0a286f 519 break;\r
fb040cce 520\r
ac0a286f
MK
521 case LOCK_PREFIX:\r
522 break;\r
fb040cce 523\r
ac0a286f
MK
524 case REPZ_PREFIX:\r
525 InstructionData->RepMode = RepZ;\r
526 break;\r
fb040cce 527\r
ac0a286f
MK
528 case REPNZ_PREFIX:\r
529 InstructionData->RepMode = RepNZ;\r
530 break;\r
fb040cce 531\r
ac0a286f
MK
532 default:\r
533 InstructionData->OpCodes = Byte;\r
534 InstructionData->OpCodeSize = (*Byte == TWO_BYTE_OPCODE_ESCAPE) ? 2 : 1;\r
fb040cce 535\r
ac0a286f
MK
536 InstructionData->End = Byte + InstructionData->OpCodeSize;\r
537 InstructionData->Displacement = InstructionData->End;\r
538 InstructionData->Immediate = InstructionData->End;\r
539 return;\r
fb040cce
TL
540 }\r
541 }\r
542}\r
543\r
544/**\r
545 Determine instruction length\r
546\r
547 Return the total length of the parsed instruction.\r
548\r
549 @param[in] InstructionData Instruction parsing context\r
550\r
551 @return Length of parsed instruction\r
552\r
553**/\r
554STATIC\r
555UINT64\r
556InstructionLength (\r
557 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
558 )\r
559{\r
ac0a286f 560 return (UINT64)(InstructionData->End - InstructionData->Begin);\r
fb040cce
TL
561}\r
562\r
563/**\r
564 Initialize the instruction parsing context.\r
565\r
566 Initialize the instruction parsing context, which includes decoding the\r
567 instruction prefixes.\r
568\r
569 @param[in, out] InstructionData Instruction parsing context\r
570 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication\r
571 Block\r
572 @param[in] Regs x64 processor context\r
573\r
574**/\r
575STATIC\r
576VOID\r
577InitInstructionData (\r
578 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,\r
579 IN GHCB *Ghcb,\r
580 IN EFI_SYSTEM_CONTEXT_X64 *Regs\r
581 )\r
582{\r
583 SetMem (InstructionData, sizeof (*InstructionData), 0);\r
ac0a286f
MK
584 InstructionData->Ghcb = Ghcb;\r
585 InstructionData->Begin = (UINT8 *)Regs->Rip;\r
586 InstructionData->End = (UINT8 *)Regs->Rip;\r
fb040cce
TL
587\r
588 DecodePrefixes (Regs, InstructionData);\r
589}\r
590\r
591/**\r
592 Report an unsupported event to the hypervisor\r
593\r
594 Use the VMGEXIT support to report an unsupported event to the hypervisor.\r
595\r
596 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication\r
597 Block\r
598 @param[in] Regs x64 processor context\r
599 @param[in] InstructionData Instruction parsing context\r
600\r
601 @return New exception value to propagate\r
602\r
603**/\r
604STATIC\r
605UINT64\r
606UnsupportedExit (\r
607 IN GHCB *Ghcb,\r
608 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
609 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
610 )\r
611{\r
612 UINT64 Status;\r
613\r
765ba5bf 614 Status = CcExitVmgExit (Ghcb, SVM_EXIT_UNSUPPORTED, Regs->ExceptionData, 0);\r
fb040cce
TL
615 if (Status == 0) {\r
616 GHCB_EVENT_INJECTION Event;\r
617\r
ac0a286f 618 Event.Uint64 = 0;\r
fb040cce
TL
619 Event.Elements.Vector = GP_EXCEPTION;\r
620 Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;\r
621 Event.Elements.Valid = 1;\r
622\r
623 Status = Event.Uint64;\r
624 }\r
625\r
626 return Status;\r
627}\r
628\r
85b8eac5
TL
629/**\r
630 Validate that the MMIO memory access is not to encrypted memory.\r
631\r
632 Examine the pagetable entry for the memory specified. MMIO should not be\r
633 performed against encrypted memory. MMIO to the APIC page is always allowed.\r
634\r
635 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication Block\r
636 @param[in] MemoryAddress Memory address to validate\r
637 @param[in] MemoryLength Memory length to validate\r
638\r
639 @retval 0 Memory is not encrypted\r
640 @return New exception value to propogate\r
641\r
642**/\r
643STATIC\r
644UINT64\r
645ValidateMmioMemory (\r
646 IN GHCB *Ghcb,\r
647 IN UINTN MemoryAddress,\r
648 IN UINTN MemoryLength\r
649 )\r
650{\r
651 MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State;\r
652 GHCB_EVENT_INJECTION GpEvent;\r
653 UINTN Address;\r
654\r
655 //\r
656 // Allow APIC accesses (which will have the encryption bit set during\r
657 // SEC and PEI phases).\r
658 //\r
659 Address = MemoryAddress & ~(SIZE_4KB - 1);\r
660 if (Address == GetLocalApicBaseAddress ()) {\r
661 return 0;\r
662 }\r
663\r
664 State = MemEncryptSevGetAddressRangeState (\r
665 0,\r
666 MemoryAddress,\r
667 MemoryLength\r
668 );\r
669 if (State == MemEncryptSevAddressRangeUnencrypted) {\r
670 return 0;\r
671 }\r
672\r
673 //\r
674 // Any state other than unencrypted is an error, issue a #GP.\r
675 //\r
ac0a286f
MK
676 DEBUG ((\r
677 DEBUG_ERROR,\r
75d1a790 678 "MMIO using encrypted memory: %lx\n",\r
ac0a286f
MK
679 (UINT64)MemoryAddress\r
680 ));\r
681 GpEvent.Uint64 = 0;\r
85b8eac5
TL
682 GpEvent.Elements.Vector = GP_EXCEPTION;\r
683 GpEvent.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;\r
684 GpEvent.Elements.Valid = 1;\r
685\r
686 return GpEvent.Uint64;\r
687}\r
688\r
c45f678a
TL
689/**\r
690 Handle an MMIO event.\r
691\r
692 Use the VMGEXIT instruction to handle either an MMIO read or an MMIO write.\r
693\r
694 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
695 Block\r
696 @param[in, out] Regs x64 processor context\r
697 @param[in, out] InstructionData Instruction parsing context\r
698\r
699 @retval 0 Event handled successfully\r
700 @return New exception value to propagate\r
701\r
702**/\r
703STATIC\r
704UINT64\r
705MmioExit (\r
706 IN OUT GHCB *Ghcb,\r
707 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
708 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
709 )\r
710{\r
711 UINT64 ExitInfo1, ExitInfo2, Status;\r
712 UINTN Bytes;\r
713 UINT64 *Register;\r
714 UINT8 OpCode, SignByte;\r
cc71bd97 715 UINTN Address;\r
c45f678a
TL
716\r
717 Bytes = 0;\r
718\r
719 OpCode = *(InstructionData->OpCodes);\r
720 if (OpCode == TWO_BYTE_OPCODE_ESCAPE) {\r
721 OpCode = *(InstructionData->OpCodes + 1);\r
722 }\r
723\r
724 switch (OpCode) {\r
ac0a286f
MK
725 //\r
726 // MMIO write (MOV reg/memX, regX)\r
727 //\r
728 case 0x88:\r
729 Bytes = 1;\r
c45f678a
TL
730 //\r
731 // fall through\r
732 //\r
ac0a286f
MK
733 case 0x89:\r
734 DecodeModRm (Regs, InstructionData);\r
735 Bytes = ((Bytes != 0) ? Bytes :\r
736 (InstructionData->DataSize == Size16Bits) ? 2 :\r
737 (InstructionData->DataSize == Size32Bits) ? 4 :\r
738 (InstructionData->DataSize == Size64Bits) ? 8 :\r
739 0);\r
740\r
741 if (InstructionData->Ext.ModRm.Mod == 3) {\r
742 //\r
743 // NPF on two register operands???\r
744 //\r
745 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
746 }\r
c45f678a 747\r
ac0a286f
MK
748 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
749 if (Status != 0) {\r
750 return Status;\r
751 }\r
85b8eac5 752\r
ac0a286f
MK
753 ExitInfo1 = InstructionData->Ext.RmData;\r
754 ExitInfo2 = Bytes;\r
755 CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes);\r
c45f678a 756\r
ac0a286f 757 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
765ba5bf
MX
758 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
759 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
ac0a286f
MK
760 if (Status != 0) {\r
761 return Status;\r
762 }\r
c45f678a 763\r
ac0a286f
MK
764 break;\r
765\r
766 //\r
767 // MMIO write (MOV moffsetX, aX)\r
768 //\r
769 case 0xA2:\r
770 Bytes = 1;\r
cc71bd97
TL
771 //\r
772 // fall through\r
773 //\r
ac0a286f
MK
774 case 0xA3:\r
775 Bytes = ((Bytes != 0) ? Bytes :\r
776 (InstructionData->DataSize == Size16Bits) ? 2 :\r
777 (InstructionData->DataSize == Size32Bits) ? 4 :\r
778 (InstructionData->DataSize == Size64Bits) ? 8 :\r
779 0);\r
cc71bd97 780\r
ac0a286f
MK
781 InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);\r
782 InstructionData->End += InstructionData->ImmediateSize;\r
cc71bd97 783\r
ac0a286f
MK
784 //\r
785 // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.\r
786 // Use a STATIC_ASSERT to be certain the code is being built as X64.\r
787 //\r
788 STATIC_ASSERT (\r
789 sizeof (UINTN) == sizeof (UINT64),\r
790 "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"\r
791 );\r
cc71bd97 792\r
ac0a286f
MK
793 Address = 0;\r
794 CopyMem (\r
795 &Address,\r
796 InstructionData->Immediate,\r
797 InstructionData->ImmediateSize\r
798 );\r
cc71bd97 799\r
ac0a286f
MK
800 Status = ValidateMmioMemory (Ghcb, Address, Bytes);\r
801 if (Status != 0) {\r
802 return Status;\r
803 }\r
cc71bd97 804\r
ac0a286f
MK
805 ExitInfo1 = Address;\r
806 ExitInfo2 = Bytes;\r
807 CopyMem (Ghcb->SharedBuffer, &Regs->Rax, Bytes);\r
808\r
809 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
765ba5bf
MX
810 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
811 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
ac0a286f
MK
812 if (Status != 0) {\r
813 return Status;\r
814 }\r
815\r
816 break;\r
817\r
818 //\r
819 // MMIO write (MOV reg/memX, immX)\r
820 //\r
821 case 0xC6:\r
822 Bytes = 1;\r
c45f678a
TL
823 //\r
824 // fall through\r
825 //\r
ac0a286f
MK
826 case 0xC7:\r
827 DecodeModRm (Regs, InstructionData);\r
828 Bytes = ((Bytes != 0) ? Bytes :\r
829 (InstructionData->DataSize == Size16Bits) ? 2 :\r
830 (InstructionData->DataSize == Size32Bits) ? 4 :\r
831 0);\r
c45f678a 832\r
ac0a286f
MK
833 InstructionData->ImmediateSize = Bytes;\r
834 InstructionData->End += Bytes;\r
c45f678a 835\r
ac0a286f
MK
836 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
837 if (Status != 0) {\r
838 return Status;\r
839 }\r
85b8eac5 840\r
ac0a286f
MK
841 ExitInfo1 = InstructionData->Ext.RmData;\r
842 ExitInfo2 = Bytes;\r
843 CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, Bytes);\r
c45f678a 844\r
ac0a286f 845 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
765ba5bf
MX
846 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
847 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
ac0a286f
MK
848 if (Status != 0) {\r
849 return Status;\r
850 }\r
c45f678a 851\r
ac0a286f
MK
852 break;\r
853\r
854 //\r
855 // MMIO read (MOV regX, reg/memX)\r
856 //\r
857 case 0x8A:\r
858 Bytes = 1;\r
c45f678a
TL
859 //\r
860 // fall through\r
861 //\r
ac0a286f
MK
862 case 0x8B:\r
863 DecodeModRm (Regs, InstructionData);\r
864 Bytes = ((Bytes != 0) ? Bytes :\r
865 (InstructionData->DataSize == Size16Bits) ? 2 :\r
866 (InstructionData->DataSize == Size32Bits) ? 4 :\r
867 (InstructionData->DataSize == Size64Bits) ? 8 :\r
868 0);\r
869 if (InstructionData->Ext.ModRm.Mod == 3) {\r
870 //\r
871 // NPF on two register operands???\r
872 //\r
873 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
874 }\r
c45f678a 875\r
ac0a286f
MK
876 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
877 if (Status != 0) {\r
878 return Status;\r
879 }\r
85b8eac5 880\r
ac0a286f
MK
881 ExitInfo1 = InstructionData->Ext.RmData;\r
882 ExitInfo2 = Bytes;\r
c45f678a 883\r
ac0a286f 884 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
765ba5bf
MX
885 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
886 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
ac0a286f
MK
887 if (Status != 0) {\r
888 return Status;\r
889 }\r
c45f678a 890\r
ac0a286f
MK
891 Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
892 if (Bytes == 4) {\r
893 //\r
894 // Zero-extend for 32-bit operation\r
895 //\r
896 *Register = 0;\r
897 }\r
898\r
899 CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
900 break;\r
c45f678a 901\r
cc71bd97 902 //\r
ac0a286f 903 // MMIO read (MOV aX, moffsetX)\r
cc71bd97 904 //\r
ac0a286f
MK
905 case 0xA0:\r
906 Bytes = 1;\r
cc71bd97 907 //\r
ac0a286f 908 // fall through\r
cc71bd97 909 //\r
ac0a286f
MK
910 case 0xA1:\r
911 Bytes = ((Bytes != 0) ? Bytes :\r
912 (InstructionData->DataSize == Size16Bits) ? 2 :\r
913 (InstructionData->DataSize == Size32Bits) ? 4 :\r
914 (InstructionData->DataSize == Size64Bits) ? 8 :\r
915 0);\r
cc71bd97 916\r
ac0a286f
MK
917 InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);\r
918 InstructionData->End += InstructionData->ImmediateSize;\r
cc71bd97 919\r
cc71bd97 920 //\r
ac0a286f
MK
921 // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.\r
922 // Use a STATIC_ASSERT to be certain the code is being built as X64.\r
cc71bd97 923 //\r
ac0a286f
MK
924 STATIC_ASSERT (\r
925 sizeof (UINTN) == sizeof (UINT64),\r
926 "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"\r
927 );\r
cc71bd97 928\r
ac0a286f
MK
929 Address = 0;\r
930 CopyMem (\r
931 &Address,\r
932 InstructionData->Immediate,\r
933 InstructionData->ImmediateSize\r
934 );\r
935\r
936 Status = ValidateMmioMemory (Ghcb, Address, Bytes);\r
937 if (Status != 0) {\r
938 return Status;\r
939 }\r
940\r
941 ExitInfo1 = Address;\r
942 ExitInfo2 = Bytes;\r
943\r
944 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
765ba5bf
MX
945 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
946 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
ac0a286f
MK
947 if (Status != 0) {\r
948 return Status;\r
949 }\r
950\r
951 if (Bytes == 4) {\r
952 //\r
953 // Zero-extend for 32-bit operation\r
954 //\r
955 Regs->Rax = 0;\r
956 }\r
957\r
958 CopyMem (&Regs->Rax, Ghcb->SharedBuffer, Bytes);\r
959 break;\r
960\r
961 //\r
962 // MMIO read w/ zero-extension ((MOVZX regX, reg/memX)\r
963 //\r
964 case 0xB6:\r
965 Bytes = 1;\r
c45f678a
TL
966 //\r
967 // fall through\r
968 //\r
ac0a286f
MK
969 case 0xB7:\r
970 DecodeModRm (Regs, InstructionData);\r
971 Bytes = (Bytes != 0) ? Bytes : 2;\r
c45f678a 972\r
ac0a286f
MK
973 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
974 if (Status != 0) {\r
975 return Status;\r
976 }\r
85b8eac5 977\r
ac0a286f
MK
978 ExitInfo1 = InstructionData->Ext.RmData;\r
979 ExitInfo2 = Bytes;\r
c45f678a 980\r
ac0a286f 981 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
765ba5bf
MX
982 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
983 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
ac0a286f
MK
984 if (Status != 0) {\r
985 return Status;\r
986 }\r
c45f678a 987\r
ac0a286f
MK
988 Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
989 SetMem (Register, (UINTN)(1 << InstructionData->DataSize), 0);\r
990 CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
991 break;\r
c45f678a 992\r
ac0a286f
MK
993 //\r
994 // MMIO read w/ sign-extension (MOVSX regX, reg/memX)\r
995 //\r
996 case 0xBE:\r
997 Bytes = 1;\r
c45f678a
TL
998 //\r
999 // fall through\r
1000 //\r
ac0a286f
MK
1001 case 0xBF:\r
1002 DecodeModRm (Regs, InstructionData);\r
1003 Bytes = (Bytes != 0) ? Bytes : 2;\r
c45f678a 1004\r
ac0a286f
MK
1005 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
1006 if (Status != 0) {\r
1007 return Status;\r
1008 }\r
85b8eac5 1009\r
ac0a286f
MK
1010 ExitInfo1 = InstructionData->Ext.RmData;\r
1011 ExitInfo2 = Bytes;\r
c45f678a 1012\r
ac0a286f 1013 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
765ba5bf
MX
1014 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
1015 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
ac0a286f
MK
1016 if (Status != 0) {\r
1017 return Status;\r
1018 }\r
c45f678a 1019\r
ac0a286f
MK
1020 if (Bytes == 1) {\r
1021 UINT8 *Data;\r
c45f678a 1022\r
ac0a286f
MK
1023 Data = (UINT8 *)Ghcb->SharedBuffer;\r
1024 SignByte = ((*Data & BIT7) != 0) ? 0xFF : 0x00;\r
1025 } else {\r
1026 UINT16 *Data;\r
c45f678a 1027\r
ac0a286f
MK
1028 Data = (UINT16 *)Ghcb->SharedBuffer;\r
1029 SignByte = ((*Data & BIT15) != 0) ? 0xFF : 0x00;\r
1030 }\r
c45f678a 1031\r
ac0a286f
MK
1032 Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
1033 SetMem (Register, (UINTN)(1 << InstructionData->DataSize), SignByte);\r
1034 CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
1035 break;\r
c45f678a 1036\r
ac0a286f
MK
1037 default:\r
1038 DEBUG ((DEBUG_ERROR, "Invalid MMIO opcode (%x)\n", OpCode));\r
1039 Status = GP_EXCEPTION;\r
1040 ASSERT (FALSE);\r
c45f678a
TL
1041 }\r
1042\r
1043 return Status;\r
1044}\r
1045\r
9f7e0d0a
TL
1046/**\r
1047 Handle a MWAIT event.\r
1048\r
1049 Use the VMGEXIT instruction to handle a MWAIT event.\r
1050\r
1051 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1052 Block\r
1053 @param[in, out] Regs x64 processor context\r
1054 @param[in] InstructionData Instruction parsing context\r
1055\r
1056 @retval 0 Event handled successfully\r
1057 @return New exception value to propagate\r
1058\r
1059**/\r
1060STATIC\r
1061UINT64\r
1062MwaitExit (\r
1063 IN OUT GHCB *Ghcb,\r
1064 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1065 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1066 )\r
1067{\r
1068 DecodeModRm (Regs, InstructionData);\r
1069\r
1070 Ghcb->SaveArea.Rax = Regs->Rax;\r
765ba5bf 1071 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
9f7e0d0a 1072 Ghcb->SaveArea.Rcx = Regs->Rcx;\r
765ba5bf 1073 CcExitVmgSetOffsetValid (Ghcb, GhcbRcx);\r
9f7e0d0a 1074\r
765ba5bf 1075 return CcExitVmgExit (Ghcb, SVM_EXIT_MWAIT, 0, 0);\r
9f7e0d0a
TL
1076}\r
1077\r
3ef8bfc2
TL
1078/**\r
1079 Handle a MONITOR event.\r
1080\r
1081 Use the VMGEXIT instruction to handle a MONITOR event.\r
1082\r
1083 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1084 Block\r
1085 @param[in, out] Regs x64 processor context\r
1086 @param[in] InstructionData Instruction parsing context\r
1087\r
1088 @retval 0 Event handled successfully\r
1089 @return New exception value to propagate\r
1090\r
1091**/\r
1092STATIC\r
1093UINT64\r
1094MonitorExit (\r
1095 IN OUT GHCB *Ghcb,\r
1096 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1097 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1098 )\r
1099{\r
1100 DecodeModRm (Regs, InstructionData);\r
1101\r
1102 Ghcb->SaveArea.Rax = Regs->Rax; // Identity mapped, so VA = PA\r
765ba5bf 1103 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
3ef8bfc2 1104 Ghcb->SaveArea.Rcx = Regs->Rcx;\r
765ba5bf 1105 CcExitVmgSetOffsetValid (Ghcb, GhcbRcx);\r
3ef8bfc2 1106 Ghcb->SaveArea.Rdx = Regs->Rdx;\r
765ba5bf 1107 CcExitVmgSetOffsetValid (Ghcb, GhcbRdx);\r
3ef8bfc2 1108\r
765ba5bf 1109 return CcExitVmgExit (Ghcb, SVM_EXIT_MONITOR, 0, 0);\r
3ef8bfc2
TL
1110}\r
1111\r
4de70479
TL
1112/**\r
1113 Handle a WBINVD event.\r
1114\r
1115 Use the VMGEXIT instruction to handle a WBINVD event.\r
1116\r
1117 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1118 Block\r
1119 @param[in, out] Regs x64 processor context\r
1120 @param[in] InstructionData Instruction parsing context\r
1121\r
1122 @retval 0 Event handled successfully\r
1123 @return New exception value to propagate\r
1124\r
1125**/\r
1126STATIC\r
1127UINT64\r
1128WbinvdExit (\r
1129 IN OUT GHCB *Ghcb,\r
1130 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1131 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1132 )\r
1133{\r
765ba5bf 1134 return CcExitVmgExit (Ghcb, SVM_EXIT_WBINVD, 0, 0);\r
4de70479
TL
1135}\r
1136\r
f4571f24
TL
1137/**\r
1138 Handle a RDTSCP event.\r
1139\r
1140 Use the VMGEXIT instruction to handle a RDTSCP event.\r
1141\r
1142 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1143 Block\r
1144 @param[in, out] Regs x64 processor context\r
1145 @param[in] InstructionData Instruction parsing context\r
1146\r
1147 @retval 0 Event handled successfully\r
1148 @return New exception value to propagate\r
1149\r
1150**/\r
1151STATIC\r
1152UINT64\r
1153RdtscpExit (\r
1154 IN OUT GHCB *Ghcb,\r
1155 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1156 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1157 )\r
1158{\r
1159 UINT64 Status;\r
1160\r
1161 DecodeModRm (Regs, InstructionData);\r
1162\r
765ba5bf 1163 Status = CcExitVmgExit (Ghcb, SVM_EXIT_RDTSCP, 0, 0);\r
f4571f24
TL
1164 if (Status != 0) {\r
1165 return Status;\r
1166 }\r
1167\r
765ba5bf
MX
1168 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax) ||\r
1169 !CcExitVmgIsOffsetValid (Ghcb, GhcbRcx) ||\r
1170 !CcExitVmgIsOffsetValid (Ghcb, GhcbRdx))\r
ac0a286f 1171 {\r
f4571f24
TL
1172 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
1173 }\r
ac0a286f 1174\r
f4571f24
TL
1175 Regs->Rax = Ghcb->SaveArea.Rax;\r
1176 Regs->Rcx = Ghcb->SaveArea.Rcx;\r
1177 Regs->Rdx = Ghcb->SaveArea.Rdx;\r
1178\r
1179 return 0;\r
1180}\r
1181\r
e4bb269a
TL
1182/**\r
1183 Handle a VMMCALL event.\r
1184\r
1185 Use the VMGEXIT instruction to handle a VMMCALL event.\r
1186\r
1187 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1188 Block\r
1189 @param[in, out] Regs x64 processor context\r
1190 @param[in] InstructionData Instruction parsing context\r
1191\r
1192 @retval 0 Event handled successfully\r
1193 @return New exception value to propagate\r
1194\r
1195**/\r
1196STATIC\r
1197UINT64\r
1198VmmCallExit (\r
1199 IN OUT GHCB *Ghcb,\r
1200 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1201 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1202 )\r
1203{\r
1204 UINT64 Status;\r
1205\r
1206 DecodeModRm (Regs, InstructionData);\r
1207\r
1208 Ghcb->SaveArea.Rax = Regs->Rax;\r
765ba5bf 1209 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
ac0a286f 1210 Ghcb->SaveArea.Cpl = (UINT8)(Regs->Cs & 0x3);\r
765ba5bf 1211 CcExitVmgSetOffsetValid (Ghcb, GhcbCpl);\r
e4bb269a 1212\r
765ba5bf 1213 Status = CcExitVmgExit (Ghcb, SVM_EXIT_VMMCALL, 0, 0);\r
e4bb269a
TL
1214 if (Status != 0) {\r
1215 return Status;\r
1216 }\r
1217\r
765ba5bf 1218 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax)) {\r
e4bb269a
TL
1219 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
1220 }\r
ac0a286f 1221\r
e4bb269a
TL
1222 Regs->Rax = Ghcb->SaveArea.Rax;\r
1223\r
1224 return 0;\r
1225}\r
1226\r
9711c923
TL
1227/**\r
1228 Handle an MSR event.\r
1229\r
1230 Use the VMGEXIT instruction to handle either a RDMSR or WRMSR event.\r
1231\r
1232 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1233 Block\r
1234 @param[in, out] Regs x64 processor context\r
1235 @param[in] InstructionData Instruction parsing context\r
1236\r
1237 @retval 0 Event handled successfully\r
1238 @return New exception value to propagate\r
1239\r
1240**/\r
1241STATIC\r
1242UINT64\r
1243MsrExit (\r
1244 IN OUT GHCB *Ghcb,\r
1245 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1246 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1247 )\r
1248{\r
1249 UINT64 ExitInfo1, Status;\r
1250\r
1251 ExitInfo1 = 0;\r
1252\r
1253 switch (*(InstructionData->OpCodes + 1)) {\r
ac0a286f
MK
1254 case 0x30: // WRMSR\r
1255 ExitInfo1 = 1;\r
1256 Ghcb->SaveArea.Rax = Regs->Rax;\r
765ba5bf 1257 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
ac0a286f 1258 Ghcb->SaveArea.Rdx = Regs->Rdx;\r
765ba5bf 1259 CcExitVmgSetOffsetValid (Ghcb, GhcbRdx);\r
9711c923
TL
1260 //\r
1261 // fall through\r
1262 //\r
ac0a286f
MK
1263 case 0x32: // RDMSR\r
1264 Ghcb->SaveArea.Rcx = Regs->Rcx;\r
765ba5bf 1265 CcExitVmgSetOffsetValid (Ghcb, GhcbRcx);\r
ac0a286f
MK
1266 break;\r
1267 default:\r
1268 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
9711c923
TL
1269 }\r
1270\r
765ba5bf 1271 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MSR, ExitInfo1, 0);\r
9711c923
TL
1272 if (Status != 0) {\r
1273 return Status;\r
1274 }\r
1275\r
1276 if (ExitInfo1 == 0) {\r
765ba5bf
MX
1277 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax) ||\r
1278 !CcExitVmgIsOffsetValid (Ghcb, GhcbRdx))\r
ac0a286f 1279 {\r
9711c923
TL
1280 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
1281 }\r
ac0a286f 1282\r
9711c923
TL
1283 Regs->Rax = Ghcb->SaveArea.Rax;\r
1284 Regs->Rdx = Ghcb->SaveArea.Rdx;\r
1285 }\r
1286\r
1287 return 0;\r
1288}\r
1289\r
fb040cce
TL
1290/**\r
1291 Build the IOIO event information.\r
1292\r
1293 The IOIO event information identifies the type of IO operation to be performed\r
1294 by the hypervisor. Build this information based on the instruction data.\r
1295\r
1296 @param[in] Regs x64 processor context\r
1297 @param[in, out] InstructionData Instruction parsing context\r
1298\r
1299 @return IOIO event information value\r
1300\r
1301**/\r
1302STATIC\r
1303UINT64\r
1304IoioExitInfo (\r
1305 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1306 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
1307 )\r
1308{\r
1309 UINT64 ExitInfo;\r
1310\r
1311 ExitInfo = 0;\r
1312\r
1313 switch (*(InstructionData->OpCodes)) {\r
ac0a286f
MK
1314 //\r
1315 // INS opcodes\r
1316 //\r
1317 case 0x6C:\r
1318 case 0x6D:\r
1319 ExitInfo |= IOIO_TYPE_INS;\r
1320 ExitInfo |= IOIO_SEG_ES;\r
1321 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
1322 break;\r
0020157a 1323\r
ac0a286f
MK
1324 //\r
1325 // OUTS opcodes\r
1326 //\r
1327 case 0x6E:\r
1328 case 0x6F:\r
1329 ExitInfo |= IOIO_TYPE_OUTS;\r
1330 ExitInfo |= IOIO_SEG_DS;\r
1331 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
1332 break;\r
0020157a 1333\r
ac0a286f
MK
1334 //\r
1335 // IN immediate opcodes\r
1336 //\r
1337 case 0xE4:\r
1338 case 0xE5:\r
1339 InstructionData->ImmediateSize = 1;\r
1340 InstructionData->End++;\r
1341 ExitInfo |= IOIO_TYPE_IN;\r
1342 ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16);\r
1343 break;\r
fb040cce 1344\r
ac0a286f
MK
1345 //\r
1346 // OUT immediate opcodes\r
1347 //\r
1348 case 0xE6:\r
1349 case 0xE7:\r
1350 InstructionData->ImmediateSize = 1;\r
1351 InstructionData->End++;\r
1352 ExitInfo |= IOIO_TYPE_OUT;\r
1353 ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT;\r
1354 break;\r
fb040cce 1355\r
ac0a286f
MK
1356 //\r
1357 // IN register opcodes\r
1358 //\r
1359 case 0xEC:\r
1360 case 0xED:\r
1361 ExitInfo |= IOIO_TYPE_IN;\r
1362 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
1363 break;\r
fb040cce 1364\r
ac0a286f
MK
1365 //\r
1366 // OUT register opcodes\r
1367 //\r
1368 case 0xEE:\r
1369 case 0xEF:\r
1370 ExitInfo |= IOIO_TYPE_OUT;\r
1371 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
1372 break;\r
fb040cce 1373\r
ac0a286f
MK
1374 default:\r
1375 return 0;\r
fb040cce
TL
1376 }\r
1377\r
1378 switch (*(InstructionData->OpCodes)) {\r
ac0a286f
MK
1379 //\r
1380 // Single-byte opcodes\r
1381 //\r
1382 case 0x6C:\r
1383 case 0x6E:\r
1384 case 0xE4:\r
1385 case 0xE6:\r
1386 case 0xEC:\r
1387 case 0xEE:\r
1388 ExitInfo |= IOIO_DATA_8;\r
1389 break;\r
fb040cce 1390\r
ac0a286f
MK
1391 //\r
1392 // Length determined by instruction parsing\r
1393 //\r
1394 default:\r
1395 ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16\r
fb040cce
TL
1396 : IOIO_DATA_32;\r
1397 }\r
1398\r
1399 switch (InstructionData->AddrSize) {\r
ac0a286f
MK
1400 case Size16Bits:\r
1401 ExitInfo |= IOIO_ADDR_16;\r
1402 break;\r
fb040cce 1403\r
ac0a286f
MK
1404 case Size32Bits:\r
1405 ExitInfo |= IOIO_ADDR_32;\r
1406 break;\r
fb040cce 1407\r
ac0a286f
MK
1408 case Size64Bits:\r
1409 ExitInfo |= IOIO_ADDR_64;\r
1410 break;\r
fb040cce 1411\r
ac0a286f
MK
1412 default:\r
1413 break;\r
fb040cce
TL
1414 }\r
1415\r
1416 if (InstructionData->RepMode != 0) {\r
1417 ExitInfo |= IOIO_REP;\r
1418 }\r
1419\r
1420 return ExitInfo;\r
1421}\r
1422\r
1423/**\r
1424 Handle an IOIO event.\r
1425\r
1426 Use the VMGEXIT instruction to handle an IOIO event.\r
1427\r
1428 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1429 Block\r
1430 @param[in, out] Regs x64 processor context\r
1431 @param[in] InstructionData Instruction parsing context\r
1432\r
1433 @retval 0 Event handled successfully\r
1434 @return New exception value to propagate\r
1435\r
1436**/\r
1437STATIC\r
1438UINT64\r
1439IoioExit (\r
1440 IN OUT GHCB *Ghcb,\r
1441 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1442 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1443 )\r
1444{\r
0020157a
TL
1445 UINT64 ExitInfo1, ExitInfo2, Status;\r
1446 BOOLEAN IsString;\r
fb040cce
TL
1447\r
1448 ExitInfo1 = IoioExitInfo (Regs, InstructionData);\r
1449 if (ExitInfo1 == 0) {\r
1450 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
1451 }\r
1452\r
0020157a
TL
1453 IsString = ((ExitInfo1 & IOIO_TYPE_STR) != 0) ? TRUE : FALSE;\r
1454 if (IsString) {\r
1455 UINTN IoBytes, VmgExitBytes;\r
1456 UINTN GhcbCount, OpCount;\r
1457\r
1458 Status = 0;\r
1459\r
ac0a286f 1460 IoBytes = IOIO_DATA_BYTES (ExitInfo1);\r
0020157a
TL
1461 GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes;\r
1462\r
1463 OpCount = ((ExitInfo1 & IOIO_REP) != 0) ? Regs->Rcx : 1;\r
1464 while (OpCount != 0) {\r
ac0a286f 1465 ExitInfo2 = MIN (OpCount, GhcbCount);\r
0020157a
TL
1466 VmgExitBytes = ExitInfo2 * IoBytes;\r
1467\r
1468 if ((ExitInfo1 & IOIO_TYPE_IN) == 0) {\r
ac0a286f 1469 CopyMem (Ghcb->SharedBuffer, (VOID *)Regs->Rsi, VmgExitBytes);\r
0020157a
TL
1470 Regs->Rsi += VmgExitBytes;\r
1471 }\r
1472\r
ac0a286f 1473 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
765ba5bf
MX
1474 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
1475 Status = CcExitVmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2);\r
0020157a
TL
1476 if (Status != 0) {\r
1477 return Status;\r
1478 }\r
1479\r
1480 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
ac0a286f 1481 CopyMem ((VOID *)Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes);\r
0020157a
TL
1482 Regs->Rdi += VmgExitBytes;\r
1483 }\r
1484\r
1485 if ((ExitInfo1 & IOIO_REP) != 0) {\r
1486 Regs->Rcx -= ExitInfo2;\r
1487 }\r
1488\r
1489 OpCount -= ExitInfo2;\r
1490 }\r
fb040cce 1491 } else {\r
0020157a
TL
1492 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
1493 Ghcb->SaveArea.Rax = 0;\r
1494 } else {\r
1495 CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));\r
1496 }\r
ac0a286f 1497\r
765ba5bf 1498 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
fb040cce 1499\r
765ba5bf 1500 Status = CcExitVmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);\r
0020157a
TL
1501 if (Status != 0) {\r
1502 return Status;\r
1503 }\r
fb040cce 1504\r
0020157a 1505 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
765ba5bf 1506 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax)) {\r
0020157a
TL
1507 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
1508 }\r
ac0a286f 1509\r
0020157a 1510 CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));\r
fb040cce 1511 }\r
fb040cce
TL
1512 }\r
1513\r
1514 return 0;\r
1515}\r
61bacc0f 1516\r
3caf1e2e
TL
1517/**\r
1518 Handle a INVD event.\r
1519\r
1520 Use the VMGEXIT instruction to handle a INVD event.\r
1521\r
1522 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1523 Block\r
1524 @param[in, out] Regs x64 processor context\r
1525 @param[in] InstructionData Instruction parsing context\r
1526\r
1527 @retval 0 Event handled successfully\r
1528 @return New exception value to propagate\r
1529\r
1530**/\r
1531STATIC\r
1532UINT64\r
1533InvdExit (\r
1534 IN OUT GHCB *Ghcb,\r
1535 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1536 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1537 )\r
1538{\r
765ba5bf 1539 return CcExitVmgExit (Ghcb, SVM_EXIT_INVD, 0, 0);\r
3caf1e2e
TL
1540}\r
1541\r
d2b998fb
MR
1542/**\r
1543 Fetch CPUID leaf/function via hypervisor/VMGEXIT.\r
1544\r
1545 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1546 Block\r
1547 @param[in] EaxIn EAX input for cpuid instruction\r
1548 @param[in] EcxIn ECX input for cpuid instruction\r
1549 @param[in] Xcr0In XCR0 at time of cpuid instruction\r
1550 @param[in, out] Eax Pointer to store leaf's EAX value\r
1551 @param[in, out] Ebx Pointer to store leaf's EBX value\r
1552 @param[in, out] Ecx Pointer to store leaf's ECX value\r
1553 @param[in, out] Edx Pointer to store leaf's EDX value\r
1554 @param[in, out] Status Pointer to store status from VMGEXIT (always 0\r
1555 unless return value indicates failure)\r
1556 @param[in, out] Unsupported Pointer to store indication of unsupported\r
1557 VMGEXIT (always false unless return value\r
1558 indicates failure)\r
1559\r
1560 @retval TRUE CPUID leaf fetch successfully.\r
1561 @retval FALSE Error occurred while fetching CPUID leaf. Callers\r
1562 should Status and Unsupported and handle\r
1563 accordingly if they indicate a more precise\r
1564 error condition.\r
1565\r
1566**/\r
1567STATIC\r
1568BOOLEAN\r
1569GetCpuidHyp (\r
1570 IN OUT GHCB *Ghcb,\r
1571 IN UINT32 EaxIn,\r
1572 IN UINT32 EcxIn,\r
1573 IN UINT64 XCr0,\r
1574 IN OUT UINT32 *Eax,\r
1575 IN OUT UINT32 *Ebx,\r
1576 IN OUT UINT32 *Ecx,\r
1577 IN OUT UINT32 *Edx,\r
1578 IN OUT UINT64 *Status,\r
1579 IN OUT BOOLEAN *UnsupportedExit\r
1580 )\r
1581{\r
1582 *UnsupportedExit = FALSE;\r
1583 Ghcb->SaveArea.Rax = EaxIn;\r
765ba5bf 1584 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
d2b998fb 1585 Ghcb->SaveArea.Rcx = EcxIn;\r
765ba5bf 1586 CcExitVmgSetOffsetValid (Ghcb, GhcbRcx);\r
d2b998fb
MR
1587 if (EaxIn == CPUID_EXTENDED_STATE) {\r
1588 Ghcb->SaveArea.XCr0 = XCr0;\r
765ba5bf 1589 CcExitVmgSetOffsetValid (Ghcb, GhcbXCr0);\r
d2b998fb
MR
1590 }\r
1591\r
765ba5bf 1592 *Status = CcExitVmgExit (Ghcb, SVM_EXIT_CPUID, 0, 0);\r
d2b998fb
MR
1593 if (*Status != 0) {\r
1594 return FALSE;\r
1595 }\r
1596\r
765ba5bf
MX
1597 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax) ||\r
1598 !CcExitVmgIsOffsetValid (Ghcb, GhcbRbx) ||\r
1599 !CcExitVmgIsOffsetValid (Ghcb, GhcbRcx) ||\r
1600 !CcExitVmgIsOffsetValid (Ghcb, GhcbRdx))\r
d2b998fb
MR
1601 {\r
1602 *UnsupportedExit = TRUE;\r
1603 return FALSE;\r
1604 }\r
1605\r
1606 if (Eax) {\r
1607 *Eax = (UINT32)(UINTN)Ghcb->SaveArea.Rax;\r
1608 }\r
1609\r
1610 if (Ebx) {\r
1611 *Ebx = (UINT32)(UINTN)Ghcb->SaveArea.Rbx;\r
1612 }\r
1613\r
1614 if (Ecx) {\r
1615 *Ecx = (UINT32)(UINTN)Ghcb->SaveArea.Rcx;\r
1616 }\r
1617\r
1618 if (Edx) {\r
1619 *Edx = (UINT32)(UINTN)Ghcb->SaveArea.Rdx;\r
1620 }\r
1621\r
1622 return TRUE;\r
1623}\r
1624\r
1625/**\r
1626 Check if SEV-SNP enabled.\r
1627\r
1628 @retval TRUE SEV-SNP is enabled.\r
1629 @retval FALSE SEV-SNP is disabled.\r
1630\r
1631**/\r
1632STATIC\r
1633BOOLEAN\r
1634SnpEnabled (\r
1635 VOID\r
1636 )\r
1637{\r
1638 MSR_SEV_STATUS_REGISTER Msr;\r
1639\r
1640 Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);\r
1641\r
1642 return !!Msr.Bits.SevSnpBit;\r
1643}\r
1644\r
1645/**\r
1646 Calculate the total XSAVE area size for enabled XSAVE areas\r
1647\r
1648 @param[in] XFeaturesEnabled Bit-mask of enabled XSAVE features/areas as\r
1649 indicated by XCR0/MSR_IA32_XSS bits\r
1650 @param[in] XSaveBaseSize Base/legacy XSAVE area size (e.g. when\r
1651 XCR0 is 1)\r
1652 @param[in, out] XSaveSize Pointer to storage for calculated XSAVE area\r
1653 size\r
1654 @param[in] Compacted Whether or not the calculation is for the\r
1655 normal XSAVE area size (leaf 0xD,0x0,EBX) or\r
1656 compacted XSAVE area size (leaf 0xD,0x1,EBX)\r
1657\r
1658\r
1659 @retval TRUE XSAVE size calculation was successful.\r
1660 @retval FALSE XSAVE size calculation was unsuccessful.\r
1661**/\r
1662STATIC\r
1663BOOLEAN\r
1664GetCpuidXSaveSize (\r
1665 IN UINT64 XFeaturesEnabled,\r
1666 IN UINT32 XSaveBaseSize,\r
1667 IN OUT UINT32 *XSaveSize,\r
1668 IN BOOLEAN Compacted\r
1669 )\r
1670{\r
1671 SEV_SNP_CPUID_INFO *CpuidInfo;\r
1672 UINT64 XFeaturesFound = 0;\r
1673 UINT32 Idx;\r
1674\r
1675 *XSaveSize = XSaveBaseSize;\r
1676 CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase);\r
1677\r
1678 for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {\r
1679 SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];\r
1680\r
1681 if (!((CpuidFn->EaxIn == 0xD) &&\r
1682 ((CpuidFn->EcxIn == 0) || (CpuidFn->EcxIn == 1))))\r
1683 {\r
1684 continue;\r
1685 }\r
1686\r
1687 if (XFeaturesFound & (1ULL << CpuidFn->EcxIn) ||\r
1688 !(XFeaturesEnabled & (1ULL << CpuidFn->EcxIn)))\r
1689 {\r
1690 continue;\r
1691 }\r
1692\r
1693 XFeaturesFound |= (1ULL << CpuidFn->EcxIn);\r
1694 if (Compacted) {\r
1695 *XSaveSize += CpuidFn->Eax;\r
1696 } else {\r
1697 *XSaveSize = MAX (*XSaveSize, CpuidFn->Eax + CpuidFn->Ebx);\r
1698 }\r
1699 }\r
1700\r
1701 /*\r
1702 * Either the guest set unsupported XCR0/XSS bits, or the corresponding\r
1703 * entries in the CPUID table were not present. This is an invalid state.\r
1704 */\r
1705 if (XFeaturesFound != (XFeaturesEnabled & ~3UL)) {\r
1706 return FALSE;\r
1707 }\r
1708\r
1709 return TRUE;\r
1710}\r
1711\r
1712/**\r
1713 Check if a CPUID leaf/function is indexed via ECX sub-leaf/sub-function\r
1714\r
1715 @param[in] EaxIn EAX input for cpuid instruction\r
1716\r
1717 @retval FALSE cpuid leaf/function is not indexed by ECX input\r
1718 @retval TRUE cpuid leaf/function is indexed by ECX input\r
1719\r
1720**/\r
1721STATIC\r
1722BOOLEAN\r
1723IsFunctionIndexed (\r
1724 IN UINT32 EaxIn\r
1725 )\r
1726{\r
1727 switch (EaxIn) {\r
1728 case CPUID_CACHE_PARAMS:\r
1729 case CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS:\r
1730 case CPUID_EXTENDED_TOPOLOGY:\r
1731 case CPUID_EXTENDED_STATE:\r
1732 case CPUID_INTEL_RDT_MONITORING:\r
1733 case CPUID_INTEL_RDT_ALLOCATION:\r
1734 case CPUID_INTEL_SGX:\r
1735 case CPUID_INTEL_PROCESSOR_TRACE:\r
1736 case CPUID_DETERMINISTIC_ADDRESS_TRANSLATION_PARAMETERS:\r
1737 case CPUID_V2_EXTENDED_TOPOLOGY:\r
1738 case 0x8000001D: /* Cache Topology Information */\r
1739 return TRUE;\r
1740 }\r
1741\r
1742 return FALSE;\r
1743}\r
1744\r
1745/**\r
1746 Fetch CPUID leaf/function via SEV-SNP CPUID table.\r
1747\r
1748 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1749 Block\r
1750 @param[in] EaxIn EAX input for cpuid instruction\r
1751 @param[in] EcxIn ECX input for cpuid instruction\r
1752 @param[in] Xcr0In XCR0 at time of cpuid instruction\r
1753 @param[in, out] Eax Pointer to store leaf's EAX value\r
1754 @param[in, out] Ebx Pointer to store leaf's EBX value\r
1755 @param[in, out] Ecx Pointer to store leaf's ECX value\r
1756 @param[in, out] Edx Pointer to store leaf's EDX value\r
1757 @param[in, out] Status Pointer to store status from VMGEXIT (always 0\r
1758 unless return value indicates failure)\r
1759 @param[in, out] Unsupported Pointer to store indication of unsupported\r
1760 VMGEXIT (always false unless return value\r
1761 indicates failure)\r
1762\r
1763 @retval TRUE CPUID leaf fetch successfully.\r
1764 @retval FALSE Error occurred while fetching CPUID leaf. Callers\r
1765 should Status and Unsupported and handle\r
1766 accordingly if they indicate a more precise\r
1767 error condition.\r
1768\r
1769**/\r
1770STATIC\r
1771BOOLEAN\r
1772GetCpuidFw (\r
1773 IN OUT GHCB *Ghcb,\r
1774 IN UINT32 EaxIn,\r
1775 IN UINT32 EcxIn,\r
1776 IN UINT64 XCr0,\r
1777 IN OUT UINT32 *Eax,\r
1778 IN OUT UINT32 *Ebx,\r
1779 IN OUT UINT32 *Ecx,\r
1780 IN OUT UINT32 *Edx,\r
1781 IN OUT UINT64 *Status,\r
1782 IN OUT BOOLEAN *Unsupported\r
1783 )\r
1784{\r
1785 SEV_SNP_CPUID_INFO *CpuidInfo;\r
1786 BOOLEAN Found;\r
1787 UINT32 Idx;\r
1788\r
1789 CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase);\r
1790 Found = FALSE;\r
1791\r
1792 for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {\r
1793 SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];\r
1794\r
1795 if (CpuidFn->EaxIn != EaxIn) {\r
1796 continue;\r
1797 }\r
1798\r
1799 if (IsFunctionIndexed (CpuidFn->EaxIn) && (CpuidFn->EcxIn != EcxIn)) {\r
1800 continue;\r
1801 }\r
1802\r
1803 *Eax = CpuidFn->Eax;\r
1804 *Ebx = CpuidFn->Ebx;\r
1805 *Ecx = CpuidFn->Ecx;\r
1806 *Edx = CpuidFn->Edx;\r
1807\r
1808 Found = TRUE;\r
1809 break;\r
1810 }\r
1811\r
1812 if (!Found) {\r
1813 *Eax = *Ebx = *Ecx = *Edx = 0;\r
1814 goto Out;\r
1815 }\r
1816\r
1817 if (EaxIn == CPUID_VERSION_INFO) {\r
1818 IA32_CR4 Cr4;\r
1819 UINT32 Ebx2;\r
1820 UINT32 Edx2;\r
1821\r
1822 if (!GetCpuidHyp (\r
1823 Ghcb,\r
1824 EaxIn,\r
1825 EcxIn,\r
1826 XCr0,\r
1827 NULL,\r
1828 &Ebx2,\r
1829 NULL,\r
1830 &Edx2,\r
1831 Status,\r
1832 Unsupported\r
1833 ))\r
1834 {\r
1835 return FALSE;\r
1836 }\r
1837\r
1838 /* initial APIC ID */\r
1839 *Ebx = (*Ebx & 0x00FFFFFF) | (Ebx2 & 0xFF000000);\r
1840 /* APIC enabled bit */\r
1841 *Edx = (*Edx & ~BIT9) | (Edx2 & BIT9);\r
1842 /* OSXSAVE enabled bit */\r
1843 Cr4.UintN = AsmReadCr4 ();\r
1844 *Ecx = (Cr4.Bits.OSXSAVE) ? (*Ecx & ~BIT27) | (*Ecx & BIT27)\r
1845 : (*Ecx & ~BIT27);\r
1846 } else if (EaxIn == CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS) {\r
1847 IA32_CR4 Cr4;\r
1848\r
1849 Cr4.UintN = AsmReadCr4 ();\r
1850 /* OSPKE enabled bit */\r
1851 *Ecx = (Cr4.Bits.PKE) ? (*Ecx | BIT4) : (*Ecx & ~BIT4);\r
1852 } else if (EaxIn == CPUID_EXTENDED_TOPOLOGY) {\r
1853 if (!GetCpuidHyp (\r
1854 Ghcb,\r
1855 EaxIn,\r
1856 EcxIn,\r
1857 XCr0,\r
1858 NULL,\r
1859 NULL,\r
1860 NULL,\r
1861 Edx,\r
1862 Status,\r
1863 Unsupported\r
1864 ))\r
1865 {\r
1866 return FALSE;\r
1867 }\r
1868 } else if ((EaxIn == CPUID_EXTENDED_STATE) && ((EcxIn == 0) || (EcxIn == 1))) {\r
1869 MSR_IA32_XSS_REGISTER XssMsr;\r
1870 BOOLEAN Compacted;\r
1871 UINT32 XSaveSize;\r
1872\r
1873 XssMsr.Uint64 = 0;\r
85589ddb 1874 Compacted = FALSE;\r
d2b998fb
MR
1875 if (EcxIn == 1) {\r
1876 /*\r
1877 * The PPR and APM aren't clear on what size should be encoded in\r
1878 * 0xD:0x1:EBX when compaction is not enabled by either XSAVEC or\r
1879 * XSAVES, as these are generally fixed to 1 on real CPUs. Report\r
1880 * this undefined case as an error.\r
1881 */\r
1882 if (!(*Eax & (BIT3 | BIT1))) {\r
1883 /* (XSAVES | XSAVEC) */\r
1884 return FALSE;\r
1885 }\r
1886\r
1887 Compacted = TRUE;\r
1888 XssMsr.Uint64 = AsmReadMsr64 (MSR_IA32_XSS);\r
1889 }\r
1890\r
1891 if (!GetCpuidXSaveSize (\r
1892 XCr0 | XssMsr.Uint64,\r
1893 *Ebx,\r
1894 &XSaveSize,\r
1895 Compacted\r
1896 ))\r
1897 {\r
1898 return FALSE;\r
1899 }\r
1900\r
1901 *Ebx = XSaveSize;\r
1902 } else if (EaxIn == 0x8000001E) {\r
1903 UINT32 Ebx2;\r
1904 UINT32 Ecx2;\r
1905\r
1906 /* extended APIC ID */\r
1907 if (!GetCpuidHyp (\r
1908 Ghcb,\r
1909 EaxIn,\r
1910 EcxIn,\r
1911 XCr0,\r
1912 Eax,\r
1913 &Ebx2,\r
1914 &Ecx2,\r
1915 NULL,\r
1916 Status,\r
1917 Unsupported\r
1918 ))\r
1919 {\r
1920 return FALSE;\r
1921 }\r
1922\r
1923 /* compute ID */\r
1924 *Ebx = (*Ebx & 0xFFFFFF00) | (Ebx2 & 0x000000FF);\r
1925 /* node ID */\r
1926 *Ecx = (*Ecx & 0xFFFFFF00) | (Ecx2 & 0x000000FF);\r
1927 }\r
1928\r
1929Out:\r
1930 *Status = 0;\r
1931 *Unsupported = FALSE;\r
1932 return TRUE;\r
1933}\r
1934\r
6587e08d
TL
1935/**\r
1936 Handle a CPUID event.\r
1937\r
d2b998fb 1938 Use VMGEXIT instruction or CPUID table to handle a CPUID event.\r
6587e08d
TL
1939\r
1940 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1941 Block\r
1942 @param[in, out] Regs x64 processor context\r
1943 @param[in] InstructionData Instruction parsing context\r
1944\r
1945 @retval 0 Event handled successfully\r
1946 @return New exception value to propagate\r
1947\r
1948**/\r
1949STATIC\r
1950UINT64\r
1951CpuidExit (\r
1952 IN OUT GHCB *Ghcb,\r
1953 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1954 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1955 )\r
1956{\r
d2b998fb
MR
1957 BOOLEAN Unsupported;\r
1958 UINT64 Status;\r
1959 UINT32 EaxIn;\r
1960 UINT32 EcxIn;\r
1961 UINT64 XCr0;\r
1962 UINT32 Eax;\r
1963 UINT32 Ebx;\r
1964 UINT32 Ecx;\r
1965 UINT32 Edx;\r
1966\r
1967 EaxIn = (UINT32)(UINTN)Regs->Rax;\r
1968 EcxIn = (UINT32)(UINTN)Regs->Rcx;\r
1969\r
1970 if (EaxIn == CPUID_EXTENDED_STATE) {\r
6587e08d
TL
1971 IA32_CR4 Cr4;\r
1972\r
ac0a286f 1973 Cr4.UintN = AsmReadCr4 ();\r
6587e08d 1974 Ghcb->SaveArea.XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;\r
d2b998fb 1975 XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;\r
6587e08d
TL
1976 }\r
1977\r
d2b998fb
MR
1978 if (SnpEnabled ()) {\r
1979 if (!GetCpuidFw (\r
1980 Ghcb,\r
1981 EaxIn,\r
1982 EcxIn,\r
1983 XCr0,\r
1984 &Eax,\r
1985 &Ebx,\r
1986 &Ecx,\r
1987 &Edx,\r
1988 &Status,\r
1989 &Unsupported\r
1990 ))\r
1991 {\r
1992 goto CpuidFail;\r
1993 }\r
1994 } else {\r
1995 if (!GetCpuidHyp (\r
1996 Ghcb,\r
1997 EaxIn,\r
1998 EcxIn,\r
1999 XCr0,\r
2000 &Eax,\r
2001 &Ebx,\r
2002 &Ecx,\r
2003 &Edx,\r
2004 &Status,\r
2005 &Unsupported\r
2006 ))\r
2007 {\r
2008 goto CpuidFail;\r
2009 }\r
6587e08d
TL
2010 }\r
2011\r
d2b998fb
MR
2012 Regs->Rax = Eax;\r
2013 Regs->Rbx = Ebx;\r
2014 Regs->Rcx = Ecx;\r
2015 Regs->Rdx = Edx;\r
2016\r
2017 return 0;\r
2018\r
2019CpuidFail:\r
2020 if (Unsupported) {\r
6587e08d
TL
2021 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
2022 }\r
ac0a286f 2023\r
d2b998fb 2024 return Status;\r
6587e08d
TL
2025}\r
2026\r
5894fb1f
TL
2027/**\r
2028 Handle a RDPMC event.\r
2029\r
2030 Use the VMGEXIT instruction to handle a RDPMC event.\r
2031\r
2032 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
2033 Block\r
2034 @param[in, out] Regs x64 processor context\r
2035 @param[in] InstructionData Instruction parsing context\r
2036\r
2037 @retval 0 Event handled successfully\r
2038 @return New exception value to propagate\r
2039\r
2040**/\r
2041STATIC\r
2042UINT64\r
2043RdpmcExit (\r
2044 IN OUT GHCB *Ghcb,\r
2045 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
2046 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
2047 )\r
2048{\r
2049 UINT64 Status;\r
2050\r
2051 Ghcb->SaveArea.Rcx = Regs->Rcx;\r
765ba5bf 2052 CcExitVmgSetOffsetValid (Ghcb, GhcbRcx);\r
5894fb1f 2053\r
765ba5bf 2054 Status = CcExitVmgExit (Ghcb, SVM_EXIT_RDPMC, 0, 0);\r
5894fb1f
TL
2055 if (Status != 0) {\r
2056 return Status;\r
2057 }\r
2058\r
765ba5bf
MX
2059 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax) ||\r
2060 !CcExitVmgIsOffsetValid (Ghcb, GhcbRdx))\r
ac0a286f 2061 {\r
5894fb1f
TL
2062 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
2063 }\r
ac0a286f 2064\r
5894fb1f
TL
2065 Regs->Rax = Ghcb->SaveArea.Rax;\r
2066 Regs->Rdx = Ghcb->SaveArea.Rdx;\r
2067\r
2068 return 0;\r
2069}\r
2070\r
68d18bef
TL
2071/**\r
2072 Handle a RDTSC event.\r
2073\r
2074 Use the VMGEXIT instruction to handle a RDTSC event.\r
2075\r
2076 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
2077 Block\r
2078 @param[in, out] Regs x64 processor context\r
2079 @param[in] InstructionData Instruction parsing context\r
2080\r
2081 @retval 0 Event handled successfully\r
2082 @return New exception value to propagate\r
2083\r
2084**/\r
2085STATIC\r
2086UINT64\r
2087RdtscExit (\r
2088 IN OUT GHCB *Ghcb,\r
2089 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
2090 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
2091 )\r
2092{\r
2093 UINT64 Status;\r
2094\r
765ba5bf 2095 Status = CcExitVmgExit (Ghcb, SVM_EXIT_RDTSC, 0, 0);\r
68d18bef
TL
2096 if (Status != 0) {\r
2097 return Status;\r
2098 }\r
2099\r
765ba5bf
MX
2100 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax) ||\r
2101 !CcExitVmgIsOffsetValid (Ghcb, GhcbRdx))\r
ac0a286f 2102 {\r
68d18bef
TL
2103 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
2104 }\r
ac0a286f 2105\r
68d18bef
TL
2106 Regs->Rax = Ghcb->SaveArea.Rax;\r
2107 Regs->Rdx = Ghcb->SaveArea.Rdx;\r
2108\r
2109 return 0;\r
2110}\r
2111\r
fefcf90c
TL
2112/**\r
2113 Handle a DR7 register write event.\r
2114\r
2115 Use the VMGEXIT instruction to handle a DR7 write event.\r
2116\r
2117 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
2118 Block\r
2119 @param[in, out] Regs x64 processor context\r
2120 @param[in] InstructionData Instruction parsing context\r
2121\r
2122 @retval 0 Event handled successfully\r
2123 @return New exception value to propagate\r
2124\r
2125**/\r
2126STATIC\r
2127UINT64\r
2128Dr7WriteExit (\r
2129 IN OUT GHCB *Ghcb,\r
2130 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
2131 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
2132 )\r
2133{\r
2134 SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
2135 SEV_ES_PER_CPU_DATA *SevEsData;\r
2136 UINT64 *Register;\r
2137 UINT64 Status;\r
2138\r
ac0a286f
MK
2139 Ext = &InstructionData->Ext;\r
2140 SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);\r
fefcf90c
TL
2141\r
2142 DecodeModRm (Regs, InstructionData);\r
2143\r
2144 //\r
2145 // MOV DRn always treats MOD == 3 no matter how encoded\r
2146 //\r
2147 Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
2148\r
2149 //\r
2150 // Using a value of 0 for ExitInfo1 means RAX holds the value\r
2151 //\r
2152 Ghcb->SaveArea.Rax = *Register;\r
765ba5bf 2153 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
fefcf90c 2154\r
765ba5bf 2155 Status = CcExitVmgExit (Ghcb, SVM_EXIT_DR7_WRITE, 0, 0);\r
fefcf90c
TL
2156 if (Status != 0) {\r
2157 return Status;\r
2158 }\r
2159\r
ac0a286f 2160 SevEsData->Dr7 = *Register;\r
31f5ebd6 2161 SevEsData->Dr7Cached = 1;\r
fefcf90c
TL
2162\r
2163 return 0;\r
2164}\r
2165\r
2166/**\r
2167 Handle a DR7 register read event.\r
2168\r
2169 Use the VMGEXIT instruction to handle a DR7 read event.\r
2170\r
2171 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
2172 Block\r
2173 @param[in, out] Regs x64 processor context\r
2174 @param[in] InstructionData Instruction parsing context\r
2175\r
2176 @retval 0 Event handled successfully\r
2177\r
2178**/\r
2179STATIC\r
2180UINT64\r
2181Dr7ReadExit (\r
2182 IN OUT GHCB *Ghcb,\r
2183 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
2184 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
2185 )\r
2186{\r
2187 SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
2188 SEV_ES_PER_CPU_DATA *SevEsData;\r
2189 UINT64 *Register;\r
2190\r
ac0a286f
MK
2191 Ext = &InstructionData->Ext;\r
2192 SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);\r
fefcf90c
TL
2193\r
2194 DecodeModRm (Regs, InstructionData);\r
2195\r
2196 //\r
2197 // MOV DRn always treats MOD == 3 no matter how encoded\r
2198 //\r
2199 Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
2200\r
2201 //\r
2202 // If there is a cached valued for DR7, return that. Otherwise return the\r
2203 // DR7 standard reset value of 0x400 (no debug breakpoints set).\r
2204 //\r
31f5ebd6 2205 *Register = (SevEsData->Dr7Cached == 1) ? SevEsData->Dr7 : 0x400;\r
fefcf90c
TL
2206\r
2207 return 0;\r
2208}\r
2209\r
61bacc0f
TL
2210/**\r
2211 Handle a #VC exception.\r
2212\r
2213 Performs the necessary processing to handle a #VC exception.\r
2214\r
5667dc43 2215 @param[in, out] Ghcb Pointer to the GHCB\r
61bacc0f
TL
2216 @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set\r
2217 as value to use on error.\r
2218 @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT\r
2219\r
2220 @retval EFI_SUCCESS Exception handled\r
2221 @retval EFI_UNSUPPORTED #VC not supported, (new) exception value to\r
2222 propagate provided\r
2223 @retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to\r
2224 propagate provided\r
2225\r
2226**/\r
2227EFI_STATUS\r
2228EFIAPI\r
5667dc43
TL
2229InternalVmgExitHandleVc (\r
2230 IN OUT GHCB *Ghcb,\r
61bacc0f
TL
2231 IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
2232 IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
2233 )\r
2234{\r
ac0a286f
MK
2235 EFI_SYSTEM_CONTEXT_X64 *Regs;\r
2236 NAE_EXIT NaeExit;\r
2237 SEV_ES_INSTRUCTION_DATA InstructionData;\r
2238 UINT64 ExitCode, Status;\r
2239 EFI_STATUS VcRet;\r
2240 BOOLEAN InterruptState;\r
61bacc0f
TL
2241\r
2242 VcRet = EFI_SUCCESS;\r
2243\r
61bacc0f 2244 Regs = SystemContext.SystemContextX64;\r
61bacc0f 2245\r
765ba5bf 2246 CcExitVmgInit (Ghcb, &InterruptState);\r
61bacc0f
TL
2247\r
2248 ExitCode = Regs->ExceptionData;\r
2249 switch (ExitCode) {\r
ac0a286f
MK
2250 case SVM_EXIT_DR7_READ:\r
2251 NaeExit = Dr7ReadExit;\r
2252 break;\r
fefcf90c 2253\r
ac0a286f
MK
2254 case SVM_EXIT_DR7_WRITE:\r
2255 NaeExit = Dr7WriteExit;\r
2256 break;\r
fefcf90c 2257\r
ac0a286f
MK
2258 case SVM_EXIT_RDTSC:\r
2259 NaeExit = RdtscExit;\r
2260 break;\r
68d18bef 2261\r
ac0a286f
MK
2262 case SVM_EXIT_RDPMC:\r
2263 NaeExit = RdpmcExit;\r
2264 break;\r
5894fb1f 2265\r
ac0a286f
MK
2266 case SVM_EXIT_CPUID:\r
2267 NaeExit = CpuidExit;\r
2268 break;\r
6587e08d 2269\r
ac0a286f
MK
2270 case SVM_EXIT_INVD:\r
2271 NaeExit = InvdExit;\r
2272 break;\r
3caf1e2e 2273\r
ac0a286f
MK
2274 case SVM_EXIT_IOIO_PROT:\r
2275 NaeExit = IoioExit;\r
2276 break;\r
fb040cce 2277\r
ac0a286f
MK
2278 case SVM_EXIT_MSR:\r
2279 NaeExit = MsrExit;\r
2280 break;\r
9711c923 2281\r
ac0a286f
MK
2282 case SVM_EXIT_VMMCALL:\r
2283 NaeExit = VmmCallExit;\r
2284 break;\r
e4bb269a 2285\r
ac0a286f
MK
2286 case SVM_EXIT_RDTSCP:\r
2287 NaeExit = RdtscpExit;\r
2288 break;\r
f4571f24 2289\r
ac0a286f
MK
2290 case SVM_EXIT_WBINVD:\r
2291 NaeExit = WbinvdExit;\r
2292 break;\r
4de70479 2293\r
ac0a286f
MK
2294 case SVM_EXIT_MONITOR:\r
2295 NaeExit = MonitorExit;\r
2296 break;\r
3ef8bfc2 2297\r
ac0a286f
MK
2298 case SVM_EXIT_MWAIT:\r
2299 NaeExit = MwaitExit;\r
2300 break;\r
9f7e0d0a 2301\r
ac0a286f
MK
2302 case SVM_EXIT_NPF:\r
2303 NaeExit = MmioExit;\r
2304 break;\r
c45f678a 2305\r
ac0a286f
MK
2306 default:\r
2307 NaeExit = UnsupportedExit;\r
fb040cce 2308 }\r
61bacc0f 2309\r
fb040cce
TL
2310 InitInstructionData (&InstructionData, Ghcb, Regs);\r
2311\r
2312 Status = NaeExit (Ghcb, Regs, &InstructionData);\r
2313 if (Status == 0) {\r
2314 Regs->Rip += InstructionLength (&InstructionData);\r
2315 } else {\r
2316 GHCB_EVENT_INJECTION Event;\r
61bacc0f 2317\r
fb040cce
TL
2318 Event.Uint64 = Status;\r
2319 if (Event.Elements.ErrorCodeValid != 0) {\r
2320 Regs->ExceptionData = Event.Elements.ErrorCode;\r
2321 } else {\r
2322 Regs->ExceptionData = 0;\r
61bacc0f
TL
2323 }\r
2324\r
fb040cce
TL
2325 *ExceptionType = Event.Elements.Vector;\r
2326\r
61bacc0f
TL
2327 VcRet = EFI_PROTOCOL_ERROR;\r
2328 }\r
2329\r
765ba5bf 2330 CcExitVmgDone (Ghcb, InterruptState);\r
61bacc0f
TL
2331\r
2332 return VcRet;\r
2333}\r
5667dc43
TL
2334\r
2335/**\r
2336 Routine to allow ASSERT from within #VC.\r
2337\r
2338 @param[in, out] SevEsData Pointer to the per-CPU data\r
2339\r
2340**/\r
2341VOID\r
2342EFIAPI\r
2343VmgExitIssueAssert (\r
2344 IN OUT SEV_ES_PER_CPU_DATA *SevEsData\r
2345 )\r
2346{\r
2347 //\r
2348 // Progress will be halted, so set VcCount to allow for ASSERT output\r
2349 // to be seen.\r
2350 //\r
2351 SevEsData->VcCount = 0;\r
2352\r
2353 ASSERT (FALSE);\r
2354 CpuDeadLoop ();\r
2355}\r