TianoCore EDK2 master
VmgExitVcHandler.c
Go to the documentation of this file.
1
9#include <Base.h>
10#include <Uefi.h>
14#include <Library/VmgExitLib.h>
15#include <Register/Amd/Msr.h>
18
19#include "VmgExitVcHandler.h"
20// #include <Library/MemEncryptSevLib.h>
21
22//
23// Instruction execution mode definition
24//
25typedef enum {
26 LongMode64Bit = 0,
27 LongModeCompat32Bit,
28 LongModeCompat16Bit,
29} SEV_ES_INSTRUCTION_MODE;
30
31//
32// Instruction size definition (for operand and address)
33//
34typedef enum {
35 Size8Bits = 0,
36 Size16Bits,
37 Size32Bits,
38 Size64Bits,
39} SEV_ES_INSTRUCTION_SIZE;
40
41//
42// Intruction segment definition
43//
44typedef enum {
45 SegmentEs = 0,
46 SegmentCs,
47 SegmentSs,
48 SegmentDs,
49 SegmentFs,
50 SegmentGs,
51} SEV_ES_INSTRUCTION_SEGMENT;
52
53//
54// Instruction rep function definition
55//
56typedef enum {
57 RepNone = 0,
58 RepZ,
59 RepNZ,
60} SEV_ES_INSTRUCTION_REP;
61
62typedef struct {
63 UINT8 Rm;
64 UINT8 Reg;
65 UINT8 Mod;
67
68typedef struct {
69 UINT8 Base;
70 UINT8 Index;
71 UINT8 Scale;
73
74//
75// Instruction opcode definition
76//
77typedef struct {
79
81
82 UINTN RegData;
83 UINTN RmData;
85
86//
87// Instruction parsing context definition
88//
89typedef struct {
90 GHCB *Ghcb;
91
92 SEV_ES_INSTRUCTION_MODE Mode;
93 SEV_ES_INSTRUCTION_SIZE DataSize;
94 SEV_ES_INSTRUCTION_SIZE AddrSize;
95 BOOLEAN SegmentSpecified;
96 SEV_ES_INSTRUCTION_SEGMENT Segment;
97 SEV_ES_INSTRUCTION_REP RepMode;
98
99 UINT8 *Begin;
100 UINT8 *End;
101
102 UINT8 *Prefixes;
103 UINT8 *OpCodes;
104 UINT8 *Displacement;
105 UINT8 *Immediate;
106
107 INSTRUCTION_REX_PREFIX RexPrefix;
108
109 BOOLEAN ModRmPresent;
110 INSTRUCTION_MODRM ModRm;
111
112 BOOLEAN SibPresent;
113 INSTRUCTION_SIB Sib;
114
115 UINTN PrefixSize;
116 UINTN OpCodeSize;
117 UINTN DisplacementSize;
118 UINTN ImmediateSize;
119
122
123//
124// Non-automatic Exit function prototype
125//
126typedef
127UINT64
128(*NAE_EXIT) (
129 GHCB *Ghcb,
131 SEV_ES_INSTRUCTION_DATA *InstructionData
132 );
133
134//
135// SEV-SNP Cpuid table entry/function
136//
137typedef PACKED struct {
138 UINT32 EaxIn;
139 UINT32 EcxIn;
140 UINT64 Unused;
141 UINT64 Unused2;
142 UINT32 Eax;
143 UINT32 Ebx;
144 UINT32 Ecx;
145 UINT32 Edx;
146 UINT64 Reserved;
147} SEV_SNP_CPUID_FUNCTION;
148
149//
150// SEV-SNP Cpuid page format
151//
152typedef PACKED struct {
153 UINT32 Count;
154 UINT32 Reserved1;
155 UINT64 Reserved2;
156 SEV_SNP_CPUID_FUNCTION function[0];
157} SEV_SNP_CPUID_INFO;
158
171STATIC
172UINT64 *
175 IN UINT8 Register
176 )
177{
178 UINT64 *Reg;
179
180 switch (Register) {
181 case 0:
182 Reg = &Regs->Rax;
183 break;
184 case 1:
185 Reg = &Regs->Rcx;
186 break;
187 case 2:
188 Reg = &Regs->Rdx;
189 break;
190 case 3:
191 Reg = &Regs->Rbx;
192 break;
193 case 4:
194 Reg = &Regs->Rsp;
195 break;
196 case 5:
197 Reg = &Regs->Rbp;
198 break;
199 case 6:
200 Reg = &Regs->Rsi;
201 break;
202 case 7:
203 Reg = &Regs->Rdi;
204 break;
205 case 8:
206 Reg = &Regs->R8;
207 break;
208 case 9:
209 Reg = &Regs->R9;
210 break;
211 case 10:
212 Reg = &Regs->R10;
213 break;
214 case 11:
215 Reg = &Regs->R11;
216 break;
217 case 12:
218 Reg = &Regs->R12;
219 break;
220 case 13:
221 Reg = &Regs->R13;
222 break;
223 case 14:
224 Reg = &Regs->R14;
225 break;
226 case 15:
227 Reg = &Regs->R15;
228 break;
229 default:
230 Reg = NULL;
231 }
232
233 ASSERT (Reg != NULL);
234
235 return Reg;
236}
237
245STATIC
246VOID
248 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,
249 IN UINTN Size
250 )
251{
252 InstructionData->DisplacementSize = Size;
253 InstructionData->Immediate += Size;
254 InstructionData->End += Size;
255}
256
269STATIC
270BOOLEAN
272 IN SEV_ES_INSTRUCTION_DATA *InstructionData
273 )
274{
276
277 Ext = &InstructionData->Ext;
278
279 return ((InstructionData->Mode == LongMode64Bit) &&
280 (Ext->ModRm.Mod == 0) &&
281 (Ext->ModRm.Rm == 5) &&
282 (InstructionData->SibPresent == FALSE));
283}
284
297STATIC
298UINT64
301 IN SEV_ES_INSTRUCTION_DATA *InstructionData
302 )
303{
305 UINT64 EffectiveAddress;
306
307 Ext = &InstructionData->Ext;
308 EffectiveAddress = 0;
309
310 if (IsRipRelative (InstructionData)) {
311 //
312 // RIP-relative displacement is a 32-bit signed value
313 //
314 INT32 RipRelative;
315
316 RipRelative = *(INT32 *)InstructionData->Displacement;
317
318 UpdateForDisplacement (InstructionData, 4);
319
320 //
321 // Negative displacement is handled by standard UINT64 wrap-around.
322 //
323 return Regs->Rip + (UINT64)RipRelative;
324 }
325
326 switch (Ext->ModRm.Mod) {
327 case 1:
328 UpdateForDisplacement (InstructionData, 1);
329 EffectiveAddress += (UINT64)(*(INT8 *)(InstructionData->Displacement));
330 break;
331 case 2:
332 switch (InstructionData->AddrSize) {
333 case Size16Bits:
334 UpdateForDisplacement (InstructionData, 2);
335 EffectiveAddress += (UINT64)(*(INT16 *)(InstructionData->Displacement));
336 break;
337 default:
338 UpdateForDisplacement (InstructionData, 4);
339 EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement));
340 break;
341 }
342
343 break;
344 }
345
346 if (InstructionData->SibPresent) {
347 INT64 Displacement;
348
349 if (Ext->Sib.Index != 4) {
350 CopyMem (
351 &Displacement,
352 GetRegisterPointer (Regs, Ext->Sib.Index),
353 sizeof (Displacement)
354 );
355 Displacement *= (INT64)(1 << Ext->Sib.Scale);
356
357 //
358 // Negative displacement is handled by standard UINT64 wrap-around.
359 //
360 EffectiveAddress += (UINT64)Displacement;
361 }
362
363 if ((Ext->Sib.Base != 5) || Ext->ModRm.Mod) {
364 EffectiveAddress += *GetRegisterPointer (Regs, Ext->Sib.Base);
365 } else {
366 UpdateForDisplacement (InstructionData, 4);
367 EffectiveAddress += (UINT64)(*(INT32 *)(InstructionData->Displacement));
368 }
369 } else {
370 EffectiveAddress += *GetRegisterPointer (Regs, Ext->ModRm.Rm);
371 }
372
373 return EffectiveAddress;
374}
375
386STATIC
387VOID
390 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData
391 )
392{
394 INSTRUCTION_REX_PREFIX *RexPrefix;
395 INSTRUCTION_MODRM *ModRm;
396 INSTRUCTION_SIB *Sib;
397
398 RexPrefix = &InstructionData->RexPrefix;
399 Ext = &InstructionData->Ext;
400 ModRm = &InstructionData->ModRm;
401 Sib = &InstructionData->Sib;
402
403 InstructionData->ModRmPresent = TRUE;
404 ModRm->Uint8 = *(InstructionData->End);
405
406 InstructionData->Displacement++;
407 InstructionData->Immediate++;
408 InstructionData->End++;
409
410 Ext->ModRm.Mod = ModRm->Bits.Mod;
411 Ext->ModRm.Reg = (RexPrefix->Bits.BitR << 3) | ModRm->Bits.Reg;
412 Ext->ModRm.Rm = (RexPrefix->Bits.BitB << 3) | ModRm->Bits.Rm;
413
414 Ext->RegData = *GetRegisterPointer (Regs, Ext->ModRm.Reg);
415
416 if (Ext->ModRm.Mod == 3) {
417 Ext->RmData = *GetRegisterPointer (Regs, Ext->ModRm.Rm);
418 } else {
419 if (ModRm->Bits.Rm == 4) {
420 InstructionData->SibPresent = TRUE;
421 Sib->Uint8 = *(InstructionData->End);
422
423 InstructionData->Displacement++;
424 InstructionData->Immediate++;
425 InstructionData->End++;
426
427 Ext->Sib.Scale = Sib->Bits.Scale;
428 Ext->Sib.Index = (RexPrefix->Bits.BitX << 3) | Sib->Bits.Index;
429 Ext->Sib.Base = (RexPrefix->Bits.BitB << 3) | Sib->Bits.Base;
430 }
431
432 Ext->RmData = GetEffectiveMemoryAddress (Regs, InstructionData);
433 }
434}
435
446STATIC
447VOID
450 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData
451 )
452{
453 SEV_ES_INSTRUCTION_MODE Mode;
454 SEV_ES_INSTRUCTION_SIZE ModeDataSize;
455 SEV_ES_INSTRUCTION_SIZE ModeAddrSize;
456 UINT8 *Byte;
457
458 //
459 // Always in 64-bit mode
460 //
461 Mode = LongMode64Bit;
462 ModeDataSize = Size32Bits;
463 ModeAddrSize = Size64Bits;
464
465 InstructionData->Mode = Mode;
466 InstructionData->DataSize = ModeDataSize;
467 InstructionData->AddrSize = ModeAddrSize;
468
469 InstructionData->Prefixes = InstructionData->Begin;
470
471 Byte = InstructionData->Prefixes;
472 for ( ; ; Byte++, InstructionData->PrefixSize++) {
473 //
474 // Check the 0x40 to 0x4F range using an if statement here since some
475 // compilers don't like the "case 0x40 ... 0x4F:" syntax. This avoids
476 // 16 case statements below.
477 //
478 if ((*Byte >= REX_PREFIX_START) && (*Byte <= REX_PREFIX_STOP)) {
479 InstructionData->RexPrefix.Uint8 = *Byte;
480 if ((*Byte & REX_64BIT_OPERAND_SIZE_MASK) != 0) {
481 InstructionData->DataSize = Size64Bits;
482 }
483
484 continue;
485 }
486
487 switch (*Byte) {
488 case OVERRIDE_SEGMENT_CS:
489 case OVERRIDE_SEGMENT_DS:
490 case OVERRIDE_SEGMENT_ES:
491 case OVERRIDE_SEGMENT_SS:
492 if (Mode != LongMode64Bit) {
493 InstructionData->SegmentSpecified = TRUE;
494 InstructionData->Segment = (*Byte >> 3) & 3;
495 }
496
497 break;
498
499 case OVERRIDE_SEGMENT_FS:
500 case OVERRIDE_SEGMENT_GS:
501 InstructionData->SegmentSpecified = TRUE;
502 InstructionData->Segment = *Byte & 7;
503 break;
504
505 case OVERRIDE_OPERAND_SIZE:
506 if (InstructionData->RexPrefix.Uint8 == 0) {
507 InstructionData->DataSize =
508 (Mode == LongMode64Bit) ? Size16Bits :
509 (Mode == LongModeCompat32Bit) ? Size16Bits :
510 (Mode == LongModeCompat16Bit) ? Size32Bits : 0;
511 }
512
513 break;
514
515 case OVERRIDE_ADDRESS_SIZE:
516 InstructionData->AddrSize =
517 (Mode == LongMode64Bit) ? Size32Bits :
518 (Mode == LongModeCompat32Bit) ? Size16Bits :
519 (Mode == LongModeCompat16Bit) ? Size32Bits : 0;
520 break;
521
522 case LOCK_PREFIX:
523 break;
524
525 case REPZ_PREFIX:
526 InstructionData->RepMode = RepZ;
527 break;
528
529 case REPNZ_PREFIX:
530 InstructionData->RepMode = RepNZ;
531 break;
532
533 default:
534 InstructionData->OpCodes = Byte;
535 InstructionData->OpCodeSize = (*Byte == TWO_BYTE_OPCODE_ESCAPE) ? 2 : 1;
536
537 InstructionData->End = Byte + InstructionData->OpCodeSize;
538 InstructionData->Displacement = InstructionData->End;
539 InstructionData->Immediate = InstructionData->End;
540 return;
541 }
542 }
543}
544
555STATIC
556UINT64
558 IN SEV_ES_INSTRUCTION_DATA *InstructionData
559 )
560{
561 return (UINT64)(InstructionData->End - InstructionData->Begin);
562}
563
576STATIC
577VOID
579 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData,
580 IN GHCB *Ghcb,
582 )
583{
584 SetMem (InstructionData, sizeof (*InstructionData), 0);
585 InstructionData->Ghcb = Ghcb;
586 InstructionData->Begin = (UINT8 *)Regs->Rip;
587 InstructionData->End = (UINT8 *)Regs->Rip;
588
589 DecodePrefixes (Regs, InstructionData);
590}
591
605STATIC
606UINT64
608 IN GHCB *Ghcb,
610 IN SEV_ES_INSTRUCTION_DATA *InstructionData
611 )
612{
613 UINT64 Status;
614
615 Status = VmgExit (Ghcb, SVM_EXIT_UNSUPPORTED, Regs->ExceptionData, 0);
616 if (Status == 0) {
618
619 Event.Uint64 = 0;
620 Event.Elements.Vector = GP_EXCEPTION;
621 Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;
622 Event.Elements.Valid = 1;
623
624 Status = Event.Uint64;
625 }
626
627 return Status;
628}
629
644STATIC
645UINT64
647 IN GHCB *Ghcb,
648 IN UINTN MemoryAddress,
649 IN UINTN MemoryLength
650 )
651{
652 MEM_ENCRYPT_SEV_ADDRESS_RANGE_STATE State;
653 GHCB_EVENT_INJECTION GpEvent;
654 UINTN Address;
655
656 //
657 // Allow APIC accesses (which will have the encryption bit set during
658 // SEC and PEI phases).
659 //
660 Address = MemoryAddress & ~(SIZE_4KB - 1);
661 if (Address == GetLocalApicBaseAddress ()) {
662 return 0;
663 }
664
666 0,
667 MemoryAddress,
668 MemoryLength
669 );
670 if (State == MemEncryptSevAddressRangeUnencrypted) {
671 return 0;
672 }
673
674 //
675 // Any state other than unencrypted is an error, issue a #GP.
676 //
677 DEBUG ((
678 DEBUG_ERROR,
679 "MMIO using encrypted memory: %lx\n",
680 (UINT64)MemoryAddress
681 ));
682 GpEvent.Uint64 = 0;
683 GpEvent.Elements.Vector = GP_EXCEPTION;
684 GpEvent.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;
685 GpEvent.Elements.Valid = 1;
686
687 return GpEvent.Uint64;
688}
689
704STATIC
705UINT64
707 IN OUT GHCB *Ghcb,
709 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData
710 )
711{
712 UINT64 ExitInfo1, ExitInfo2, Status;
713 UINTN Bytes;
714 UINT64 *Register;
715 UINT8 OpCode, SignByte;
716 UINTN Address;
717
718 Bytes = 0;
719
720 OpCode = *(InstructionData->OpCodes);
721 if (OpCode == TWO_BYTE_OPCODE_ESCAPE) {
722 OpCode = *(InstructionData->OpCodes + 1);
723 }
724
725 switch (OpCode) {
726 //
727 // MMIO write (MOV reg/memX, regX)
728 //
729 case 0x88:
730 Bytes = 1;
731 //
732 // fall through
733 //
734 case 0x89:
735 DecodeModRm (Regs, InstructionData);
736 Bytes = ((Bytes != 0) ? Bytes :
737 (InstructionData->DataSize == Size16Bits) ? 2 :
738 (InstructionData->DataSize == Size32Bits) ? 4 :
739 (InstructionData->DataSize == Size64Bits) ? 8 :
740 0);
741
742 if (InstructionData->Ext.ModRm.Mod == 3) {
743 //
744 // NPF on two register operands???
745 //
746 return UnsupportedExit (Ghcb, Regs, InstructionData);
747 }
748
749 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
750 if (Status != 0) {
751 return Status;
752 }
753
754 ExitInfo1 = InstructionData->Ext.RmData;
755 ExitInfo2 = Bytes;
756 CopyMem (Ghcb->SharedBuffer, &InstructionData->Ext.RegData, Bytes);
757
758 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
759 VmgSetOffsetValid (Ghcb, GhcbSwScratch);
760 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
761 if (Status != 0) {
762 return Status;
763 }
764
765 break;
766
767 //
768 // MMIO write (MOV moffsetX, aX)
769 //
770 case 0xA2:
771 Bytes = 1;
772 //
773 // fall through
774 //
775 case 0xA3:
776 Bytes = ((Bytes != 0) ? Bytes :
777 (InstructionData->DataSize == Size16Bits) ? 2 :
778 (InstructionData->DataSize == Size32Bits) ? 4 :
779 (InstructionData->DataSize == Size64Bits) ? 8 :
780 0);
781
782 InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);
783 InstructionData->End += InstructionData->ImmediateSize;
784
785 //
786 // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
787 // Use a STATIC_ASSERT to be certain the code is being built as X64.
788 //
790 sizeof (UINTN) == sizeof (UINT64),
791 "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
792 );
793
794 Address = 0;
795 CopyMem (
796 &Address,
797 InstructionData->Immediate,
798 InstructionData->ImmediateSize
799 );
800
801 Status = ValidateMmioMemory (Ghcb, Address, Bytes);
802 if (Status != 0) {
803 return Status;
804 }
805
806 ExitInfo1 = Address;
807 ExitInfo2 = Bytes;
808 CopyMem (Ghcb->SharedBuffer, &Regs->Rax, Bytes);
809
810 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
811 VmgSetOffsetValid (Ghcb, GhcbSwScratch);
812 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
813 if (Status != 0) {
814 return Status;
815 }
816
817 break;
818
819 //
820 // MMIO write (MOV reg/memX, immX)
821 //
822 case 0xC6:
823 Bytes = 1;
824 //
825 // fall through
826 //
827 case 0xC7:
828 DecodeModRm (Regs, InstructionData);
829 Bytes = ((Bytes != 0) ? Bytes :
830 (InstructionData->DataSize == Size16Bits) ? 2 :
831 (InstructionData->DataSize == Size32Bits) ? 4 :
832 0);
833
834 InstructionData->ImmediateSize = Bytes;
835 InstructionData->End += Bytes;
836
837 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
838 if (Status != 0) {
839 return Status;
840 }
841
842 ExitInfo1 = InstructionData->Ext.RmData;
843 ExitInfo2 = Bytes;
844 CopyMem (Ghcb->SharedBuffer, InstructionData->Immediate, Bytes);
845
846 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
847 VmgSetOffsetValid (Ghcb, GhcbSwScratch);
848 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_WRITE, ExitInfo1, ExitInfo2);
849 if (Status != 0) {
850 return Status;
851 }
852
853 break;
854
855 //
856 // MMIO read (MOV regX, reg/memX)
857 //
858 case 0x8A:
859 Bytes = 1;
860 //
861 // fall through
862 //
863 case 0x8B:
864 DecodeModRm (Regs, InstructionData);
865 Bytes = ((Bytes != 0) ? Bytes :
866 (InstructionData->DataSize == Size16Bits) ? 2 :
867 (InstructionData->DataSize == Size32Bits) ? 4 :
868 (InstructionData->DataSize == Size64Bits) ? 8 :
869 0);
870 if (InstructionData->Ext.ModRm.Mod == 3) {
871 //
872 // NPF on two register operands???
873 //
874 return UnsupportedExit (Ghcb, Regs, InstructionData);
875 }
876
877 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
878 if (Status != 0) {
879 return Status;
880 }
881
882 ExitInfo1 = InstructionData->Ext.RmData;
883 ExitInfo2 = Bytes;
884
885 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
886 VmgSetOffsetValid (Ghcb, GhcbSwScratch);
887 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
888 if (Status != 0) {
889 return Status;
890 }
891
892 Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
893 if (Bytes == 4) {
894 //
895 // Zero-extend for 32-bit operation
896 //
897 *Register = 0;
898 }
899
900 CopyMem (Register, Ghcb->SharedBuffer, Bytes);
901 break;
902
903 //
904 // MMIO read (MOV aX, moffsetX)
905 //
906 case 0xA0:
907 Bytes = 1;
908 //
909 // fall through
910 //
911 case 0xA1:
912 Bytes = ((Bytes != 0) ? Bytes :
913 (InstructionData->DataSize == Size16Bits) ? 2 :
914 (InstructionData->DataSize == Size32Bits) ? 4 :
915 (InstructionData->DataSize == Size64Bits) ? 8 :
916 0);
917
918 InstructionData->ImmediateSize = (UINTN)(1 << InstructionData->AddrSize);
919 InstructionData->End += InstructionData->ImmediateSize;
920
921 //
922 // This code is X64 only, so a possible 8-byte copy to a UINTN is ok.
923 // Use a STATIC_ASSERT to be certain the code is being built as X64.
924 //
926 sizeof (UINTN) == sizeof (UINT64),
927 "sizeof (UINTN) != sizeof (UINT64), this file must be built as X64"
928 );
929
930 Address = 0;
931 CopyMem (
932 &Address,
933 InstructionData->Immediate,
934 InstructionData->ImmediateSize
935 );
936
937 Status = ValidateMmioMemory (Ghcb, Address, Bytes);
938 if (Status != 0) {
939 return Status;
940 }
941
942 ExitInfo1 = Address;
943 ExitInfo2 = Bytes;
944
945 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
946 VmgSetOffsetValid (Ghcb, GhcbSwScratch);
947 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
948 if (Status != 0) {
949 return Status;
950 }
951
952 if (Bytes == 4) {
953 //
954 // Zero-extend for 32-bit operation
955 //
956 Regs->Rax = 0;
957 }
958
959 CopyMem (&Regs->Rax, Ghcb->SharedBuffer, Bytes);
960 break;
961
962 //
963 // MMIO read w/ zero-extension ((MOVZX regX, reg/memX)
964 //
965 case 0xB6:
966 Bytes = 1;
967 //
968 // fall through
969 //
970 case 0xB7:
971 DecodeModRm (Regs, InstructionData);
972 Bytes = (Bytes != 0) ? Bytes : 2;
973
974 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
975 if (Status != 0) {
976 return Status;
977 }
978
979 ExitInfo1 = InstructionData->Ext.RmData;
980 ExitInfo2 = Bytes;
981
982 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
983 VmgSetOffsetValid (Ghcb, GhcbSwScratch);
984 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
985 if (Status != 0) {
986 return Status;
987 }
988
989 Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
990 SetMem (Register, (UINTN)(1 << InstructionData->DataSize), 0);
991 CopyMem (Register, Ghcb->SharedBuffer, Bytes);
992 break;
993
994 //
995 // MMIO read w/ sign-extension (MOVSX regX, reg/memX)
996 //
997 case 0xBE:
998 Bytes = 1;
999 //
1000 // fall through
1001 //
1002 case 0xBF:
1003 DecodeModRm (Regs, InstructionData);
1004 Bytes = (Bytes != 0) ? Bytes : 2;
1005
1006 Status = ValidateMmioMemory (Ghcb, InstructionData->Ext.RmData, Bytes);
1007 if (Status != 0) {
1008 return Status;
1009 }
1010
1011 ExitInfo1 = InstructionData->Ext.RmData;
1012 ExitInfo2 = Bytes;
1013
1014 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
1015 VmgSetOffsetValid (Ghcb, GhcbSwScratch);
1016 Status = VmgExit (Ghcb, SVM_EXIT_MMIO_READ, ExitInfo1, ExitInfo2);
1017 if (Status != 0) {
1018 return Status;
1019 }
1020
1021 if (Bytes == 1) {
1022 UINT8 *Data;
1023
1024 Data = (UINT8 *)Ghcb->SharedBuffer;
1025 SignByte = ((*Data & BIT7) != 0) ? 0xFF : 0x00;
1026 } else {
1027 UINT16 *Data;
1028
1029 Data = (UINT16 *)Ghcb->SharedBuffer;
1030 SignByte = ((*Data & BIT15) != 0) ? 0xFF : 0x00;
1031 }
1032
1033 Register = GetRegisterPointer (Regs, InstructionData->Ext.ModRm.Reg);
1034 SetMem (Register, (UINTN)(1 << InstructionData->DataSize), SignByte);
1035 CopyMem (Register, Ghcb->SharedBuffer, Bytes);
1036 break;
1037
1038 default:
1039 DEBUG ((DEBUG_ERROR, "Invalid MMIO opcode (%x)\n", OpCode));
1040 Status = GP_EXCEPTION;
1041 ASSERT (FALSE);
1042 }
1043
1044 return Status;
1045}
1046
1061STATIC
1062UINT64
1064 IN OUT GHCB *Ghcb,
1066 IN SEV_ES_INSTRUCTION_DATA *InstructionData
1067 )
1068{
1069 DecodeModRm (Regs, InstructionData);
1070
1071 Ghcb->SaveArea.Rax = Regs->Rax;
1072 VmgSetOffsetValid (Ghcb, GhcbRax);
1073 Ghcb->SaveArea.Rcx = Regs->Rcx;
1074 VmgSetOffsetValid (Ghcb, GhcbRcx);
1075
1076 return VmgExit (Ghcb, SVM_EXIT_MWAIT, 0, 0);
1077}
1078
1093STATIC
1094UINT64
1096 IN OUT GHCB *Ghcb,
1098 IN SEV_ES_INSTRUCTION_DATA *InstructionData
1099 )
1100{
1101 DecodeModRm (Regs, InstructionData);
1102
1103 Ghcb->SaveArea.Rax = Regs->Rax; // Identity mapped, so VA = PA
1104 VmgSetOffsetValid (Ghcb, GhcbRax);
1105 Ghcb->SaveArea.Rcx = Regs->Rcx;
1106 VmgSetOffsetValid (Ghcb, GhcbRcx);
1107 Ghcb->SaveArea.Rdx = Regs->Rdx;
1108 VmgSetOffsetValid (Ghcb, GhcbRdx);
1109
1110 return VmgExit (Ghcb, SVM_EXIT_MONITOR, 0, 0);
1111}
1112
1127STATIC
1128UINT64
1130 IN OUT GHCB *Ghcb,
1132 IN SEV_ES_INSTRUCTION_DATA *InstructionData
1133 )
1134{
1135 return VmgExit (Ghcb, SVM_EXIT_WBINVD, 0, 0);
1136}
1137
1152STATIC
1153UINT64
1155 IN OUT GHCB *Ghcb,
1157 IN SEV_ES_INSTRUCTION_DATA *InstructionData
1158 )
1159{
1160 UINT64 Status;
1161
1162 DecodeModRm (Regs, InstructionData);
1163
1164 Status = VmgExit (Ghcb, SVM_EXIT_RDTSCP, 0, 0);
1165 if (Status != 0) {
1166 return Status;
1167 }
1168
1169 if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||
1170 !VmgIsOffsetValid (Ghcb, GhcbRcx) ||
1171 !VmgIsOffsetValid (Ghcb, GhcbRdx))
1172 {
1173 return UnsupportedExit (Ghcb, Regs, InstructionData);
1174 }
1175
1176 Regs->Rax = Ghcb->SaveArea.Rax;
1177 Regs->Rcx = Ghcb->SaveArea.Rcx;
1178 Regs->Rdx = Ghcb->SaveArea.Rdx;
1179
1180 return 0;
1181}
1182
1197STATIC
1198UINT64
1200 IN OUT GHCB *Ghcb,
1202 IN SEV_ES_INSTRUCTION_DATA *InstructionData
1203 )
1204{
1205 UINT64 Status;
1206
1207 DecodeModRm (Regs, InstructionData);
1208
1209 Ghcb->SaveArea.Rax = Regs->Rax;
1210 VmgSetOffsetValid (Ghcb, GhcbRax);
1211 Ghcb->SaveArea.Cpl = (UINT8)(Regs->Cs & 0x3);
1212 VmgSetOffsetValid (Ghcb, GhcbCpl);
1213
1214 Status = VmgExit (Ghcb, SVM_EXIT_VMMCALL, 0, 0);
1215 if (Status != 0) {
1216 return Status;
1217 }
1218
1219 if (!VmgIsOffsetValid (Ghcb, GhcbRax)) {
1220 return UnsupportedExit (Ghcb, Regs, InstructionData);
1221 }
1222
1223 Regs->Rax = Ghcb->SaveArea.Rax;
1224
1225 return 0;
1226}
1227
1242STATIC
1243UINT64
1245 IN OUT GHCB *Ghcb,
1247 IN SEV_ES_INSTRUCTION_DATA *InstructionData
1248 )
1249{
1250 UINT64 ExitInfo1, Status;
1251
1252 ExitInfo1 = 0;
1253
1254 switch (*(InstructionData->OpCodes + 1)) {
1255 case 0x30: // WRMSR
1256 ExitInfo1 = 1;
1257 Ghcb->SaveArea.Rax = Regs->Rax;
1258 VmgSetOffsetValid (Ghcb, GhcbRax);
1259 Ghcb->SaveArea.Rdx = Regs->Rdx;
1260 VmgSetOffsetValid (Ghcb, GhcbRdx);
1261 //
1262 // fall through
1263 //
1264 case 0x32: // RDMSR
1265 Ghcb->SaveArea.Rcx = Regs->Rcx;
1266 VmgSetOffsetValid (Ghcb, GhcbRcx);
1267 break;
1268 default:
1269 return UnsupportedExit (Ghcb, Regs, InstructionData);
1270 }
1271
1272 Status = VmgExit (Ghcb, SVM_EXIT_MSR, ExitInfo1, 0);
1273 if (Status != 0) {
1274 return Status;
1275 }
1276
1277 if (ExitInfo1 == 0) {
1278 if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||
1279 !VmgIsOffsetValid (Ghcb, GhcbRdx))
1280 {
1281 return UnsupportedExit (Ghcb, Regs, InstructionData);
1282 }
1283
1284 Regs->Rax = Ghcb->SaveArea.Rax;
1285 Regs->Rdx = Ghcb->SaveArea.Rdx;
1286 }
1287
1288 return 0;
1289}
1290
1303STATIC
1304UINT64
1307 IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData
1308 )
1309{
1310 UINT64 ExitInfo;
1311
1312 ExitInfo = 0;
1313
1314 switch (*(InstructionData->OpCodes)) {
1315 //
1316 // INS opcodes
1317 //
1318 case 0x6C:
1319 case 0x6D:
1320 ExitInfo |= IOIO_TYPE_INS;
1321 ExitInfo |= IOIO_SEG_ES;
1322 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
1323 break;
1324
1325 //
1326 // OUTS opcodes
1327 //
1328 case 0x6E:
1329 case 0x6F:
1330 ExitInfo |= IOIO_TYPE_OUTS;
1331 ExitInfo |= IOIO_SEG_DS;
1332 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
1333 break;
1334
1335 //
1336 // IN immediate opcodes
1337 //
1338 case 0xE4:
1339 case 0xE5:
1340 InstructionData->ImmediateSize = 1;
1341 InstructionData->End++;
1342 ExitInfo |= IOIO_TYPE_IN;
1343 ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16);
1344 break;
1345
1346 //
1347 // OUT immediate opcodes
1348 //
1349 case 0xE6:
1350 case 0xE7:
1351 InstructionData->ImmediateSize = 1;
1352 InstructionData->End++;
1353 ExitInfo |= IOIO_TYPE_OUT;
1354 ExitInfo |= ((*(InstructionData->OpCodes + 1)) << 16) | IOIO_TYPE_OUT;
1355 break;
1356
1357 //
1358 // IN register opcodes
1359 //
1360 case 0xEC:
1361 case 0xED:
1362 ExitInfo |= IOIO_TYPE_IN;
1363 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
1364 break;
1365
1366 //
1367 // OUT register opcodes
1368 //
1369 case 0xEE:
1370 case 0xEF:
1371 ExitInfo |= IOIO_TYPE_OUT;
1372 ExitInfo |= ((Regs->Rdx & 0xffff) << 16);
1373 break;
1374
1375 default:
1376 return 0;
1377 }
1378
1379 switch (*(InstructionData->OpCodes)) {
1380 //
1381 // Single-byte opcodes
1382 //
1383 case 0x6C:
1384 case 0x6E:
1385 case 0xE4:
1386 case 0xE6:
1387 case 0xEC:
1388 case 0xEE:
1389 ExitInfo |= IOIO_DATA_8;
1390 break;
1391
1392 //
1393 // Length determined by instruction parsing
1394 //
1395 default:
1396 ExitInfo |= (InstructionData->DataSize == Size16Bits) ? IOIO_DATA_16
1397 : IOIO_DATA_32;
1398 }
1399
1400 switch (InstructionData->AddrSize) {
1401 case Size16Bits:
1402 ExitInfo |= IOIO_ADDR_16;
1403 break;
1404
1405 case Size32Bits:
1406 ExitInfo |= IOIO_ADDR_32;
1407 break;
1408
1409 case Size64Bits:
1410 ExitInfo |= IOIO_ADDR_64;
1411 break;
1412
1413 default:
1414 break;
1415 }
1416
1417 if (InstructionData->RepMode != 0) {
1418 ExitInfo |= IOIO_REP;
1419 }
1420
1421 return ExitInfo;
1422}
1423
1438STATIC
1439UINT64
1441 IN OUT GHCB *Ghcb,
1443 IN SEV_ES_INSTRUCTION_DATA *InstructionData
1444 )
1445{
1446 UINT64 ExitInfo1, ExitInfo2, Status;
1447 BOOLEAN IsString;
1448
1449 ExitInfo1 = IoioExitInfo (Regs, InstructionData);
1450 if (ExitInfo1 == 0) {
1451 return UnsupportedExit (Ghcb, Regs, InstructionData);
1452 }
1453
1454 IsString = ((ExitInfo1 & IOIO_TYPE_STR) != 0) ? TRUE : FALSE;
1455 if (IsString) {
1456 UINTN IoBytes, VmgExitBytes;
1457 UINTN GhcbCount, OpCount;
1458
1459 Status = 0;
1460
1461 IoBytes = IOIO_DATA_BYTES (ExitInfo1);
1462 GhcbCount = sizeof (Ghcb->SharedBuffer) / IoBytes;
1463
1464 OpCount = ((ExitInfo1 & IOIO_REP) != 0) ? Regs->Rcx : 1;
1465 while (OpCount != 0) {
1466 ExitInfo2 = MIN (OpCount, GhcbCount);
1467 VmgExitBytes = ExitInfo2 * IoBytes;
1468
1469 if ((ExitInfo1 & IOIO_TYPE_IN) == 0) {
1470 CopyMem (Ghcb->SharedBuffer, (VOID *)Regs->Rsi, VmgExitBytes);
1471 Regs->Rsi += VmgExitBytes;
1472 }
1473
1474 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
1475 VmgSetOffsetValid (Ghcb, GhcbSwScratch);
1476 Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, ExitInfo2);
1477 if (Status != 0) {
1478 return Status;
1479 }
1480
1481 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
1482 CopyMem ((VOID *)Regs->Rdi, Ghcb->SharedBuffer, VmgExitBytes);
1483 Regs->Rdi += VmgExitBytes;
1484 }
1485
1486 if ((ExitInfo1 & IOIO_REP) != 0) {
1487 Regs->Rcx -= ExitInfo2;
1488 }
1489
1490 OpCount -= ExitInfo2;
1491 }
1492 } else {
1493 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
1494 Ghcb->SaveArea.Rax = 0;
1495 } else {
1496 CopyMem (&Ghcb->SaveArea.Rax, &Regs->Rax, IOIO_DATA_BYTES (ExitInfo1));
1497 }
1498
1499 VmgSetOffsetValid (Ghcb, GhcbRax);
1500
1501 Status = VmgExit (Ghcb, SVM_EXIT_IOIO_PROT, ExitInfo1, 0);
1502 if (Status != 0) {
1503 return Status;
1504 }
1505
1506 if ((ExitInfo1 & IOIO_TYPE_IN) != 0) {
1507 if (!VmgIsOffsetValid (Ghcb, GhcbRax)) {
1508 return UnsupportedExit (Ghcb, Regs, InstructionData);
1509 }
1510
1511 CopyMem (&Regs->Rax, &Ghcb->SaveArea.Rax, IOIO_DATA_BYTES (ExitInfo1));
1512 }
1513 }
1514
1515 return 0;
1516}
1517
1532STATIC
1533UINT64
1535 IN OUT GHCB *Ghcb,
1537 IN SEV_ES_INSTRUCTION_DATA *InstructionData
1538 )
1539{
1540 return VmgExit (Ghcb, SVM_EXIT_INVD, 0, 0);
1541}
1542
1568STATIC
1569BOOLEAN
1571 IN OUT GHCB *Ghcb,
1572 IN UINT32 EaxIn,
1573 IN UINT32 EcxIn,
1574 IN UINT64 XCr0,
1575 IN OUT UINT32 *Eax,
1576 IN OUT UINT32 *Ebx,
1577 IN OUT UINT32 *Ecx,
1578 IN OUT UINT32 *Edx,
1579 IN OUT UINT64 *Status,
1580 IN OUT BOOLEAN *UnsupportedExit
1581 )
1582{
1584 Ghcb->SaveArea.Rax = EaxIn;
1585 VmgSetOffsetValid (Ghcb, GhcbRax);
1586 Ghcb->SaveArea.Rcx = EcxIn;
1587 VmgSetOffsetValid (Ghcb, GhcbRcx);
1588 if (EaxIn == CPUID_EXTENDED_STATE) {
1589 Ghcb->SaveArea.XCr0 = XCr0;
1590 VmgSetOffsetValid (Ghcb, GhcbXCr0);
1591 }
1592
1593 *Status = VmgExit (Ghcb, SVM_EXIT_CPUID, 0, 0);
1594 if (*Status != 0) {
1595 return FALSE;
1596 }
1597
1598 if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||
1599 !VmgIsOffsetValid (Ghcb, GhcbRbx) ||
1600 !VmgIsOffsetValid (Ghcb, GhcbRcx) ||
1601 !VmgIsOffsetValid (Ghcb, GhcbRdx))
1602 {
1604 return FALSE;
1605 }
1606
1607 if (Eax) {
1608 *Eax = (UINT32)(UINTN)Ghcb->SaveArea.Rax;
1609 }
1610
1611 if (Ebx) {
1612 *Ebx = (UINT32)(UINTN)Ghcb->SaveArea.Rbx;
1613 }
1614
1615 if (Ecx) {
1616 *Ecx = (UINT32)(UINTN)Ghcb->SaveArea.Rcx;
1617 }
1618
1619 if (Edx) {
1620 *Edx = (UINT32)(UINTN)Ghcb->SaveArea.Rdx;
1621 }
1622
1623 return TRUE;
1624}
1625
1633STATIC
1634BOOLEAN
1636 VOID
1637 )
1638{
1640
1641 Msr.Uint32 = AsmReadMsr32 (MSR_SEV_STATUS);
1642
1643 return !!Msr.Bits.SevSnpBit;
1644}
1645
1663STATIC
1664BOOLEAN
1666 IN UINT64 XFeaturesEnabled,
1667 IN UINT32 XSaveBaseSize,
1668 IN OUT UINT32 *XSaveSize,
1669 IN BOOLEAN Compacted
1670 )
1671{
1672 SEV_SNP_CPUID_INFO *CpuidInfo;
1673 UINT64 XFeaturesFound = 0;
1674 UINT32 Idx;
1675
1676 *XSaveSize = XSaveBaseSize;
1677 CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase);
1678
1679 for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {
1680 SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];
1681
1682 if (!((CpuidFn->EaxIn == 0xD) &&
1683 ((CpuidFn->EcxIn == 0) || (CpuidFn->EcxIn == 1))))
1684 {
1685 continue;
1686 }
1687
1688 if (XFeaturesFound & (1ULL << CpuidFn->EcxIn) ||
1689 !(XFeaturesEnabled & (1ULL << CpuidFn->EcxIn)))
1690 {
1691 continue;
1692 }
1693
1694 XFeaturesFound |= (1ULL << CpuidFn->EcxIn);
1695 if (Compacted) {
1696 *XSaveSize += CpuidFn->Eax;
1697 } else {
1698 *XSaveSize = MAX (*XSaveSize, CpuidFn->Eax + CpuidFn->Ebx);
1699 }
1700 }
1701
1702 /*
1703 * Either the guest set unsupported XCR0/XSS bits, or the corresponding
1704 * entries in the CPUID table were not present. This is an invalid state.
1705 */
1706 if (XFeaturesFound != (XFeaturesEnabled & ~3UL)) {
1707 return FALSE;
1708 }
1709
1710 return TRUE;
1711}
1712
1722STATIC
1723BOOLEAN
1725 IN UINT32 EaxIn
1726 )
1727{
1728 switch (EaxIn) {
1729 case CPUID_CACHE_PARAMS:
1735 case CPUID_INTEL_SGX:
1739 case 0x8000001D: /* Cache Topology Information */
1740 return TRUE;
1741 }
1742
1743 return FALSE;
1744}
1745
1771STATIC
1772BOOLEAN
1774 IN OUT GHCB *Ghcb,
1775 IN UINT32 EaxIn,
1776 IN UINT32 EcxIn,
1777 IN UINT64 XCr0,
1778 IN OUT UINT32 *Eax,
1779 IN OUT UINT32 *Ebx,
1780 IN OUT UINT32 *Ecx,
1781 IN OUT UINT32 *Edx,
1782 IN OUT UINT64 *Status,
1783 IN OUT BOOLEAN *Unsupported
1784 )
1785{
1786 SEV_SNP_CPUID_INFO *CpuidInfo;
1787 BOOLEAN Found;
1788 UINT32 Idx;
1789
1790 CpuidInfo = (SEV_SNP_CPUID_INFO *)(UINT64)PcdGet32 (PcdOvmfCpuidBase);
1791 Found = FALSE;
1792
1793 for (Idx = 0; Idx < CpuidInfo->Count; Idx++) {
1794 SEV_SNP_CPUID_FUNCTION *CpuidFn = &CpuidInfo->function[Idx];
1795
1796 if (CpuidFn->EaxIn != EaxIn) {
1797 continue;
1798 }
1799
1800 if (IsFunctionIndexed (CpuidFn->EaxIn) && (CpuidFn->EcxIn != EcxIn)) {
1801 continue;
1802 }
1803
1804 *Eax = CpuidFn->Eax;
1805 *Ebx = CpuidFn->Ebx;
1806 *Ecx = CpuidFn->Ecx;
1807 *Edx = CpuidFn->Edx;
1808
1809 Found = TRUE;
1810 break;
1811 }
1812
1813 if (!Found) {
1814 *Eax = *Ebx = *Ecx = *Edx = 0;
1815 goto Out;
1816 }
1817
1818 if (EaxIn == CPUID_VERSION_INFO) {
1819 IA32_CR4 Cr4;
1820 UINT32 Ebx2;
1821 UINT32 Edx2;
1822
1823 if (!GetCpuidHyp (
1824 Ghcb,
1825 EaxIn,
1826 EcxIn,
1827 XCr0,
1828 NULL,
1829 &Ebx2,
1830 NULL,
1831 &Edx2,
1832 Status,
1833 Unsupported
1834 ))
1835 {
1836 return FALSE;
1837 }
1838
1839 /* initial APIC ID */
1840 *Ebx = (*Ebx & 0x00FFFFFF) | (Ebx2 & 0xFF000000);
1841 /* APIC enabled bit */
1842 *Edx = (*Edx & ~BIT9) | (Edx2 & BIT9);
1843 /* OSXSAVE enabled bit */
1844 Cr4.UintN = AsmReadCr4 ();
1845 *Ecx = (Cr4.Bits.OSXSAVE) ? (*Ecx & ~BIT27) | (*Ecx & BIT27)
1846 : (*Ecx & ~BIT27);
1847 } else if (EaxIn == CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS) {
1848 IA32_CR4 Cr4;
1849
1850 Cr4.UintN = AsmReadCr4 ();
1851 /* OSPKE enabled bit */
1852 *Ecx = (Cr4.Bits.PKE) ? (*Ecx | BIT4) : (*Ecx & ~BIT4);
1853 } else if (EaxIn == CPUID_EXTENDED_TOPOLOGY) {
1854 if (!GetCpuidHyp (
1855 Ghcb,
1856 EaxIn,
1857 EcxIn,
1858 XCr0,
1859 NULL,
1860 NULL,
1861 NULL,
1862 Edx,
1863 Status,
1864 Unsupported
1865 ))
1866 {
1867 return FALSE;
1868 }
1869 } else if ((EaxIn == CPUID_EXTENDED_STATE) && ((EcxIn == 0) || (EcxIn == 1))) {
1870 MSR_IA32_XSS_REGISTER XssMsr;
1871 BOOLEAN Compacted;
1872 UINT32 XSaveSize;
1873
1874 XssMsr.Uint64 = 0;
1875 Compacted = FALSE;
1876 if (EcxIn == 1) {
1877 /*
1878 * The PPR and APM aren't clear on what size should be encoded in
1879 * 0xD:0x1:EBX when compaction is not enabled by either XSAVEC or
1880 * XSAVES, as these are generally fixed to 1 on real CPUs. Report
1881 * this undefined case as an error.
1882 */
1883 if (!(*Eax & (BIT3 | BIT1))) {
1884 /* (XSAVES | XSAVEC) */
1885 return FALSE;
1886 }
1887
1888 Compacted = TRUE;
1889 XssMsr.Uint64 = AsmReadMsr64 (MSR_IA32_XSS);
1890 }
1891
1892 if (!GetCpuidXSaveSize (
1893 XCr0 | XssMsr.Uint64,
1894 *Ebx,
1895 &XSaveSize,
1896 Compacted
1897 ))
1898 {
1899 return FALSE;
1900 }
1901
1902 *Ebx = XSaveSize;
1903 } else if (EaxIn == 0x8000001E) {
1904 UINT32 Ebx2;
1905 UINT32 Ecx2;
1906
1907 /* extended APIC ID */
1908 if (!GetCpuidHyp (
1909 Ghcb,
1910 EaxIn,
1911 EcxIn,
1912 XCr0,
1913 Eax,
1914 &Ebx2,
1915 &Ecx2,
1916 NULL,
1917 Status,
1918 Unsupported
1919 ))
1920 {
1921 return FALSE;
1922 }
1923
1924 /* compute ID */
1925 *Ebx = (*Ebx & 0xFFFFFF00) | (Ebx2 & 0x000000FF);
1926 /* node ID */
1927 *Ecx = (*Ecx & 0xFFFFFF00) | (Ecx2 & 0x000000FF);
1928 }
1929
1930Out:
1931 *Status = 0;
1932 *Unsupported = FALSE;
1933 return TRUE;
1934}
1935
1950STATIC
1951UINT64
1953 IN OUT GHCB *Ghcb,
1955 IN SEV_ES_INSTRUCTION_DATA *InstructionData
1956 )
1957{
1958 BOOLEAN Unsupported;
1959 UINT64 Status;
1960 UINT32 EaxIn;
1961 UINT32 EcxIn;
1962 UINT64 XCr0;
1963 UINT32 Eax;
1964 UINT32 Ebx;
1965 UINT32 Ecx;
1966 UINT32 Edx;
1967
1968 EaxIn = (UINT32)(UINTN)Regs->Rax;
1969 EcxIn = (UINT32)(UINTN)Regs->Rcx;
1970
1971 if (EaxIn == CPUID_EXTENDED_STATE) {
1972 IA32_CR4 Cr4;
1973
1974 Cr4.UintN = AsmReadCr4 ();
1975 Ghcb->SaveArea.XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;
1976 XCr0 = (Cr4.Bits.OSXSAVE == 1) ? AsmXGetBv (0) : 1;
1977 }
1978
1979 if (SnpEnabled ()) {
1980 if (!GetCpuidFw (
1981 Ghcb,
1982 EaxIn,
1983 EcxIn,
1984 XCr0,
1985 &Eax,
1986 &Ebx,
1987 &Ecx,
1988 &Edx,
1989 &Status,
1990 &Unsupported
1991 ))
1992 {
1993 goto CpuidFail;
1994 }
1995 } else {
1996 if (!GetCpuidHyp (
1997 Ghcb,
1998 EaxIn,
1999 EcxIn,
2000 XCr0,
2001 &Eax,
2002 &Ebx,
2003 &Ecx,
2004 &Edx,
2005 &Status,
2006 &Unsupported
2007 ))
2008 {
2009 goto CpuidFail;
2010 }
2011 }
2012
2013 Regs->Rax = Eax;
2014 Regs->Rbx = Ebx;
2015 Regs->Rcx = Ecx;
2016 Regs->Rdx = Edx;
2017
2018 return 0;
2019
2020CpuidFail:
2021 if (Unsupported) {
2022 return UnsupportedExit (Ghcb, Regs, InstructionData);
2023 }
2024
2025 return Status;
2026}
2027
2042STATIC
2043UINT64
2045 IN OUT GHCB *Ghcb,
2047 IN SEV_ES_INSTRUCTION_DATA *InstructionData
2048 )
2049{
2050 UINT64 Status;
2051
2052 Ghcb->SaveArea.Rcx = Regs->Rcx;
2053 VmgSetOffsetValid (Ghcb, GhcbRcx);
2054
2055 Status = VmgExit (Ghcb, SVM_EXIT_RDPMC, 0, 0);
2056 if (Status != 0) {
2057 return Status;
2058 }
2059
2060 if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||
2061 !VmgIsOffsetValid (Ghcb, GhcbRdx))
2062 {
2063 return UnsupportedExit (Ghcb, Regs, InstructionData);
2064 }
2065
2066 Regs->Rax = Ghcb->SaveArea.Rax;
2067 Regs->Rdx = Ghcb->SaveArea.Rdx;
2068
2069 return 0;
2070}
2071
2086STATIC
2087UINT64
2089 IN OUT GHCB *Ghcb,
2091 IN SEV_ES_INSTRUCTION_DATA *InstructionData
2092 )
2093{
2094 UINT64 Status;
2095
2096 Status = VmgExit (Ghcb, SVM_EXIT_RDTSC, 0, 0);
2097 if (Status != 0) {
2098 return Status;
2099 }
2100
2101 if (!VmgIsOffsetValid (Ghcb, GhcbRax) ||
2102 !VmgIsOffsetValid (Ghcb, GhcbRdx))
2103 {
2104 return UnsupportedExit (Ghcb, Regs, InstructionData);
2105 }
2106
2107 Regs->Rax = Ghcb->SaveArea.Rax;
2108 Regs->Rdx = Ghcb->SaveArea.Rdx;
2109
2110 return 0;
2111}
2112
2127STATIC
2128UINT64
2130 IN OUT GHCB *Ghcb,
2132 IN SEV_ES_INSTRUCTION_DATA *InstructionData
2133 )
2134{
2136 SEV_ES_PER_CPU_DATA *SevEsData;
2137 UINT64 *Register;
2138 UINT64 Status;
2139
2140 Ext = &InstructionData->Ext;
2141 SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);
2142
2143 DecodeModRm (Regs, InstructionData);
2144
2145 //
2146 // MOV DRn always treats MOD == 3 no matter how encoded
2147 //
2148 Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);
2149
2150 //
2151 // Using a value of 0 for ExitInfo1 means RAX holds the value
2152 //
2153 Ghcb->SaveArea.Rax = *Register;
2154 VmgSetOffsetValid (Ghcb, GhcbRax);
2155
2156 Status = VmgExit (Ghcb, SVM_EXIT_DR7_WRITE, 0, 0);
2157 if (Status != 0) {
2158 return Status;
2159 }
2160
2161 SevEsData->Dr7 = *Register;
2162 SevEsData->Dr7Cached = 1;
2163
2164 return 0;
2165}
2166
2180STATIC
2181UINT64
2183 IN OUT GHCB *Ghcb,
2185 IN SEV_ES_INSTRUCTION_DATA *InstructionData
2186 )
2187{
2189 SEV_ES_PER_CPU_DATA *SevEsData;
2190 UINT64 *Register;
2191
2192 Ext = &InstructionData->Ext;
2193 SevEsData = (SEV_ES_PER_CPU_DATA *)(Ghcb + 1);
2194
2195 DecodeModRm (Regs, InstructionData);
2196
2197 //
2198 // MOV DRn always treats MOD == 3 no matter how encoded
2199 //
2200 Register = GetRegisterPointer (Regs, Ext->ModRm.Rm);
2201
2202 //
2203 // If there is a cached valued for DR7, return that. Otherwise return the
2204 // DR7 standard reset value of 0x400 (no debug breakpoints set).
2205 //
2206 *Register = (SevEsData->Dr7Cached == 1) ? SevEsData->Dr7 : 0x400;
2207
2208 return 0;
2209}
2210
2229EFIAPI
2231 IN OUT GHCB *Ghcb,
2232 IN OUT EFI_EXCEPTION_TYPE *ExceptionType,
2233 IN OUT EFI_SYSTEM_CONTEXT SystemContext
2234 )
2235{
2237 NAE_EXIT NaeExit;
2238 SEV_ES_INSTRUCTION_DATA InstructionData;
2239 UINT64 ExitCode, Status;
2240 EFI_STATUS VcRet;
2241 BOOLEAN InterruptState;
2242
2243 VcRet = EFI_SUCCESS;
2244
2245 Regs = SystemContext.SystemContextX64;
2246
2247 VmgInit (Ghcb, &InterruptState);
2248
2249 ExitCode = Regs->ExceptionData;
2250 switch (ExitCode) {
2251 case SVM_EXIT_DR7_READ:
2252 NaeExit = Dr7ReadExit;
2253 break;
2254
2255 case SVM_EXIT_DR7_WRITE:
2256 NaeExit = Dr7WriteExit;
2257 break;
2258
2259 case SVM_EXIT_RDTSC:
2260 NaeExit = RdtscExit;
2261 break;
2262
2263 case SVM_EXIT_RDPMC:
2264 NaeExit = RdpmcExit;
2265 break;
2266
2267 case SVM_EXIT_CPUID:
2268 NaeExit = CpuidExit;
2269 break;
2270
2271 case SVM_EXIT_INVD:
2272 NaeExit = InvdExit;
2273 break;
2274
2275 case SVM_EXIT_IOIO_PROT:
2276 NaeExit = IoioExit;
2277 break;
2278
2279 case SVM_EXIT_MSR:
2280 NaeExit = MsrExit;
2281 break;
2282
2283 case SVM_EXIT_VMMCALL:
2284 NaeExit = VmmCallExit;
2285 break;
2286
2287 case SVM_EXIT_RDTSCP:
2288 NaeExit = RdtscpExit;
2289 break;
2290
2291 case SVM_EXIT_WBINVD:
2292 NaeExit = WbinvdExit;
2293 break;
2294
2295 case SVM_EXIT_MONITOR:
2296 NaeExit = MonitorExit;
2297 break;
2298
2299 case SVM_EXIT_MWAIT:
2300 NaeExit = MwaitExit;
2301 break;
2302
2303 case SVM_EXIT_NPF:
2304 NaeExit = MmioExit;
2305 break;
2306
2307 default:
2308 NaeExit = UnsupportedExit;
2309 }
2310
2311 InitInstructionData (&InstructionData, Ghcb, Regs);
2312
2313 Status = NaeExit (Ghcb, Regs, &InstructionData);
2314 if (Status == 0) {
2315 Regs->Rip += InstructionLength (&InstructionData);
2316 } else {
2318
2319 Event.Uint64 = Status;
2320 if (Event.Elements.ErrorCodeValid != 0) {
2321 Regs->ExceptionData = Event.Elements.ErrorCode;
2322 } else {
2323 Regs->ExceptionData = 0;
2324 }
2325
2326 *ExceptionType = Event.Elements.Vector;
2327
2328 VcRet = EFI_PROTOCOL_ERROR;
2329 }
2330
2331 VmgDone (Ghcb, InterruptState);
2332
2333 return VcRet;
2334}
2335
2342VOID
2343EFIAPI
2345 IN OUT SEV_ES_PER_CPU_DATA *SevEsData
2346 )
2347{
2348 //
2349 // Progress will be halted, so set VcCount to allow for ASSERT output
2350 // to be seen.
2351 //
2352 SevEsData->VcCount = 0;
2353
2354 ASSERT (FALSE);
2355 CpuDeadLoop ();
2356}
UINT64 UINTN
#define NULL
Definition: Base.h:312
#define STATIC
Definition: Base.h:264
#define STATIC_ASSERT
Definition: Base.h:766
#define MIN(a, b)
Definition: Base.h:903
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define MAX(a, b)
Definition: Base.h:888
VOID EFIAPI CpuDeadLoop(VOID)
Definition: CpuDeadLoop.c:23
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
#define DEBUG(Expression)
Definition: DebugLib.h:417
#define ASSERT(Expression)
Definition: DebugLib.h:391
#define MSR_SEV_STATUS
Definition: Fam17Msr.h:99
UINT64 EFIAPI AsmReadMsr64(IN UINT32 Index)
Definition: GccInlinePriv.c:60
UINTN EFIAPI AsmReadCr4(VOID)
UINTN EFIAPI GetLocalApicBaseAddress(VOID)
Definition: BaseXApicLib.c:67
INTN EFI_EXCEPTION_TYPE
Definition: DebugSupport.h:35
#define MSR_IA32_XSS
#define CPUID_INTEL_PROCESSOR_TRACE
Definition: Cpuid.h:2919
#define CPUID_DETERMINISTIC_ADDRESS_TRANSLATION_PARAMETERS
Definition: Cpuid.h:3457
#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:2182
#define CPUID_VERSION_INFO
Definition: Cpuid.h:81
#define CPUID_EXTENDED_STATE
Definition: Cpuid.h:1913
#define CPUID_INTEL_SGX
Definition: Cpuid.h:2643
#define CPUID_EXTENDED_TOPOLOGY
Definition: Cpuid.h:1810
#define CPUID_V2_EXTENDED_TOPOLOGY
Definition: Cpuid.h:3680
#define CPUID_INTEL_RDT_ALLOCATION
Definition: Cpuid.h:2298
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)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:28
#define EFI_SUCCESS
Definition: UefiBaseType.h:111
VOID EFIAPI VmgSetOffsetValid(IN OUT GHCB *Ghcb, IN GHCB_REGISTER Offset)
Definition: VmgExitLib.c:197
BOOLEAN EFIAPI VmgIsOffsetValid(IN GHCB *Ghcb, IN GHCB_REGISTER Offset)
Definition: VmgExitLib.c:226
UINT64 EFIAPI VmgExit(IN OUT GHCB *Ghcb, IN UINT64 ExitCode, IN UINT64 ExitInfo1, IN UINT64 ExitInfo2)
Definition: VmgExitLib.c:105
VOID EFIAPI VmgInit(IN OUT GHCB *Ghcb, IN OUT BOOLEAN *InterruptState)
Definition: VmgExitLib.c:145
VOID EFIAPI VmgDone(IN OUT GHCB *Ghcb, IN BOOLEAN InterruptState)
Definition: VmgExitLib.c:175
STATIC UINT64 ValidateMmioMemory(IN GHCB *Ghcb, IN UINTN MemoryAddress, IN UINTN MemoryLength)
STATIC BOOLEAN SnpEnabled(VOID)
STATIC UINT64 RdtscpExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 Dr7WriteExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 MsrExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 MwaitExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 UnsupportedExit(IN GHCB *Ghcb, IN EFI_SYSTEM_CONTEXT_X64 *Regs, IN SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 VmmCallExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC BOOLEAN GetCpuidXSaveSize(IN UINT64 XFeaturesEnabled, IN UINT32 XSaveBaseSize, IN OUT UINT32 *XSaveSize, IN BOOLEAN Compacted)
STATIC UINT64 * GetRegisterPointer(IN EFI_SYSTEM_CONTEXT_X64 *Regs, IN UINT8 Register)
STATIC UINT64 MonitorExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 Dr7ReadExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN SEV_ES_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 CpuidExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC VOID DecodePrefixes(IN EFI_SYSTEM_CONTEXT_X64 *Regs, IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 InvdExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 GetEffectiveMemoryAddress(IN EFI_SYSTEM_CONTEXT_X64 *Regs, IN SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 RdpmcExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC VOID UpdateForDisplacement(IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData, IN UINTN Size)
STATIC VOID InitInstructionData(IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData, IN GHCB *Ghcb, IN EFI_SYSTEM_CONTEXT_X64 *Regs)
EFI_STATUS EFIAPI InternalVmgExitHandleVc(IN OUT GHCB *Ghcb, IN OUT EFI_EXCEPTION_TYPE *ExceptionType, IN OUT EFI_SYSTEM_CONTEXT SystemContext)
STATIC BOOLEAN IsRipRelative(IN SEV_ES_INSTRUCTION_DATA *InstructionData)
VOID EFIAPI VmgExitIssueAssert(IN OUT SEV_ES_PER_CPU_DATA *SevEsData)
STATIC BOOLEAN IsFunctionIndexed(IN UINT32 EaxIn)
STATIC UINT64 MmioExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData)
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 IoioExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 RdtscExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 WbinvdExit(IN OUT GHCB *Ghcb, IN OUT EFI_SYSTEM_CONTEXT_X64 *Regs, IN SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 IoioExitInfo(IN EFI_SYSTEM_CONTEXT_X64 *Regs, IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC VOID DecodeModRm(IN EFI_SYSTEM_CONTEXT_X64 *Regs, IN OUT SEV_ES_INSTRUCTION_DATA *InstructionData)
STATIC UINT64 InstructionLength(IN SEV_ES_INSTRUCTION_DATA *InstructionData)
UINT32 EFIAPI AsmReadMsr32(IN UINT32 Index)
Definition: X86Msr.c:27