TianoCore EDK2 master
Loading...
Searching...
No Matches
AmdSvsmLib.c
Go to the documentation of this file.
1
9#include <Base.h>
10#include <Uefi.h>
12#include <Library/AmdSvsmLib.h>
13#include <Register/Amd/Msr.h>
14#include <Register/Amd/Svsm.h>
15
16#define PAGES_PER_2MB_ENTRY 512
17
25VOID
27 VOID
28 )
29{
31
32 //
33 // Use the GHCB MSR Protocol to request termination by the hypervisor
34 //
35 Msr.Uint64 = 0;
36 Msr.GhcbTerminate.Function = GHCB_INFO_TERMINATE_REQUEST;
37 Msr.GhcbTerminate.ReasonCodeSet = GHCB_TERMINATE_GHCB;
38 Msr.GhcbTerminate.ReasonCode = GHCB_TERMINATE_GHCB_GENERAL;
39 AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.Uint64);
40
41 AsmVmgExit ();
42
43 ASSERT (FALSE);
44 CpuDeadLoop ();
45}
46
59 IN OUT SVSM_CALL_DATA *SvsmCallData
60 )
61{
63 UINT64 CurrentMsr;
64 UINT8 Pending;
65 BOOLEAN InterruptState;
66 UINTN Ret;
67
68 do {
69 //
70 // Be sure that an interrupt can't cause a #VC while the GHCB MSR protocol
71 // is being used (#VC handler will ASSERT if lower 12-bits are not zero).
72 //
73 InterruptState = GetInterruptState ();
74 if (InterruptState) {
76 }
77
78 Pending = 0;
79 SvsmCallData->CallPending = &Pending;
80
81 CurrentMsr = AsmReadMsr64 (MSR_SEV_ES_GHCB);
82
83 Msr.Uint64 = 0;
84 Msr.SnpVmplRequest.Function = GHCB_INFO_SNP_VMPL_REQUEST;
85 Msr.SnpVmplRequest.Vmpl = 0;
86 AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.Uint64);
87
88 //
89 // Guest memory is used for the guest-SVSM communication, so fence the
90 // invocation of the VMGEXIT instruction to ensure VMSA accesses are
91 // synchronized properly.
92 //
93 MemoryFence ();
94 Ret = AsmVmgExitSvsm (SvsmCallData);
95 MemoryFence ();
96
97 Msr.Uint64 = AsmReadMsr64 (MSR_SEV_ES_GHCB);
98
99 AsmWriteMsr64 (MSR_SEV_ES_GHCB, CurrentMsr);
100
101 if (InterruptState) {
103 }
104
105 if (Pending != 0) {
106 SnpTerminate ();
107 }
108
109 if ((Msr.SnpVmplResponse.Function != GHCB_INFO_SNP_VMPL_RESPONSE) ||
110 (Msr.SnpVmplResponse.ErrorCode != 0))
111 {
112 SnpTerminate ();
113 }
114 } while (Ret == SVSM_ERR_INCOMPLETE || Ret == SVSM_ERR_BUSY);
115
116 return Ret;
117}
118
128BOOLEAN
129EFIAPI
131 VOID
132 )
133{
134 SVSM_INFORMATION *SvsmInfo;
135
136 SvsmInfo = (SVSM_INFORMATION *)(UINTN)PcdGet32 (PcdOvmfSnpSecretsBase);
137
138 return (SvsmInfo != NULL && SvsmInfo->SvsmSize != 0);
139}
140
151UINT8
152EFIAPI
154 VOID
155 )
156{
157 SVSM_INFORMATION *SvsmInfo;
158
159 SvsmInfo = (SVSM_INFORMATION *)(UINTN)PcdGet32 (PcdOvmfSnpSecretsBase);
160
161 return AmdSvsmIsSvsmPresent () ? SvsmInfo->SvsmGuestVmpl : 0;
162}
163
172UINT64
173EFIAPI
175 VOID
176 )
177{
178 SVSM_INFORMATION *SvsmInfo;
179
180 SvsmInfo = (SVSM_INFORMATION *)(UINTN)PcdGet32 (PcdOvmfSnpSecretsBase);
181
182 return AmdSvsmIsSvsmPresent () ? SvsmInfo->SvsmCaa : 0;
183}
184
194STATIC
195VOID
198 )
199{
200 SVSM_CALL_DATA SvsmCallData;
201 SVSM_CAA *Caa;
202 SVSM_PVALIDATE_REQUEST *Request;
203 SVSM_FUNCTION Function;
204 BOOLEAN Validate;
205 UINTN Entry;
206 UINTN EntryLimit;
207 UINTN Index;
208 UINTN EndIndex;
209 UINT64 Gfn;
210 UINT64 GfnEnd;
211 UINTN Ret;
212
213 Caa = (SVSM_CAA *)AmdSvsmSnpGetCaa ();
214 ZeroMem (Caa->SvsmBuffer, sizeof (Caa->SvsmBuffer));
215
216 Function.Id.Protocol = 0;
217 Function.Id.CallId = 1;
218
219 Request = (SVSM_PVALIDATE_REQUEST *)Caa->SvsmBuffer;
220 EntryLimit = ((sizeof (Caa->SvsmBuffer) - sizeof (*Request)) /
221 sizeof (Request->Entry[0])) - 1;
222
223 SvsmCallData.Caa = Caa;
224 SvsmCallData.RaxIn = Function.Uint64;
225 SvsmCallData.RcxIn = (UINT64)(UINTN)Request;
226
227 Entry = 0;
228 Index = Info->Header.CurrentEntry;
229 EndIndex = Info->Header.EndEntry;
230
231 while (Index <= EndIndex) {
232 Validate = Info->Entry[Index].Operation == SNP_PAGE_STATE_PRIVATE;
233
234 Request->Header.Entries++;
235 Request->Entry[Entry].Bits.PageSize = Info->Entry[Index].PageSize;
236 Request->Entry[Entry].Bits.Action = (Validate == TRUE) ? 1 : 0;
237 Request->Entry[Entry].Bits.IgnoreCf = 0;
238 Request->Entry[Entry].Bits.Address = Info->Entry[Index].GuestFrameNumber;
239
240 Entry++;
241 if ((Entry > EntryLimit) || (Index == EndIndex)) {
242 Ret = SvsmMsrProtocol (&SvsmCallData);
243 if ((Ret == SVSM_ERR_PVALIDATE_FAIL_SIZE_MISMATCH) &&
244 (Request->Entry[Request->Header.Next].Bits.PageSize != 0))
245 {
246 // Calculate the Index of the entry after the entry that failed
247 // before clearing the buffer so that processing can continue
248 // from that point
249 Index = Index - (Entry - Request->Header.Next) + 2;
250
251 // Obtain the failing GFN before clearing the buffer
252 Gfn = Request->Entry[Request->Header.Next].Bits.Address;
253
254 // Clear the buffer in prep for creating all new entries
255 ZeroMem (Caa->SvsmBuffer, sizeof (Caa->SvsmBuffer));
256 Entry = 0;
257
258 GfnEnd = Gfn + PAGES_PER_2MB_ENTRY - 1;
259 for ( ; Gfn <= GfnEnd; Gfn++) {
260 Request->Header.Entries++;
261 Request->Entry[Entry].Bits.PageSize = 0;
262 Request->Entry[Entry].Bits.Action = (Validate == TRUE) ? 1 : 0;
263 Request->Entry[Entry].Bits.IgnoreCf = 0;
264 Request->Entry[Entry].Bits.Address = Gfn;
265
266 Entry++;
267 if ((Entry > EntryLimit) || (Gfn == GfnEnd)) {
268 Ret = SvsmMsrProtocol (&SvsmCallData);
269 if (Ret != 0) {
270 SnpTerminate ();
271 }
272
273 ZeroMem (Caa->SvsmBuffer, sizeof (Caa->SvsmBuffer));
274 Entry = 0;
275 }
276 }
277
278 continue;
279 }
280
281 if (Ret != 0) {
282 SnpTerminate ();
283 }
284
285 ZeroMem (Caa->SvsmBuffer, sizeof (Caa->SvsmBuffer));
286 Entry = 0;
287 }
288
289 Index++;
290 }
291}
292
301STATIC
302VOID
305 )
306{
307 UINTN RmpPageSize;
308 UINTN StartIndex;
309 UINTN EndIndex;
310 UINTN Index;
311 UINTN Ret;
312 EFI_PHYSICAL_ADDRESS Address;
313 BOOLEAN Validate;
314
315 StartIndex = Info->Header.CurrentEntry;
316 EndIndex = Info->Header.EndEntry;
317
318 for ( ; StartIndex <= EndIndex; StartIndex++) {
319 //
320 // Get the address and the page size from the Info.
321 //
322 Address = ((EFI_PHYSICAL_ADDRESS)Info->Entry[StartIndex].GuestFrameNumber) << EFI_PAGE_SHIFT;
323 RmpPageSize = Info->Entry[StartIndex].PageSize;
324 Validate = Info->Entry[StartIndex].Operation == SNP_PAGE_STATE_PRIVATE;
325
326 Ret = AsmPvalidate (RmpPageSize, Validate, Address);
327
328 //
329 // If we fail to validate due to size mismatch then try with the
330 // smaller page size. This senario will occur if the backing page in
331 // the RMP entry is 4K and we are validating it as a 2MB.
332 //
333 if ((Ret == PVALIDATE_RET_SIZE_MISMATCH) && (RmpPageSize == PvalidatePageSize2MB)) {
334 for (Index = 0; Index < PAGES_PER_2MB_ENTRY; Index++) {
335 Ret = AsmPvalidate (PvalidatePageSize4K, Validate, Address);
336 if (Ret) {
337 break;
338 }
339
340 Address = Address + EFI_PAGE_SIZE;
341 }
342 }
343
344 //
345 // If validation failed then do not continue.
346 //
347 if (Ret) {
348 DEBUG ((
349 DEBUG_ERROR,
350 "%a:%a: Failed to %a address 0x%Lx Error code %d\n",
351 gEfiCallerBaseName,
352 __func__,
353 Validate ? "Validate" : "Invalidate",
354 Address,
355 Ret
356 ));
357
358 SnpTerminate ();
359 }
360 }
361}
362
371VOID
372EFIAPI
375 )
376{
378}
379
396STATIC
399 IN SEV_ES_SAVE_AREA *Vmsa,
400 IN UINT32 ApicId,
401 IN BOOLEAN SetVmsa
402 )
403{
404 SVSM_CALL_DATA SvsmCallData;
405 SVSM_FUNCTION Function;
406 UINTN Ret;
407
408 SvsmCallData.Caa = (SVSM_CAA *)AmdSvsmSnpGetCaa ();
409
410 Function.Id.Protocol = 0;
411
412 if (SetVmsa) {
413 Function.Id.CallId = 2;
414
415 SvsmCallData.RaxIn = Function.Uint64;
416 SvsmCallData.RcxIn = (UINT64)(UINTN)Vmsa;
417 SvsmCallData.RdxIn = (UINT64)(UINTN)Vmsa + SIZE_4KB;
418 SvsmCallData.R8In = ApicId;
419 } else {
420 Function.Id.CallId = 3;
421
422 SvsmCallData.RaxIn = Function.Uint64;
423 SvsmCallData.RcxIn = (UINT64)(UINTN)Vmsa;
424 }
425
426 Ret = SvsmMsrProtocol (&SvsmCallData);
427
428 return (Ret == 0) ? EFI_SUCCESS : EFI_INVALID_PARAMETER;
429}
430
445STATIC
448 IN SEV_ES_SAVE_AREA *Vmsa,
449 IN BOOLEAN SetVmsa
450 )
451{
452 UINT64 Rdx;
453 UINT32 Ret;
454
455 //
456 // The RMPADJUST instruction is used to set or clear the VMSA bit for a
457 // page. The VMSA change is only made when running at VMPL0 and is ignored
458 // otherwise. If too low a target VMPL is specified, the instruction can
459 // succeed without changing the VMSA bit when not running at VMPL0. Using a
460 // target VMPL level of 1, RMPADJUST will return a FAIL_PERMISSION error if
461 // not running at VMPL0, thus ensuring that the VMSA bit is set appropriately
462 // when no error is returned.
463 //
464 Rdx = 1;
465 if (SetVmsa) {
466 Rdx |= RMPADJUST_VMSA_PAGE_BIT;
467 }
468
469 Ret = AsmRmpAdjust ((UINT64)(UINTN)Vmsa, 0, Rdx);
470
471 return (Ret == 0) ? EFI_SUCCESS : EFI_INVALID_PARAMETER;
472}
473
491EFIAPI
493 IN SEV_ES_SAVE_AREA *Vmsa,
494 IN UINT32 ApicId,
495 IN BOOLEAN SetVmsa
496 )
497{
498 return AmdSvsmIsSvsmPresent () ? SvsmVmsaRmpAdjust (Vmsa, ApicId, SetVmsa)
499 : BaseVmsaRmpAdjust (Vmsa, SetVmsa);
500}
UINT64 UINTN
BOOLEAN EFIAPI AmdSvsmIsSvsmPresent(VOID)
Definition: AmdSvsmLib.c:130
UINT8 EFIAPI AmdSvsmSnpGetVmpl(VOID)
Definition: AmdSvsmLib.c:153
STATIC VOID BasePvalidate(IN SNP_PAGE_STATE_CHANGE_INFO *Info)
Definition: AmdSvsmLib.c:303
EFI_STATUS EFIAPI AmdSvsmSnpVmsaRmpAdjust(IN SEV_ES_SAVE_AREA *Vmsa, IN UINT32 ApicId, IN BOOLEAN SetVmsa)
Definition: AmdSvsmLib.c:492
UINT64 EFIAPI AmdSvsmSnpGetCaa(VOID)
Definition: AmdSvsmLib.c:174
VOID EFIAPI AmdSvsmSnpPvalidate(IN SNP_PAGE_STATE_CHANGE_INFO *Info)
Definition: AmdSvsmLib.c:373
STATIC UINTN SvsmMsrProtocol(IN OUT SVSM_CALL_DATA *SvsmCallData)
Definition: AmdSvsmLib.c:58
STATIC VOID SvsmPvalidate(IN SNP_PAGE_STATE_CHANGE_INFO *Info)
Definition: AmdSvsmLib.c:196
STATIC VOID SnpTerminate(VOID)
Definition: AmdSvsmLib.c:26
STATIC EFI_STATUS BaseVmsaRmpAdjust(IN SEV_ES_SAVE_AREA *Vmsa, IN BOOLEAN SetVmsa)
Definition: AmdSvsmLib.c:447
STATIC EFI_STATUS SvsmVmsaRmpAdjust(IN SEV_ES_SAVE_AREA *Vmsa, IN UINT32 ApicId, IN BOOLEAN SetVmsa)
Definition: AmdSvsmLib.c:398
BOOLEAN EFIAPI GetInterruptState(VOID)
Definition: CpuBreakpoint.c:86
VOID EFIAPI CpuDeadLoop(VOID)
Definition: CpuDeadLoop.c:25
VOID EFIAPI MemoryFence(VOID)
Definition: CpuBreakpoint.c:42
VOID EFIAPI EnableInterrupts(VOID)
Definition: CpuBreakpoint.c:67
VOID EFIAPI DisableInterrupts(VOID)
Definition: CpuBreakpoint.c:54
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
UINT64 EFIAPI AsmReadMsr64(IN UINT32 Index)
Definition: GccInlinePriv.c:60
UINT64 EFIAPI AsmWriteMsr64(IN UINT32 Index, IN UINT64 Value)
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#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 DEBUG(Expression)
Definition: DebugLib.h:434
#define PcdGet32(TokenName)
Definition: PcdLib.h:362
#define MSR_SEV_ES_GHCB
Definition: SevSnpMsr.h:24
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112