]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/VmgExitLib/VmgExitVcHandler.c
OvmfPkg: Apply uncrustify changes
[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
85b8eac5 12#include <Library/LocalApicLib.h>\r
5667dc43 13#include <Library/MemEncryptSevLib.h>\r
61bacc0f
TL
14#include <Library/VmgExitLib.h>\r
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
5667dc43
TL
19#include "VmgExitVcHandler.h"\r
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
c45f678a
TL
133/**\r
134 Return a pointer to the contents of the specified register.\r
135\r
136 Based upon the input register, return a pointer to the registers contents\r
137 in the x86 processor context.\r
138\r
139 @param[in] Regs x64 processor context\r
140 @param[in] Register Register to obtain pointer for\r
141\r
142 @return Pointer to the contents of the requested register\r
143\r
144**/\r
145STATIC\r
146UINT64 *\r
147GetRegisterPointer (\r
ac0a286f
MK
148 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
149 IN UINT8 Register\r
c45f678a
TL
150 )\r
151{\r
ac0a286f 152 UINT64 *Reg;\r
c45f678a
TL
153\r
154 switch (Register) {\r
ac0a286f
MK
155 case 0:\r
156 Reg = &Regs->Rax;\r
157 break;\r
158 case 1:\r
159 Reg = &Regs->Rcx;\r
160 break;\r
161 case 2:\r
162 Reg = &Regs->Rdx;\r
163 break;\r
164 case 3:\r
165 Reg = &Regs->Rbx;\r
166 break;\r
167 case 4:\r
168 Reg = &Regs->Rsp;\r
169 break;\r
170 case 5:\r
171 Reg = &Regs->Rbp;\r
172 break;\r
173 case 6:\r
174 Reg = &Regs->Rsi;\r
175 break;\r
176 case 7:\r
177 Reg = &Regs->Rdi;\r
178 break;\r
179 case 8:\r
180 Reg = &Regs->R8;\r
181 break;\r
182 case 9:\r
183 Reg = &Regs->R9;\r
184 break;\r
185 case 10:\r
186 Reg = &Regs->R10;\r
187 break;\r
188 case 11:\r
189 Reg = &Regs->R11;\r
190 break;\r
191 case 12:\r
192 Reg = &Regs->R12;\r
193 break;\r
194 case 13:\r
195 Reg = &Regs->R13;\r
196 break;\r
197 case 14:\r
198 Reg = &Regs->R14;\r
199 break;\r
200 case 15:\r
201 Reg = &Regs->R15;\r
202 break;\r
203 default:\r
204 Reg = NULL;\r
c45f678a 205 }\r
ac0a286f 206\r
c45f678a
TL
207 ASSERT (Reg != NULL);\r
208\r
209 return Reg;\r
210}\r
211\r
212/**\r
213 Update the instruction parsing context for displacement bytes.\r
214\r
215 @param[in, out] InstructionData Instruction parsing context\r
216 @param[in] Size The instruction displacement size\r
217\r
218**/\r
219STATIC\r
220VOID\r
221UpdateForDisplacement (\r
222 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,\r
223 IN UINTN Size\r
224 )\r
225{\r
226 InstructionData->DisplacementSize = Size;\r
ac0a286f
MK
227 InstructionData->Immediate += Size;\r
228 InstructionData->End += Size;\r
c45f678a
TL
229}\r
230\r
231/**\r
232 Determine if an instruction address if RIP relative.\r
233\r
234 Examine the instruction parsing context to determine if the address offset\r
235 is relative to the instruction pointer.\r
236\r
237 @param[in] InstructionData Instruction parsing context\r
238\r
239 @retval TRUE Instruction addressing is RIP relative\r
240 @retval FALSE Instruction addressing is not RIP relative\r
241\r
242**/\r
243STATIC\r
244BOOLEAN\r
245IsRipRelative (\r
246 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
247 )\r
248{\r
249 SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
250\r
251 Ext = &InstructionData->Ext;\r
252\r
253 return ((InstructionData->Mode == LongMode64Bit) &&\r
254 (Ext->ModRm.Mod == 0) &&\r
255 (Ext->ModRm.Rm == 5) &&\r
256 (InstructionData->SibPresent == FALSE));\r
257}\r
258\r
259/**\r
260 Return the effective address of a memory operand.\r
261\r
262 Examine the instruction parsing context to obtain the effective memory\r
263 address of a memory operand.\r
264\r
265 @param[in] Regs x64 processor context\r
266 @param[in] InstructionData Instruction parsing context\r
267\r
268 @return The memory operand effective address\r
269\r
270**/\r
271STATIC\r
272UINT64\r
273GetEffectiveMemoryAddress (\r
274 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
275 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
276 )\r
277{\r
278 SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
279 UINT64 EffectiveAddress;\r
280\r
ac0a286f 281 Ext = &InstructionData->Ext;\r
c45f678a
TL
282 EffectiveAddress = 0;\r
283\r
284 if (IsRipRelative (InstructionData)) {\r
285 //\r
286 // RIP-relative displacement is a 32-bit signed value\r
287 //\r
ac0a286f 288 INT32 RipRelative;\r
c45f678a 289\r
ac0a286f 290 RipRelative = *(INT32 *)InstructionData->Displacement;\r
c45f678a
TL
291\r
292 UpdateForDisplacement (InstructionData, 4);\r
293\r
294 //\r
295 // Negative displacement is handled by standard UINT64 wrap-around.\r
296 //\r
ac0a286f 297 return Regs->Rip + (UINT64)RipRelative;\r
c45f678a
TL
298 }\r
299\r
300 switch (Ext->ModRm.Mod) {\r
ac0a286f
MK
301 case 1:\r
302 UpdateForDisplacement (InstructionData, 1);\r
303 EffectiveAddress += (UINT64)(*(INT8 *)(InstructionData->Displacement));\r
c45f678a 304 break;\r
ac0a286f
MK
305 case 2:\r
306 switch (InstructionData->AddrSize) {\r
307 case Size16Bits:\r
308 UpdateForDisplacement (InstructionData, 2);\r
309 EffectiveAddress += (UINT64)(*(INT16 *)(InstructionData->Displacement));\r
310 break;\r
311 default:\r
312 UpdateForDisplacement (InstructionData, 4);\r
313 EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement));\r
314 break;\r
315 }\r
316\r
c45f678a 317 break;\r
c45f678a
TL
318 }\r
319\r
320 if (InstructionData->SibPresent) {\r
321 INT64 Displacement;\r
322\r
323 if (Ext->Sib.Index != 4) {\r
324 CopyMem (\r
325 &Displacement,\r
326 GetRegisterPointer (Regs, Ext->Sib.Index),\r
327 sizeof (Displacement)\r
328 );\r
329 Displacement *= (INT64)(1 << Ext->Sib.Scale);\r
330\r
331 //\r
332 // Negative displacement is handled by standard UINT64 wrap-around.\r
333 //\r
ac0a286f 334 EffectiveAddress += (UINT64)Displacement;\r
c45f678a
TL
335 }\r
336\r
337 if ((Ext->Sib.Base != 5) || Ext->ModRm.Mod) {\r
338 EffectiveAddress += *GetRegisterPointer (Regs, Ext->Sib.Base);\r
339 } else {\r
340 UpdateForDisplacement (InstructionData, 4);\r
ac0a286f 341 EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement));\r
c45f678a
TL
342 }\r
343 } else {\r
344 EffectiveAddress += *GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
345 }\r
346\r
347 return EffectiveAddress;\r
348}\r
349\r
350/**\r
351 Decode a ModRM byte.\r
352\r
353 Examine the instruction parsing context to decode a ModRM byte and the SIB\r
354 byte, if present.\r
355\r
356 @param[in] Regs x64 processor context\r
357 @param[in, out] InstructionData Instruction parsing context\r
358\r
359**/\r
360STATIC\r
361VOID\r
362DecodeModRm (\r
363 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
364 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
365 )\r
366{\r
367 SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
368 INSTRUCTION_REX_PREFIX *RexPrefix;\r
369 INSTRUCTION_MODRM *ModRm;\r
370 INSTRUCTION_SIB *Sib;\r
371\r
372 RexPrefix = &InstructionData->RexPrefix;\r
ac0a286f
MK
373 Ext = &InstructionData->Ext;\r
374 ModRm = &InstructionData->ModRm;\r
375 Sib = &InstructionData->Sib;\r
c45f678a
TL
376\r
377 InstructionData->ModRmPresent = TRUE;\r
ac0a286f 378 ModRm->Uint8 = *(InstructionData->End);\r
c45f678a
TL
379\r
380 InstructionData->Displacement++;\r
381 InstructionData->Immediate++;\r
382 InstructionData->End++;\r
383\r
384 Ext->ModRm.Mod = ModRm->Bits.Mod;\r
385 Ext->ModRm.Reg = (RexPrefix->Bits.BitR << 3) | ModRm->Bits.Reg;\r
386 Ext->ModRm.Rm = (RexPrefix->Bits.BitB << 3) | ModRm->Bits.Rm;\r
387\r
388 Ext->RegData = *GetRegisterPointer (Regs, Ext->ModRm.Reg);\r
389\r
390 if (Ext->ModRm.Mod == 3) {\r
391 Ext->RmData = *GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
392 } else {\r
393 if (ModRm->Bits.Rm == 4) {\r
394 InstructionData->SibPresent = TRUE;\r
ac0a286f 395 Sib->Uint8 = *(InstructionData->End);\r
c45f678a
TL
396\r
397 InstructionData->Displacement++;\r
398 InstructionData->Immediate++;\r
399 InstructionData->End++;\r
400\r
401 Ext->Sib.Scale = Sib->Bits.Scale;\r
402 Ext->Sib.Index = (RexPrefix->Bits.BitX << 3) | Sib->Bits.Index;\r
403 Ext->Sib.Base = (RexPrefix->Bits.BitB << 3) | Sib->Bits.Base;\r
404 }\r
405\r
406 Ext->RmData = GetEffectiveMemoryAddress (Regs, InstructionData);\r
407 }\r
408}\r
409\r
fb040cce
TL
410/**\r
411 Decode instruction prefixes.\r
412\r
413 Parse the instruction data to track the instruction prefixes that have\r
414 been used.\r
415\r
416 @param[in] Regs x64 processor context\r
417 @param[in, out] InstructionData Instruction parsing context\r
418\r
419**/\r
420STATIC\r
421VOID\r
422DecodePrefixes (\r
423 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
424 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
425 )\r
426{\r
427 SEV_ES_INSTRUCTION_MODE Mode;\r
428 SEV_ES_INSTRUCTION_SIZE ModeDataSize;\r
429 SEV_ES_INSTRUCTION_SIZE ModeAddrSize;\r
430 UINT8 *Byte;\r
431\r
432 //\r
433 // Always in 64-bit mode\r
434 //\r
ac0a286f 435 Mode = LongMode64Bit;\r
fb040cce
TL
436 ModeDataSize = Size32Bits;\r
437 ModeAddrSize = Size64Bits;\r
438\r
ac0a286f 439 InstructionData->Mode = Mode;\r
fb040cce
TL
440 InstructionData->DataSize = ModeDataSize;\r
441 InstructionData->AddrSize = ModeAddrSize;\r
442\r
443 InstructionData->Prefixes = InstructionData->Begin;\r
444\r
445 Byte = InstructionData->Prefixes;\r
446 for ( ; ; Byte++, InstructionData->PrefixSize++) {\r
447 //\r
448 // Check the 0x40 to 0x4F range using an if statement here since some\r
449 // compilers don't like the "case 0x40 ... 0x4F:" syntax. This avoids\r
450 // 16 case statements below.\r
451 //\r
452 if ((*Byte >= REX_PREFIX_START) && (*Byte <= REX_PREFIX_STOP)) {\r
453 InstructionData->RexPrefix.Uint8 = *Byte;\r
454 if ((*Byte & REX_64BIT_OPERAND_SIZE_MASK) != 0) {\r
455 InstructionData->DataSize = Size64Bits;\r
456 }\r
ac0a286f 457\r
fb040cce
TL
458 continue;\r
459 }\r
460\r
461 switch (*Byte) {\r
ac0a286f
MK
462 case OVERRIDE_SEGMENT_CS:\r
463 case OVERRIDE_SEGMENT_DS:\r
464 case OVERRIDE_SEGMENT_ES:\r
465 case OVERRIDE_SEGMENT_SS:\r
466 if (Mode != LongMode64Bit) {\r
467 InstructionData->SegmentSpecified = TRUE;\r
468 InstructionData->Segment = (*Byte >> 3) & 3;\r
469 }\r
470\r
471 break;\r
472\r
473 case OVERRIDE_SEGMENT_FS:\r
474 case OVERRIDE_SEGMENT_GS:\r
fb040cce 475 InstructionData->SegmentSpecified = TRUE;\r
ac0a286f
MK
476 InstructionData->Segment = *Byte & 7;\r
477 break;\r
478\r
479 case OVERRIDE_OPERAND_SIZE:\r
480 if (InstructionData->RexPrefix.Uint8 == 0) {\r
481 InstructionData->DataSize =\r
482 (Mode == LongMode64Bit) ? Size16Bits :\r
483 (Mode == LongModeCompat32Bit) ? Size16Bits :\r
484 (Mode == LongModeCompat16Bit) ? Size32Bits : 0;\r
485 }\r
486\r
487 break;\r
488\r
489 case OVERRIDE_ADDRESS_SIZE:\r
490 InstructionData->AddrSize =\r
491 (Mode == LongMode64Bit) ? Size32Bits :\r
fb040cce
TL
492 (Mode == LongModeCompat32Bit) ? Size16Bits :\r
493 (Mode == LongModeCompat16Bit) ? Size32Bits : 0;\r
ac0a286f 494 break;\r
fb040cce 495\r
ac0a286f
MK
496 case LOCK_PREFIX:\r
497 break;\r
fb040cce 498\r
ac0a286f
MK
499 case REPZ_PREFIX:\r
500 InstructionData->RepMode = RepZ;\r
501 break;\r
fb040cce 502\r
ac0a286f
MK
503 case REPNZ_PREFIX:\r
504 InstructionData->RepMode = RepNZ;\r
505 break;\r
fb040cce 506\r
ac0a286f
MK
507 default:\r
508 InstructionData->OpCodes = Byte;\r
509 InstructionData->OpCodeSize = (*Byte == TWO_BYTE_OPCODE_ESCAPE) ? 2 : 1;\r
fb040cce 510\r
ac0a286f
MK
511 InstructionData->End = Byte + InstructionData->OpCodeSize;\r
512 InstructionData->Displacement = InstructionData->End;\r
513 InstructionData->Immediate = InstructionData->End;\r
514 return;\r
fb040cce
TL
515 }\r
516 }\r
517}\r
518\r
519/**\r
520 Determine instruction length\r
521\r
522 Return the total length of the parsed instruction.\r
523\r
524 @param[in] InstructionData Instruction parsing context\r
525\r
526 @return Length of parsed instruction\r
527\r
528**/\r
529STATIC\r
530UINT64\r
531InstructionLength (\r
532 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
533 )\r
534{\r
ac0a286f 535 return (UINT64)(InstructionData->End - InstructionData->Begin);\r
fb040cce
TL
536}\r
537\r
538/**\r
539 Initialize the instruction parsing context.\r
540\r
541 Initialize the instruction parsing context, which includes decoding the\r
542 instruction prefixes.\r
543\r
544 @param[in, out] InstructionData Instruction parsing context\r
545 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication\r
546 Block\r
547 @param[in] Regs x64 processor context\r
548\r
549**/\r
550STATIC\r
551VOID\r
552InitInstructionData (\r
553 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,\r
554 IN GHCB *Ghcb,\r
555 IN EFI_SYSTEM_CONTEXT_X64 *Regs\r
556 )\r
557{\r
558 SetMem (InstructionData, sizeof (*InstructionData), 0);\r
ac0a286f
MK
559 InstructionData->Ghcb = Ghcb;\r
560 InstructionData->Begin = (UINT8 *)Regs->Rip;\r
561 InstructionData->End = (UINT8 *)Regs->Rip;\r
fb040cce
TL
562\r
563 DecodePrefixes (Regs, InstructionData);\r
564}\r
565\r
566/**\r
567 Report an unsupported event to the hypervisor\r
568\r
569 Use the VMGEXIT support to report an unsupported event to the hypervisor.\r
570\r
571 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication\r
572 Block\r
573 @param[in] Regs x64 processor context\r
574 @param[in] InstructionData Instruction parsing context\r
575\r
576 @return New exception value to propagate\r
577\r
578**/\r
579STATIC\r
580UINT64\r
581UnsupportedExit (\r
582 IN GHCB *Ghcb,\r
583 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
584 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
585 )\r
586{\r
587 UINT64 Status;\r
588\r
589 Status = VmgExit (Ghcb, SVM_EXIT_UNSUPPORTED, Regs->ExceptionData, 0);\r
590 if (Status == 0) {\r
591 GHCB_EVENT_INJECTION Event;\r
592\r
ac0a286f 593 Event.Uint64 = 0;\r
fb040cce
TL
594 Event.Elements.Vector = GP_EXCEPTION;\r
595 Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;\r
596 Event.Elements.Valid = 1;\r
597\r
598 Status = Event.Uint64;\r
599 }\r
600\r
601 return Status;\r
602}\r
603\r
85b8eac5
TL
604/**\r
605 Validate that the MMIO memory access is not to encrypted memory.\r
606\r
607 Examine the pagetable entry for the memory specified. MMIO should not be\r
608 performed against encrypted memory. MMIO to the APIC page is always allowed.\r
609\r
610 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication Block\r
611 @param[in] MemoryAddress Memory address to validate\r
612 @param[in] MemoryLength Memory length to validate\r
613\r
614 @retval 0 Memory is not encrypted\r
615 @return New exception value to propogate\r
616\r
617**/\r
618STATIC\r
619UINT64\r
620ValidateMmioMemory (\r
621 IN GHCB *Ghcb,\r
622 IN UINTN MemoryAddress,\r
623 IN UINTN MemoryLength\r
624 )\r
625{\r
626 MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State;\r
627 GHCB_EVENT_INJECTION GpEvent;\r
628 UINTN Address;\r
629\r
630 //\r
631 // Allow APIC accesses (which will have the encryption bit set during\r
632 // SEC and PEI phases).\r
633 //\r
634 Address = MemoryAddress & ~(SIZE_4KB - 1);\r
635 if (Address == GetLocalApicBaseAddress ()) {\r
636 return 0;\r
637 }\r
638\r
639 State = MemEncryptSevGetAddressRangeState (\r
640 0,\r
641 MemoryAddress,\r
642 MemoryLength\r
643 );\r
644 if (State == MemEncryptSevAddressRangeUnencrypted) {\r
645 return 0;\r
646 }\r
647\r
648 //\r
649 // Any state other than unencrypted is an error, issue a #GP.\r
650 //\r
ac0a286f
MK
651 DEBUG ((\r
652 DEBUG_ERROR,\r
75d1a790 653 "MMIO using encrypted memory: %lx\n",\r
ac0a286f
MK
654 (UINT64)MemoryAddress\r
655 ));\r
656 GpEvent.Uint64 = 0;\r
85b8eac5
TL
657 GpEvent.Elements.Vector = GP_EXCEPTION;\r
658 GpEvent.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;\r
659 GpEvent.Elements.Valid = 1;\r
660\r
661 return GpEvent.Uint64;\r
662}\r
663\r
c45f678a
TL
664/**\r
665 Handle an MMIO event.\r
666\r
667 Use the VMGEXIT instruction to handle either an MMIO read or an MMIO write.\r
668\r
669 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
670 Block\r
671 @param[in, out] Regs x64 processor context\r
672 @param[in, out] InstructionData Instruction parsing context\r
673\r
674 @retval 0 Event handled successfully\r
675 @return New exception value to propagate\r
676\r
677**/\r
678STATIC\r
679UINT64\r
680MmioExit (\r
681 IN OUT GHCB *Ghcb,\r
682 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
683 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
684 )\r
685{\r
686 UINT64 ExitInfo1, ExitInfo2, Status;\r
687 UINTN Bytes;\r
688 UINT64 *Register;\r
689 UINT8 OpCode, SignByte;\r
cc71bd97 690 UINTN Address;\r
c45f678a
TL
691\r
692 Bytes = 0;\r
693\r
694 OpCode = *(InstructionData->OpCodes);\r
695 if (OpCode == TWO_BYTE_OPCODE_ESCAPE) {\r
696 OpCode = *(InstructionData->OpCodes + 1);\r
697 }\r
698\r
699 switch (OpCode) {\r
ac0a286f
MK
700 //\r
701 // MMIO write (MOV reg/memX, regX)\r
702 //\r
703 case 0x88:\r
704 Bytes = 1;\r
c45f678a
TL
705 //\r
706 // fall through\r
707 //\r
ac0a286f
MK
708 case 0x89:\r
709 DecodeModRm (Regs, InstructionData);\r
710 Bytes = ((Bytes != 0) ? Bytes :\r
711 (InstructionData->DataSize == Size16Bits) ? 2 :\r
712 (InstructionData->DataSize == Size32Bits) ? 4 :\r
713 (InstructionData->DataSize == Size64Bits) ? 8 :\r
714 0);\r
715\r
716 if (InstructionData->Ext.ModRm.Mod == 3) {\r
717 //\r
718 // NPF on two register operands???\r
719 //\r
720 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
721 }\r
c45f678a 722\r
ac0a286f
MK
723 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
724 if (Status != 0) {\r
725 return Status;\r
726 }\r
85b8eac5 727\r
ac0a286f
MK
728 ExitInfo1 = InstructionData->Ext.RmData;\r
729 ExitInfo2 = Bytes;\r
730 CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes);\r
c45f678a 731\r
ac0a286f
MK
732 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
733 VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
734 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
735 if (Status != 0) {\r
736 return Status;\r
737 }\r
c45f678a 738\r
ac0a286f
MK
739 break;\r
740\r
741 //\r
742 // MMIO write (MOV moffsetX, aX)\r
743 //\r
744 case 0xA2:\r
745 Bytes = 1;\r
cc71bd97
TL
746 //\r
747 // fall through\r
748 //\r
ac0a286f
MK
749 case 0xA3:\r
750 Bytes = ((Bytes != 0) ? Bytes :\r
751 (InstructionData->DataSize == Size16Bits) ? 2 :\r
752 (InstructionData->DataSize == Size32Bits) ? 4 :\r
753 (InstructionData->DataSize == Size64Bits) ? 8 :\r
754 0);\r
cc71bd97 755\r
ac0a286f
MK
756 InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);\r
757 InstructionData->End += InstructionData->ImmediateSize;\r
cc71bd97 758\r
ac0a286f
MK
759 //\r
760 // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.\r
761 // Use a STATIC_ASSERT to be certain the code is being built as X64.\r
762 //\r
763 STATIC_ASSERT (\r
764 sizeof (UINTN) == sizeof (UINT64),\r
765 "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"\r
766 );\r
cc71bd97 767\r
ac0a286f
MK
768 Address = 0;\r
769 CopyMem (\r
770 &Address,\r
771 InstructionData->Immediate,\r
772 InstructionData->ImmediateSize\r
773 );\r
cc71bd97 774\r
ac0a286f
MK
775 Status = ValidateMmioMemory (Ghcb, Address, Bytes);\r
776 if (Status != 0) {\r
777 return Status;\r
778 }\r
cc71bd97 779\r
ac0a286f
MK
780 ExitInfo1 = Address;\r
781 ExitInfo2 = Bytes;\r
782 CopyMem (Ghcb->SharedBuffer, &Regs->Rax, Bytes);\r
783\r
784 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
785 VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
786 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
787 if (Status != 0) {\r
788 return Status;\r
789 }\r
790\r
791 break;\r
792\r
793 //\r
794 // MMIO write (MOV reg/memX, immX)\r
795 //\r
796 case 0xC6:\r
797 Bytes = 1;\r
c45f678a
TL
798 //\r
799 // fall through\r
800 //\r
ac0a286f
MK
801 case 0xC7:\r
802 DecodeModRm (Regs, InstructionData);\r
803 Bytes = ((Bytes != 0) ? Bytes :\r
804 (InstructionData->DataSize == Size16Bits) ? 2 :\r
805 (InstructionData->DataSize == Size32Bits) ? 4 :\r
806 0);\r
c45f678a 807\r
ac0a286f
MK
808 InstructionData->ImmediateSize = Bytes;\r
809 InstructionData->End += Bytes;\r
c45f678a 810\r
ac0a286f
MK
811 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
812 if (Status != 0) {\r
813 return Status;\r
814 }\r
85b8eac5 815\r
ac0a286f
MK
816 ExitInfo1 = InstructionData->Ext.RmData;\r
817 ExitInfo2 = Bytes;\r
818 CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, Bytes);\r
c45f678a 819\r
ac0a286f
MK
820 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
821 VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
822 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
823 if (Status != 0) {\r
824 return Status;\r
825 }\r
c45f678a 826\r
ac0a286f
MK
827 break;\r
828\r
829 //\r
830 // MMIO read (MOV regX, reg/memX)\r
831 //\r
832 case 0x8A:\r
833 Bytes = 1;\r
c45f678a
TL
834 //\r
835 // fall through\r
836 //\r
ac0a286f
MK
837 case 0x8B:\r
838 DecodeModRm (Regs, InstructionData);\r
839 Bytes = ((Bytes != 0) ? Bytes :\r
840 (InstructionData->DataSize == Size16Bits) ? 2 :\r
841 (InstructionData->DataSize == Size32Bits) ? 4 :\r
842 (InstructionData->DataSize == Size64Bits) ? 8 :\r
843 0);\r
844 if (InstructionData->Ext.ModRm.Mod == 3) {\r
845 //\r
846 // NPF on two register operands???\r
847 //\r
848 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
849 }\r
c45f678a 850\r
ac0a286f
MK
851 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
852 if (Status != 0) {\r
853 return Status;\r
854 }\r
85b8eac5 855\r
ac0a286f
MK
856 ExitInfo1 = InstructionData->Ext.RmData;\r
857 ExitInfo2 = Bytes;\r
c45f678a 858\r
ac0a286f
MK
859 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
860 VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
861 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
862 if (Status != 0) {\r
863 return Status;\r
864 }\r
c45f678a 865\r
ac0a286f
MK
866 Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
867 if (Bytes == 4) {\r
868 //\r
869 // Zero-extend for 32-bit operation\r
870 //\r
871 *Register = 0;\r
872 }\r
873\r
874 CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
875 break;\r
c45f678a 876\r
cc71bd97 877 //\r
ac0a286f 878 // MMIO read (MOV aX, moffsetX)\r
cc71bd97 879 //\r
ac0a286f
MK
880 case 0xA0:\r
881 Bytes = 1;\r
cc71bd97 882 //\r
ac0a286f 883 // fall through\r
cc71bd97 884 //\r
ac0a286f
MK
885 case 0xA1:\r
886 Bytes = ((Bytes != 0) ? Bytes :\r
887 (InstructionData->DataSize == Size16Bits) ? 2 :\r
888 (InstructionData->DataSize == Size32Bits) ? 4 :\r
889 (InstructionData->DataSize == Size64Bits) ? 8 :\r
890 0);\r
cc71bd97 891\r
ac0a286f
MK
892 InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);\r
893 InstructionData->End += InstructionData->ImmediateSize;\r
cc71bd97 894\r
cc71bd97 895 //\r
ac0a286f
MK
896 // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.\r
897 // Use a STATIC_ASSERT to be certain the code is being built as X64.\r
cc71bd97 898 //\r
ac0a286f
MK
899 STATIC_ASSERT (\r
900 sizeof (UINTN) == sizeof (UINT64),\r
901 "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"\r
902 );\r
cc71bd97 903\r
ac0a286f
MK
904 Address = 0;\r
905 CopyMem (\r
906 &Address,\r
907 InstructionData->Immediate,\r
908 InstructionData->ImmediateSize\r
909 );\r
910\r
911 Status = ValidateMmioMemory (Ghcb, Address, Bytes);\r
912 if (Status != 0) {\r
913 return Status;\r
914 }\r
915\r
916 ExitInfo1 = Address;\r
917 ExitInfo2 = Bytes;\r
918\r
919 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
920 VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
921 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
922 if (Status != 0) {\r
923 return Status;\r
924 }\r
925\r
926 if (Bytes == 4) {\r
927 //\r
928 // Zero-extend for 32-bit operation\r
929 //\r
930 Regs->Rax = 0;\r
931 }\r
932\r
933 CopyMem (&Regs->Rax, Ghcb->SharedBuffer, Bytes);\r
934 break;\r
935\r
936 //\r
937 // MMIO read w/ zero-extension ((MOVZX regX, reg/memX)\r
938 //\r
939 case 0xB6:\r
940 Bytes = 1;\r
c45f678a
TL
941 //\r
942 // fall through\r
943 //\r
ac0a286f
MK
944 case 0xB7:\r
945 DecodeModRm (Regs, InstructionData);\r
946 Bytes = (Bytes != 0) ? Bytes : 2;\r
c45f678a 947\r
ac0a286f
MK
948 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
949 if (Status != 0) {\r
950 return Status;\r
951 }\r
85b8eac5 952\r
ac0a286f
MK
953 ExitInfo1 = InstructionData->Ext.RmData;\r
954 ExitInfo2 = Bytes;\r
c45f678a 955\r
ac0a286f
MK
956 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
957 VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
958 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
959 if (Status != 0) {\r
960 return Status;\r
961 }\r
c45f678a 962\r
ac0a286f
MK
963 Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
964 SetMem (Register, (UINTN)(1 << InstructionData->DataSize), 0);\r
965 CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
966 break;\r
c45f678a 967\r
ac0a286f
MK
968 //\r
969 // MMIO read w/ sign-extension (MOVSX regX, reg/memX)\r
970 //\r
971 case 0xBE:\r
972 Bytes = 1;\r
c45f678a
TL
973 //\r
974 // fall through\r
975 //\r
ac0a286f
MK
976 case 0xBF:\r
977 DecodeModRm (Regs, InstructionData);\r
978 Bytes = (Bytes != 0) ? Bytes : 2;\r
c45f678a 979\r
ac0a286f
MK
980 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
981 if (Status != 0) {\r
982 return Status;\r
983 }\r
85b8eac5 984\r
ac0a286f
MK
985 ExitInfo1 = InstructionData->Ext.RmData;\r
986 ExitInfo2 = Bytes;\r
c45f678a 987\r
ac0a286f
MK
988 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
989 VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
990 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
991 if (Status != 0) {\r
992 return Status;\r
993 }\r
c45f678a 994\r
ac0a286f
MK
995 if (Bytes == 1) {\r
996 UINT8 *Data;\r
c45f678a 997\r
ac0a286f
MK
998 Data = (UINT8 *)Ghcb->SharedBuffer;\r
999 SignByte = ((*Data & BIT7) != 0) ? 0xFF : 0x00;\r
1000 } else {\r
1001 UINT16 *Data;\r
c45f678a 1002\r
ac0a286f
MK
1003 Data = (UINT16 *)Ghcb->SharedBuffer;\r
1004 SignByte = ((*Data & BIT15) != 0) ? 0xFF : 0x00;\r
1005 }\r
c45f678a 1006\r
ac0a286f
MK
1007 Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
1008 SetMem (Register, (UINTN)(1 << InstructionData->DataSize), SignByte);\r
1009 CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
1010 break;\r
c45f678a 1011\r
ac0a286f
MK
1012 default:\r
1013 DEBUG ((DEBUG_ERROR, "Invalid MMIO opcode (%x)\n", OpCode));\r
1014 Status = GP_EXCEPTION;\r
1015 ASSERT (FALSE);\r
c45f678a
TL
1016 }\r
1017\r
1018 return Status;\r
1019}\r
1020\r
9f7e0d0a
TL
1021/**\r
1022 Handle a MWAIT event.\r
1023\r
1024 Use the VMGEXIT instruction to handle a MWAIT event.\r
1025\r
1026 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1027 Block\r
1028 @param[in, out] Regs x64 processor context\r
1029 @param[in] InstructionData Instruction parsing context\r
1030\r
1031 @retval 0 Event handled successfully\r
1032 @return New exception value to propagate\r
1033\r
1034**/\r
1035STATIC\r
1036UINT64\r
1037MwaitExit (\r
1038 IN OUT GHCB *Ghcb,\r
1039 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1040 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1041 )\r
1042{\r
1043 DecodeModRm (Regs, InstructionData);\r
1044\r
1045 Ghcb->SaveArea.Rax = Regs->Rax;\r
a13967f2 1046 VmgSetOffsetValid (Ghcb, GhcbRax);\r
9f7e0d0a 1047 Ghcb->SaveArea.Rcx = Regs->Rcx;\r
a13967f2 1048 VmgSetOffsetValid (Ghcb, GhcbRcx);\r
9f7e0d0a
TL
1049\r
1050 return VmgExit (Ghcb, SVM_EXIT_MWAIT, 0, 0);\r
1051}\r
1052\r
3ef8bfc2
TL
1053/**\r
1054 Handle a MONITOR event.\r
1055\r
1056 Use the VMGEXIT instruction to handle a MONITOR event.\r
1057\r
1058 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1059 Block\r
1060 @param[in, out] Regs x64 processor context\r
1061 @param[in] InstructionData Instruction parsing context\r
1062\r
1063 @retval 0 Event handled successfully\r
1064 @return New exception value to propagate\r
1065\r
1066**/\r
1067STATIC\r
1068UINT64\r
1069MonitorExit (\r
1070 IN OUT GHCB *Ghcb,\r
1071 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1072 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1073 )\r
1074{\r
1075 DecodeModRm (Regs, InstructionData);\r
1076\r
1077 Ghcb->SaveArea.Rax = Regs->Rax; // Identity mapped, so VA = PA\r
a13967f2 1078 VmgSetOffsetValid (Ghcb, GhcbRax);\r
3ef8bfc2 1079 Ghcb->SaveArea.Rcx = Regs->Rcx;\r
a13967f2 1080 VmgSetOffsetValid (Ghcb, GhcbRcx);\r
3ef8bfc2 1081 Ghcb->SaveArea.Rdx = Regs->Rdx;\r
a13967f2 1082 VmgSetOffsetValid (Ghcb, GhcbRdx);\r
3ef8bfc2
TL
1083\r
1084 return VmgExit (Ghcb, SVM_EXIT_MONITOR, 0, 0);\r
1085}\r
1086\r
4de70479
TL
1087/**\r
1088 Handle a WBINVD event.\r
1089\r
1090 Use the VMGEXIT instruction to handle a WBINVD event.\r
1091\r
1092 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1093 Block\r
1094 @param[in, out] Regs x64 processor context\r
1095 @param[in] InstructionData Instruction parsing context\r
1096\r
1097 @retval 0 Event handled successfully\r
1098 @return New exception value to propagate\r
1099\r
1100**/\r
1101STATIC\r
1102UINT64\r
1103WbinvdExit (\r
1104 IN OUT GHCB *Ghcb,\r
1105 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1106 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1107 )\r
1108{\r
1109 return VmgExit (Ghcb, SVM_EXIT_WBINVD, 0, 0);\r
1110}\r
1111\r
f4571f24
TL
1112/**\r
1113 Handle a RDTSCP event.\r
1114\r
1115 Use the VMGEXIT instruction to handle a RDTSCP 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
1128RdtscpExit (\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
1134 UINT64 Status;\r
1135\r
1136 DecodeModRm (Regs, InstructionData);\r
1137\r
1138 Status = VmgExit (Ghcb, SVM_EXIT_RDTSCP, 0, 0);\r
1139 if (Status != 0) {\r
1140 return Status;\r
1141 }\r
1142\r
a13967f2
TL
1143 if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
1144 !VmgIsOffsetValid (Ghcb, GhcbRcx) ||\r
ac0a286f
MK
1145 !VmgIsOffsetValid (Ghcb, GhcbRdx))\r
1146 {\r
f4571f24
TL
1147 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
1148 }\r
ac0a286f 1149\r
f4571f24
TL
1150 Regs->Rax = Ghcb->SaveArea.Rax;\r
1151 Regs->Rcx = Ghcb->SaveArea.Rcx;\r
1152 Regs->Rdx = Ghcb->SaveArea.Rdx;\r
1153\r
1154 return 0;\r
1155}\r
1156\r
e4bb269a
TL
1157/**\r
1158 Handle a VMMCALL event.\r
1159\r
1160 Use the VMGEXIT instruction to handle a VMMCALL event.\r
1161\r
1162 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1163 Block\r
1164 @param[in, out] Regs x64 processor context\r
1165 @param[in] InstructionData Instruction parsing context\r
1166\r
1167 @retval 0 Event handled successfully\r
1168 @return New exception value to propagate\r
1169\r
1170**/\r
1171STATIC\r
1172UINT64\r
1173VmmCallExit (\r
1174 IN OUT GHCB *Ghcb,\r
1175 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1176 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1177 )\r
1178{\r
1179 UINT64 Status;\r
1180\r
1181 DecodeModRm (Regs, InstructionData);\r
1182\r
1183 Ghcb->SaveArea.Rax = Regs->Rax;\r
a13967f2 1184 VmgSetOffsetValid (Ghcb, GhcbRax);\r
ac0a286f 1185 Ghcb->SaveArea.Cpl = (UINT8)(Regs->Cs & 0x3);\r
a13967f2 1186 VmgSetOffsetValid (Ghcb, GhcbCpl);\r
e4bb269a
TL
1187\r
1188 Status = VmgExit (Ghcb, SVM_EXIT_VMMCALL, 0, 0);\r
1189 if (Status != 0) {\r
1190 return Status;\r
1191 }\r
1192\r
a13967f2 1193 if (!VmgIsOffsetValid (Ghcb, GhcbRax)) {\r
e4bb269a
TL
1194 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
1195 }\r
ac0a286f 1196\r
e4bb269a
TL
1197 Regs->Rax = Ghcb->SaveArea.Rax;\r
1198\r
1199 return 0;\r
1200}\r
1201\r
9711c923
TL
1202/**\r
1203 Handle an MSR event.\r
1204\r
1205 Use the VMGEXIT instruction to handle either a RDMSR or WRMSR event.\r
1206\r
1207 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1208 Block\r
1209 @param[in, out] Regs x64 processor context\r
1210 @param[in] InstructionData Instruction parsing context\r
1211\r
1212 @retval 0 Event handled successfully\r
1213 @return New exception value to propagate\r
1214\r
1215**/\r
1216STATIC\r
1217UINT64\r
1218MsrExit (\r
1219 IN OUT GHCB *Ghcb,\r
1220 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1221 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1222 )\r
1223{\r
1224 UINT64 ExitInfo1, Status;\r
1225\r
1226 ExitInfo1 = 0;\r
1227\r
1228 switch (*(InstructionData->OpCodes + 1)) {\r
ac0a286f
MK
1229 case 0x30: // WRMSR\r
1230 ExitInfo1 = 1;\r
1231 Ghcb->SaveArea.Rax = Regs->Rax;\r
1232 VmgSetOffsetValid (Ghcb, GhcbRax);\r
1233 Ghcb->SaveArea.Rdx = Regs->Rdx;\r
1234 VmgSetOffsetValid (Ghcb, GhcbRdx);\r
9711c923
TL
1235 //\r
1236 // fall through\r
1237 //\r
ac0a286f
MK
1238 case 0x32: // RDMSR\r
1239 Ghcb->SaveArea.Rcx = Regs->Rcx;\r
1240 VmgSetOffsetValid (Ghcb, GhcbRcx);\r
1241 break;\r
1242 default:\r
1243 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
9711c923
TL
1244 }\r
1245\r
1246 Status = VmgExit (Ghcb, SVM_EXIT_MSR, ExitInfo1, 0);\r
1247 if (Status != 0) {\r
1248 return Status;\r
1249 }\r
1250\r
1251 if (ExitInfo1 == 0) {\r
a13967f2 1252 if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
ac0a286f
MK
1253 !VmgIsOffsetValid (Ghcb, GhcbRdx))\r
1254 {\r
9711c923
TL
1255 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
1256 }\r
ac0a286f 1257\r
9711c923
TL
1258 Regs->Rax = Ghcb->SaveArea.Rax;\r
1259 Regs->Rdx = Ghcb->SaveArea.Rdx;\r
1260 }\r
1261\r
1262 return 0;\r
1263}\r
1264\r
fb040cce
TL
1265/**\r
1266 Build the IOIO event information.\r
1267\r
1268 The IOIO event information identifies the type of IO operation to be performed\r
1269 by the hypervisor. Build this information based on the instruction data.\r
1270\r
1271 @param[in] Regs x64 processor context\r
1272 @param[in, out] InstructionData Instruction parsing context\r
1273\r
1274 @return IOIO event information value\r
1275\r
1276**/\r
1277STATIC\r
1278UINT64\r
1279IoioExitInfo (\r
1280 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1281 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData\r
1282 )\r
1283{\r
1284 UINT64 ExitInfo;\r
1285\r
1286 ExitInfo = 0;\r
1287\r
1288 switch (*(InstructionData->OpCodes)) {\r
ac0a286f
MK
1289 //\r
1290 // INS opcodes\r
1291 //\r
1292 case 0x6C:\r
1293 case 0x6D:\r
1294 ExitInfo |= IOIO_TYPE_INS;\r
1295 ExitInfo |= IOIO_SEG_ES;\r
1296 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
1297 break;\r
0020157a 1298\r
ac0a286f
MK
1299 //\r
1300 // OUTS opcodes\r
1301 //\r
1302 case 0x6E:\r
1303 case 0x6F:\r
1304 ExitInfo |= IOIO_TYPE_OUTS;\r
1305 ExitInfo |= IOIO_SEG_DS;\r
1306 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
1307 break;\r
0020157a 1308\r
ac0a286f
MK
1309 //\r
1310 // IN immediate opcodes\r
1311 //\r
1312 case 0xE4:\r
1313 case 0xE5:\r
1314 InstructionData->ImmediateSize = 1;\r
1315 InstructionData->End++;\r
1316 ExitInfo |= IOIO_TYPE_IN;\r
1317 ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16);\r
1318 break;\r
fb040cce 1319\r
ac0a286f
MK
1320 //\r
1321 // OUT immediate opcodes\r
1322 //\r
1323 case 0xE6:\r
1324 case 0xE7:\r
1325 InstructionData->ImmediateSize = 1;\r
1326 InstructionData->End++;\r
1327 ExitInfo |= IOIO_TYPE_OUT;\r
1328 ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT;\r
1329 break;\r
fb040cce 1330\r
ac0a286f
MK
1331 //\r
1332 // IN register opcodes\r
1333 //\r
1334 case 0xEC:\r
1335 case 0xED:\r
1336 ExitInfo |= IOIO_TYPE_IN;\r
1337 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
1338 break;\r
fb040cce 1339\r
ac0a286f
MK
1340 //\r
1341 // OUT register opcodes\r
1342 //\r
1343 case 0xEE:\r
1344 case 0xEF:\r
1345 ExitInfo |= IOIO_TYPE_OUT;\r
1346 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
1347 break;\r
fb040cce 1348\r
ac0a286f
MK
1349 default:\r
1350 return 0;\r
fb040cce
TL
1351 }\r
1352\r
1353 switch (*(InstructionData->OpCodes)) {\r
ac0a286f
MK
1354 //\r
1355 // Single-byte opcodes\r
1356 //\r
1357 case 0x6C:\r
1358 case 0x6E:\r
1359 case 0xE4:\r
1360 case 0xE6:\r
1361 case 0xEC:\r
1362 case 0xEE:\r
1363 ExitInfo |= IOIO_DATA_8;\r
1364 break;\r
fb040cce 1365\r
ac0a286f
MK
1366 //\r
1367 // Length determined by instruction parsing\r
1368 //\r
1369 default:\r
1370 ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16\r
fb040cce
TL
1371 : IOIO_DATA_32;\r
1372 }\r
1373\r
1374 switch (InstructionData->AddrSize) {\r
ac0a286f
MK
1375 case Size16Bits:\r
1376 ExitInfo |= IOIO_ADDR_16;\r
1377 break;\r
fb040cce 1378\r
ac0a286f
MK
1379 case Size32Bits:\r
1380 ExitInfo |= IOIO_ADDR_32;\r
1381 break;\r
fb040cce 1382\r
ac0a286f
MK
1383 case Size64Bits:\r
1384 ExitInfo |= IOIO_ADDR_64;\r
1385 break;\r
fb040cce 1386\r
ac0a286f
MK
1387 default:\r
1388 break;\r
fb040cce
TL
1389 }\r
1390\r
1391 if (InstructionData->RepMode != 0) {\r
1392 ExitInfo |= IOIO_REP;\r
1393 }\r
1394\r
1395 return ExitInfo;\r
1396}\r
1397\r
1398/**\r
1399 Handle an IOIO event.\r
1400\r
1401 Use the VMGEXIT instruction to handle an IOIO event.\r
1402\r
1403 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1404 Block\r
1405 @param[in, out] Regs x64 processor context\r
1406 @param[in] InstructionData Instruction parsing context\r
1407\r
1408 @retval 0 Event handled successfully\r
1409 @return New exception value to propagate\r
1410\r
1411**/\r
1412STATIC\r
1413UINT64\r
1414IoioExit (\r
1415 IN OUT GHCB *Ghcb,\r
1416 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1417 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1418 )\r
1419{\r
0020157a
TL
1420 UINT64 ExitInfo1, ExitInfo2, Status;\r
1421 BOOLEAN IsString;\r
fb040cce
TL
1422\r
1423 ExitInfo1 = IoioExitInfo (Regs, InstructionData);\r
1424 if (ExitInfo1 == 0) {\r
1425 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
1426 }\r
1427\r
0020157a
TL
1428 IsString = ((ExitInfo1 & IOIO_TYPE_STR) != 0) ? TRUE : FALSE;\r
1429 if (IsString) {\r
1430 UINTN IoBytes, VmgExitBytes;\r
1431 UINTN GhcbCount, OpCount;\r
1432\r
1433 Status = 0;\r
1434\r
ac0a286f 1435 IoBytes = IOIO_DATA_BYTES (ExitInfo1);\r
0020157a
TL
1436 GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes;\r
1437\r
1438 OpCount = ((ExitInfo1 & IOIO_REP) != 0) ? Regs->Rcx : 1;\r
1439 while (OpCount != 0) {\r
ac0a286f 1440 ExitInfo2 = MIN (OpCount, GhcbCount);\r
0020157a
TL
1441 VmgExitBytes = ExitInfo2 * IoBytes;\r
1442\r
1443 if ((ExitInfo1 & IOIO_TYPE_IN) == 0) {\r
ac0a286f 1444 CopyMem (Ghcb->SharedBuffer, (VOID *)Regs->Rsi, VmgExitBytes);\r
0020157a
TL
1445 Regs->Rsi += VmgExitBytes;\r
1446 }\r
1447\r
ac0a286f 1448 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
8d9698ec 1449 VmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
0020157a
TL
1450 Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2);\r
1451 if (Status != 0) {\r
1452 return Status;\r
1453 }\r
1454\r
1455 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
ac0a286f 1456 CopyMem ((VOID *)Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes);\r
0020157a
TL
1457 Regs->Rdi += VmgExitBytes;\r
1458 }\r
1459\r
1460 if ((ExitInfo1 & IOIO_REP) != 0) {\r
1461 Regs->Rcx -= ExitInfo2;\r
1462 }\r
1463\r
1464 OpCount -= ExitInfo2;\r
1465 }\r
fb040cce 1466 } else {\r
0020157a
TL
1467 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
1468 Ghcb->SaveArea.Rax = 0;\r
1469 } else {\r
1470 CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));\r
1471 }\r
ac0a286f 1472\r
a13967f2 1473 VmgSetOffsetValid (Ghcb, GhcbRax);\r
fb040cce 1474\r
0020157a
TL
1475 Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);\r
1476 if (Status != 0) {\r
1477 return Status;\r
1478 }\r
fb040cce 1479\r
0020157a 1480 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
a13967f2 1481 if (!VmgIsOffsetValid (Ghcb, GhcbRax)) {\r
0020157a
TL
1482 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
1483 }\r
ac0a286f 1484\r
0020157a 1485 CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));\r
fb040cce 1486 }\r
fb040cce
TL
1487 }\r
1488\r
1489 return 0;\r
1490}\r
61bacc0f 1491\r
3caf1e2e
TL
1492/**\r
1493 Handle a INVD event.\r
1494\r
1495 Use the VMGEXIT instruction to handle a INVD event.\r
1496\r
1497 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1498 Block\r
1499 @param[in, out] Regs x64 processor context\r
1500 @param[in] InstructionData Instruction parsing context\r
1501\r
1502 @retval 0 Event handled successfully\r
1503 @return New exception value to propagate\r
1504\r
1505**/\r
1506STATIC\r
1507UINT64\r
1508InvdExit (\r
1509 IN OUT GHCB *Ghcb,\r
1510 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1511 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1512 )\r
1513{\r
1514 return VmgExit (Ghcb, SVM_EXIT_INVD, 0, 0);\r
1515}\r
1516\r
6587e08d
TL
1517/**\r
1518 Handle a CPUID event.\r
1519\r
1520 Use the VMGEXIT instruction to handle a CPUID 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
1533CpuidExit (\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
1539 UINT64 Status;\r
1540\r
1541 Ghcb->SaveArea.Rax = Regs->Rax;\r
a13967f2 1542 VmgSetOffsetValid (Ghcb, GhcbRax);\r
6587e08d 1543 Ghcb->SaveArea.Rcx = Regs->Rcx;\r
a13967f2 1544 VmgSetOffsetValid (Ghcb, GhcbRcx);\r
6587e08d
TL
1545 if (Regs->Rax == CPUID_EXTENDED_STATE) {\r
1546 IA32_CR4 Cr4;\r
1547\r
ac0a286f 1548 Cr4.UintN = AsmReadCr4 ();\r
6587e08d 1549 Ghcb->SaveArea.XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;\r
a13967f2 1550 VmgSetOffsetValid (Ghcb, GhcbXCr0);\r
6587e08d
TL
1551 }\r
1552\r
1553 Status = VmgExit (Ghcb, SVM_EXIT_CPUID, 0, 0);\r
1554 if (Status != 0) {\r
1555 return Status;\r
1556 }\r
1557\r
a13967f2
TL
1558 if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
1559 !VmgIsOffsetValid (Ghcb, GhcbRbx) ||\r
1560 !VmgIsOffsetValid (Ghcb, GhcbRcx) ||\r
ac0a286f
MK
1561 !VmgIsOffsetValid (Ghcb, GhcbRdx))\r
1562 {\r
6587e08d
TL
1563 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
1564 }\r
ac0a286f 1565\r
6587e08d
TL
1566 Regs->Rax = Ghcb->SaveArea.Rax;\r
1567 Regs->Rbx = Ghcb->SaveArea.Rbx;\r
1568 Regs->Rcx = Ghcb->SaveArea.Rcx;\r
1569 Regs->Rdx = Ghcb->SaveArea.Rdx;\r
1570\r
1571 return 0;\r
1572}\r
1573\r
5894fb1f
TL
1574/**\r
1575 Handle a RDPMC event.\r
1576\r
1577 Use the VMGEXIT instruction to handle a RDPMC event.\r
1578\r
1579 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1580 Block\r
1581 @param[in, out] Regs x64 processor context\r
1582 @param[in] InstructionData Instruction parsing context\r
1583\r
1584 @retval 0 Event handled successfully\r
1585 @return New exception value to propagate\r
1586\r
1587**/\r
1588STATIC\r
1589UINT64\r
1590RdpmcExit (\r
1591 IN OUT GHCB *Ghcb,\r
1592 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1593 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1594 )\r
1595{\r
1596 UINT64 Status;\r
1597\r
1598 Ghcb->SaveArea.Rcx = Regs->Rcx;\r
a13967f2 1599 VmgSetOffsetValid (Ghcb, GhcbRcx);\r
5894fb1f
TL
1600\r
1601 Status = VmgExit (Ghcb, SVM_EXIT_RDPMC, 0, 0);\r
1602 if (Status != 0) {\r
1603 return Status;\r
1604 }\r
1605\r
a13967f2 1606 if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
ac0a286f
MK
1607 !VmgIsOffsetValid (Ghcb, GhcbRdx))\r
1608 {\r
5894fb1f
TL
1609 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
1610 }\r
ac0a286f 1611\r
5894fb1f
TL
1612 Regs->Rax = Ghcb->SaveArea.Rax;\r
1613 Regs->Rdx = Ghcb->SaveArea.Rdx;\r
1614\r
1615 return 0;\r
1616}\r
1617\r
68d18bef
TL
1618/**\r
1619 Handle a RDTSC event.\r
1620\r
1621 Use the VMGEXIT instruction to handle a RDTSC event.\r
1622\r
1623 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1624 Block\r
1625 @param[in, out] Regs x64 processor context\r
1626 @param[in] InstructionData Instruction parsing context\r
1627\r
1628 @retval 0 Event handled successfully\r
1629 @return New exception value to propagate\r
1630\r
1631**/\r
1632STATIC\r
1633UINT64\r
1634RdtscExit (\r
1635 IN OUT GHCB *Ghcb,\r
1636 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1637 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1638 )\r
1639{\r
1640 UINT64 Status;\r
1641\r
1642 Status = VmgExit (Ghcb, SVM_EXIT_RDTSC, 0, 0);\r
1643 if (Status != 0) {\r
1644 return Status;\r
1645 }\r
1646\r
a13967f2 1647 if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||\r
ac0a286f
MK
1648 !VmgIsOffsetValid (Ghcb, GhcbRdx))\r
1649 {\r
68d18bef
TL
1650 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
1651 }\r
ac0a286f 1652\r
68d18bef
TL
1653 Regs->Rax = Ghcb->SaveArea.Rax;\r
1654 Regs->Rdx = Ghcb->SaveArea.Rdx;\r
1655\r
1656 return 0;\r
1657}\r
1658\r
fefcf90c
TL
1659/**\r
1660 Handle a DR7 register write event.\r
1661\r
1662 Use the VMGEXIT instruction to handle a DR7 write event.\r
1663\r
1664 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1665 Block\r
1666 @param[in, out] Regs x64 processor context\r
1667 @param[in] InstructionData Instruction parsing context\r
1668\r
1669 @retval 0 Event handled successfully\r
1670 @return New exception value to propagate\r
1671\r
1672**/\r
1673STATIC\r
1674UINT64\r
1675Dr7WriteExit (\r
1676 IN OUT GHCB *Ghcb,\r
1677 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1678 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1679 )\r
1680{\r
1681 SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
1682 SEV_ES_PER_CPU_DATA *SevEsData;\r
1683 UINT64 *Register;\r
1684 UINT64 Status;\r
1685\r
ac0a286f
MK
1686 Ext = &InstructionData->Ext;\r
1687 SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);\r
fefcf90c
TL
1688\r
1689 DecodeModRm (Regs, InstructionData);\r
1690\r
1691 //\r
1692 // MOV DRn always treats MOD == 3 no matter how encoded\r
1693 //\r
1694 Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
1695\r
1696 //\r
1697 // Using a value of 0 for ExitInfo1 means RAX holds the value\r
1698 //\r
1699 Ghcb->SaveArea.Rax = *Register;\r
a13967f2 1700 VmgSetOffsetValid (Ghcb, GhcbRax);\r
fefcf90c
TL
1701\r
1702 Status = VmgExit (Ghcb, SVM_EXIT_DR7_WRITE, 0, 0);\r
1703 if (Status != 0) {\r
1704 return Status;\r
1705 }\r
1706\r
ac0a286f 1707 SevEsData->Dr7 = *Register;\r
31f5ebd6 1708 SevEsData->Dr7Cached = 1;\r
fefcf90c
TL
1709\r
1710 return 0;\r
1711}\r
1712\r
1713/**\r
1714 Handle a DR7 register read event.\r
1715\r
1716 Use the VMGEXIT instruction to handle a DR7 read event.\r
1717\r
1718 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1719 Block\r
1720 @param[in, out] Regs x64 processor context\r
1721 @param[in] InstructionData Instruction parsing context\r
1722\r
1723 @retval 0 Event handled successfully\r
1724\r
1725**/\r
1726STATIC\r
1727UINT64\r
1728Dr7ReadExit (\r
1729 IN OUT GHCB *Ghcb,\r
1730 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1731 IN SEV_ES_INSTRUCTION_DATA *InstructionData\r
1732 )\r
1733{\r
1734 SEV_ES_INSTRUCTION_OPCODE_EXT *Ext;\r
1735 SEV_ES_PER_CPU_DATA *SevEsData;\r
1736 UINT64 *Register;\r
1737\r
ac0a286f
MK
1738 Ext = &InstructionData->Ext;\r
1739 SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);\r
fefcf90c
TL
1740\r
1741 DecodeModRm (Regs, InstructionData);\r
1742\r
1743 //\r
1744 // MOV DRn always treats MOD == 3 no matter how encoded\r
1745 //\r
1746 Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);\r
1747\r
1748 //\r
1749 // If there is a cached valued for DR7, return that. Otherwise return the\r
1750 // DR7 standard reset value of 0x400 (no debug breakpoints set).\r
1751 //\r
31f5ebd6 1752 *Register = (SevEsData->Dr7Cached == 1) ? SevEsData->Dr7 : 0x400;\r
fefcf90c
TL
1753\r
1754 return 0;\r
1755}\r
1756\r
61bacc0f
TL
1757/**\r
1758 Handle a #VC exception.\r
1759\r
1760 Performs the necessary processing to handle a #VC exception.\r
1761\r
5667dc43 1762 @param[in, out] Ghcb Pointer to the GHCB\r
61bacc0f
TL
1763 @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set\r
1764 as value to use on error.\r
1765 @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT\r
1766\r
1767 @retval EFI_SUCCESS Exception handled\r
1768 @retval EFI_UNSUPPORTED #VC not supported, (new) exception value to\r
1769 propagate provided\r
1770 @retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to\r
1771 propagate provided\r
1772\r
1773**/\r
1774EFI_STATUS\r
1775EFIAPI\r
5667dc43
TL
1776InternalVmgExitHandleVc (\r
1777 IN OUT GHCB *Ghcb,\r
61bacc0f
TL
1778 IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
1779 IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
1780 )\r
1781{\r
ac0a286f
MK
1782 EFI_SYSTEM_CONTEXT_X64 *Regs;\r
1783 NAE_EXIT NaeExit;\r
1784 SEV_ES_INSTRUCTION_DATA InstructionData;\r
1785 UINT64 ExitCode, Status;\r
1786 EFI_STATUS VcRet;\r
1787 BOOLEAN InterruptState;\r
61bacc0f
TL
1788\r
1789 VcRet = EFI_SUCCESS;\r
1790\r
61bacc0f 1791 Regs = SystemContext.SystemContextX64;\r
61bacc0f 1792\r
1b0db1ec 1793 VmgInit (Ghcb, &InterruptState);\r
61bacc0f
TL
1794\r
1795 ExitCode = Regs->ExceptionData;\r
1796 switch (ExitCode) {\r
ac0a286f
MK
1797 case SVM_EXIT_DR7_READ:\r
1798 NaeExit = Dr7ReadExit;\r
1799 break;\r
fefcf90c 1800\r
ac0a286f
MK
1801 case SVM_EXIT_DR7_WRITE:\r
1802 NaeExit = Dr7WriteExit;\r
1803 break;\r
fefcf90c 1804\r
ac0a286f
MK
1805 case SVM_EXIT_RDTSC:\r
1806 NaeExit = RdtscExit;\r
1807 break;\r
68d18bef 1808\r
ac0a286f
MK
1809 case SVM_EXIT_RDPMC:\r
1810 NaeExit = RdpmcExit;\r
1811 break;\r
5894fb1f 1812\r
ac0a286f
MK
1813 case SVM_EXIT_CPUID:\r
1814 NaeExit = CpuidExit;\r
1815 break;\r
6587e08d 1816\r
ac0a286f
MK
1817 case SVM_EXIT_INVD:\r
1818 NaeExit = InvdExit;\r
1819 break;\r
3caf1e2e 1820\r
ac0a286f
MK
1821 case SVM_EXIT_IOIO_PROT:\r
1822 NaeExit = IoioExit;\r
1823 break;\r
fb040cce 1824\r
ac0a286f
MK
1825 case SVM_EXIT_MSR:\r
1826 NaeExit = MsrExit;\r
1827 break;\r
9711c923 1828\r
ac0a286f
MK
1829 case SVM_EXIT_VMMCALL:\r
1830 NaeExit = VmmCallExit;\r
1831 break;\r
e4bb269a 1832\r
ac0a286f
MK
1833 case SVM_EXIT_RDTSCP:\r
1834 NaeExit = RdtscpExit;\r
1835 break;\r
f4571f24 1836\r
ac0a286f
MK
1837 case SVM_EXIT_WBINVD:\r
1838 NaeExit = WbinvdExit;\r
1839 break;\r
4de70479 1840\r
ac0a286f
MK
1841 case SVM_EXIT_MONITOR:\r
1842 NaeExit = MonitorExit;\r
1843 break;\r
3ef8bfc2 1844\r
ac0a286f
MK
1845 case SVM_EXIT_MWAIT:\r
1846 NaeExit = MwaitExit;\r
1847 break;\r
9f7e0d0a 1848\r
ac0a286f
MK
1849 case SVM_EXIT_NPF:\r
1850 NaeExit = MmioExit;\r
1851 break;\r
c45f678a 1852\r
ac0a286f
MK
1853 default:\r
1854 NaeExit = UnsupportedExit;\r
fb040cce 1855 }\r
61bacc0f 1856\r
fb040cce
TL
1857 InitInstructionData (&InstructionData, Ghcb, Regs);\r
1858\r
1859 Status = NaeExit (Ghcb, Regs, &InstructionData);\r
1860 if (Status == 0) {\r
1861 Regs->Rip += InstructionLength (&InstructionData);\r
1862 } else {\r
1863 GHCB_EVENT_INJECTION Event;\r
61bacc0f 1864\r
fb040cce
TL
1865 Event.Uint64 = Status;\r
1866 if (Event.Elements.ErrorCodeValid != 0) {\r
1867 Regs->ExceptionData = Event.Elements.ErrorCode;\r
1868 } else {\r
1869 Regs->ExceptionData = 0;\r
61bacc0f
TL
1870 }\r
1871\r
fb040cce
TL
1872 *ExceptionType = Event.Elements.Vector;\r
1873\r
61bacc0f
TL
1874 VcRet = EFI_PROTOCOL_ERROR;\r
1875 }\r
1876\r
1b0db1ec 1877 VmgDone (Ghcb, InterruptState);\r
61bacc0f
TL
1878\r
1879 return VcRet;\r
1880}\r
5667dc43
TL
1881\r
1882/**\r
1883 Routine to allow ASSERT from within #VC.\r
1884\r
1885 @param[in, out] SevEsData Pointer to the per-CPU data\r
1886\r
1887**/\r
1888VOID\r
1889EFIAPI\r
1890VmgExitIssueAssert (\r
1891 IN OUT SEV_ES_PER_CPU_DATA *SevEsData\r
1892 )\r
1893{\r
1894 //\r
1895 // Progress will be halted, so set VcCount to allow for ASSERT output\r
1896 // to be seen.\r
1897 //\r
1898 SevEsData->VcCount = 0;\r
1899\r
1900 ASSERT (FALSE);\r
1901 CpuDeadLoop ();\r
1902}\r