]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/CcExitLib/CcExitVcHandler.c
OvmfPkg/CcExitLib: Move common X86 instruction code to separate file
[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
c0162205 20#include "CcInstruction.h"\r
fb040cce
TL
21\r
22//\r
23// Non-automatic Exit function prototype\r
24//\r
25typedef\r
26UINT64\r
27(*NAE_EXIT) (\r
c0162205
MX
28 GHCB *Ghcb,\r
29 EFI_SYSTEM_CONTEXT_X64 *Regs,\r
30 CC_INSTRUCTION_DATA *InstructionData\r
fb040cce
TL
31 );\r
32\r
d2b998fb
MR
33//\r
34// SEV-SNP Cpuid table entry/function\r
35//\r
36typedef PACKED struct {\r
37 UINT32 EaxIn;\r
38 UINT32 EcxIn;\r
39 UINT64 Unused;\r
40 UINT64 Unused2;\r
41 UINT32 Eax;\r
42 UINT32 Ebx;\r
43 UINT32 Ecx;\r
44 UINT32 Edx;\r
45 UINT64 Reserved;\r
46} SEV_SNP_CPUID_FUNCTION;\r
47\r
48//\r
49// SEV-SNP Cpuid page format\r
50//\r
51typedef PACKED struct {\r
52 UINT32 Count;\r
53 UINT32 Reserved1;\r
54 UINT64 Reserved2;\r
55 SEV_SNP_CPUID_FUNCTION function[0];\r
56} SEV_SNP_CPUID_INFO;\r
57\r
fb040cce
TL
58/**\r
59 Report an unsupported event to the hypervisor\r
60\r
61 Use the VMGEXIT support to report an unsupported event to the hypervisor.\r
62\r
63 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication\r
64 Block\r
65 @param[in] Regs x64 processor context\r
66 @param[in] InstructionData Instruction parsing context\r
67\r
68 @return New exception value to propagate\r
69\r
70**/\r
71STATIC\r
72UINT64\r
73UnsupportedExit (\r
c0162205
MX
74 IN GHCB *Ghcb,\r
75 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
76 IN CC_INSTRUCTION_DATA *InstructionData\r
fb040cce
TL
77 )\r
78{\r
79 UINT64 Status;\r
80\r
765ba5bf 81 Status = CcExitVmgExit (Ghcb, SVM_EXIT_UNSUPPORTED, Regs->ExceptionData, 0);\r
fb040cce
TL
82 if (Status == 0) {\r
83 GHCB_EVENT_INJECTION Event;\r
84\r
ac0a286f 85 Event.Uint64 = 0;\r
fb040cce
TL
86 Event.Elements.Vector = GP_EXCEPTION;\r
87 Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;\r
88 Event.Elements.Valid = 1;\r
89\r
90 Status = Event.Uint64;\r
91 }\r
92\r
93 return Status;\r
94}\r
95\r
85b8eac5
TL
96/**\r
97 Validate that the MMIO memory access is not to encrypted memory.\r
98\r
99 Examine the pagetable entry for the memory specified. MMIO should not be\r
100 performed against encrypted memory. MMIO to the APIC page is always allowed.\r
101\r
102 @param[in] Ghcb Pointer to the Guest-Hypervisor Communication Block\r
103 @param[in] MemoryAddress Memory address to validate\r
104 @param[in] MemoryLength Memory length to validate\r
105\r
106 @retval 0 Memory is not encrypted\r
107 @return New exception value to propogate\r
108\r
109**/\r
110STATIC\r
111UINT64\r
112ValidateMmioMemory (\r
113 IN GHCB *Ghcb,\r
114 IN UINTN MemoryAddress,\r
115 IN UINTN MemoryLength\r
116 )\r
117{\r
118 MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State;\r
119 GHCB_EVENT_INJECTION GpEvent;\r
120 UINTN Address;\r
121\r
122 //\r
123 // Allow APIC accesses (which will have the encryption bit set during\r
124 // SEC and PEI phases).\r
125 //\r
126 Address = MemoryAddress & ~(SIZE_4KB - 1);\r
127 if (Address == GetLocalApicBaseAddress ()) {\r
128 return 0;\r
129 }\r
130\r
131 State = MemEncryptSevGetAddressRangeState (\r
132 0,\r
133 MemoryAddress,\r
134 MemoryLength\r
135 );\r
136 if (State == MemEncryptSevAddressRangeUnencrypted) {\r
137 return 0;\r
138 }\r
139\r
140 //\r
141 // Any state other than unencrypted is an error, issue a #GP.\r
142 //\r
ac0a286f
MK
143 DEBUG ((\r
144 DEBUG_ERROR,\r
75d1a790 145 "MMIO using encrypted memory: %lx\n",\r
ac0a286f
MK
146 (UINT64)MemoryAddress\r
147 ));\r
148 GpEvent.Uint64 = 0;\r
85b8eac5
TL
149 GpEvent.Elements.Vector = GP_EXCEPTION;\r
150 GpEvent.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;\r
151 GpEvent.Elements.Valid = 1;\r
152\r
153 return GpEvent.Uint64;\r
154}\r
155\r
c45f678a
TL
156/**\r
157 Handle an MMIO event.\r
158\r
159 Use the VMGEXIT instruction to handle either an MMIO read or an MMIO write.\r
160\r
161 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
162 Block\r
163 @param[in, out] Regs x64 processor context\r
164 @param[in, out] InstructionData Instruction parsing context\r
165\r
166 @retval 0 Event handled successfully\r
167 @return New exception value to propagate\r
168\r
169**/\r
170STATIC\r
171UINT64\r
172MmioExit (\r
c0162205
MX
173 IN OUT GHCB *Ghcb,\r
174 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
175 IN OUT CC_INSTRUCTION_DATA *InstructionData\r
c45f678a
TL
176 )\r
177{\r
178 UINT64 ExitInfo1, ExitInfo2, Status;\r
179 UINTN Bytes;\r
180 UINT64 *Register;\r
181 UINT8 OpCode, SignByte;\r
cc71bd97 182 UINTN Address;\r
c45f678a
TL
183\r
184 Bytes = 0;\r
185\r
186 OpCode = *(InstructionData->OpCodes);\r
187 if (OpCode == TWO_BYTE_OPCODE_ESCAPE) {\r
188 OpCode = *(InstructionData->OpCodes + 1);\r
189 }\r
190\r
191 switch (OpCode) {\r
ac0a286f
MK
192 //\r
193 // MMIO write (MOV reg/memX, regX)\r
194 //\r
195 case 0x88:\r
196 Bytes = 1;\r
c45f678a
TL
197 //\r
198 // fall through\r
199 //\r
ac0a286f 200 case 0x89:\r
c0162205 201 CcDecodeModRm (Regs, InstructionData);\r
ac0a286f
MK
202 Bytes = ((Bytes != 0) ? Bytes :\r
203 (InstructionData->DataSize == Size16Bits) ? 2 :\r
204 (InstructionData->DataSize == Size32Bits) ? 4 :\r
205 (InstructionData->DataSize == Size64Bits) ? 8 :\r
206 0);\r
207\r
208 if (InstructionData->Ext.ModRm.Mod == 3) {\r
209 //\r
210 // NPF on two register operands???\r
211 //\r
212 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
213 }\r
c45f678a 214\r
ac0a286f
MK
215 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
216 if (Status != 0) {\r
217 return Status;\r
218 }\r
85b8eac5 219\r
ac0a286f
MK
220 ExitInfo1 = InstructionData->Ext.RmData;\r
221 ExitInfo2 = Bytes;\r
222 CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes);\r
c45f678a 223\r
ac0a286f 224 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
765ba5bf
MX
225 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
226 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
ac0a286f
MK
227 if (Status != 0) {\r
228 return Status;\r
229 }\r
c45f678a 230\r
ac0a286f
MK
231 break;\r
232\r
233 //\r
234 // MMIO write (MOV moffsetX, aX)\r
235 //\r
236 case 0xA2:\r
237 Bytes = 1;\r
cc71bd97
TL
238 //\r
239 // fall through\r
240 //\r
ac0a286f
MK
241 case 0xA3:\r
242 Bytes = ((Bytes != 0) ? Bytes :\r
243 (InstructionData->DataSize == Size16Bits) ? 2 :\r
244 (InstructionData->DataSize == Size32Bits) ? 4 :\r
245 (InstructionData->DataSize == Size64Bits) ? 8 :\r
246 0);\r
cc71bd97 247\r
ac0a286f
MK
248 InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);\r
249 InstructionData->End += InstructionData->ImmediateSize;\r
cc71bd97 250\r
ac0a286f
MK
251 //\r
252 // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.\r
253 // Use a STATIC_ASSERT to be certain the code is being built as X64.\r
254 //\r
255 STATIC_ASSERT (\r
256 sizeof (UINTN) == sizeof (UINT64),\r
257 "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"\r
258 );\r
cc71bd97 259\r
ac0a286f
MK
260 Address = 0;\r
261 CopyMem (\r
262 &Address,\r
263 InstructionData->Immediate,\r
264 InstructionData->ImmediateSize\r
265 );\r
cc71bd97 266\r
ac0a286f
MK
267 Status = ValidateMmioMemory (Ghcb, Address, Bytes);\r
268 if (Status != 0) {\r
269 return Status;\r
270 }\r
cc71bd97 271\r
ac0a286f
MK
272 ExitInfo1 = Address;\r
273 ExitInfo2 = Bytes;\r
274 CopyMem (Ghcb->SharedBuffer, &Regs->Rax, Bytes);\r
275\r
276 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
765ba5bf
MX
277 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
278 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
ac0a286f
MK
279 if (Status != 0) {\r
280 return Status;\r
281 }\r
282\r
283 break;\r
284\r
285 //\r
286 // MMIO write (MOV reg/memX, immX)\r
287 //\r
288 case 0xC6:\r
289 Bytes = 1;\r
c45f678a
TL
290 //\r
291 // fall through\r
292 //\r
ac0a286f 293 case 0xC7:\r
c0162205 294 CcDecodeModRm (Regs, InstructionData);\r
ac0a286f
MK
295 Bytes = ((Bytes != 0) ? Bytes :\r
296 (InstructionData->DataSize == Size16Bits) ? 2 :\r
297 (InstructionData->DataSize == Size32Bits) ? 4 :\r
298 0);\r
c45f678a 299\r
ac0a286f
MK
300 InstructionData->ImmediateSize = Bytes;\r
301 InstructionData->End += Bytes;\r
c45f678a 302\r
ac0a286f
MK
303 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
304 if (Status != 0) {\r
305 return Status;\r
306 }\r
85b8eac5 307\r
ac0a286f
MK
308 ExitInfo1 = InstructionData->Ext.RmData;\r
309 ExitInfo2 = Bytes;\r
310 CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, Bytes);\r
c45f678a 311\r
ac0a286f 312 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
765ba5bf
MX
313 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
314 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);\r
ac0a286f
MK
315 if (Status != 0) {\r
316 return Status;\r
317 }\r
c45f678a 318\r
ac0a286f
MK
319 break;\r
320\r
321 //\r
322 // MMIO read (MOV regX, reg/memX)\r
323 //\r
324 case 0x8A:\r
325 Bytes = 1;\r
c45f678a
TL
326 //\r
327 // fall through\r
328 //\r
ac0a286f 329 case 0x8B:\r
c0162205 330 CcDecodeModRm (Regs, InstructionData);\r
ac0a286f
MK
331 Bytes = ((Bytes != 0) ? Bytes :\r
332 (InstructionData->DataSize == Size16Bits) ? 2 :\r
333 (InstructionData->DataSize == Size32Bits) ? 4 :\r
334 (InstructionData->DataSize == Size64Bits) ? 8 :\r
335 0);\r
336 if (InstructionData->Ext.ModRm.Mod == 3) {\r
337 //\r
338 // NPF on two register operands???\r
339 //\r
340 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
341 }\r
c45f678a 342\r
ac0a286f
MK
343 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
344 if (Status != 0) {\r
345 return Status;\r
346 }\r
85b8eac5 347\r
ac0a286f
MK
348 ExitInfo1 = InstructionData->Ext.RmData;\r
349 ExitInfo2 = Bytes;\r
c45f678a 350\r
ac0a286f 351 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
765ba5bf
MX
352 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
353 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
ac0a286f
MK
354 if (Status != 0) {\r
355 return Status;\r
356 }\r
c45f678a 357\r
c0162205 358 Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
ac0a286f
MK
359 if (Bytes == 4) {\r
360 //\r
361 // Zero-extend for 32-bit operation\r
362 //\r
363 *Register = 0;\r
364 }\r
365\r
366 CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
367 break;\r
c45f678a 368\r
cc71bd97 369 //\r
ac0a286f 370 // MMIO read (MOV aX, moffsetX)\r
cc71bd97 371 //\r
ac0a286f
MK
372 case 0xA0:\r
373 Bytes = 1;\r
cc71bd97 374 //\r
ac0a286f 375 // fall through\r
cc71bd97 376 //\r
ac0a286f
MK
377 case 0xA1:\r
378 Bytes = ((Bytes != 0) ? Bytes :\r
379 (InstructionData->DataSize == Size16Bits) ? 2 :\r
380 (InstructionData->DataSize == Size32Bits) ? 4 :\r
381 (InstructionData->DataSize == Size64Bits) ? 8 :\r
382 0);\r
cc71bd97 383\r
ac0a286f
MK
384 InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);\r
385 InstructionData->End += InstructionData->ImmediateSize;\r
cc71bd97 386\r
cc71bd97 387 //\r
ac0a286f
MK
388 // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.\r
389 // Use a STATIC_ASSERT to be certain the code is being built as X64.\r
cc71bd97 390 //\r
ac0a286f
MK
391 STATIC_ASSERT (\r
392 sizeof (UINTN) == sizeof (UINT64),\r
393 "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"\r
394 );\r
cc71bd97 395\r
ac0a286f
MK
396 Address = 0;\r
397 CopyMem (\r
398 &Address,\r
399 InstructionData->Immediate,\r
400 InstructionData->ImmediateSize\r
401 );\r
402\r
403 Status = ValidateMmioMemory (Ghcb, Address, Bytes);\r
404 if (Status != 0) {\r
405 return Status;\r
406 }\r
407\r
408 ExitInfo1 = Address;\r
409 ExitInfo2 = Bytes;\r
410\r
411 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
765ba5bf
MX
412 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
413 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
ac0a286f
MK
414 if (Status != 0) {\r
415 return Status;\r
416 }\r
417\r
418 if (Bytes == 4) {\r
419 //\r
420 // Zero-extend for 32-bit operation\r
421 //\r
422 Regs->Rax = 0;\r
423 }\r
424\r
425 CopyMem (&Regs->Rax, Ghcb->SharedBuffer, Bytes);\r
426 break;\r
427\r
428 //\r
429 // MMIO read w/ zero-extension ((MOVZX regX, reg/memX)\r
430 //\r
431 case 0xB6:\r
432 Bytes = 1;\r
c45f678a
TL
433 //\r
434 // fall through\r
435 //\r
ac0a286f 436 case 0xB7:\r
c0162205 437 CcDecodeModRm (Regs, InstructionData);\r
ac0a286f 438 Bytes = (Bytes != 0) ? Bytes : 2;\r
c45f678a 439\r
ac0a286f
MK
440 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
441 if (Status != 0) {\r
442 return Status;\r
443 }\r
85b8eac5 444\r
ac0a286f
MK
445 ExitInfo1 = InstructionData->Ext.RmData;\r
446 ExitInfo2 = Bytes;\r
c45f678a 447\r
ac0a286f 448 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
765ba5bf
MX
449 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
450 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
ac0a286f
MK
451 if (Status != 0) {\r
452 return Status;\r
453 }\r
c45f678a 454\r
c0162205 455 Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
ac0a286f
MK
456 SetMem (Register, (UINTN)(1 << InstructionData->DataSize), 0);\r
457 CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
458 break;\r
c45f678a 459\r
ac0a286f
MK
460 //\r
461 // MMIO read w/ sign-extension (MOVSX regX, reg/memX)\r
462 //\r
463 case 0xBE:\r
464 Bytes = 1;\r
c45f678a
TL
465 //\r
466 // fall through\r
467 //\r
ac0a286f 468 case 0xBF:\r
c0162205 469 CcDecodeModRm (Regs, InstructionData);\r
ac0a286f 470 Bytes = (Bytes != 0) ? Bytes : 2;\r
c45f678a 471\r
ac0a286f
MK
472 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);\r
473 if (Status != 0) {\r
474 return Status;\r
475 }\r
85b8eac5 476\r
ac0a286f
MK
477 ExitInfo1 = InstructionData->Ext.RmData;\r
478 ExitInfo2 = Bytes;\r
c45f678a 479\r
ac0a286f 480 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
765ba5bf
MX
481 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
482 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);\r
ac0a286f
MK
483 if (Status != 0) {\r
484 return Status;\r
485 }\r
c45f678a 486\r
ac0a286f
MK
487 if (Bytes == 1) {\r
488 UINT8 *Data;\r
c45f678a 489\r
ac0a286f
MK
490 Data = (UINT8 *)Ghcb->SharedBuffer;\r
491 SignByte = ((*Data & BIT7) != 0) ? 0xFF : 0x00;\r
492 } else {\r
493 UINT16 *Data;\r
c45f678a 494\r
ac0a286f
MK
495 Data = (UINT16 *)Ghcb->SharedBuffer;\r
496 SignByte = ((*Data & BIT15) != 0) ? 0xFF : 0x00;\r
497 }\r
c45f678a 498\r
c0162205 499 Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);\r
ac0a286f
MK
500 SetMem (Register, (UINTN)(1 << InstructionData->DataSize), SignByte);\r
501 CopyMem (Register, Ghcb->SharedBuffer, Bytes);\r
502 break;\r
c45f678a 503\r
ac0a286f
MK
504 default:\r
505 DEBUG ((DEBUG_ERROR, "Invalid MMIO opcode (%x)\n", OpCode));\r
506 Status = GP_EXCEPTION;\r
507 ASSERT (FALSE);\r
c45f678a
TL
508 }\r
509\r
510 return Status;\r
511}\r
512\r
9f7e0d0a
TL
513/**\r
514 Handle a MWAIT event.\r
515\r
516 Use the VMGEXIT instruction to handle a MWAIT event.\r
517\r
518 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
519 Block\r
520 @param[in, out] Regs x64 processor context\r
521 @param[in] InstructionData Instruction parsing context\r
522\r
523 @retval 0 Event handled successfully\r
524 @return New exception value to propagate\r
525\r
526**/\r
527STATIC\r
528UINT64\r
529MwaitExit (\r
c0162205
MX
530 IN OUT GHCB *Ghcb,\r
531 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
532 IN CC_INSTRUCTION_DATA *InstructionData\r
9f7e0d0a
TL
533 )\r
534{\r
c0162205 535 CcDecodeModRm (Regs, InstructionData);\r
9f7e0d0a
TL
536\r
537 Ghcb->SaveArea.Rax = Regs->Rax;\r
765ba5bf 538 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
9f7e0d0a 539 Ghcb->SaveArea.Rcx = Regs->Rcx;\r
765ba5bf 540 CcExitVmgSetOffsetValid (Ghcb, GhcbRcx);\r
9f7e0d0a 541\r
765ba5bf 542 return CcExitVmgExit (Ghcb, SVM_EXIT_MWAIT, 0, 0);\r
9f7e0d0a
TL
543}\r
544\r
3ef8bfc2
TL
545/**\r
546 Handle a MONITOR event.\r
547\r
548 Use the VMGEXIT instruction to handle a MONITOR event.\r
549\r
550 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
551 Block\r
552 @param[in, out] Regs x64 processor context\r
553 @param[in] InstructionData Instruction parsing context\r
554\r
555 @retval 0 Event handled successfully\r
556 @return New exception value to propagate\r
557\r
558**/\r
559STATIC\r
560UINT64\r
561MonitorExit (\r
c0162205
MX
562 IN OUT GHCB *Ghcb,\r
563 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
564 IN CC_INSTRUCTION_DATA *InstructionData\r
3ef8bfc2
TL
565 )\r
566{\r
c0162205 567 CcDecodeModRm (Regs, InstructionData);\r
3ef8bfc2
TL
568\r
569 Ghcb->SaveArea.Rax = Regs->Rax; // Identity mapped, so VA = PA\r
765ba5bf 570 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
3ef8bfc2 571 Ghcb->SaveArea.Rcx = Regs->Rcx;\r
765ba5bf 572 CcExitVmgSetOffsetValid (Ghcb, GhcbRcx);\r
3ef8bfc2 573 Ghcb->SaveArea.Rdx = Regs->Rdx;\r
765ba5bf 574 CcExitVmgSetOffsetValid (Ghcb, GhcbRdx);\r
3ef8bfc2 575\r
765ba5bf 576 return CcExitVmgExit (Ghcb, SVM_EXIT_MONITOR, 0, 0);\r
3ef8bfc2
TL
577}\r
578\r
4de70479
TL
579/**\r
580 Handle a WBINVD event.\r
581\r
582 Use the VMGEXIT instruction to handle a WBINVD event.\r
583\r
584 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
585 Block\r
586 @param[in, out] Regs x64 processor context\r
587 @param[in] InstructionData Instruction parsing context\r
588\r
589 @retval 0 Event handled successfully\r
590 @return New exception value to propagate\r
591\r
592**/\r
593STATIC\r
594UINT64\r
595WbinvdExit (\r
c0162205
MX
596 IN OUT GHCB *Ghcb,\r
597 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
598 IN CC_INSTRUCTION_DATA *InstructionData\r
4de70479
TL
599 )\r
600{\r
765ba5bf 601 return CcExitVmgExit (Ghcb, SVM_EXIT_WBINVD, 0, 0);\r
4de70479
TL
602}\r
603\r
f4571f24
TL
604/**\r
605 Handle a RDTSCP event.\r
606\r
607 Use the VMGEXIT instruction to handle a RDTSCP event.\r
608\r
609 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
610 Block\r
611 @param[in, out] Regs x64 processor context\r
612 @param[in] InstructionData Instruction parsing context\r
613\r
614 @retval 0 Event handled successfully\r
615 @return New exception value to propagate\r
616\r
617**/\r
618STATIC\r
619UINT64\r
620RdtscpExit (\r
c0162205
MX
621 IN OUT GHCB *Ghcb,\r
622 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
623 IN CC_INSTRUCTION_DATA *InstructionData\r
f4571f24
TL
624 )\r
625{\r
626 UINT64 Status;\r
627\r
c0162205 628 CcDecodeModRm (Regs, InstructionData);\r
f4571f24 629\r
765ba5bf 630 Status = CcExitVmgExit (Ghcb, SVM_EXIT_RDTSCP, 0, 0);\r
f4571f24
TL
631 if (Status != 0) {\r
632 return Status;\r
633 }\r
634\r
765ba5bf
MX
635 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax) ||\r
636 !CcExitVmgIsOffsetValid (Ghcb, GhcbRcx) ||\r
637 !CcExitVmgIsOffsetValid (Ghcb, GhcbRdx))\r
ac0a286f 638 {\r
f4571f24
TL
639 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
640 }\r
ac0a286f 641\r
f4571f24
TL
642 Regs->Rax = Ghcb->SaveArea.Rax;\r
643 Regs->Rcx = Ghcb->SaveArea.Rcx;\r
644 Regs->Rdx = Ghcb->SaveArea.Rdx;\r
645\r
646 return 0;\r
647}\r
648\r
e4bb269a
TL
649/**\r
650 Handle a VMMCALL event.\r
651\r
652 Use the VMGEXIT instruction to handle a VMMCALL event.\r
653\r
654 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
655 Block\r
656 @param[in, out] Regs x64 processor context\r
657 @param[in] InstructionData Instruction parsing context\r
658\r
659 @retval 0 Event handled successfully\r
660 @return New exception value to propagate\r
661\r
662**/\r
663STATIC\r
664UINT64\r
665VmmCallExit (\r
c0162205
MX
666 IN OUT GHCB *Ghcb,\r
667 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
668 IN CC_INSTRUCTION_DATA *InstructionData\r
e4bb269a
TL
669 )\r
670{\r
671 UINT64 Status;\r
672\r
c0162205 673 CcDecodeModRm (Regs, InstructionData);\r
e4bb269a
TL
674\r
675 Ghcb->SaveArea.Rax = Regs->Rax;\r
765ba5bf 676 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
ac0a286f 677 Ghcb->SaveArea.Cpl = (UINT8)(Regs->Cs & 0x3);\r
765ba5bf 678 CcExitVmgSetOffsetValid (Ghcb, GhcbCpl);\r
e4bb269a 679\r
765ba5bf 680 Status = CcExitVmgExit (Ghcb, SVM_EXIT_VMMCALL, 0, 0);\r
e4bb269a
TL
681 if (Status != 0) {\r
682 return Status;\r
683 }\r
684\r
765ba5bf 685 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax)) {\r
e4bb269a
TL
686 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
687 }\r
ac0a286f 688\r
e4bb269a
TL
689 Regs->Rax = Ghcb->SaveArea.Rax;\r
690\r
691 return 0;\r
692}\r
693\r
9711c923
TL
694/**\r
695 Handle an MSR event.\r
696\r
697 Use the VMGEXIT instruction to handle either a RDMSR or WRMSR event.\r
698\r
699 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
700 Block\r
701 @param[in, out] Regs x64 processor context\r
702 @param[in] InstructionData Instruction parsing context\r
703\r
704 @retval 0 Event handled successfully\r
705 @return New exception value to propagate\r
706\r
707**/\r
708STATIC\r
709UINT64\r
710MsrExit (\r
c0162205
MX
711 IN OUT GHCB *Ghcb,\r
712 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
713 IN CC_INSTRUCTION_DATA *InstructionData\r
9711c923
TL
714 )\r
715{\r
716 UINT64 ExitInfo1, Status;\r
717\r
718 ExitInfo1 = 0;\r
719\r
720 switch (*(InstructionData->OpCodes + 1)) {\r
ac0a286f
MK
721 case 0x30: // WRMSR\r
722 ExitInfo1 = 1;\r
723 Ghcb->SaveArea.Rax = Regs->Rax;\r
765ba5bf 724 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
ac0a286f 725 Ghcb->SaveArea.Rdx = Regs->Rdx;\r
765ba5bf 726 CcExitVmgSetOffsetValid (Ghcb, GhcbRdx);\r
9711c923
TL
727 //\r
728 // fall through\r
729 //\r
ac0a286f
MK
730 case 0x32: // RDMSR\r
731 Ghcb->SaveArea.Rcx = Regs->Rcx;\r
765ba5bf 732 CcExitVmgSetOffsetValid (Ghcb, GhcbRcx);\r
ac0a286f
MK
733 break;\r
734 default:\r
735 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
9711c923
TL
736 }\r
737\r
765ba5bf 738 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MSR, ExitInfo1, 0);\r
9711c923
TL
739 if (Status != 0) {\r
740 return Status;\r
741 }\r
742\r
743 if (ExitInfo1 == 0) {\r
765ba5bf
MX
744 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax) ||\r
745 !CcExitVmgIsOffsetValid (Ghcb, GhcbRdx))\r
ac0a286f 746 {\r
9711c923
TL
747 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
748 }\r
ac0a286f 749\r
9711c923
TL
750 Regs->Rax = Ghcb->SaveArea.Rax;\r
751 Regs->Rdx = Ghcb->SaveArea.Rdx;\r
752 }\r
753\r
754 return 0;\r
755}\r
756\r
fb040cce
TL
757/**\r
758 Build the IOIO event information.\r
759\r
760 The IOIO event information identifies the type of IO operation to be performed\r
761 by the hypervisor. Build this information based on the instruction data.\r
762\r
763 @param[in] Regs x64 processor context\r
764 @param[in, out] InstructionData Instruction parsing context\r
765\r
766 @return IOIO event information value\r
767\r
768**/\r
769STATIC\r
770UINT64\r
771IoioExitInfo (\r
c0162205
MX
772 IN EFI_SYSTEM_CONTEXT_X64 *Regs,\r
773 IN OUT CC_INSTRUCTION_DATA *InstructionData\r
fb040cce
TL
774 )\r
775{\r
776 UINT64 ExitInfo;\r
777\r
778 ExitInfo = 0;\r
779\r
780 switch (*(InstructionData->OpCodes)) {\r
ac0a286f
MK
781 //\r
782 // INS opcodes\r
783 //\r
784 case 0x6C:\r
785 case 0x6D:\r
786 ExitInfo |= IOIO_TYPE_INS;\r
787 ExitInfo |= IOIO_SEG_ES;\r
788 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
789 break;\r
0020157a 790\r
ac0a286f
MK
791 //\r
792 // OUTS opcodes\r
793 //\r
794 case 0x6E:\r
795 case 0x6F:\r
796 ExitInfo |= IOIO_TYPE_OUTS;\r
797 ExitInfo |= IOIO_SEG_DS;\r
798 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
799 break;\r
0020157a 800\r
ac0a286f
MK
801 //\r
802 // IN immediate opcodes\r
803 //\r
804 case 0xE4:\r
805 case 0xE5:\r
806 InstructionData->ImmediateSize = 1;\r
807 InstructionData->End++;\r
808 ExitInfo |= IOIO_TYPE_IN;\r
809 ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16);\r
810 break;\r
fb040cce 811\r
ac0a286f
MK
812 //\r
813 // OUT immediate opcodes\r
814 //\r
815 case 0xE6:\r
816 case 0xE7:\r
817 InstructionData->ImmediateSize = 1;\r
818 InstructionData->End++;\r
819 ExitInfo |= IOIO_TYPE_OUT;\r
820 ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT;\r
821 break;\r
fb040cce 822\r
ac0a286f
MK
823 //\r
824 // IN register opcodes\r
825 //\r
826 case 0xEC:\r
827 case 0xED:\r
828 ExitInfo |= IOIO_TYPE_IN;\r
829 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
830 break;\r
fb040cce 831\r
ac0a286f
MK
832 //\r
833 // OUT register opcodes\r
834 //\r
835 case 0xEE:\r
836 case 0xEF:\r
837 ExitInfo |= IOIO_TYPE_OUT;\r
838 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);\r
839 break;\r
fb040cce 840\r
ac0a286f
MK
841 default:\r
842 return 0;\r
fb040cce
TL
843 }\r
844\r
845 switch (*(InstructionData->OpCodes)) {\r
ac0a286f
MK
846 //\r
847 // Single-byte opcodes\r
848 //\r
849 case 0x6C:\r
850 case 0x6E:\r
851 case 0xE4:\r
852 case 0xE6:\r
853 case 0xEC:\r
854 case 0xEE:\r
855 ExitInfo |= IOIO_DATA_8;\r
856 break;\r
fb040cce 857\r
ac0a286f
MK
858 //\r
859 // Length determined by instruction parsing\r
860 //\r
861 default:\r
862 ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16\r
fb040cce
TL
863 : IOIO_DATA_32;\r
864 }\r
865\r
866 switch (InstructionData->AddrSize) {\r
ac0a286f
MK
867 case Size16Bits:\r
868 ExitInfo |= IOIO_ADDR_16;\r
869 break;\r
fb040cce 870\r
ac0a286f
MK
871 case Size32Bits:\r
872 ExitInfo |= IOIO_ADDR_32;\r
873 break;\r
fb040cce 874\r
ac0a286f
MK
875 case Size64Bits:\r
876 ExitInfo |= IOIO_ADDR_64;\r
877 break;\r
fb040cce 878\r
ac0a286f
MK
879 default:\r
880 break;\r
fb040cce
TL
881 }\r
882\r
883 if (InstructionData->RepMode != 0) {\r
884 ExitInfo |= IOIO_REP;\r
885 }\r
886\r
887 return ExitInfo;\r
888}\r
889\r
890/**\r
891 Handle an IOIO event.\r
892\r
893 Use the VMGEXIT instruction to handle an IOIO event.\r
894\r
895 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
896 Block\r
897 @param[in, out] Regs x64 processor context\r
898 @param[in] InstructionData Instruction parsing context\r
899\r
900 @retval 0 Event handled successfully\r
901 @return New exception value to propagate\r
902\r
903**/\r
904STATIC\r
905UINT64\r
906IoioExit (\r
c0162205
MX
907 IN OUT GHCB *Ghcb,\r
908 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
909 IN CC_INSTRUCTION_DATA *InstructionData\r
fb040cce
TL
910 )\r
911{\r
0020157a
TL
912 UINT64 ExitInfo1, ExitInfo2, Status;\r
913 BOOLEAN IsString;\r
fb040cce
TL
914\r
915 ExitInfo1 = IoioExitInfo (Regs, InstructionData);\r
916 if (ExitInfo1 == 0) {\r
917 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
918 }\r
919\r
0020157a
TL
920 IsString = ((ExitInfo1 & IOIO_TYPE_STR) != 0) ? TRUE : FALSE;\r
921 if (IsString) {\r
922 UINTN IoBytes, VmgExitBytes;\r
923 UINTN GhcbCount, OpCount;\r
924\r
925 Status = 0;\r
926\r
ac0a286f 927 IoBytes = IOIO_DATA_BYTES (ExitInfo1);\r
0020157a
TL
928 GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes;\r
929\r
930 OpCount = ((ExitInfo1 & IOIO_REP) != 0) ? Regs->Rcx : 1;\r
931 while (OpCount != 0) {\r
ac0a286f 932 ExitInfo2 = MIN (OpCount, GhcbCount);\r
0020157a
TL
933 VmgExitBytes = ExitInfo2 * IoBytes;\r
934\r
935 if ((ExitInfo1 & IOIO_TYPE_IN) == 0) {\r
ac0a286f 936 CopyMem (Ghcb->SharedBuffer, (VOID *)Regs->Rsi, VmgExitBytes);\r
0020157a
TL
937 Regs->Rsi += VmgExitBytes;\r
938 }\r
939\r
ac0a286f 940 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;\r
765ba5bf
MX
941 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);\r
942 Status = CcExitVmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2);\r
0020157a
TL
943 if (Status != 0) {\r
944 return Status;\r
945 }\r
946\r
947 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
ac0a286f 948 CopyMem ((VOID *)Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes);\r
0020157a
TL
949 Regs->Rdi += VmgExitBytes;\r
950 }\r
951\r
952 if ((ExitInfo1 & IOIO_REP) != 0) {\r
953 Regs->Rcx -= ExitInfo2;\r
954 }\r
955\r
956 OpCount -= ExitInfo2;\r
957 }\r
fb040cce 958 } else {\r
0020157a
TL
959 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
960 Ghcb->SaveArea.Rax = 0;\r
961 } else {\r
962 CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));\r
963 }\r
ac0a286f 964\r
765ba5bf 965 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
fb040cce 966\r
765ba5bf 967 Status = CcExitVmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);\r
0020157a
TL
968 if (Status != 0) {\r
969 return Status;\r
970 }\r
fb040cce 971\r
0020157a 972 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {\r
765ba5bf 973 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax)) {\r
0020157a
TL
974 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
975 }\r
ac0a286f 976\r
0020157a 977 CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));\r
fb040cce 978 }\r
fb040cce
TL
979 }\r
980\r
981 return 0;\r
982}\r
61bacc0f 983\r
3caf1e2e
TL
984/**\r
985 Handle a INVD event.\r
986\r
987 Use the VMGEXIT instruction to handle a INVD event.\r
988\r
989 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
990 Block\r
991 @param[in, out] Regs x64 processor context\r
992 @param[in] InstructionData Instruction parsing context\r
993\r
994 @retval 0 Event handled successfully\r
995 @return New exception value to propagate\r
996\r
997**/\r
998STATIC\r
999UINT64\r
1000InvdExit (\r
c0162205
MX
1001 IN OUT GHCB *Ghcb,\r
1002 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1003 IN CC_INSTRUCTION_DATA *InstructionData\r
3caf1e2e
TL
1004 )\r
1005{\r
765ba5bf 1006 return CcExitVmgExit (Ghcb, SVM_EXIT_INVD, 0, 0);\r
3caf1e2e
TL
1007}\r
1008\r
d2b998fb
MR
1009/**\r
1010 Fetch CPUID leaf/function via hypervisor/VMGEXIT.\r
1011\r
1012 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1013 Block\r
1014 @param[in] EaxIn EAX input for cpuid instruction\r
1015 @param[in] EcxIn ECX input for cpuid instruction\r
1016 @param[in] Xcr0In XCR0 at time of cpuid instruction\r
1017 @param[in, out] Eax Pointer to store leaf's EAX value\r
1018 @param[in, out] Ebx Pointer to store leaf's EBX value\r
1019 @param[in, out] Ecx Pointer to store leaf's ECX value\r
1020 @param[in, out] Edx Pointer to store leaf's EDX value\r
1021 @param[in, out] Status Pointer to store status from VMGEXIT (always 0\r
1022 unless return value indicates failure)\r
1023 @param[in, out] Unsupported Pointer to store indication of unsupported\r
1024 VMGEXIT (always false unless return value\r
1025 indicates failure)\r
1026\r
1027 @retval TRUE CPUID leaf fetch successfully.\r
1028 @retval FALSE Error occurred while fetching CPUID leaf. Callers\r
1029 should Status and Unsupported and handle\r
1030 accordingly if they indicate a more precise\r
1031 error condition.\r
1032\r
1033**/\r
1034STATIC\r
1035BOOLEAN\r
1036GetCpuidHyp (\r
1037 IN OUT GHCB *Ghcb,\r
1038 IN UINT32 EaxIn,\r
1039 IN UINT32 EcxIn,\r
1040 IN UINT64 XCr0,\r
1041 IN OUT UINT32 *Eax,\r
1042 IN OUT UINT32 *Ebx,\r
1043 IN OUT UINT32 *Ecx,\r
1044 IN OUT UINT32 *Edx,\r
1045 IN OUT UINT64 *Status,\r
1046 IN OUT BOOLEAN *UnsupportedExit\r
1047 )\r
1048{\r
1049 *UnsupportedExit = FALSE;\r
1050 Ghcb->SaveArea.Rax = EaxIn;\r
765ba5bf 1051 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
d2b998fb 1052 Ghcb->SaveArea.Rcx = EcxIn;\r
765ba5bf 1053 CcExitVmgSetOffsetValid (Ghcb, GhcbRcx);\r
d2b998fb
MR
1054 if (EaxIn == CPUID_EXTENDED_STATE) {\r
1055 Ghcb->SaveArea.XCr0 = XCr0;\r
765ba5bf 1056 CcExitVmgSetOffsetValid (Ghcb, GhcbXCr0);\r
d2b998fb
MR
1057 }\r
1058\r
765ba5bf 1059 *Status = CcExitVmgExit (Ghcb, SVM_EXIT_CPUID, 0, 0);\r
d2b998fb
MR
1060 if (*Status != 0) {\r
1061 return FALSE;\r
1062 }\r
1063\r
765ba5bf
MX
1064 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax) ||\r
1065 !CcExitVmgIsOffsetValid (Ghcb, GhcbRbx) ||\r
1066 !CcExitVmgIsOffsetValid (Ghcb, GhcbRcx) ||\r
1067 !CcExitVmgIsOffsetValid (Ghcb, GhcbRdx))\r
d2b998fb
MR
1068 {\r
1069 *UnsupportedExit = TRUE;\r
1070 return FALSE;\r
1071 }\r
1072\r
1073 if (Eax) {\r
1074 *Eax = (UINT32)(UINTN)Ghcb->SaveArea.Rax;\r
1075 }\r
1076\r
1077 if (Ebx) {\r
1078 *Ebx = (UINT32)(UINTN)Ghcb->SaveArea.Rbx;\r
1079 }\r
1080\r
1081 if (Ecx) {\r
1082 *Ecx = (UINT32)(UINTN)Ghcb->SaveArea.Rcx;\r
1083 }\r
1084\r
1085 if (Edx) {\r
1086 *Edx = (UINT32)(UINTN)Ghcb->SaveArea.Rdx;\r
1087 }\r
1088\r
1089 return TRUE;\r
1090}\r
1091\r
1092/**\r
1093 Check if SEV-SNP enabled.\r
1094\r
1095 @retval TRUE SEV-SNP is enabled.\r
1096 @retval FALSE SEV-SNP is disabled.\r
1097\r
1098**/\r
1099STATIC\r
1100BOOLEAN\r
1101SnpEnabled (\r
1102 VOID\r
1103 )\r
1104{\r
1105 MSR_SEV_STATUS_REGISTER Msr;\r
1106\r
1107 Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);\r
1108\r
1109 return !!Msr.Bits.SevSnpBit;\r
1110}\r
1111\r
1112/**\r
1113 Calculate the total XSAVE area size for enabled XSAVE areas\r
1114\r
1115 @param[in] XFeaturesEnabled Bit-mask of enabled XSAVE features/areas as\r
1116 indicated by XCR0/MSR_IA32_XSS bits\r
1117 @param[in] XSaveBaseSize Base/legacy XSAVE area size (e.g. when\r
1118 XCR0 is 1)\r
1119 @param[in, out] XSaveSize Pointer to storage for calculated XSAVE area\r
1120 size\r
1121 @param[in] Compacted Whether or not the calculation is for the\r
1122 normal XSAVE area size (leaf 0xD,0x0,EBX) or\r
1123 compacted XSAVE area size (leaf 0xD,0x1,EBX)\r
1124\r
1125\r
1126 @retval TRUE XSAVE size calculation was successful.\r
1127 @retval FALSE XSAVE size calculation was unsuccessful.\r
1128**/\r
1129STATIC\r
1130BOOLEAN\r
1131GetCpuidXSaveSize (\r
1132 IN UINT64 XFeaturesEnabled,\r
1133 IN UINT32 XSaveBaseSize,\r
1134 IN OUT UINT32 *XSaveSize,\r
1135 IN BOOLEAN Compacted\r
1136 )\r
1137{\r
1138 SEV_SNP_CPUID_INFO *CpuidInfo;\r
1139 UINT64 XFeaturesFound = 0;\r
1140 UINT32 Idx;\r
1141\r
1142 *XSaveSize = XSaveBaseSize;\r
1143 CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase);\r
1144\r
1145 for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {\r
1146 SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];\r
1147\r
1148 if (!((CpuidFn->EaxIn == 0xD) &&\r
1149 ((CpuidFn->EcxIn == 0) || (CpuidFn->EcxIn == 1))))\r
1150 {\r
1151 continue;\r
1152 }\r
1153\r
1154 if (XFeaturesFound & (1ULL << CpuidFn->EcxIn) ||\r
1155 !(XFeaturesEnabled & (1ULL << CpuidFn->EcxIn)))\r
1156 {\r
1157 continue;\r
1158 }\r
1159\r
1160 XFeaturesFound |= (1ULL << CpuidFn->EcxIn);\r
1161 if (Compacted) {\r
1162 *XSaveSize += CpuidFn->Eax;\r
1163 } else {\r
1164 *XSaveSize = MAX (*XSaveSize, CpuidFn->Eax + CpuidFn->Ebx);\r
1165 }\r
1166 }\r
1167\r
1168 /*\r
1169 * Either the guest set unsupported XCR0/XSS bits, or the corresponding\r
1170 * entries in the CPUID table were not present. This is an invalid state.\r
1171 */\r
1172 if (XFeaturesFound != (XFeaturesEnabled & ~3UL)) {\r
1173 return FALSE;\r
1174 }\r
1175\r
1176 return TRUE;\r
1177}\r
1178\r
1179/**\r
1180 Check if a CPUID leaf/function is indexed via ECX sub-leaf/sub-function\r
1181\r
1182 @param[in] EaxIn EAX input for cpuid instruction\r
1183\r
1184 @retval FALSE cpuid leaf/function is not indexed by ECX input\r
1185 @retval TRUE cpuid leaf/function is indexed by ECX input\r
1186\r
1187**/\r
1188STATIC\r
1189BOOLEAN\r
1190IsFunctionIndexed (\r
1191 IN UINT32 EaxIn\r
1192 )\r
1193{\r
1194 switch (EaxIn) {\r
1195 case CPUID_CACHE_PARAMS:\r
1196 case CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS:\r
1197 case CPUID_EXTENDED_TOPOLOGY:\r
1198 case CPUID_EXTENDED_STATE:\r
1199 case CPUID_INTEL_RDT_MONITORING:\r
1200 case CPUID_INTEL_RDT_ALLOCATION:\r
1201 case CPUID_INTEL_SGX:\r
1202 case CPUID_INTEL_PROCESSOR_TRACE:\r
1203 case CPUID_DETERMINISTIC_ADDRESS_TRANSLATION_PARAMETERS:\r
1204 case CPUID_V2_EXTENDED_TOPOLOGY:\r
1205 case 0x8000001D: /* Cache Topology Information */\r
1206 return TRUE;\r
1207 }\r
1208\r
1209 return FALSE;\r
1210}\r
1211\r
1212/**\r
1213 Fetch CPUID leaf/function via SEV-SNP CPUID table.\r
1214\r
1215 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1216 Block\r
1217 @param[in] EaxIn EAX input for cpuid instruction\r
1218 @param[in] EcxIn ECX input for cpuid instruction\r
1219 @param[in] Xcr0In XCR0 at time of cpuid instruction\r
1220 @param[in, out] Eax Pointer to store leaf's EAX value\r
1221 @param[in, out] Ebx Pointer to store leaf's EBX value\r
1222 @param[in, out] Ecx Pointer to store leaf's ECX value\r
1223 @param[in, out] Edx Pointer to store leaf's EDX value\r
1224 @param[in, out] Status Pointer to store status from VMGEXIT (always 0\r
1225 unless return value indicates failure)\r
1226 @param[in, out] Unsupported Pointer to store indication of unsupported\r
1227 VMGEXIT (always false unless return value\r
1228 indicates failure)\r
1229\r
1230 @retval TRUE CPUID leaf fetch successfully.\r
1231 @retval FALSE Error occurred while fetching CPUID leaf. Callers\r
1232 should Status and Unsupported and handle\r
1233 accordingly if they indicate a more precise\r
1234 error condition.\r
1235\r
1236**/\r
1237STATIC\r
1238BOOLEAN\r
1239GetCpuidFw (\r
1240 IN OUT GHCB *Ghcb,\r
1241 IN UINT32 EaxIn,\r
1242 IN UINT32 EcxIn,\r
1243 IN UINT64 XCr0,\r
1244 IN OUT UINT32 *Eax,\r
1245 IN OUT UINT32 *Ebx,\r
1246 IN OUT UINT32 *Ecx,\r
1247 IN OUT UINT32 *Edx,\r
1248 IN OUT UINT64 *Status,\r
1249 IN OUT BOOLEAN *Unsupported\r
1250 )\r
1251{\r
1252 SEV_SNP_CPUID_INFO *CpuidInfo;\r
1253 BOOLEAN Found;\r
1254 UINT32 Idx;\r
1255\r
1256 CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase);\r
1257 Found = FALSE;\r
1258\r
1259 for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {\r
1260 SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];\r
1261\r
1262 if (CpuidFn->EaxIn != EaxIn) {\r
1263 continue;\r
1264 }\r
1265\r
1266 if (IsFunctionIndexed (CpuidFn->EaxIn) && (CpuidFn->EcxIn != EcxIn)) {\r
1267 continue;\r
1268 }\r
1269\r
1270 *Eax = CpuidFn->Eax;\r
1271 *Ebx = CpuidFn->Ebx;\r
1272 *Ecx = CpuidFn->Ecx;\r
1273 *Edx = CpuidFn->Edx;\r
1274\r
1275 Found = TRUE;\r
1276 break;\r
1277 }\r
1278\r
1279 if (!Found) {\r
1280 *Eax = *Ebx = *Ecx = *Edx = 0;\r
1281 goto Out;\r
1282 }\r
1283\r
1284 if (EaxIn == CPUID_VERSION_INFO) {\r
1285 IA32_CR4 Cr4;\r
1286 UINT32 Ebx2;\r
1287 UINT32 Edx2;\r
1288\r
1289 if (!GetCpuidHyp (\r
1290 Ghcb,\r
1291 EaxIn,\r
1292 EcxIn,\r
1293 XCr0,\r
1294 NULL,\r
1295 &Ebx2,\r
1296 NULL,\r
1297 &Edx2,\r
1298 Status,\r
1299 Unsupported\r
1300 ))\r
1301 {\r
1302 return FALSE;\r
1303 }\r
1304\r
1305 /* initial APIC ID */\r
1306 *Ebx = (*Ebx & 0x00FFFFFF) | (Ebx2 & 0xFF000000);\r
1307 /* APIC enabled bit */\r
1308 *Edx = (*Edx & ~BIT9) | (Edx2 & BIT9);\r
1309 /* OSXSAVE enabled bit */\r
1310 Cr4.UintN = AsmReadCr4 ();\r
1311 *Ecx = (Cr4.Bits.OSXSAVE) ? (*Ecx & ~BIT27) | (*Ecx & BIT27)\r
1312 : (*Ecx & ~BIT27);\r
1313 } else if (EaxIn == CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS) {\r
1314 IA32_CR4 Cr4;\r
1315\r
1316 Cr4.UintN = AsmReadCr4 ();\r
1317 /* OSPKE enabled bit */\r
1318 *Ecx = (Cr4.Bits.PKE) ? (*Ecx | BIT4) : (*Ecx & ~BIT4);\r
1319 } else if (EaxIn == CPUID_EXTENDED_TOPOLOGY) {\r
1320 if (!GetCpuidHyp (\r
1321 Ghcb,\r
1322 EaxIn,\r
1323 EcxIn,\r
1324 XCr0,\r
1325 NULL,\r
1326 NULL,\r
1327 NULL,\r
1328 Edx,\r
1329 Status,\r
1330 Unsupported\r
1331 ))\r
1332 {\r
1333 return FALSE;\r
1334 }\r
1335 } else if ((EaxIn == CPUID_EXTENDED_STATE) && ((EcxIn == 0) || (EcxIn == 1))) {\r
1336 MSR_IA32_XSS_REGISTER XssMsr;\r
1337 BOOLEAN Compacted;\r
1338 UINT32 XSaveSize;\r
1339\r
1340 XssMsr.Uint64 = 0;\r
85589ddb 1341 Compacted = FALSE;\r
d2b998fb
MR
1342 if (EcxIn == 1) {\r
1343 /*\r
1344 * The PPR and APM aren't clear on what size should be encoded in\r
1345 * 0xD:0x1:EBX when compaction is not enabled by either XSAVEC or\r
1346 * XSAVES, as these are generally fixed to 1 on real CPUs. Report\r
1347 * this undefined case as an error.\r
1348 */\r
1349 if (!(*Eax & (BIT3 | BIT1))) {\r
1350 /* (XSAVES | XSAVEC) */\r
1351 return FALSE;\r
1352 }\r
1353\r
1354 Compacted = TRUE;\r
1355 XssMsr.Uint64 = AsmReadMsr64 (MSR_IA32_XSS);\r
1356 }\r
1357\r
1358 if (!GetCpuidXSaveSize (\r
1359 XCr0 | XssMsr.Uint64,\r
1360 *Ebx,\r
1361 &XSaveSize,\r
1362 Compacted\r
1363 ))\r
1364 {\r
1365 return FALSE;\r
1366 }\r
1367\r
1368 *Ebx = XSaveSize;\r
1369 } else if (EaxIn == 0x8000001E) {\r
1370 UINT32 Ebx2;\r
1371 UINT32 Ecx2;\r
1372\r
1373 /* extended APIC ID */\r
1374 if (!GetCpuidHyp (\r
1375 Ghcb,\r
1376 EaxIn,\r
1377 EcxIn,\r
1378 XCr0,\r
1379 Eax,\r
1380 &Ebx2,\r
1381 &Ecx2,\r
1382 NULL,\r
1383 Status,\r
1384 Unsupported\r
1385 ))\r
1386 {\r
1387 return FALSE;\r
1388 }\r
1389\r
1390 /* compute ID */\r
1391 *Ebx = (*Ebx & 0xFFFFFF00) | (Ebx2 & 0x000000FF);\r
1392 /* node ID */\r
1393 *Ecx = (*Ecx & 0xFFFFFF00) | (Ecx2 & 0x000000FF);\r
1394 }\r
1395\r
1396Out:\r
1397 *Status = 0;\r
1398 *Unsupported = FALSE;\r
1399 return TRUE;\r
1400}\r
1401\r
6587e08d
TL
1402/**\r
1403 Handle a CPUID event.\r
1404\r
d2b998fb 1405 Use VMGEXIT instruction or CPUID table to handle a CPUID event.\r
6587e08d
TL
1406\r
1407 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1408 Block\r
1409 @param[in, out] Regs x64 processor context\r
1410 @param[in] InstructionData Instruction parsing context\r
1411\r
1412 @retval 0 Event handled successfully\r
1413 @return New exception value to propagate\r
1414\r
1415**/\r
1416STATIC\r
1417UINT64\r
1418CpuidExit (\r
c0162205
MX
1419 IN OUT GHCB *Ghcb,\r
1420 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1421 IN CC_INSTRUCTION_DATA *InstructionData\r
6587e08d
TL
1422 )\r
1423{\r
d2b998fb
MR
1424 BOOLEAN Unsupported;\r
1425 UINT64 Status;\r
1426 UINT32 EaxIn;\r
1427 UINT32 EcxIn;\r
1428 UINT64 XCr0;\r
1429 UINT32 Eax;\r
1430 UINT32 Ebx;\r
1431 UINT32 Ecx;\r
1432 UINT32 Edx;\r
1433\r
1434 EaxIn = (UINT32)(UINTN)Regs->Rax;\r
1435 EcxIn = (UINT32)(UINTN)Regs->Rcx;\r
1436\r
1437 if (EaxIn == CPUID_EXTENDED_STATE) {\r
6587e08d
TL
1438 IA32_CR4 Cr4;\r
1439\r
ac0a286f 1440 Cr4.UintN = AsmReadCr4 ();\r
6587e08d 1441 Ghcb->SaveArea.XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;\r
d2b998fb 1442 XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;\r
6587e08d
TL
1443 }\r
1444\r
d2b998fb
MR
1445 if (SnpEnabled ()) {\r
1446 if (!GetCpuidFw (\r
1447 Ghcb,\r
1448 EaxIn,\r
1449 EcxIn,\r
1450 XCr0,\r
1451 &Eax,\r
1452 &Ebx,\r
1453 &Ecx,\r
1454 &Edx,\r
1455 &Status,\r
1456 &Unsupported\r
1457 ))\r
1458 {\r
1459 goto CpuidFail;\r
1460 }\r
1461 } else {\r
1462 if (!GetCpuidHyp (\r
1463 Ghcb,\r
1464 EaxIn,\r
1465 EcxIn,\r
1466 XCr0,\r
1467 &Eax,\r
1468 &Ebx,\r
1469 &Ecx,\r
1470 &Edx,\r
1471 &Status,\r
1472 &Unsupported\r
1473 ))\r
1474 {\r
1475 goto CpuidFail;\r
1476 }\r
6587e08d
TL
1477 }\r
1478\r
d2b998fb
MR
1479 Regs->Rax = Eax;\r
1480 Regs->Rbx = Ebx;\r
1481 Regs->Rcx = Ecx;\r
1482 Regs->Rdx = Edx;\r
1483\r
1484 return 0;\r
1485\r
1486CpuidFail:\r
1487 if (Unsupported) {\r
6587e08d
TL
1488 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
1489 }\r
ac0a286f 1490\r
d2b998fb 1491 return Status;\r
6587e08d
TL
1492}\r
1493\r
5894fb1f
TL
1494/**\r
1495 Handle a RDPMC event.\r
1496\r
1497 Use the VMGEXIT instruction to handle a RDPMC event.\r
1498\r
1499 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1500 Block\r
1501 @param[in, out] Regs x64 processor context\r
1502 @param[in] InstructionData Instruction parsing context\r
1503\r
1504 @retval 0 Event handled successfully\r
1505 @return New exception value to propagate\r
1506\r
1507**/\r
1508STATIC\r
1509UINT64\r
1510RdpmcExit (\r
c0162205
MX
1511 IN OUT GHCB *Ghcb,\r
1512 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1513 IN CC_INSTRUCTION_DATA *InstructionData\r
5894fb1f
TL
1514 )\r
1515{\r
1516 UINT64 Status;\r
1517\r
1518 Ghcb->SaveArea.Rcx = Regs->Rcx;\r
765ba5bf 1519 CcExitVmgSetOffsetValid (Ghcb, GhcbRcx);\r
5894fb1f 1520\r
765ba5bf 1521 Status = CcExitVmgExit (Ghcb, SVM_EXIT_RDPMC, 0, 0);\r
5894fb1f
TL
1522 if (Status != 0) {\r
1523 return Status;\r
1524 }\r
1525\r
765ba5bf
MX
1526 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax) ||\r
1527 !CcExitVmgIsOffsetValid (Ghcb, GhcbRdx))\r
ac0a286f 1528 {\r
5894fb1f
TL
1529 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
1530 }\r
ac0a286f 1531\r
5894fb1f
TL
1532 Regs->Rax = Ghcb->SaveArea.Rax;\r
1533 Regs->Rdx = Ghcb->SaveArea.Rdx;\r
1534\r
1535 return 0;\r
1536}\r
1537\r
68d18bef
TL
1538/**\r
1539 Handle a RDTSC event.\r
1540\r
1541 Use the VMGEXIT instruction to handle a RDTSC event.\r
1542\r
1543 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1544 Block\r
1545 @param[in, out] Regs x64 processor context\r
1546 @param[in] InstructionData Instruction parsing context\r
1547\r
1548 @retval 0 Event handled successfully\r
1549 @return New exception value to propagate\r
1550\r
1551**/\r
1552STATIC\r
1553UINT64\r
1554RdtscExit (\r
c0162205
MX
1555 IN OUT GHCB *Ghcb,\r
1556 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1557 IN CC_INSTRUCTION_DATA *InstructionData\r
68d18bef
TL
1558 )\r
1559{\r
1560 UINT64 Status;\r
1561\r
765ba5bf 1562 Status = CcExitVmgExit (Ghcb, SVM_EXIT_RDTSC, 0, 0);\r
68d18bef
TL
1563 if (Status != 0) {\r
1564 return Status;\r
1565 }\r
1566\r
765ba5bf
MX
1567 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax) ||\r
1568 !CcExitVmgIsOffsetValid (Ghcb, GhcbRdx))\r
ac0a286f 1569 {\r
68d18bef
TL
1570 return UnsupportedExit (Ghcb, Regs, InstructionData);\r
1571 }\r
ac0a286f 1572\r
68d18bef
TL
1573 Regs->Rax = Ghcb->SaveArea.Rax;\r
1574 Regs->Rdx = Ghcb->SaveArea.Rdx;\r
1575\r
1576 return 0;\r
1577}\r
1578\r
fefcf90c
TL
1579/**\r
1580 Handle a DR7 register write event.\r
1581\r
1582 Use the VMGEXIT instruction to handle a DR7 write event.\r
1583\r
1584 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1585 Block\r
1586 @param[in, out] Regs x64 processor context\r
1587 @param[in] InstructionData Instruction parsing context\r
1588\r
1589 @retval 0 Event handled successfully\r
1590 @return New exception value to propagate\r
1591\r
1592**/\r
1593STATIC\r
1594UINT64\r
1595Dr7WriteExit (\r
c0162205
MX
1596 IN OUT GHCB *Ghcb,\r
1597 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1598 IN CC_INSTRUCTION_DATA *InstructionData\r
fefcf90c
TL
1599 )\r
1600{\r
c0162205
MX
1601 CC_INSTRUCTION_OPCODE_EXT *Ext;\r
1602 SEV_ES_PER_CPU_DATA *SevEsData;\r
1603 UINT64 *Register;\r
1604 UINT64 Status;\r
fefcf90c 1605\r
ac0a286f
MK
1606 Ext = &InstructionData->Ext;\r
1607 SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);\r
fefcf90c 1608\r
c0162205 1609 CcDecodeModRm (Regs, InstructionData);\r
fefcf90c
TL
1610\r
1611 //\r
1612 // MOV DRn always treats MOD == 3 no matter how encoded\r
1613 //\r
c0162205 1614 Register = CcGetRegisterPointer (Regs, Ext->ModRm.Rm);\r
fefcf90c
TL
1615\r
1616 //\r
1617 // Using a value of 0 for ExitInfo1 means RAX holds the value\r
1618 //\r
1619 Ghcb->SaveArea.Rax = *Register;\r
765ba5bf 1620 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);\r
fefcf90c 1621\r
765ba5bf 1622 Status = CcExitVmgExit (Ghcb, SVM_EXIT_DR7_WRITE, 0, 0);\r
fefcf90c
TL
1623 if (Status != 0) {\r
1624 return Status;\r
1625 }\r
1626\r
ac0a286f 1627 SevEsData->Dr7 = *Register;\r
31f5ebd6 1628 SevEsData->Dr7Cached = 1;\r
fefcf90c
TL
1629\r
1630 return 0;\r
1631}\r
1632\r
1633/**\r
1634 Handle a DR7 register read event.\r
1635\r
1636 Use the VMGEXIT instruction to handle a DR7 read event.\r
1637\r
1638 @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication\r
1639 Block\r
1640 @param[in, out] Regs x64 processor context\r
1641 @param[in] InstructionData Instruction parsing context\r
1642\r
1643 @retval 0 Event handled successfully\r
1644\r
1645**/\r
1646STATIC\r
1647UINT64\r
1648Dr7ReadExit (\r
c0162205
MX
1649 IN OUT GHCB *Ghcb,\r
1650 IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs,\r
1651 IN CC_INSTRUCTION_DATA *InstructionData\r
fefcf90c
TL
1652 )\r
1653{\r
c0162205
MX
1654 CC_INSTRUCTION_OPCODE_EXT *Ext;\r
1655 SEV_ES_PER_CPU_DATA *SevEsData;\r
1656 UINT64 *Register;\r
fefcf90c 1657\r
ac0a286f
MK
1658 Ext = &InstructionData->Ext;\r
1659 SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);\r
fefcf90c 1660\r
c0162205 1661 CcDecodeModRm (Regs, InstructionData);\r
fefcf90c
TL
1662\r
1663 //\r
1664 // MOV DRn always treats MOD == 3 no matter how encoded\r
1665 //\r
c0162205 1666 Register = CcGetRegisterPointer (Regs, Ext->ModRm.Rm);\r
fefcf90c
TL
1667\r
1668 //\r
1669 // If there is a cached valued for DR7, return that. Otherwise return the\r
1670 // DR7 standard reset value of 0x400 (no debug breakpoints set).\r
1671 //\r
31f5ebd6 1672 *Register = (SevEsData->Dr7Cached == 1) ? SevEsData->Dr7 : 0x400;\r
fefcf90c
TL
1673\r
1674 return 0;\r
1675}\r
1676\r
61bacc0f
TL
1677/**\r
1678 Handle a #VC exception.\r
1679\r
1680 Performs the necessary processing to handle a #VC exception.\r
1681\r
5667dc43 1682 @param[in, out] Ghcb Pointer to the GHCB\r
61bacc0f
TL
1683 @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set\r
1684 as value to use on error.\r
1685 @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT\r
1686\r
1687 @retval EFI_SUCCESS Exception handled\r
1688 @retval EFI_UNSUPPORTED #VC not supported, (new) exception value to\r
1689 propagate provided\r
1690 @retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to\r
1691 propagate provided\r
1692\r
1693**/\r
1694EFI_STATUS\r
1695EFIAPI\r
5667dc43
TL
1696InternalVmgExitHandleVc (\r
1697 IN OUT GHCB *Ghcb,\r
61bacc0f
TL
1698 IN OUT EFI_EXCEPTION_TYPE *ExceptionType,\r
1699 IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
1700 )\r
1701{\r
c0162205
MX
1702 EFI_SYSTEM_CONTEXT_X64 *Regs;\r
1703 NAE_EXIT NaeExit;\r
1704 CC_INSTRUCTION_DATA InstructionData;\r
1705 UINT64 ExitCode, Status;\r
1706 EFI_STATUS VcRet;\r
1707 BOOLEAN InterruptState;\r
61bacc0f
TL
1708\r
1709 VcRet = EFI_SUCCESS;\r
1710\r
61bacc0f 1711 Regs = SystemContext.SystemContextX64;\r
61bacc0f 1712\r
765ba5bf 1713 CcExitVmgInit (Ghcb, &InterruptState);\r
61bacc0f
TL
1714\r
1715 ExitCode = Regs->ExceptionData;\r
1716 switch (ExitCode) {\r
ac0a286f
MK
1717 case SVM_EXIT_DR7_READ:\r
1718 NaeExit = Dr7ReadExit;\r
1719 break;\r
fefcf90c 1720\r
ac0a286f
MK
1721 case SVM_EXIT_DR7_WRITE:\r
1722 NaeExit = Dr7WriteExit;\r
1723 break;\r
fefcf90c 1724\r
ac0a286f
MK
1725 case SVM_EXIT_RDTSC:\r
1726 NaeExit = RdtscExit;\r
1727 break;\r
68d18bef 1728\r
ac0a286f
MK
1729 case SVM_EXIT_RDPMC:\r
1730 NaeExit = RdpmcExit;\r
1731 break;\r
5894fb1f 1732\r
ac0a286f
MK
1733 case SVM_EXIT_CPUID:\r
1734 NaeExit = CpuidExit;\r
1735 break;\r
6587e08d 1736\r
ac0a286f
MK
1737 case SVM_EXIT_INVD:\r
1738 NaeExit = InvdExit;\r
1739 break;\r
3caf1e2e 1740\r
ac0a286f
MK
1741 case SVM_EXIT_IOIO_PROT:\r
1742 NaeExit = IoioExit;\r
1743 break;\r
fb040cce 1744\r
ac0a286f
MK
1745 case SVM_EXIT_MSR:\r
1746 NaeExit = MsrExit;\r
1747 break;\r
9711c923 1748\r
ac0a286f
MK
1749 case SVM_EXIT_VMMCALL:\r
1750 NaeExit = VmmCallExit;\r
1751 break;\r
e4bb269a 1752\r
ac0a286f
MK
1753 case SVM_EXIT_RDTSCP:\r
1754 NaeExit = RdtscpExit;\r
1755 break;\r
f4571f24 1756\r
ac0a286f
MK
1757 case SVM_EXIT_WBINVD:\r
1758 NaeExit = WbinvdExit;\r
1759 break;\r
4de70479 1760\r
ac0a286f
MK
1761 case SVM_EXIT_MONITOR:\r
1762 NaeExit = MonitorExit;\r
1763 break;\r
3ef8bfc2 1764\r
ac0a286f
MK
1765 case SVM_EXIT_MWAIT:\r
1766 NaeExit = MwaitExit;\r
1767 break;\r
9f7e0d0a 1768\r
ac0a286f
MK
1769 case SVM_EXIT_NPF:\r
1770 NaeExit = MmioExit;\r
1771 break;\r
c45f678a 1772\r
ac0a286f
MK
1773 default:\r
1774 NaeExit = UnsupportedExit;\r
fb040cce 1775 }\r
61bacc0f 1776\r
c0162205 1777 CcInitInstructionData (&InstructionData, Ghcb, Regs);\r
fb040cce
TL
1778\r
1779 Status = NaeExit (Ghcb, Regs, &InstructionData);\r
1780 if (Status == 0) {\r
c0162205 1781 Regs->Rip += CcInstructionLength (&InstructionData);\r
fb040cce
TL
1782 } else {\r
1783 GHCB_EVENT_INJECTION Event;\r
61bacc0f 1784\r
fb040cce
TL
1785 Event.Uint64 = Status;\r
1786 if (Event.Elements.ErrorCodeValid != 0) {\r
1787 Regs->ExceptionData = Event.Elements.ErrorCode;\r
1788 } else {\r
1789 Regs->ExceptionData = 0;\r
61bacc0f
TL
1790 }\r
1791\r
fb040cce
TL
1792 *ExceptionType = Event.Elements.Vector;\r
1793\r
61bacc0f
TL
1794 VcRet = EFI_PROTOCOL_ERROR;\r
1795 }\r
1796\r
765ba5bf 1797 CcExitVmgDone (Ghcb, InterruptState);\r
61bacc0f
TL
1798\r
1799 return VcRet;\r
1800}\r
5667dc43
TL
1801\r
1802/**\r
1803 Routine to allow ASSERT from within #VC.\r
1804\r
1805 @param[in, out] SevEsData Pointer to the per-CPU data\r
1806\r
1807**/\r
1808VOID\r
1809EFIAPI\r
1810VmgExitIssueAssert (\r
1811 IN OUT SEV_ES_PER_CPU_DATA *SevEsData\r
1812 )\r
1813{\r
1814 //\r
1815 // Progress will be halted, so set VcCount to allow for ASSERT output\r
1816 // to be seen.\r
1817 //\r
1818 SevEsData->VcCount = 0;\r
1819\r
1820 ASSERT (FALSE);\r
1821 CpuDeadLoop ();\r
1822}\r