TianoCore EDK2 master
AmdSev.c
Go to the documentation of this file.
1
11#include "MpLib.h"
12#include <Library/VmgExitLib.h>
14#include <Register/Amd/Ghcb.h>
15
23VOID
25 IN CPU_MP_DATA *CpuMpData,
26 IN CPU_AP_DATA *CpuData,
27 UINT32 ApicId
28 )
29{
30 SEV_ES_SAVE_AREA *SaveArea;
31 IA32_CR0 ApCr0;
32 IA32_CR0 ResetCr0;
33 IA32_CR4 ApCr4;
34 IA32_CR4 ResetCr4;
35 UINTN StartIp;
36 UINT8 SipiVector;
37 UINT32 RmpAdjustStatus;
38 UINT64 VmgExitStatus;
40 GHCB *Ghcb;
41 BOOLEAN InterruptState;
42 UINT64 ExitInfo1;
43 UINT64 ExitInfo2;
44
45 //
46 // Allocate a single page for the SEV-ES Save Area and initialize it.
47 //
48 SaveArea = AllocateReservedPages (1);
49 if (!SaveArea) {
50 return;
51 }
52
53 ZeroMem (SaveArea, EFI_PAGE_SIZE);
54
55 //
56 // Propogate the CR0.NW and CR0.CD setting to the AP
57 //
58 ResetCr0.UintN = 0x00000010;
59 ApCr0.UintN = CpuData->VolatileRegisters.Cr0;
60 if (ApCr0.Bits.NW) {
61 ResetCr0.Bits.NW = 1;
62 }
63
64 if (ApCr0.Bits.CD) {
65 ResetCr0.Bits.CD = 1;
66 }
67
68 //
69 // Propagate the CR4.MCE setting to the AP
70 //
71 ResetCr4.UintN = 0;
72 ApCr4.UintN = CpuData->VolatileRegisters.Cr4;
73 if (ApCr4.Bits.MCE) {
74 ResetCr4.Bits.MCE = 1;
75 }
76
77 //
78 // Convert the start IP into a SIPI Vector
79 //
80 StartIp = CpuMpData->MpCpuExchangeInfo->BufferStart;
81 SipiVector = (UINT8)(StartIp >> 12);
82
83 //
84 // Set the CS:RIP value based on the start IP
85 //
86 SaveArea->Cs.Base = SipiVector << 12;
87 SaveArea->Cs.Selector = SipiVector << 8;
88 SaveArea->Cs.Limit = 0xFFFF;
89 SaveArea->Cs.Attributes.Bits.Present = 1;
90 SaveArea->Cs.Attributes.Bits.Sbit = 1;
91 SaveArea->Cs.Attributes.Bits.Type = SEV_ES_RESET_CODE_SEGMENT_TYPE;
92 SaveArea->Rip = StartIp & 0xFFF;
93
94 //
95 // Set the remaining values as defined in APM for INIT
96 //
97 SaveArea->Ds.Limit = 0xFFFF;
98 SaveArea->Ds.Attributes.Bits.Present = 1;
99 SaveArea->Ds.Attributes.Bits.Sbit = 1;
100 SaveArea->Ds.Attributes.Bits.Type = SEV_ES_RESET_DATA_SEGMENT_TYPE;
101 SaveArea->Es = SaveArea->Ds;
102 SaveArea->Fs = SaveArea->Ds;
103 SaveArea->Gs = SaveArea->Ds;
104 SaveArea->Ss = SaveArea->Ds;
105
106 SaveArea->Gdtr.Limit = 0xFFFF;
107 SaveArea->Ldtr.Limit = 0xFFFF;
108 SaveArea->Ldtr.Attributes.Bits.Present = 1;
109 SaveArea->Ldtr.Attributes.Bits.Type = SEV_ES_RESET_LDT_TYPE;
110 SaveArea->Idtr.Limit = 0xFFFF;
111 SaveArea->Tr.Limit = 0xFFFF;
112 SaveArea->Ldtr.Attributes.Bits.Present = 1;
113 SaveArea->Ldtr.Attributes.Bits.Type = SEV_ES_RESET_TSS_TYPE;
114
115 SaveArea->Efer = 0x1000;
116 SaveArea->Cr4 = ResetCr4.UintN;
117 SaveArea->Cr0 = ResetCr0.UintN;
118 SaveArea->Dr7 = 0x0400;
119 SaveArea->Dr6 = 0xFFFF0FF0;
120 SaveArea->Rflags = 0x0002;
121 SaveArea->GPat = 0x0007040600070406ULL;
122 SaveArea->XCr0 = 0x0001;
123 SaveArea->Mxcsr = 0x1F80;
124 SaveArea->X87Ftw = 0x5555;
125 SaveArea->X87Fcw = 0x0040;
126
127 //
128 // Set the SEV-SNP specific fields for the save area:
129 // VMPL - always VMPL0
130 // SEV_FEATURES - equivalent to the SEV_STATUS MSR right shifted 2 bits
131 //
132 SaveArea->Vmpl = 0;
133 SaveArea->SevFeatures = AsmReadMsr64 (MSR_SEV_STATUS) >> 2;
134
135 //
136 // To turn the page into a recognized VMSA page, issue RMPADJUST:
137 // Target VMPL but numerically higher than current VMPL
138 // Target PermissionMask is not used
139 //
140 RmpAdjustStatus = SevSnpRmpAdjust (
141 (EFI_PHYSICAL_ADDRESS)(UINTN)SaveArea,
142 TRUE
143 );
144 ASSERT (RmpAdjustStatus == 0);
145
146 ExitInfo1 = (UINT64)ApicId << 32;
147 ExitInfo1 |= SVM_VMGEXIT_SNP_AP_CREATE;
148 ExitInfo2 = (UINT64)(UINTN)SaveArea;
149
150 Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
151 Ghcb = Msr.Ghcb;
152
153 VmgInit (Ghcb, &InterruptState);
154 Ghcb->SaveArea.Rax = SaveArea->SevFeatures;
155 VmgSetOffsetValid (Ghcb, GhcbRax);
156 VmgExitStatus = VmgExit (
157 Ghcb,
158 SVM_EXIT_SNP_AP_CREATION,
159 ExitInfo1,
160 ExitInfo2
161 );
162 VmgDone (Ghcb, InterruptState);
163
164 ASSERT (VmgExitStatus == 0);
165 if (VmgExitStatus != 0) {
166 RmpAdjustStatus = SevSnpRmpAdjust (
167 (EFI_PHYSICAL_ADDRESS)(UINTN)SaveArea,
168 FALSE
169 );
170 if (RmpAdjustStatus == 0) {
171 FreePages (SaveArea, 1);
172 } else {
173 DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed, leaking VMSA page\n"));
174 }
175
176 SaveArea = NULL;
177 }
178
179 if (CpuData->SevEsSaveArea) {
180 RmpAdjustStatus = SevSnpRmpAdjust (
181 (EFI_PHYSICAL_ADDRESS)(UINTN)CpuData->SevEsSaveArea,
182 FALSE
183 );
184 if (RmpAdjustStatus == 0) {
185 FreePages (CpuData->SevEsSaveArea, 1);
186 } else {
187 DEBUG ((DEBUG_INFO, "SEV-SNP: RMPADJUST failed, leaking VMSA page\n"));
188 }
189 }
190
191 CpuData->SevEsSaveArea = SaveArea;
192}
193
201VOID
203 IN CPU_MP_DATA *CpuMpData,
204 IN INTN ProcessorNumber
205 )
206{
207 CPU_INFO_IN_HOB *CpuInfoInHob;
208 CPU_AP_DATA *CpuData;
209 UINTN Index;
210 UINT32 ApicId;
211
212 ASSERT (CpuMpData->MpCpuExchangeInfo->BufferStart < 0x100000);
213
214 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
215
216 if (ProcessorNumber < 0) {
217 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
218 if (Index != CpuMpData->BspNumber) {
219 CpuData = &CpuMpData->CpuData[Index];
220 ApicId = CpuInfoInHob[Index].ApicId,
221 SevSnpCreateSaveArea (CpuMpData, CpuData, ApicId);
222 }
223 }
224 } else {
225 Index = (UINTN)ProcessorNumber;
226 CpuData = &CpuMpData->CpuData[Index];
227 ApicId = CpuInfoInHob[ProcessorNumber].ApicId,
228 SevSnpCreateSaveArea (CpuMpData, CpuData, ApicId);
229 }
230}
231
240UINT32
242 IN EFI_PHYSICAL_ADDRESS PageAddress,
243 IN BOOLEAN VmsaPage
244 )
245{
246 UINT64 Rdx;
247
248 //
249 // The RMPADJUST instruction is used to set or clear the VMSA bit for a
250 // page. The VMSA change is only made when running at VMPL0 and is ignored
251 // otherwise. If too low a target VMPL is specified, the instruction can
252 // succeed without changing the VMSA bit when not running at VMPL0. Using a
253 // target VMPL level of 1, RMPADJUST will return a FAIL_PERMISSION error if
254 // not running at VMPL0, thus ensuring that the VMSA bit is set appropriately
255 // when no error is returned.
256 //
257 Rdx = 1;
258 if (VmsaPage) {
259 Rdx |= RMPADJUST_VMSA_PAGE_BIT;
260 }
261
262 return AsmRmpAdjust ((UINT64)PageAddress, 0, Rdx);
263}
UINT64 UINTN
INT64 INTN
#define NULL
Definition: Base.h:312
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
#define DEBUG(Expression)
Definition: DebugLib.h:417
#define ASSERT(Expression)
Definition: DebugLib.h:391
VOID EFIAPI FreePages(IN VOID *Buffer, IN UINTN Pages)
VOID *EFIAPI AllocateReservedPages(IN UINTN Pages)
#define MSR_SEV_STATUS
Definition: Fam17Msr.h:99
#define MSR_SEV_ES_GHCB
Definition: Fam17Msr.h:24
UINT64 EFIAPI AsmReadMsr64(IN UINT32 Index)
Definition: GccInlinePriv.c:60
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:49
UINT32 SevSnpRmpAdjust(IN EFI_PHYSICAL_ADDRESS PageAddress, IN BOOLEAN VmsaPage)
Definition: AmdSev.c:61
VOID SevSnpCreateAP(IN CPU_MP_DATA *CpuMpData, IN INTN ProcessorNumber)
Definition: AmdSev.c:41
VOID SevSnpCreateSaveArea(IN CPU_MP_DATA *CpuMpData, IN CPU_AP_DATA *CpuData, UINT32 ApicId)
Definition: AmdSev.c:21
VOID EFIAPI VmgSetOffsetValid(IN OUT GHCB *Ghcb, IN GHCB_REGISTER Offset)
Definition: VmgExitLib.c:197
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