TianoCore EDK2 master
Loading...
Searching...
No Matches
CpuPaging.c
Go to the documentation of this file.
1
11#include <Register/Intel/Msr.h>
13#include <Library/CpuLib.h>
14#include <Library/BaseLib.h>
15#include <Guid/MigratedFvInfo.h>
16
17#include "CpuMpPei.h"
18#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull
19
20EFI_PEI_NOTIFY_DESCRIPTOR mPostMemNotifyList[] = {
21 {
22 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
23 &gEfiPeiMemoryDiscoveredPpiGuid,
25 }
26};
27
35BOOLEAN
37 VOID
38 )
39{
40 UINT32 RegEax;
42
44 if (RegEax >= CPUID_VERSION_INFO) {
46 if (RegEdx.Bits.PAE != 0) {
47 return TRUE;
48 }
49 }
50
51 return FALSE;
52}
53
62VOID *
64 IN UINTN Pages
65 )
66{
67 VOID *Address;
68
69 Address = AllocatePages (Pages);
70 if (Address != NULL) {
71 ZeroMem (Address, EFI_PAGES_TO_SIZE (Pages));
72 }
73
74 return Address;
75}
76
93RETURN_STATUS
95 IN PHYSICAL_ADDRESS BaseAddress,
96 IN UINT64 Length
97 )
98{
99 EFI_STATUS Status;
100 UINTN PageTable;
102 UINTN BufferSize;
103 IA32_MAP_ATTRIBUTE MapAttribute;
104 IA32_MAP_ATTRIBUTE MapMask;
105 PAGING_MODE PagingMode;
106 IA32_CR4 Cr4;
107 BOOLEAN Page5LevelSupport;
108 UINT32 RegEax;
109 BOOLEAN Page1GSupport;
111
112 if (sizeof (UINTN) == sizeof (UINT64)) {
113 //
114 // Check Page5Level Support or not.
115 //
116 Cr4.UintN = AsmReadCr4 ();
117 Page5LevelSupport = (Cr4.Bits.LA57 ? TRUE : FALSE);
118
119 //
120 // Check Page1G Support or not.
121 //
122 Page1GSupport = FALSE;
123 AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
124 if (RegEax >= CPUID_EXTENDED_CPU_SIG) {
126 if (RegEdx.Bits.Page1GB != 0) {
127 Page1GSupport = TRUE;
128 }
129 }
130
131 //
132 // Decide Paging Mode according Page5LevelSupport & Page1GSupport.
133 //
134 if (Page5LevelSupport) {
135 PagingMode = Page1GSupport ? Paging5Level1GB : Paging5Level;
136 } else {
137 PagingMode = Page1GSupport ? Paging4Level1GB : Paging4Level;
138 }
139 } else {
140 PagingMode = PagingPae;
141 }
142
143 MapAttribute.Uint64 = 0;
144 MapMask.Uint64 = 0;
145 MapMask.Bits.Present = 1;
146 PageTable = AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64;
147 BufferSize = 0;
148
149 //
150 // Get required buffer size for the pagetable that will be created.
151 //
152 Status = PageTableMap (&PageTable, PagingMode, 0, &BufferSize, BaseAddress, Length, &MapAttribute, &MapMask, NULL);
153 if (Status == EFI_BUFFER_TOO_SMALL) {
154 //
155 // Allocate required Buffer.
156 //
157 Status = PeiServicesAllocatePages (
159 EFI_SIZE_TO_PAGES (BufferSize),
160 &Buffer
161 );
162 ASSERT_EFI_ERROR (Status);
163 if (EFI_ERROR (Status)) {
164 return EFI_OUT_OF_RESOURCES;
165 }
166
167 Status = PageTableMap (&PageTable, PagingMode, (VOID *)(UINTN)Buffer, &BufferSize, BaseAddress, Length, &MapAttribute, &MapMask, NULL);
168 }
169
170 ASSERT_EFI_ERROR (Status);
171 return Status;
172}
173
183 VOID
184 )
185{
186 EFI_STATUS Status;
187
188 UINTN PageTable;
189 VOID *Buffer;
190 UINTN BufferSize;
191 IA32_MAP_ATTRIBUTE MapAttribute;
192 IA32_MAP_ATTRIBUTE MapMask;
193
194 PageTable = 0;
195 Buffer = NULL;
196 BufferSize = 0;
197 MapAttribute.Uint64 = 0;
198 MapMask.Uint64 = MAX_UINT64;
199 MapAttribute.Bits.Present = 1;
200 MapAttribute.Bits.ReadWrite = 1;
201
202 //
203 // 1:1 map 4GB in 32bit mode
204 //
205 Status = PageTableMap (&PageTable, PagingPae, 0, &BufferSize, 0, SIZE_4GB, &MapAttribute, &MapMask, NULL);
206 ASSERT (Status == EFI_BUFFER_TOO_SMALL);
207 if (Status != EFI_BUFFER_TOO_SMALL) {
208 return Status;
209 }
210
211 //
212 // Allocate required Buffer.
213 //
214 Buffer = AllocatePageTableMemory (EFI_SIZE_TO_PAGES (BufferSize));
215 ASSERT (Buffer != NULL);
216 if (Buffer == NULL) {
217 return EFI_OUT_OF_RESOURCES;
218 }
219
220 Status = PageTableMap (&PageTable, PagingPae, Buffer, &BufferSize, 0, SIZE_4GB, &MapAttribute, &MapMask, NULL);
221 ASSERT_EFI_ERROR (Status);
222 if (EFI_ERROR (Status) || (PageTable == 0)) {
223 return EFI_OUT_OF_RESOURCES;
224 }
225
226 //
227 // Write the Pagetable to CR3.
228 //
229 AsmWriteCr3 (PageTable);
230
231 //
232 // Enable CR4.PAE
233 //
234 AsmWriteCr4 (AsmReadCr4 () | BIT5);
235
236 //
237 // Enable CR0.PG
238 //
239 AsmWriteCr0 (AsmReadCr0 () | BIT31);
240
241 DEBUG ((
242 DEBUG_INFO,
243 "EnablePaePageTable: Created PageTable = 0x%x, BufferSize = %x\n",
244 PageTable,
245 BufferSize
246 ));
247
248 return Status;
249}
250
263VOID
264EFIAPI
266 IN OUT VOID *Buffer
267 )
268{
269 EFI_PHYSICAL_ADDRESS StackBase;
270 UINTN Index;
271
272 MpInitLibWhoAmI (&Index);
273 StackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)&StackBase;
274 StackBase += BASE_4KB;
275 StackBase &= ~((EFI_PHYSICAL_ADDRESS)BASE_4KB - 1);
276 StackBase -= PcdGet32 (PcdCpuApStackSize);
277
278 *((EFI_PHYSICAL_ADDRESS *)Buffer + Index) = StackBase;
279}
280
286VOID
288 VOID
289 )
290{
292 EFI_PHYSICAL_ADDRESS *StackBase;
293 UINTN NumberOfProcessors;
294 UINTN Bsp;
295 UINTN Index;
296 EFI_STATUS Status;
297
298 //
299 // One extra page at the bottom of the stack is needed for Guard page.
300 //
301 if (PcdGet32 (PcdCpuApStackSize) <= EFI_PAGE_SIZE) {
302 DEBUG ((DEBUG_ERROR, "PcdCpuApStackSize is not big enough for Stack Guard!\n"));
303 ASSERT (FALSE);
304 }
305
306 Status = MpInitLibGetNumberOfProcessors (&NumberOfProcessors, NULL);
307 ASSERT_EFI_ERROR (Status);
308
309 if (EFI_ERROR (Status)) {
310 NumberOfProcessors = 1;
311 }
312
313 StackBase = (EFI_PHYSICAL_ADDRESS *)AllocatePages (EFI_SIZE_TO_PAGES (sizeof (EFI_PHYSICAL_ADDRESS) * NumberOfProcessors));
314 ASSERT (StackBase != NULL);
315 if (StackBase == NULL) {
316 return;
317 }
318
319 ZeroMem (StackBase, sizeof (EFI_PHYSICAL_ADDRESS) * NumberOfProcessors);
320 MpInitLibStartupAllAPs (GetStackBase, FALSE, NULL, 0, (VOID *)StackBase, NULL);
321 MpInitLibWhoAmI (&Bsp);
322 Hob.Raw = GetHobList ();
323 while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) {
324 if (CompareGuid (
325 &gEfiHobMemoryAllocStackGuid,
326 &(Hob.MemoryAllocationStack->AllocDescriptor.Name)
327 ))
328 {
329 StackBase[Bsp] = Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress;
330 break;
331 }
332
333 Hob.Raw = GET_NEXT_HOB (Hob);
334 }
335
336 for (Index = 0; Index < NumberOfProcessors; ++Index) {
337 ASSERT (StackBase[Index] != 0);
338 //
339 // Set Guard page at stack base address.
340 //
341 ConvertMemoryPageToNotPresent (StackBase[Index], EFI_PAGE_SIZE);
342 DEBUG ((
343 DEBUG_INFO,
344 "Stack Guard set at %lx [cpu%lu]!\n",
345 (UINT64)StackBase[Index],
346 (UINT64)Index
347 ));
348 }
349
350 FreePages (StackBase, EFI_SIZE_TO_PAGES (sizeof (EFI_PHYSICAL_ADDRESS) * NumberOfProcessors));
351 //
352 // Publish the changes of page table.
353 //
354 CpuFlushTlb ();
355}
356
371EFIAPI
373 IN EFI_PEI_SERVICES **PeiServices,
374 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
375 IN VOID *Ppi
376 )
377{
378 EFI_STATUS Status;
379 BOOLEAN InitStackGuard;
380 EDKII_MIGRATED_FV_INFO *MigratedFvInfo;
382 IA32_CR0 Cr0;
383
384 //
385 // Paging must be setup first. Otherwise the exception TSS setup during MP
386 // initialization later will not contain paging information and then fail
387 // the task switch (for the sake of stack switch).
388 //
389 InitStackGuard = FALSE;
390 Hob.Raw = NULL;
391 if (IsIa32PaeSupported ()) {
392 Hob.Raw = GetFirstGuidHob (&gEdkiiMigratedFvInfoGuid);
393 InitStackGuard = PcdGetBool (PcdCpuStackGuard);
394 }
395
396 //
397 // Some security features depend on the page table enabling. So, here
398 // is to enable paging if it is not enabled (only in 32bit mode).
399 //
400 Cr0.UintN = AsmReadCr0 ();
401 if ((Cr0.Bits.PG == 0) && (InitStackGuard || (Hob.Raw != NULL))) {
402 ASSERT (sizeof (UINTN) == sizeof (UINT32));
403
404 Status = EnablePaePageTable ();
405 if (EFI_ERROR (Status)) {
406 DEBUG ((DEBUG_ERROR, "MemoryDiscoveredPpiNotifyCallback: Failed to enable PAE page table: %r.\n", Status));
407 CpuDeadLoop ();
408 }
409 }
410
411 Status = InitializeCpuMpWorker ((CONST EFI_PEI_SERVICES **)PeiServices);
412 ASSERT_EFI_ERROR (Status);
413
414 if (InitStackGuard) {
416 }
417
418 while (Hob.Raw != NULL) {
419 MigratedFvInfo = GET_GUID_HOB_DATA (Hob);
420
421 //
422 // Enable #PF exception, so if the code access SPI after disable NEM, it will generate
423 // the exception to avoid potential vulnerability.
424 //
425 ConvertMemoryPageToNotPresent (MigratedFvInfo->FvOrgBase, MigratedFvInfo->FvLength);
426
427 Hob.Raw = GET_NEXT_HOB (Hob);
428 Hob.Raw = GetNextGuidHob (&gEdkiiMigratedFvInfoGuid, Hob.Raw);
429 }
430
431 CpuFlushTlb ();
432
433 return Status;
434}
UINT64 UINTN
VOID *EFIAPI GetFirstGuidHob(IN CONST EFI_GUID *Guid)
Definition: HobLib.c:215
VOID *EFIAPI GetNextHob(IN UINT16 Type, IN CONST VOID *HobStart)
Definition: HobLib.c:103
VOID *EFIAPI GetNextGuidHob(IN CONST EFI_GUID *Guid, IN CONST VOID *HobStart)
Definition: HobLib.c:176
VOID *EFIAPI GetHobList(VOID)
Definition: HobLib.c:76
VOID EFIAPI CpuDeadLoop(VOID)
Definition: CpuDeadLoop.c:25
BOOLEAN EFIAPI CompareGuid(IN CONST GUID *Guid1, IN CONST GUID *Guid2)
Definition: MemLibGuid.c:73
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID EFIAPI CpuFlushTlb(VOID)
EFI_STATUS InitializeCpuMpWorker(IN CONST EFI_PEI_SERVICES **PeiServices)
Definition: CpuMpPei.c:711
RETURN_STATUS EFIAPI PageTableMap(IN OUT UINTN *PageTable OPTIONAL, IN PAGING_MODE PagingMode, IN VOID *Buffer, IN OUT UINTN *BufferSize, IN UINT64 LinearAddress, IN UINT64 Length, IN IA32_MAP_ATTRIBUTE *Attribute, IN IA32_MAP_ATTRIBUTE *Mask, OUT BOOLEAN *IsModified OPTIONAL)
VOID SetupStackGuardPage(VOID)
Definition: CpuPaging.c:287
BOOLEAN IsIa32PaeSupported(VOID)
Definition: CpuPaging.c:36
EFI_STATUS EFIAPI MemoryDiscoveredPpiNotifyCallback(IN EFI_PEI_SERVICES **PeiServices, IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, IN VOID *Ppi)
Definition: CpuPaging.c:372
VOID * AllocatePageTableMemory(IN UINTN Pages)
Definition: CpuPaging.c:63
RETURN_STATUS ConvertMemoryPageToNotPresent(IN PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length)
Definition: CpuPaging.c:94
EFI_STATUS EnablePaePageTable(VOID)
Definition: CpuPaging.c:182
VOID EFIAPI GetStackBase(IN OUT VOID *Buffer)
Definition: CpuPaging.c:265
VOID EFIAPI FreePages(IN VOID *Buffer, IN UINTN Pages)
EFI_STATUS EFIAPI PeiServicesAllocatePages(IN EFI_MEMORY_TYPE MemoryType, IN UINTN Pages, OUT EFI_PHYSICAL_ADDRESS *Memory)
UINTN EFIAPI AsmReadCr3(VOID)
UINTN EFIAPI AsmWriteCr3(UINTN Cr3)
UINTN EFIAPI AsmWriteCr4(UINTN Cr4)
UINTN EFIAPI AsmReadCr0(VOID)
UINTN EFIAPI AsmWriteCr0(UINTN Cr0)
UINTN EFIAPI AsmReadCr4(VOID)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#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 ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
#define CPUID_SIGNATURE
Definition: Cpuid.h:45
#define CPUID_VERSION_INFO
Definition: Cpuid.h:81
#define CPUID_EXTENDED_CPU_SIG
Definition: Cpuid.h:3768
UINT32 EFIAPI AsmCpuid(IN UINT32 Index, OUT UINT32 *RegisterEax OPTIONAL, OUT UINT32 *RegisterEbx OPTIONAL, OUT UINT32 *RegisterEcx OPTIONAL, OUT UINT32 *RegisterEdx OPTIONAL)
Definition: CpuId.c:36
EFI_STATUS EFIAPI MpInitLibStartupAllAPs(IN EFI_AP_PROCEDURE Procedure, IN BOOLEAN SingleThread, IN EFI_EVENT WaitEvent OPTIONAL, IN UINTN TimeoutInMicroseconds, IN VOID *ProcedureArgument OPTIONAL, OUT UINTN **FailedCpuList OPTIONAL)
Definition: DxeMpLib.c:682
EFI_STATUS EFIAPI MpInitLibWhoAmI(OUT UINTN *ProcessorNumber)
Definition: MpLib.c:1522
EFI_STATUS EFIAPI MpInitLibGetNumberOfProcessors(OUT UINTN *NumberOfProcessors OPTIONAL, OUT UINTN *NumberOfEnabledProcessors OPTIONAL)
Definition: MpLib.c:1559
#define PcdGet32(TokenName)
Definition: PcdLib.h:362
#define PcdGetBool(TokenName)
Definition: PcdLib.h:401
VOID *EFIAPI AllocatePages(IN UINTN Pages)
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
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
@ EfiBootServicesData
EFI_PHYSICAL_ADDRESS MemoryBaseAddress
Definition: PiHob.h:119
EFI_HOB_MEMORY_ALLOCATION_HEADER AllocDescriptor
Definition: PiHob.h:174
struct CPUID_EXTENDED_CPU_SIG_EDX::@750 Bits
struct CPUID_VERSION_INFO_EDX::@696 Bits