TianoCore EDK2 master
Loading...
Searching...
No Matches
SnpPageStateChangeInternal.c
Go to the documentation of this file.
1
11#include <Uefi/UefiBaseType.h>
12#include <Library/BaseLib.h>
15#include <Library/DebugLib.h>
16#include <Library/CcExitLib.h>
17#include <Library/AmdSvsmLib.h>
18
19#include <Register/Amd/Ghcb.h>
20#include <Register/Amd/Msr.h>
21#include <Register/Amd/Svsm.h>
22
23#include "SnpPageStateChange.h"
24
27MemoryStateToGhcbOp (
28 IN SEV_SNP_PAGE_STATE State
29 )
30{
31 UINTN Cmd;
32
33 switch (State) {
34 case SevSnpPageShared: Cmd = SNP_PAGE_STATE_SHARED;
35 break;
36 case SevSnpPagePrivate: Cmd = SNP_PAGE_STATE_PRIVATE;
37 break;
38 default: ASSERT (0);
39 }
40
41 return Cmd;
42}
43
44VOID
45SnpPageStateFailureTerminate (
46 VOID
47 )
48{
50
51 //
52 // Use the GHCB MSR Protocol to request termination by the hypervisor
53 //
54 Msr.GhcbPhysicalAddress = 0;
55 Msr.GhcbTerminate.Function = GHCB_INFO_TERMINATE_REQUEST;
56 Msr.GhcbTerminate.ReasonCodeSet = GHCB_TERMINATE_GHCB;
57 Msr.GhcbTerminate.ReasonCode = GHCB_TERMINATE_GHCB_GENERAL;
58 AsmWriteMsr64 (MSR_SEV_ES_GHCB, Msr.GhcbPhysicalAddress);
59
60 AsmVmgExit ();
61
62 ASSERT (FALSE);
63 CpuDeadLoop ();
64}
65
68BuildPageStateBuffer (
69 IN EFI_PHYSICAL_ADDRESS BaseAddress,
70 IN EFI_PHYSICAL_ADDRESS EndAddress,
71 IN SEV_SNP_PAGE_STATE State,
72 IN BOOLEAN UseLargeEntry,
74 IN UINTN InfoSize
75 )
76{
77 EFI_PHYSICAL_ADDRESS NextAddress;
78 UINTN RmpPageSize;
79 UINTN Index;
80 UINTN IndexMax;
81 UINTN PscIndexMax;
82 UINTN SvsmIndexMax;
83
84 // Clear the page state structure
85 SetMem (Info, InfoSize, 0);
86
87 Index = 0;
88 IndexMax = (InfoSize - sizeof (Info->Header)) / sizeof (Info->Entry[0]);
89 NextAddress = EndAddress;
90
91 //
92 // Make the use of the work area as efficient as possible relative to
93 // exiting from the guest to the hypervisor. Maximize the number of entries
94 // that can be processed per exit.
95 //
96 PscIndexMax = (IndexMax / SNP_PAGE_STATE_MAX_ENTRY) * SNP_PAGE_STATE_MAX_ENTRY;
97 if (PscIndexMax > 0) {
98 IndexMax = MIN (IndexMax, PscIndexMax);
99 }
100
101 SvsmIndexMax = (IndexMax / SVSM_PVALIDATE_MAX_ENTRY) * SVSM_PVALIDATE_MAX_ENTRY;
102 if (SvsmIndexMax > 0) {
103 IndexMax = MIN (IndexMax, SvsmIndexMax);
104 }
105
106 //
107 // Populate the page state entry structure
108 //
109 while ((BaseAddress < EndAddress) && (Index < IndexMax)) {
110 //
111 // Is this a 2MB aligned page? Check if we can use the Large RMP entry.
112 //
113 if (UseLargeEntry && IS_ALIGNED (BaseAddress, SIZE_2MB) &&
114 ((EndAddress - BaseAddress) >= SIZE_2MB))
115 {
116 RmpPageSize = PvalidatePageSize2MB;
117 NextAddress = BaseAddress + SIZE_2MB;
118 } else {
119 RmpPageSize = PvalidatePageSize4K;
120 NextAddress = BaseAddress + EFI_PAGE_SIZE;
121 }
122
123 Info->Entry[Index].GuestFrameNumber = BaseAddress >> EFI_PAGE_SHIFT;
124 Info->Entry[Index].PageSize = RmpPageSize;
125 Info->Entry[Index].Operation = MemoryStateToGhcbOp (State);
126 Info->Entry[Index].CurrentPage = 0;
127 Info->Header.EndEntry = (UINT16)Index;
128
129 BaseAddress = NextAddress;
130 Index++;
131 }
132
133 return NextAddress;
134}
135
136STATIC
137VOID
138PageStateChangeVmgExit (
139 IN GHCB *Ghcb,
141 IN UINT16 Count
142 )
143{
145 EFI_STATUS Status;
146 BOOLEAN InterruptState;
147
148 ASSERT (Count <= SNP_PAGE_STATE_MAX_ENTRY);
149 if (Count > SNP_PAGE_STATE_MAX_ENTRY) {
150 SnpPageStateFailureTerminate ();
151 }
152
153 //
154 // Initialize the GHCB
155 //
156 CcExitVmgInit (Ghcb, &InterruptState);
157
158 GhcbInfo = (SNP_PAGE_STATE_CHANGE_INFO *)Ghcb->SharedBuffer;
159 GhcbInfo->Header.CurrentEntry = 0;
160 GhcbInfo->Header.EndEntry = Count - 1;
161 CopyMem (GhcbInfo->Entry, Start, sizeof (*Start) * Count);
162
163 //
164 // As per the GHCB specification, the hypervisor can resume the guest before
165 // processing all the entries. Checks whether all the entries are processed.
166 //
167 // The stragtegy here is to wait for the hypervisor to change the page
168 // state in the RMP table before guest access the memory pages. If the
169 // page state was not successful, then later memory access will result
170 // in the crash.
171 //
172 while (GhcbInfo->Header.CurrentEntry <= GhcbInfo->Header.EndEntry) {
173 Ghcb->SaveArea.SwScratch = (UINT64)Ghcb->SharedBuffer;
174 CcExitVmgSetOffsetValid (Ghcb, GhcbSwScratch);
175
176 Status = CcExitVmgExit (Ghcb, SVM_EXIT_SNP_PAGE_STATE_CHANGE, 0, 0);
177
178 //
179 // The Page State Change VMGEXIT can pass the failure through the
180 // ExitInfo2. Lets check both the return value as well as ExitInfo2.
181 //
182 if ((Status != 0) || (Ghcb->SaveArea.SwExitInfo2)) {
183 SnpPageStateFailureTerminate ();
184 }
185 }
186
187 CcExitVmgDone (Ghcb, InterruptState);
188}
189
190STATIC
191VOID
192PageStateChange (
194 )
195{
196 GHCB *Ghcb;
198 SNP_PAGE_STATE_HEADER *Header;
199 UINT16 Index;
200 UINT16 Count;
201
202 Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
203 Ghcb = Msr.Ghcb;
204
205 Header = &Info->Header;
206
207 for (Index = Header->CurrentEntry; Index <= Header->EndEntry;) {
208 Count = MIN (Header->EndEntry - Index + 1, SNP_PAGE_STATE_MAX_ENTRY);
209
210 PageStateChangeVmgExit (Ghcb, &Info->Entry[Index], Count);
211
212 Index += Count;
213 }
214}
215
224VOID
226 IN EFI_PHYSICAL_ADDRESS BaseAddress,
227 IN UINTN NumPages,
228 IN SEV_SNP_PAGE_STATE State,
229 IN BOOLEAN UseLargeEntry,
230 IN VOID *PscBuffer,
231 IN UINTN PscBufferSize
232 )
233{
234 EFI_PHYSICAL_ADDRESS NextAddress, EndAddress;
236
237 EndAddress = BaseAddress + EFI_PAGES_TO_SIZE (NumPages);
238
239 DEBUG ((
240 DEBUG_VERBOSE,
241 "%a:%a Address 0x%Lx - 0x%Lx State = %a LargeEntry = %d\n",
242 gEfiCallerBaseName,
243 __func__,
244 BaseAddress,
245 EndAddress,
246 State == SevSnpPageShared ? "Shared" : "Private",
247 UseLargeEntry
248 ));
249
250 Info = (SNP_PAGE_STATE_CHANGE_INFO *)PscBuffer;
251
252 for (NextAddress = BaseAddress; NextAddress < EndAddress;) {
253 //
254 // Build the page state structure
255 //
256 NextAddress = BuildPageStateBuffer (
257 NextAddress,
258 EndAddress,
259 State,
260 UseLargeEntry,
261 PscBuffer,
262 PscBufferSize
263 );
264
265 //
266 // If the caller requested to change the page state to shared then
267 // invalidate the pages before making the page shared in the RMP table.
268 //
269 if (State == SevSnpPageShared) {
270 AmdSvsmSnpPvalidate (Info);
271 }
272
273 //
274 // Invoke the page state change VMGEXIT.
275 //
276 PageStateChange (Info);
277
278 //
279 // If the caller requested to change the page state to private then
280 // validate the pages after it has been added in the RMP table.
281 //
282 if (State == SevSnpPagePrivate) {
283 AmdSvsmSnpPvalidate (Info);
284 }
285 }
286}
UINT64 UINTN
VOID EFIAPI AmdSvsmSnpPvalidate(IN SNP_PAGE_STATE_CHANGE_INFO *Info)
Definition: AmdSvsmLib.c:373
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
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
UINT64 EFIAPI AsmReadMsr64(IN UINT32 Index)
Definition: GccInlinePriv.c:60
UINT64 EFIAPI AsmWriteMsr64(IN UINT32 Index, IN UINT64 Value)
#define STATIC
Definition: Base.h:264
#define MIN(a, b)
Definition: Base.h:1007
#define IS_ALIGNED(Value, Alignment)
Definition: Base.h:912
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define MSR_SEV_ES_GHCB
Definition: SevSnpMsr.h:24
VOID InternalSetPageState(IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINTN NumPages, IN SEV_SNP_PAGE_STATE State, IN BOOLEAN UseLargeEntry, IN VOID *PscBuffer, IN UINTN PscBufferSize)
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
#define EFI_PAGES_TO_SIZE(Pages)
Definition: UefiBaseType.h:213
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29