TianoCore EDK2 master
Loading...
Searching...
No Matches
CcExitVcHandler.c
Go to the documentation of this file.
1
9#include <Base.h>
10#include <Uefi.h>
14#include <Library/CcExitLib.h>
15#include <Library/AmdSvsmLib.h>
16#include <Register/Amd/Msr.h>
19
20#include "CcExitVcHandler.h"
21#include "CcInstruction.h"
22
23//
24// Non-automatic Exit function prototype
25//
26typedef
27UINT64
28(*NAE_EXIT) (
29 GHCB *Ghcb,
31 CC_INSTRUCTION_DATA *InstructionData
32 );
33
34//
35// SEV-SNP Cpuid table entry/function
36//
37typedef PACKED struct {
38 UINT32 EaxIn;
39 UINT32 EcxIn;
40 UINT64 Unused;
41 UINT64 Unused2;
42 UINT32 Eax;
43 UINT32 Ebx;
44 UINT32 Ecx;
45 UINT32 Edx;
46 UINT64 Reserved;
47} SEV_SNP_CPUID_FUNCTION;
48
49//
50// SEV-SNP Cpuid page format
51//
52typedef PACKED struct {
53 UINT32 Count;
54 UINT32 Reserved1;
55 UINT64 Reserved2;
56 SEV_SNP_CPUID_FUNCTION function[0];
57} SEV_SNP_CPUID_INFO;
58
73UINT64
75 IN GHCB *Ghcb,
77 IN CC_INSTRUCTION_DATA *InstructionData
78 )
79{
80 UINT64 Status;
81
82 Status = CcExitVmgExit (Ghcb, SVM_EXIT_UNSUPPORTED, Regs->ExceptionData, 0);
83 if (Status == 0) {
85
86 Event.Uint64 = 0;
87 Event.Elements.Vector = GP_EXCEPTION;
88 Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;
89 Event.Elements.Valid = 1;
90
91 Status = Event.Uint64;
92 }
93
94 return Status;
95}
96
111STATIC
112UINT64
114 IN GHCB *Ghcb,
115 IN UINTN MemoryAddress,
116 IN UINTN MemoryLength
117 )
118{
119 MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State;
120 GHCB_EVENT_INJECTION GpEvent;
121
123 0,
124 MemoryAddress,
125 MemoryLength
126 );
127 if (State == MemEncryptSevAddressRangeUnencrypted) {
128 return 0;
129 }
130
131 //
132 // Any state other than unencrypted is an error, issue a #GP.
133 //
134 DEBUG ((
135 DEBUG_ERROR,
136 "MMIO using encrypted memory: %lx\n",
137 (UINT64)MemoryAddress
138 ));
139 GpEvent.Uint64 = 0;
140 GpEvent.Elements.Vector = GP_EXCEPTION;
141 GpEvent.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;
142 GpEvent.Elements.Valid = 1;
143
144 return GpEvent.Uint64;
145}
146
161STATIC
162UINT64
164 IN OUT GHCB *Ghcb,
166 IN OUT CC_INSTRUCTION_DATA *InstructionData
167 )
168{
169 UINT64 ExitInfo1, ExitInfo2, Status;
170 UINTN Bytes;
171 UINT64 *Register;
172 UINT8 OpCode, SignByte;
173 UINTN Address;
174
175 Bytes = 0;
176
177 OpCode = *(InstructionData->OpCodes);
178 if (OpCode == TWO_BYTE_OPCODE_ESCAPE) {
179 OpCode = *(InstructionData->OpCodes + 1);
180 }
181
182 switch (OpCode) {
183 //
184 // MMIO write (MOV reg/memX, regX)
185 //
186 case 0x88:
187 Bytes = 1;
188 //
189 // fall through
190 //
191 case 0x89:
192 CcDecodeModRm (Regs, InstructionData);
193 Bytes = ((Bytes != 0) ? Bytes :
194 (InstructionData->DataSize == Size16Bits) ? 2 :
195 (InstructionData->DataSize == Size32Bits) ? 4 :
196 (InstructionData->DataSize == Size64Bits) ? 8 :
197 0);
198
199 if (InstructionData->Ext.ModRm.Mod == 3) {
200 //
201 // NPF on two register operands???
202 //
203 return UnsupportedExit (Ghcb, Regs, InstructionData);
204 }
205
206 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
207 if (Status != 0) {
208 return Status;
209 }
210
211 ExitInfo1 = InstructionData->Ext.RmData;
212 ExitInfo2 = Bytes;
213 CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes);
214
215 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
216 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);
217 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
218 if (Status != 0) {
219 return Status;
220 }
221
222 break;
223
224 //
225 // MMIO write (MOV moffsetX, aX)
226 //
227 case 0xA2:
228 Bytes = 1;
229 //
230 // fall through
231 //
232 case 0xA3:
233 Bytes = ((Bytes != 0) ? Bytes :
234 (InstructionData->DataSize == Size16Bits) ? 2 :
235 (InstructionData->DataSize == Size32Bits) ? 4 :
236 (InstructionData->DataSize == Size64Bits) ? 8 :
237 0);
238
239 InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);
240 InstructionData->End += InstructionData->ImmediateSize;
241
242 //
243 // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
244 // Use a STATIC_ASSERT to be certain the code is being built as X64.
245 //
247 sizeof (UINTN) == sizeof (UINT64),
248 "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
249 );
250
251 Address = 0;
252 CopyMem (
253 &Address,
254 InstructionData->Immediate,
255 InstructionData->ImmediateSize
256 );
257
258 Status = ValidateMmioMemory (Ghcb, Address, Bytes);
259 if (Status != 0) {
260 return Status;
261 }
262
263 ExitInfo1 = Address;
264 ExitInfo2 = Bytes;
265 CopyMem (Ghcb->SharedBuffer, &Regs->Rax, Bytes);
266
267 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
268 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);
269 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
270 if (Status != 0) {
271 return Status;
272 }
273
274 break;
275
276 //
277 // MMIO write (MOV reg/memX, immX)
278 //
279 case 0xC6:
280 Bytes = 1;
281 //
282 // fall through
283 //
284 case 0xC7:
285 CcDecodeModRm (Regs, InstructionData);
286 Bytes = ((Bytes != 0) ? Bytes :
287 (InstructionData->DataSize == Size16Bits) ? 2 :
288 (InstructionData->DataSize == Size32Bits) ? 4 :
289 0);
290
291 InstructionData->ImmediateSize = Bytes;
292 InstructionData->End += Bytes;
293
294 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
295 if (Status != 0) {
296 return Status;
297 }
298
299 ExitInfo1 = InstructionData->Ext.RmData;
300 ExitInfo2 = Bytes;
301 CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, Bytes);
302
303 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
304 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);
305 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
306 if (Status != 0) {
307 return Status;
308 }
309
310 break;
311
312 //
313 // MMIO read (MOV regX, reg/memX)
314 //
315 case 0x8A:
316 Bytes = 1;
317 //
318 // fall through
319 //
320 case 0x8B:
321 CcDecodeModRm (Regs, InstructionData);
322 Bytes = ((Bytes != 0) ? Bytes :
323 (InstructionData->DataSize == Size16Bits) ? 2 :
324 (InstructionData->DataSize == Size32Bits) ? 4 :
325 (InstructionData->DataSize == Size64Bits) ? 8 :
326 0);
327 if (InstructionData->Ext.ModRm.Mod == 3) {
328 //
329 // NPF on two register operands???
330 //
331 return UnsupportedExit (Ghcb, Regs, InstructionData);
332 }
333
334 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
335 if (Status != 0) {
336 return Status;
337 }
338
339 ExitInfo1 = InstructionData->Ext.RmData;
340 ExitInfo2 = Bytes;
341
342 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
343 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);
344 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
345 if (Status != 0) {
346 return Status;
347 }
348
349 Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
350 if (Bytes == 4) {
351 //
352 // Zero-extend for 32-bit operation
353 //
354 *Register = 0;
355 }
356
357 CopyMem (Register, Ghcb->SharedBuffer, Bytes);
358 break;
359
360 //
361 // MMIO read (MOV aX, moffsetX)
362 //
363 case 0xA0:
364 Bytes = 1;
365 //
366 // fall through
367 //
368 case 0xA1:
369 Bytes = ((Bytes != 0) ? Bytes :
370 (InstructionData->DataSize == Size16Bits) ? 2 :
371 (InstructionData->DataSize == Size32Bits) ? 4 :
372 (InstructionData->DataSize == Size64Bits) ? 8 :
373 0);
374
375 InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);
376 InstructionData->End += InstructionData->ImmediateSize;
377
378 //
379 // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
380 // Use a STATIC_ASSERT to be certain the code is being built as X64.
381 //
383 sizeof (UINTN) == sizeof (UINT64),
384 "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
385 );
386
387 Address = 0;
388 CopyMem (
389 &Address,
390 InstructionData->Immediate,
391 InstructionData->ImmediateSize
392 );
393
394 Status = ValidateMmioMemory (Ghcb, Address, Bytes);
395 if (Status != 0) {
396 return Status;
397 }
398
399 ExitInfo1 = Address;
400 ExitInfo2 = Bytes;
401
402 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
403 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);
404 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
405 if (Status != 0) {
406 return Status;
407 }
408
409 if (Bytes == 4) {
410 //
411 // Zero-extend for 32-bit operation
412 //
413 Regs->Rax = 0;
414 }
415
416 CopyMem (&Regs->Rax, Ghcb->SharedBuffer, Bytes);
417 break;
418
419 //
420 // MMIO read w/ zero-extension ((MOVZX regX, reg/memX)
421 //
422 case 0xB6:
423 Bytes = 1;
424 //
425 // fall through
426 //
427 case 0xB7:
428 CcDecodeModRm (Regs, InstructionData);
429 Bytes = (Bytes != 0) ? Bytes : 2;
430
431 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
432 if (Status != 0) {
433 return Status;
434 }
435
436 ExitInfo1 = InstructionData->Ext.RmData;
437 ExitInfo2 = Bytes;
438
439 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
440 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);
441 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
442 if (Status != 0) {
443 return Status;
444 }
445
446 Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
447 SetMem (Register, (UINTN)(1 << InstructionData->DataSize), 0);
448 CopyMem (Register, Ghcb->SharedBuffer, Bytes);
449 break;
450
451 //
452 // MMIO read w/ sign-extension (MOVSX regX, reg/memX)
453 //
454 case 0xBE:
455 Bytes = 1;
456 //
457 // fall through
458 //
459 case 0xBF:
460 CcDecodeModRm (Regs, InstructionData);
461 Bytes = (Bytes != 0) ? Bytes : 2;
462
463 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
464 if (Status != 0) {
465 return Status;
466 }
467
468 ExitInfo1 = InstructionData->Ext.RmData;
469 ExitInfo2 = Bytes;
470
471 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
472 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);
473 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
474 if (Status != 0) {
475 return Status;
476 }
477
478 if (Bytes == 1) {
479 UINT8 *Data;
480
481 Data = (UINT8 *)Ghcb->SharedBuffer;
482 SignByte = ((*Data & BIT7) != 0) ? 0xFF : 0x00;
483 } else {
484 UINT16 *Data;
485
486 Data = (UINT16 *)Ghcb->SharedBuffer;
487 SignByte = ((*Data & BIT15) != 0) ? 0xFF : 0x00;
488 }
489
490 Register = CcGetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
491 SetMem (Register, (UINTN)(1 << InstructionData->DataSize), SignByte);
492 CopyMem (Register, Ghcb->SharedBuffer, Bytes);
493 break;
494
495 default:
496 DEBUG ((DEBUG_ERROR, "Invalid MMIO opcode (%x)\n", OpCode));
497 Status = GP_EXCEPTION;
498 ASSERT (FALSE);
499 }
500
501 return Status;
502}
503
518STATIC
519UINT64
521 IN OUT GHCB *Ghcb,
523 IN CC_INSTRUCTION_DATA *InstructionData
524 )
525{
526 Ghcb->SaveArea.Rax = Regs->Rax;
527 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);
528 Ghcb->SaveArea.Rcx = Regs->Rcx;
529 CcExitVmgSetOffsetValid (Ghcb, GhcbRcx);
530
531 return CcExitVmgExit (Ghcb, SVM_EXIT_MWAIT, 0, 0);
532}
533
548STATIC
549UINT64
551 IN OUT GHCB *Ghcb,
553 IN CC_INSTRUCTION_DATA *InstructionData
554 )
555{
556 Ghcb->SaveArea.Rax = Regs->Rax; // Identity mapped, so VA = PA
557 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);
558 Ghcb->SaveArea.Rcx = Regs->Rcx;
559 CcExitVmgSetOffsetValid (Ghcb, GhcbRcx);
560 Ghcb->SaveArea.Rdx = Regs->Rdx;
561 CcExitVmgSetOffsetValid (Ghcb, GhcbRdx);
562
563 return CcExitVmgExit (Ghcb, SVM_EXIT_MONITOR, 0, 0);
564}
565
580STATIC
581UINT64
583 IN OUT GHCB *Ghcb,
585 IN CC_INSTRUCTION_DATA *InstructionData
586 )
587{
588 return CcExitVmgExit (Ghcb, SVM_EXIT_WBINVD, 0, 0);
589}
590
605STATIC
606UINT64
608 IN OUT GHCB *Ghcb,
610 IN CC_INSTRUCTION_DATA *InstructionData
611 )
612{
613 UINT64 Status;
614
615 CcDecodeModRm (Regs, InstructionData);
616
617 Status = CcExitVmgExit (Ghcb, SVM_EXIT_RDTSCP, 0, 0);
618 if (Status != 0) {
619 return Status;
620 }
621
622 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax) ||
623 !CcExitVmgIsOffsetValid (Ghcb, GhcbRcx) ||
624 !CcExitVmgIsOffsetValid (Ghcb, GhcbRdx))
625 {
626 return UnsupportedExit (Ghcb, Regs, InstructionData);
627 }
628
629 Regs->Rax = Ghcb->SaveArea.Rax;
630 Regs->Rcx = Ghcb->SaveArea.Rcx;
631 Regs->Rdx = Ghcb->SaveArea.Rdx;
632
633 return 0;
634}
635
650STATIC
651UINT64
653 IN OUT GHCB *Ghcb,
655 IN CC_INSTRUCTION_DATA *InstructionData
656 )
657{
658 UINT64 Status;
659
660 Ghcb->SaveArea.Rax = Regs->Rax;
661 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);
662 Ghcb->SaveArea.Cpl = (UINT8)(Regs->Cs & 0x3);
663 CcExitVmgSetOffsetValid (Ghcb, GhcbCpl);
664
665 Status = CcExitVmgExit (Ghcb, SVM_EXIT_VMMCALL, 0, 0);
666 if (Status != 0) {
667 return Status;
668 }
669
670 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax)) {
671 return UnsupportedExit (Ghcb, Regs, InstructionData);
672 }
673
674 Regs->Rax = Ghcb->SaveArea.Rax;
675
676 return 0;
677}
678
693STATIC
694UINT64
696 IN OUT GHCB *Ghcb,
698 IN CC_INSTRUCTION_DATA *InstructionData
699 )
700{
702 UINT64 ExitInfo1;
703 UINT64 Status;
704
705 ExitInfo1 = 0;
706
707 //
708 // The SVSM CAA MSR is a software implemented MSR and not supported
709 // by the hardware, handle it directly.
710 //
711 if (Regs->Rax == MSR_SVSM_CAA) {
712 // Writes to the SVSM CAA MSR are ignored
713 if (*(InstructionData->OpCodes + 1) == 0x30) {
714 return 0;
715 }
716
717 Msr.Uint64 = AmdSvsmSnpGetCaa ();
718 Regs->Rax = Msr.Bits.Lower32Bits;
719 Regs->Rdx = Msr.Bits.Upper32Bits;
720
721 return 0;
722 }
723
724 switch (*(InstructionData->OpCodes + 1)) {
725 case 0x30: // WRMSR
726 ExitInfo1 = 1;
727 Ghcb->SaveArea.Rax = Regs->Rax;
728 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);
729 Ghcb->SaveArea.Rdx = Regs->Rdx;
730 CcExitVmgSetOffsetValid (Ghcb, GhcbRdx);
731 //
732 // fall through
733 //
734 case 0x32: // RDMSR
735 Ghcb->SaveArea.Rcx = Regs->Rcx;
736 CcExitVmgSetOffsetValid (Ghcb, GhcbRcx);
737 break;
738 default:
739 return UnsupportedExit (Ghcb, Regs, InstructionData);
740 }
741
742 Status = CcExitVmgExit (Ghcb, SVM_EXIT_MSR, ExitInfo1, 0);
743 if (Status != 0) {
744 return Status;
745 }
746
747 if (ExitInfo1 == 0) {
748 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax) ||
749 !CcExitVmgIsOffsetValid (Ghcb, GhcbRdx))
750 {
751 return UnsupportedExit (Ghcb, Regs, InstructionData);
752 }
753
754 Regs->Rax = Ghcb->SaveArea.Rax;
755 Regs->Rdx = Ghcb->SaveArea.Rdx;
756 }
757
758 return 0;
759}
760
773STATIC
774UINT64
777 IN OUT CC_INSTRUCTION_DATA *InstructionData
778 )
779{
780 UINT64 ExitInfo;
781
782 ExitInfo = 0;
783
784 switch (*(InstructionData->OpCodes)) {
785 //
786 // INS opcodes
787 //
788 case 0x6C:
789 case 0x6D:
790 ExitInfo |= IOIO_TYPE_INS;
791 ExitInfo |= IOIO_SEG_ES;
792 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
793 break;
794
795 //
796 // OUTS opcodes
797 //
798 case 0x6E:
799 case 0x6F:
800 ExitInfo |= IOIO_TYPE_OUTS;
801 ExitInfo |= IOIO_SEG_DS;
802 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
803 break;
804
805 //
806 // IN immediate opcodes
807 //
808 case 0xE4:
809 case 0xE5:
810 InstructionData->ImmediateSize = 1;
811 InstructionData->End++;
812 ExitInfo |= IOIO_TYPE_IN;
813 ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16);
814 break;
815
816 //
817 // OUT immediate opcodes
818 //
819 case 0xE6:
820 case 0xE7:
821 InstructionData->ImmediateSize = 1;
822 InstructionData->End++;
823 ExitInfo |= IOIO_TYPE_OUT;
824 ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT;
825 break;
826
827 //
828 // IN register opcodes
829 //
830 case 0xEC:
831 case 0xED:
832 ExitInfo |= IOIO_TYPE_IN;
833 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
834 break;
835
836 //
837 // OUT register opcodes
838 //
839 case 0xEE:
840 case 0xEF:
841 ExitInfo |= IOIO_TYPE_OUT;
842 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
843 break;
844
845 default:
846 return 0;
847 }
848
849 switch (*(InstructionData->OpCodes)) {
850 //
851 // Single-byte opcodes
852 //
853 case 0x6C:
854 case 0x6E:
855 case 0xE4:
856 case 0xE6:
857 case 0xEC:
858 case 0xEE:
859 ExitInfo |= IOIO_DATA_8;
860 break;
861
862 //
863 // Length determined by instruction parsing
864 //
865 default:
866 ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
867 : IOIO_DATA_32;
868 }
869
870 switch (InstructionData->AddrSize) {
871 case Size16Bits:
872 ExitInfo |= IOIO_ADDR_16;
873 break;
874
875 case Size32Bits:
876 ExitInfo |= IOIO_ADDR_32;
877 break;
878
879 case Size64Bits:
880 ExitInfo |= IOIO_ADDR_64;
881 break;
882
883 default:
884 break;
885 }
886
887 if (InstructionData->RepMode != 0) {
888 ExitInfo |= IOIO_REP;
889 }
890
891 return ExitInfo;
892}
893
908STATIC
909UINT64
911 IN OUT GHCB *Ghcb,
913 IN CC_INSTRUCTION_DATA *InstructionData
914 )
915{
916 UINT64 ExitInfo1, ExitInfo2, Status;
917 BOOLEAN IsString;
918
919 ExitInfo1 = IoioExitInfo (Regs, InstructionData);
920 if (ExitInfo1 == 0) {
921 return UnsupportedExit (Ghcb, Regs, InstructionData);
922 }
923
924 IsString = ((ExitInfo1 & IOIO_TYPE_STR) != 0) ? TRUE : FALSE;
925 if (IsString) {
926 UINTN IoBytes, VmgExitBytes;
927 UINTN GhcbCount, OpCount;
928
929 Status = 0;
930
931 IoBytes = IOIO_DATA_BYTES (ExitInfo1);
932 GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes;
933
934 OpCount = ((ExitInfo1 & IOIO_REP) != 0) ? Regs->Rcx : 1;
935 while (OpCount != 0) {
936 ExitInfo2 = MIN (OpCount, GhcbCount);
937 VmgExitBytes = ExitInfo2 * IoBytes;
938
939 if ((ExitInfo1 & IOIO_TYPE_IN) == 0) {
940 CopyMem (Ghcb->SharedBuffer, (VOID *)Regs->Rsi, VmgExitBytes);
941 Regs->Rsi += VmgExitBytes;
942 }
943
944 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
945 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);
946 Status = CcExitVmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2);
947 if (Status != 0) {
948 return Status;
949 }
950
951 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
952 CopyMem ((VOID *)Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes);
953 Regs->Rdi += VmgExitBytes;
954 }
955
956 if ((ExitInfo1 & IOIO_REP) != 0) {
957 Regs->Rcx -= ExitInfo2;
958 }
959
960 OpCount -= ExitInfo2;
961 }
962 } else {
963 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
964 Ghcb->SaveArea.Rax = 0;
965 } else {
966 CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));
967 }
968
969 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);
970
971 Status = CcExitVmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);
972 if (Status != 0) {
973 return Status;
974 }
975
976 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
977 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax)) {
978 return UnsupportedExit (Ghcb, Regs, InstructionData);
979 }
980
981 CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));
982 }
983 }
984
985 return 0;
986}
987
1002STATIC
1003UINT64
1005 IN OUT GHCB *Ghcb,
1007 IN CC_INSTRUCTION_DATA *InstructionData
1008 )
1009{
1010 return CcExitVmgExit (Ghcb, SVM_EXIT_INVD, 0, 0);
1011}
1012
1038STATIC
1039BOOLEAN
1041 IN OUT GHCB *Ghcb,
1042 IN UINT32 EaxIn,
1043 IN UINT32 EcxIn,
1044 IN UINT64 XCr0,
1045 IN OUT UINT32 *Eax,
1046 IN OUT UINT32 *Ebx,
1047 IN OUT UINT32 *Ecx,
1048 IN OUT UINT32 *Edx,
1049 IN OUT UINT64 *Status,
1050 IN OUT BOOLEAN *UnsupportedExit
1051 )
1052{
1054 Ghcb->SaveArea.Rax = EaxIn;
1055 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);
1056 Ghcb->SaveArea.Rcx = EcxIn;
1057 CcExitVmgSetOffsetValid (Ghcb, GhcbRcx);
1058 if (EaxIn == CPUID_EXTENDED_STATE) {
1059 Ghcb->SaveArea.XCr0 = XCr0;
1060 CcExitVmgSetOffsetValid (Ghcb, GhcbXCr0);
1061 }
1062
1063 *Status = CcExitVmgExit (Ghcb, SVM_EXIT_CPUID, 0, 0);
1064 if (*Status != 0) {
1065 return FALSE;
1066 }
1067
1068 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax) ||
1069 !CcExitVmgIsOffsetValid (Ghcb, GhcbRbx) ||
1070 !CcExitVmgIsOffsetValid (Ghcb, GhcbRcx) ||
1071 !CcExitVmgIsOffsetValid (Ghcb, GhcbRdx))
1072 {
1074 return FALSE;
1075 }
1076
1077 if (Eax) {
1078 *Eax = (UINT32)(UINTN)Ghcb->SaveArea.Rax;
1079 }
1080
1081 if (Ebx) {
1082 *Ebx = (UINT32)(UINTN)Ghcb->SaveArea.Rbx;
1083 }
1084
1085 if (Ecx) {
1086 *Ecx = (UINT32)(UINTN)Ghcb->SaveArea.Rcx;
1087 }
1088
1089 if (Edx) {
1090 *Edx = (UINT32)(UINTN)Ghcb->SaveArea.Rdx;
1091 }
1092
1093 return TRUE;
1094}
1095
1103STATIC
1104BOOLEAN
1106 VOID
1107 )
1108{
1110
1111 Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);
1112
1113 return !!Msr.Bits.SevSnpBit;
1114}
1115
1131STATIC
1132BOOLEAN
1134 IN UINT64 XFeaturesEnabled,
1135 IN OUT UINT32 *XSaveSize,
1136 IN BOOLEAN Compacted
1137 )
1138{
1139 SEV_SNP_CPUID_INFO *CpuidInfo;
1140 UINT64 XFeaturesFound = 0;
1141 UINT32 Idx;
1142
1143 //
1144 // The base/legacy XSave size is documented to be 0x240 in the APM.
1145 //
1146 *XSaveSize = 0x240;
1147 CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase);
1148
1149 for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {
1150 SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];
1151
1152 if (!((CpuidFn->EaxIn == 0xD) && (CpuidFn->EcxIn > 1))) {
1153 continue;
1154 }
1155
1156 if (XFeaturesFound & (1ULL << CpuidFn->EcxIn) ||
1157 !(XFeaturesEnabled & (1ULL << CpuidFn->EcxIn)))
1158 {
1159 continue;
1160 }
1161
1162 XFeaturesFound |= (1ULL << CpuidFn->EcxIn);
1163 if (Compacted) {
1164 *XSaveSize += CpuidFn->Eax;
1165 } else {
1166 *XSaveSize = MAX (*XSaveSize, CpuidFn->Eax + CpuidFn->Ebx);
1167 }
1168 }
1169
1170 /*
1171 * Either the guest set unsupported XCR0/XSS bits, or the corresponding
1172 * entries in the CPUID table were not present. This is an invalid state.
1173 */
1174 if (XFeaturesFound != (XFeaturesEnabled & ~3UL)) {
1175 return FALSE;
1176 }
1177
1178 return TRUE;
1179}
1180
1190STATIC
1191BOOLEAN
1193 IN UINT32 EaxIn
1194 )
1195{
1196 switch (EaxIn) {
1197 case CPUID_CACHE_PARAMS:
1203 case CPUID_INTEL_SGX:
1207 case 0x8000001D: /* Cache Topology Information */
1208 return TRUE;
1209 }
1210
1211 return FALSE;
1212}
1213
1239STATIC
1240BOOLEAN
1242 IN OUT GHCB *Ghcb,
1243 IN UINT32 EaxIn,
1244 IN UINT32 EcxIn,
1245 IN UINT64 XCr0,
1246 IN OUT UINT32 *Eax,
1247 IN OUT UINT32 *Ebx,
1248 IN OUT UINT32 *Ecx,
1249 IN OUT UINT32 *Edx,
1250 IN OUT UINT64 *Status,
1251 IN OUT BOOLEAN *Unsupported
1252 )
1253{
1254 SEV_SNP_CPUID_INFO *CpuidInfo;
1255 BOOLEAN Found;
1256 UINT32 Idx;
1257
1258 CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase);
1259 Found = FALSE;
1260
1261 for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {
1262 SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];
1263
1264 if (CpuidFn->EaxIn != EaxIn) {
1265 continue;
1266 }
1267
1268 if (IsFunctionIndexed (CpuidFn->EaxIn) && (CpuidFn->EcxIn != EcxIn)) {
1269 continue;
1270 }
1271
1272 *Eax = CpuidFn->Eax;
1273 *Ebx = CpuidFn->Ebx;
1274 *Ecx = CpuidFn->Ecx;
1275 *Edx = CpuidFn->Edx;
1276
1277 Found = TRUE;
1278 break;
1279 }
1280
1281 if (!Found) {
1282 *Eax = *Ebx = *Ecx = *Edx = 0;
1283 goto Out;
1284 }
1285
1286 if (EaxIn == CPUID_VERSION_INFO) {
1287 IA32_CR4 Cr4;
1288 UINT32 Ebx2;
1289 UINT32 Edx2;
1290
1291 if (!GetCpuidHyp (
1292 Ghcb,
1293 EaxIn,
1294 EcxIn,
1295 XCr0,
1296 NULL,
1297 &Ebx2,
1298 NULL,
1299 &Edx2,
1300 Status,
1301 Unsupported
1302 ))
1303 {
1304 return FALSE;
1305 }
1306
1307 /* initial APIC ID */
1308 *Ebx = (*Ebx & 0x00FFFFFF) | (Ebx2 & 0xFF000000);
1309 /* APIC enabled bit */
1310 *Edx = (*Edx & ~BIT9) | (Edx2 & BIT9);
1311 /* OSXSAVE enabled bit */
1312 Cr4.UintN = AsmReadCr4 ();
1313 *Ecx = (Cr4.Bits.OSXSAVE) ? (*Ecx & ~BIT27) | (*Ecx & BIT27)
1314 : (*Ecx & ~BIT27);
1315 } else if (EaxIn == CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS) {
1316 IA32_CR4 Cr4;
1317
1318 Cr4.UintN = AsmReadCr4 ();
1319 /* OSPKE enabled bit */
1320 *Ecx = (Cr4.Bits.PKE) ? (*Ecx | BIT4) : (*Ecx & ~BIT4);
1321 } else if (EaxIn == CPUID_EXTENDED_TOPOLOGY) {
1322 if (!GetCpuidHyp (
1323 Ghcb,
1324 EaxIn,
1325 EcxIn,
1326 XCr0,
1327 NULL,
1328 NULL,
1329 NULL,
1330 Edx,
1331 Status,
1332 Unsupported
1333 ))
1334 {
1335 return FALSE;
1336 }
1337 } else if ((EaxIn == CPUID_EXTENDED_STATE) && ((EcxIn == 0) || (EcxIn == 1))) {
1338 MSR_IA32_XSS_REGISTER XssMsr;
1339 BOOLEAN Compacted;
1340 UINT32 XSaveSize;
1341
1342 XssMsr.Uint64 = 0;
1343 Compacted = FALSE;
1344 if (EcxIn == 1) {
1345 /*
1346 * The PPR and APM aren't clear on what size should be encoded in
1347 * 0xD:0x1:EBX when compaction is not enabled by either XSAVEC or
1348 * XSAVES, as these are generally fixed to 1 on real CPUs. Report
1349 * this undefined case as an error.
1350 */
1351 if (!(*Eax & (BIT3 | BIT1))) {
1352 /* (XSAVES | XSAVEC) */
1353 return FALSE;
1354 }
1355
1356 Compacted = TRUE;
1357 XssMsr.Uint64 = AsmReadMsr64 (MSR_IA32_XSS);
1358 }
1359
1360 if (!GetCpuidXSaveSize (
1361 XCr0 | XssMsr.Uint64,
1362 &XSaveSize,
1363 Compacted
1364 ))
1365 {
1366 return FALSE;
1367 }
1368
1369 *Ebx = XSaveSize;
1370 } else if (EaxIn == 0x8000001E) {
1371 UINT32 Ebx2;
1372 UINT32 Ecx2;
1373
1374 /* extended APIC ID */
1375 if (!GetCpuidHyp (
1376 Ghcb,
1377 EaxIn,
1378 EcxIn,
1379 XCr0,
1380 Eax,
1381 &Ebx2,
1382 &Ecx2,
1383 NULL,
1384 Status,
1385 Unsupported
1386 ))
1387 {
1388 return FALSE;
1389 }
1390
1391 /* compute ID */
1392 *Ebx = (*Ebx & 0xFFFFFF00) | (Ebx2 & 0x000000FF);
1393 /* node ID */
1394 *Ecx = (*Ecx & 0xFFFFFF00) | (Ecx2 & 0x000000FF);
1395 } else if (EaxIn == 0x8000001F) {
1396 /* Set the SVSM feature bit if running under an SVSM */
1397 if (AmdSvsmIsSvsmPresent ()) {
1398 *Eax |= BIT28;
1399 }
1400 }
1401
1402Out:
1403 *Status = 0;
1404 *Unsupported = FALSE;
1405 return TRUE;
1406}
1407
1422STATIC
1423UINT64
1425 IN OUT GHCB *Ghcb,
1427 IN CC_INSTRUCTION_DATA *InstructionData
1428 )
1429{
1430 BOOLEAN Unsupported;
1431 UINT64 Status;
1432 UINT32 EaxIn;
1433 UINT32 EcxIn;
1434 UINT64 XCr0;
1435 UINT32 Eax;
1436 UINT32 Ebx;
1437 UINT32 Ecx;
1438 UINT32 Edx;
1439
1440 EaxIn = (UINT32)(UINTN)Regs->Rax;
1441 EcxIn = (UINT32)(UINTN)Regs->Rcx;
1442
1443 if (EaxIn == CPUID_EXTENDED_STATE) {
1444 IA32_CR4 Cr4;
1445
1446 Cr4.UintN = AsmReadCr4 ();
1447 Ghcb->SaveArea.XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;
1448 XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;
1449 }
1450
1451 if (SnpEnabled ()) {
1452 if (!GetCpuidFw (
1453 Ghcb,
1454 EaxIn,
1455 EcxIn,
1456 XCr0,
1457 &Eax,
1458 &Ebx,
1459 &Ecx,
1460 &Edx,
1461 &Status,
1462 &Unsupported
1463 ))
1464 {
1465 goto CpuidFail;
1466 }
1467 } else {
1468 if (!GetCpuidHyp (
1469 Ghcb,
1470 EaxIn,
1471 EcxIn,
1472 XCr0,
1473 &Eax,
1474 &Ebx,
1475 &Ecx,
1476 &Edx,
1477 &Status,
1478 &Unsupported
1479 ))
1480 {
1481 goto CpuidFail;
1482 }
1483 }
1484
1485 Regs->Rax = Eax;
1486 Regs->Rbx = Ebx;
1487 Regs->Rcx = Ecx;
1488 Regs->Rdx = Edx;
1489
1490 return 0;
1491
1492CpuidFail:
1493 if (Unsupported) {
1494 return UnsupportedExit (Ghcb, Regs, InstructionData);
1495 }
1496
1497 return Status;
1498}
1499
1514STATIC
1515UINT64
1517 IN OUT GHCB *Ghcb,
1519 IN CC_INSTRUCTION_DATA *InstructionData
1520 )
1521{
1522 UINT64 Status;
1523
1524 Ghcb->SaveArea.Rcx = Regs->Rcx;
1525 CcExitVmgSetOffsetValid (Ghcb, GhcbRcx);
1526
1527 Status = CcExitVmgExit (Ghcb, SVM_EXIT_RDPMC, 0, 0);
1528 if (Status != 0) {
1529 return Status;
1530 }
1531
1532 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax) ||
1533 !CcExitVmgIsOffsetValid (Ghcb, GhcbRdx))
1534 {
1535 return UnsupportedExit (Ghcb, Regs, InstructionData);
1536 }
1537
1538 Regs->Rax = Ghcb->SaveArea.Rax;
1539 Regs->Rdx = Ghcb->SaveArea.Rdx;
1540
1541 return 0;
1542}
1543
1558STATIC
1559UINT64
1561 IN OUT GHCB *Ghcb,
1563 IN CC_INSTRUCTION_DATA *InstructionData
1564 )
1565{
1566 UINT64 Status;
1567
1568 Status = CcExitVmgExit (Ghcb, SVM_EXIT_RDTSC, 0, 0);
1569 if (Status != 0) {
1570 return Status;
1571 }
1572
1573 if (!CcExitVmgIsOffsetValid (Ghcb, GhcbRax) ||
1574 !CcExitVmgIsOffsetValid (Ghcb, GhcbRdx))
1575 {
1576 return UnsupportedExit (Ghcb, Regs, InstructionData);
1577 }
1578
1579 Regs->Rax = Ghcb->SaveArea.Rax;
1580 Regs->Rdx = Ghcb->SaveArea.Rdx;
1581
1582 return 0;
1583}
1584
1599STATIC
1600UINT64
1602 IN OUT GHCB *Ghcb,
1604 IN CC_INSTRUCTION_DATA *InstructionData
1605 )
1606{
1608 SEV_ES_PER_CPU_DATA *SevEsData;
1609 UINT64 *Register;
1610 UINT64 Status;
1611
1613 return UnsupportedExit (Ghcb, Regs, InstructionData);
1614 }
1615
1616 Ext = &InstructionData->Ext;
1617 SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);
1618
1619 //
1620 // MOV DRn always treats MOD == 3 no matter how encoded
1621 //
1622 Register = CcGetRegisterPointer (Regs, Ext->ModRm.Rm);
1623
1624 //
1625 // Using a value of 0 for ExitInfo1 means RAX holds the value
1626 //
1627 Ghcb->SaveArea.Rax = *Register;
1628 CcExitVmgSetOffsetValid (Ghcb, GhcbRax);
1629
1630 Status = CcExitVmgExit (Ghcb, SVM_EXIT_DR7_WRITE, 0, 0);
1631 if (Status != 0) {
1632 return Status;
1633 }
1634
1635 SevEsData->Dr7 = *Register;
1636 SevEsData->Dr7Cached = 1;
1637
1638 return 0;
1639}
1640
1654STATIC
1655UINT64
1657 IN OUT GHCB *Ghcb,
1659 IN CC_INSTRUCTION_DATA *InstructionData
1660 )
1661{
1663 SEV_ES_PER_CPU_DATA *SevEsData;
1664 UINT64 *Register;
1665
1667 return UnsupportedExit (Ghcb, Regs, InstructionData);
1668 }
1669
1670 Ext = &InstructionData->Ext;
1671 SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);
1672
1673 //
1674 // MOV DRn always treats MOD == 3 no matter how encoded
1675 //
1676 Register = CcGetRegisterPointer (Regs, Ext->ModRm.Rm);
1677
1678 //
1679 // If there is a cached valued for DR7, return that. Otherwise return the
1680 // DR7 standard reset value of 0x400 (no debug breakpoints set).
1681 //
1682 *Register = (SevEsData->Dr7Cached == 1) ? SevEsData->Dr7 : 0x400;
1683
1684 return 0;
1685}
1686
1708STATIC
1709UINT64
1711 IN OUT GHCB *Ghcb,
1713 IN OUT CC_INSTRUCTION_DATA *InstructionData,
1714 IN UINT64 ExitCode
1715 )
1716{
1717 UINT8 OpCode;
1718
1719 //
1720 // Expected opcodes are either 1 or 2 bytes. If they are 2 bytes, they always
1721 // start with TWO_BYTE_OPCODE_ESCAPE (0x0f), so skip over that.
1722 //
1723 OpCode = *(InstructionData->OpCodes);
1724 if (OpCode == TWO_BYTE_OPCODE_ESCAPE) {
1725 OpCode = *(InstructionData->OpCodes + 1);
1726 }
1727
1728 switch (ExitCode) {
1729 case SVM_EXIT_IOIO_PROT:
1730 case SVM_EXIT_NPF:
1731 /* handled separately */
1732 return 0;
1733
1734 case SVM_EXIT_CPUID:
1735 if (OpCode == 0xa2) {
1736 return 0;
1737 }
1738
1739 break;
1740
1741 case SVM_EXIT_INVD:
1742 if (OpCode == 0x08) {
1743 return 0;
1744 }
1745
1746 break;
1747
1748 case SVM_EXIT_MONITOR:
1749 CcDecodeModRm (Regs, InstructionData);
1750
1751 if ((OpCode == 0x01) &&
1752 ( (InstructionData->ModRm.Uint8 == 0xc8) /* MONITOR */
1753 || (InstructionData->ModRm.Uint8 == 0xfa))) /* MONITORX */
1754 {
1755 return 0;
1756 }
1757
1758 break;
1759
1760 case SVM_EXIT_MWAIT:
1761 CcDecodeModRm (Regs, InstructionData);
1762
1763 if ((OpCode == 0x01) &&
1764 ( (InstructionData->ModRm.Uint8 == 0xc9) /* MWAIT */
1765 || (InstructionData->ModRm.Uint8 == 0xfb))) /* MWAITX */
1766 {
1767 return 0;
1768 }
1769
1770 break;
1771
1772 case SVM_EXIT_MSR:
1773 /* RDMSR */
1774 if ((OpCode == 0x32) ||
1775 /* WRMSR */
1776 (OpCode == 0x30))
1777 {
1778 return 0;
1779 }
1780
1781 break;
1782
1783 case SVM_EXIT_RDPMC:
1784 if (OpCode == 0x33) {
1785 return 0;
1786 }
1787
1788 break;
1789
1790 case SVM_EXIT_RDTSC:
1791 if (OpCode == 0x31) {
1792 return 0;
1793 }
1794
1795 break;
1796
1797 case SVM_EXIT_RDTSCP:
1798 CcDecodeModRm (Regs, InstructionData);
1799
1800 if ((OpCode == 0x01) && (InstructionData->ModRm.Uint8 == 0xf9)) {
1801 return 0;
1802 }
1803
1804 break;
1805
1806 case SVM_EXIT_DR7_READ:
1807 CcDecodeModRm (Regs, InstructionData);
1808
1809 if ((OpCode == 0x21) &&
1810 (InstructionData->Ext.ModRm.Reg == 7))
1811 {
1812 return 0;
1813 }
1814
1815 break;
1816
1817 case SVM_EXIT_VMMCALL:
1818 CcDecodeModRm (Regs, InstructionData);
1819
1820 if ((OpCode == 0x01) && (InstructionData->ModRm.Uint8 == 0xd9)) {
1821 return 0;
1822 }
1823
1824 break;
1825
1826 case SVM_EXIT_DR7_WRITE:
1827 CcDecodeModRm (Regs, InstructionData);
1828
1829 if ((OpCode == 0x23) &&
1830 (InstructionData->Ext.ModRm.Reg == 7))
1831 {
1832 return 0;
1833 }
1834
1835 break;
1836
1837 case SVM_EXIT_WBINVD:
1838 if (OpCode == 0x9) {
1839 return 0;
1840 }
1841
1842 break;
1843
1844 default:
1845 break;
1846 }
1847
1848 return UnsupportedExit (Ghcb, Regs, InstructionData);
1849}
1850
1869EFIAPI
1871 IN OUT GHCB *Ghcb,
1872 IN OUT EFI_EXCEPTION_TYPE *ExceptionType,
1873 IN OUT EFI_SYSTEM_CONTEXT SystemContext
1874 )
1875{
1877 NAE_EXIT NaeExit;
1878 CC_INSTRUCTION_DATA InstructionData;
1879 UINT64 ExitCode, Status;
1880 EFI_STATUS VcRet;
1881 BOOLEAN InterruptState;
1882
1883 VcRet = EFI_SUCCESS;
1884
1885 Regs = SystemContext.SystemContextX64;
1886
1887 CcExitVmgInit (Ghcb, &InterruptState);
1888
1889 ExitCode = Regs->ExceptionData;
1890 switch (ExitCode) {
1891 case SVM_EXIT_DR7_READ:
1892 NaeExit = Dr7ReadExit;
1893 break;
1894
1895 case SVM_EXIT_DR7_WRITE:
1896 NaeExit = Dr7WriteExit;
1897 break;
1898
1899 case SVM_EXIT_RDTSC:
1900 NaeExit = RdtscExit;
1901 break;
1902
1903 case SVM_EXIT_RDPMC:
1904 NaeExit = RdpmcExit;
1905 break;
1906
1907 case SVM_EXIT_CPUID:
1908 NaeExit = CpuidExit;
1909 break;
1910
1911 case SVM_EXIT_INVD:
1912 NaeExit = InvdExit;
1913 break;
1914
1915 case SVM_EXIT_IOIO_PROT:
1916 NaeExit = IoioExit;
1917 break;
1918
1919 case SVM_EXIT_MSR:
1920 NaeExit = MsrExit;
1921 break;
1922
1923 case SVM_EXIT_VMMCALL:
1924 NaeExit = VmmCallExit;
1925 break;
1926
1927 case SVM_EXIT_RDTSCP:
1928 NaeExit = RdtscpExit;
1929 break;
1930
1931 case SVM_EXIT_WBINVD:
1932 NaeExit = WbinvdExit;
1933 break;
1934
1935 case SVM_EXIT_MONITOR:
1936 NaeExit = MonitorExit;
1937 break;
1938
1939 case SVM_EXIT_MWAIT:
1940 NaeExit = MwaitExit;
1941 break;
1942
1943 case SVM_EXIT_NPF:
1944 NaeExit = MmioExit;
1945 break;
1946
1947 default:
1948 NaeExit = UnsupportedExit;
1949 }
1950
1951 CcInitInstructionData (&InstructionData, Ghcb, Regs);
1952
1953 Status = VcCheckOpcodeBytes (Ghcb, Regs, &InstructionData, ExitCode);
1954
1955 //
1956 // If the opcode does not match the exit code, do not process the exception
1957 //
1958 if (Status == 0) {
1959 Status = NaeExit (Ghcb, Regs, &InstructionData);
1960 }
1961
1962 if (Status == 0) {
1963 Regs->Rip += CcInstructionLength (&InstructionData);
1964 } else {
1966
1967 Event.Uint64 = Status;
1968 if (Event.Elements.ErrorCodeValid != 0) {
1969 Regs->ExceptionData = Event.Elements.ErrorCode;
1970 } else {
1971 Regs->ExceptionData = 0;
1972 }
1973
1974 *ExceptionType = Event.Elements.Vector;
1975
1976 VcRet = EFI_PROTOCOL_ERROR;
1977 }
1978
1979 CcExitVmgDone (Ghcb, InterruptState);
1980
1981 return VcRet;
1982}
1983
1990VOID
1991EFIAPI
1993 IN OUT SEV_ES_PER_CPU_DATA *SevEsData
1994 )
1995{
1996 //
1997 // Progress will be halted, so set VcCount to allow for ASSERT output
1998 // to be seen.
1999 //
2000 SevEsData->VcCount = 0;
2001
2002 ASSERT (FALSE);
2003 CpuDeadLoop ();
2004}
UINT64 UINTN
BOOLEAN EFIAPI AmdSvsmIsSvsmPresent(VOID)
Definition: AmdSvsmLib.c:130
UINT64 EFIAPI AmdSvsmSnpGetCaa(VOID)
Definition: AmdSvsmLib.c:174
VOID EFIAPI CpuDeadLoop(VOID)
Definition: CpuDeadLoop.c:25
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI SetMem(OUT VOID *Buffer, IN UINTN Length, IN UINT8 Value)
Definition: SetMemWrapper.c:38
UINT64 EFIAPI CcExitVmgExit(IN OUT GHCB *Ghcb, IN UINT64 ExitCode, IN UINT64 ExitInfo1, IN UINT64 ExitInfo2)
Definition: CcExitLib.c:106
BOOLEAN EFIAPI CcExitVmgIsOffsetValid(IN GHCB *Ghcb, IN GHCB_REGISTER Offset)
Definition: CcExitLib.c:227
VOID EFIAPI CcExitVmgSetOffsetValid(IN OUT GHCB *Ghcb, IN GHCB_REGISTER Offset)
Definition: CcExitLib.c:198
VOID EFIAPI CcExitVmgInit(IN OUT GHCB *Ghcb, IN OUT BOOLEAN *InterruptState)
Definition: CcExitLib.c:146
VOID EFIAPI CcExitVmgDone(IN OUT GHCB *Ghcb, IN BOOLEAN InterruptState)
Definition: CcExitLib.c:176
STATIC UINT64 ValidateMmioMemory(IN GHCB *Ghcb, IN UINTN MemoryAddress, IN UINTN MemoryLength)
STATIC UINT64 MmioExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN OUT CC_INSTRUCTION_DATA *InstructionData)
STATIC BOOLEAN SnpEnabled(VOID)
STATIC UINT64 VmmCallExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN CC_INSTRUCTION_DATA *InstructionData)
STATIC BOOLEAN GetCpuidXSaveSize(IN UINT64 XFeaturesEnabled, IN OUT UINT32 *XSaveSize, IN BOOLEAN Compacted)
STATIC UINT64 Dr7ReadExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN CC_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 InvdExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN CC_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 Dr7WriteExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN CC_INSTRUCTION_DATA *InstructionData)
STATIC BOOLEAN GetCpuidHyp(IN OUT GHCB *Ghcb, IN UINT32 EaxIn, IN UINT32 EcxIn, IN UINT64 XCr0, IN OUT UINT32 *Eax, IN OUT UINT32 *Ebx, IN OUT UINT32 *Ecx, IN OUT UINT32 *Edx, IN OUT UINT64 *Status, IN OUT BOOLEAN *UnsupportedExit)
STATIC UINT64 IoioExitInfo(IN EFI_SYSTEM_CONTEXT_X64 *Regs, IN OUT CC_INSTRUCTION_DATA *InstructionData)
EFI_STATUS EFIAPI InternalVmgExitHandleVc(IN OUT GHCB *Ghcb, IN OUT EFI_EXCEPTION_TYPE *ExceptionType, IN OUT EFI_SYSTEM_CONTEXT SystemContext)
STATIC UINT64 VcCheckOpcodeBytes(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN OUT CC_INSTRUCTION_DATA *InstructionData, IN UINT64 ExitCode)
STATIC UINT64 IoioExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN CC_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 RdtscExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN CC_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 MwaitExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN CC_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 RdtscpExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN CC_INSTRUCTION_DATA *InstructionData)
VOID EFIAPI VmgExitIssueAssert(IN OUT SEV_ES_PER_CPU_DATA *SevEsData)
STATIC UINT64 WbinvdExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN CC_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 MonitorExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN CC_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 UnsupportedExit(IN GHCB *Ghcb, IN EFI_SYSTEM_CONTEXT_X64 *Regs, IN CC_INSTRUCTION_DATA *InstructionData)
STATIC BOOLEAN IsFunctionIndexed(IN UINT32 EaxIn)
STATIC BOOLEAN GetCpuidFw(IN OUT GHCB *Ghcb, IN UINT32 EaxIn, IN UINT32 EcxIn, IN UINT64 XCr0, IN OUT UINT32 *Eax, IN OUT UINT32 *Ebx, IN OUT UINT32 *Ecx, IN OUT UINT32 *Edx, IN OUT UINT64 *Status, IN OUT BOOLEAN *Unsupported)
STATIC UINT64 RdpmcExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN CC_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 CpuidExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN CC_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 MsrExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN CC_INSTRUCTION_DATA *InstructionData)
UINT64 * CcGetRegisterPointer(IN EFI_SYSTEM_CONTEXT_X64 *Regs, IN UINT8 Register)
Definition: CcInstruction.c:31
VOID CcDecodeModRm(IN EFI_SYSTEM_CONTEXT_X64 *Regs, IN OUT CC_INSTRUCTION_DATA *InstructionData)
EFI_STATUS CcInitInstructionData(IN OUT CC_INSTRUCTION_DATA *InstructionData, IN GHCB *Ghcb, IN EFI_SYSTEM_CONTEXT_X64 *Regs)
UINT64 CcInstructionLength(IN CC_INSTRUCTION_DATA *InstructionData)
UINT64 EFIAPI AsmReadMsr64(IN UINT32 Index)
Definition: GccInlinePriv.c:60
UINTN EFIAPI AsmReadCr4(VOID)
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define MIN(a, b)
Definition: Base.h:1007
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define STATIC_ASSERT
Definition: Base.h:808
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define MAX(a, b)
Definition: Base.h:992
#define DEBUG(Expression)
Definition: DebugLib.h:434
INTN EFI_EXCEPTION_TYPE
Definition: DebugSupport.h:35
#define MSR_IA32_XSS
#define CPUID_INTEL_PROCESSOR_TRACE
Definition: Cpuid.h:2924
#define CPUID_DETERMINISTIC_ADDRESS_TRANSLATION_PARAMETERS
Definition: Cpuid.h:3462
#define CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS
Definition: Cpuid.h:1301
#define CPUID_CACHE_PARAMS
Definition: Cpuid.h:802
#define CPUID_INTEL_RDT_MONITORING
Definition: Cpuid.h:2187
#define CPUID_VERSION_INFO
Definition: Cpuid.h:81
#define CPUID_EXTENDED_STATE
Definition: Cpuid.h:1918
#define CPUID_INTEL_SGX
Definition: Cpuid.h:2648
#define CPUID_EXTENDED_TOPOLOGY
Definition: Cpuid.h:1815
#define CPUID_V2_EXTENDED_TOPOLOGY
Definition: Cpuid.h:3685
#define CPUID_INTEL_RDT_ALLOCATION
Definition: Cpuid.h:2303
BOOLEAN EFIAPI MemEncryptSevEsDebugVirtualizationIsEnabled(VOID)
MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE EFIAPI MemEncryptSevGetAddressRangeState(IN PHYSICAL_ADDRESS Cr3BaseAddress, IN PHYSICAL_ADDRESS BaseAddress, IN UINTN Length)
#define PcdGet32(TokenName)
Definition: PcdLib.h:362
EFI_STATUS EFIAPI Register(IN EFI_PEI_RSC_HANDLER_CALLBACK Callback)
#define MSR_SEV_STATUS
Definition: SevSnpMsr.h:116
#define MSR_SVSM_CAA
Definition: SvsmMsr.h:21
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
UINT32 EFIAPI AsmReadMsr32(IN UINT32 Index)
Definition: X86Msr.c:27