]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuMpPei/CpuPaging.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / CpuMpPei / CpuPaging.c
CommitLineData
0a0d5296
JW
1/** @file\r
2 Basic paging support for the CPU to enable Stack Guard.\r
3\r
01acb06c 4Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>\r
0a0d5296 5\r
0acd8697 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
0a0d5296
JW
7\r
8**/\r
9\r
01acb06c
RN
10#include <Register/Intel/Cpuid.h>\r
11#include <Register/Intel/Msr.h>\r
0a0d5296
JW
12#include <Library/MemoryAllocationLib.h>\r
13#include <Library/CpuLib.h>\r
14#include <Library/BaseLib.h>\r
d7c9de51 15#include <Guid/MigratedFvInfo.h>\r
0a0d5296
JW
16\r
17#include "CpuMpPei.h"\r
18\r
053e878b
MK
19#define IA32_PG_P BIT0\r
20#define IA32_PG_RW BIT1\r
21#define IA32_PG_U BIT2\r
22#define IA32_PG_A BIT5\r
23#define IA32_PG_D BIT6\r
24#define IA32_PG_PS BIT7\r
25#define IA32_PG_NX BIT63\r
26\r
27#define PAGE_ATTRIBUTE_BITS (IA32_PG_RW | IA32_PG_P)\r
28#define PAGE_PROGATE_BITS (IA32_PG_D | IA32_PG_A | IA32_PG_NX | IA32_PG_U | \\r
0a0d5296
JW
29 PAGE_ATTRIBUTE_BITS)\r
30\r
053e878b
MK
31#define PAGING_PAE_INDEX_MASK 0x1FF\r
32#define PAGING_4K_ADDRESS_MASK_64 0x000FFFFFFFFFF000ull\r
33#define PAGING_2M_ADDRESS_MASK_64 0x000FFFFFFFE00000ull\r
34#define PAGING_1G_ADDRESS_MASK_64 0x000FFFFFC0000000ull\r
35#define PAGING_512G_ADDRESS_MASK_64 0x000FFF8000000000ull\r
0a0d5296
JW
36\r
37typedef enum {\r
38 PageNone = 0,\r
39 PageMin = 1,\r
40 Page4K = PageMin,\r
41 Page2M = 2,\r
42 Page1G = 3,\r
43 Page512G = 4,\r
44 PageMax = Page512G\r
45} PAGE_ATTRIBUTE;\r
46\r
47typedef struct {\r
053e878b
MK
48 PAGE_ATTRIBUTE Attribute;\r
49 UINT64 Length;\r
50 UINT64 AddressMask;\r
51 UINTN AddressBitOffset;\r
52 UINTN AddressBitLength;\r
0a0d5296
JW
53} PAGE_ATTRIBUTE_TABLE;\r
54\r
053e878b
MK
55PAGE_ATTRIBUTE_TABLE mPageAttributeTable[] = {\r
56 { PageNone, 0, 0, 0, 0 },\r
57 { Page4K, SIZE_4KB, PAGING_4K_ADDRESS_MASK_64, 12, 9 },\r
58 { Page2M, SIZE_2MB, PAGING_2M_ADDRESS_MASK_64, 21, 9 },\r
59 { Page1G, SIZE_1GB, PAGING_1G_ADDRESS_MASK_64, 30, 9 },\r
60 { Page512G, SIZE_512GB, PAGING_512G_ADDRESS_MASK_64, 39, 9 },\r
0a0d5296
JW
61};\r
62\r
63EFI_PEI_NOTIFY_DESCRIPTOR mPostMemNotifyList[] = {\r
64 {\r
65 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
66 &gEfiPeiMemoryDiscoveredPpiGuid,\r
67 MemoryDiscoveredPpiNotifyCallback\r
68 }\r
69};\r
70\r
71/**\r
72 The function will check if IA32 PAE is supported.\r
73\r
74 @retval TRUE IA32 PAE is supported.\r
75 @retval FALSE IA32 PAE is not supported.\r
76\r
77**/\r
78BOOLEAN\r
79IsIa32PaeSupported (\r
80 VOID\r
81 )\r
82{\r
053e878b
MK
83 UINT32 RegEax;\r
84 CPUID_VERSION_INFO_EDX RegEdx;\r
0a0d5296
JW
85\r
86 AsmCpuid (CPUID_SIGNATURE, &RegEax, NULL, NULL, NULL);\r
87 if (RegEax >= CPUID_VERSION_INFO) {\r
88 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx.Uint32);\r
89 if (RegEdx.Bits.PAE != 0) {\r
90 return TRUE;\r
91 }\r
92 }\r
93\r
94 return FALSE;\r
95}\r
96\r
97/**\r
98 This API provides a way to allocate memory for page table.\r
99\r
100 @param Pages The number of 4 KB pages to allocate.\r
101\r
102 @return A pointer to the allocated buffer or NULL if allocation fails.\r
103\r
104**/\r
105VOID *\r
106AllocatePageTableMemory (\r
053e878b 107 IN UINTN Pages\r
0a0d5296
JW
108 )\r
109{\r
053e878b 110 VOID *Address;\r
0a0d5296 111\r
053e878b 112 Address = AllocatePages (Pages);\r
0a0d5296 113 if (Address != NULL) {\r
053e878b 114 ZeroMem (Address, EFI_PAGES_TO_SIZE (Pages));\r
0a0d5296
JW
115 }\r
116\r
117 return Address;\r
118}\r
119\r
120/**\r
121 Get the address width supported by current processor.\r
122\r
123 @retval 32 If processor is in 32-bit mode.\r
124 @retval 36-48 If processor is in 64-bit mode.\r
125\r
126**/\r
127UINTN\r
128GetPhysicalAddressWidth (\r
129 VOID\r
130 )\r
131{\r
053e878b 132 UINT32 RegEax;\r
0a0d5296 133\r
053e878b 134 if (sizeof (UINTN) == 4) {\r
0a0d5296
JW
135 return 32;\r
136 }\r
137\r
053e878b 138 AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);\r
0a0d5296
JW
139 if (RegEax >= CPUID_VIR_PHY_ADDRESS_SIZE) {\r
140 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &RegEax, NULL, NULL, NULL);\r
141 RegEax &= 0xFF;\r
142 if (RegEax > 48) {\r
143 return 48;\r
144 }\r
145\r
146 return (UINTN)RegEax;\r
147 }\r
148\r
149 return 36;\r
150}\r
151\r
152/**\r
153 Get the type of top level page table.\r
154\r
155 @retval Page512G PML4 paging.\r
92c19c68 156 @retval Page1G PAE paging.\r
0a0d5296
JW
157\r
158**/\r
159PAGE_ATTRIBUTE\r
160GetPageTableTopLevelType (\r
161 VOID\r
162 )\r
163{\r
053e878b 164 MSR_IA32_EFER_REGISTER MsrEfer;\r
0a0d5296
JW
165\r
166 MsrEfer.Uint64 = AsmReadMsr64 (MSR_CORE_IA32_EFER);\r
167\r
168 return (MsrEfer.Bits.LMA == 1) ? Page512G : Page1G;\r
169}\r
170\r
171/**\r
172 Return page table entry matching the address.\r
173\r
174 @param[in] Address The address to be checked.\r
175 @param[out] PageAttributes The page attribute of the page entry.\r
176\r
177 @return The page entry.\r
178**/\r
179VOID *\r
180GetPageTableEntry (\r
053e878b
MK
181 IN PHYSICAL_ADDRESS Address,\r
182 OUT PAGE_ATTRIBUTE *PageAttribute\r
0a0d5296
JW
183 )\r
184{\r
053e878b
MK
185 INTN Level;\r
186 UINTN Index;\r
187 UINT64 *PageTable;\r
188 UINT64 AddressEncMask;\r
0a0d5296
JW
189\r
190 AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask);\r
053e878b 191 PageTable = (UINT64 *)(UINTN)(AsmReadCr3 () & PAGING_4K_ADDRESS_MASK_64);\r
0a0d5296 192 for (Level = (INTN)GetPageTableTopLevelType (); Level > 0; --Level) {\r
053e878b 193 Index = (UINTN)RShiftU64 (Address, mPageAttributeTable[Level].AddressBitOffset);\r
0a0d5296
JW
194 Index &= PAGING_PAE_INDEX_MASK;\r
195\r
196 //\r
197 // No mapping?\r
198 //\r
199 if (PageTable[Index] == 0) {\r
200 *PageAttribute = PageNone;\r
201 return NULL;\r
202 }\r
203\r
204 //\r
205 // Page memory?\r
206 //\r
053e878b 207 if (((PageTable[Index] & IA32_PG_PS) != 0) || (Level == PageMin)) {\r
0a0d5296
JW
208 *PageAttribute = (PAGE_ATTRIBUTE)Level;\r
209 return &PageTable[Index];\r
210 }\r
211\r
212 //\r
213 // Page directory or table\r
214 //\r
215 PageTable = (UINT64 *)(UINTN)(PageTable[Index] &\r
216 ~AddressEncMask &\r
217 PAGING_4K_ADDRESS_MASK_64);\r
218 }\r
219\r
220 *PageAttribute = PageNone;\r
221 return NULL;\r
222}\r
223\r
224/**\r
225 This function splits one page entry to smaller page entries.\r
226\r
227 @param[in] PageEntry The page entry to be splitted.\r
228 @param[in] PageAttribute The page attribute of the page entry.\r
229 @param[in] SplitAttribute How to split the page entry.\r
230 @param[in] Recursively Do the split recursively or not.\r
231\r
232 @retval RETURN_SUCCESS The page entry is splitted.\r
233 @retval RETURN_INVALID_PARAMETER If target page attribute is invalid\r
234 @retval RETURN_OUT_OF_RESOURCES No resource to split page entry.\r
235**/\r
236RETURN_STATUS\r
237SplitPage (\r
053e878b
MK
238 IN UINT64 *PageEntry,\r
239 IN PAGE_ATTRIBUTE PageAttribute,\r
240 IN PAGE_ATTRIBUTE SplitAttribute,\r
241 IN BOOLEAN Recursively\r
0a0d5296
JW
242 )\r
243{\r
053e878b
MK
244 UINT64 BaseAddress;\r
245 UINT64 *NewPageEntry;\r
246 UINTN Index;\r
247 UINT64 AddressEncMask;\r
248 PAGE_ATTRIBUTE SplitTo;\r
0a0d5296 249\r
053e878b 250 if ((SplitAttribute == PageNone) || (SplitAttribute >= PageAttribute)) {\r
0a0d5296
JW
251 ASSERT (SplitAttribute != PageNone);\r
252 ASSERT (SplitAttribute < PageAttribute);\r
253 return RETURN_INVALID_PARAMETER;\r
254 }\r
255\r
256 NewPageEntry = AllocatePageTableMemory (1);\r
257 if (NewPageEntry == NULL) {\r
258 ASSERT (NewPageEntry != NULL);\r
259 return RETURN_OUT_OF_RESOURCES;\r
260 }\r
261\r
262 //\r
263 // One level down each step to achieve more compact page table.\r
264 //\r
053e878b 265 SplitTo = PageAttribute - 1;\r
0a0d5296
JW
266 AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) &\r
267 mPageAttributeTable[SplitTo].AddressMask;\r
053e878b
MK
268 BaseAddress = *PageEntry &\r
269 ~PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) &\r
270 mPageAttributeTable[PageAttribute].AddressMask;\r
271 for (Index = 0; Index < SIZE_4KB / sizeof (UINT64); Index++) {\r
0a0d5296
JW
272 NewPageEntry[Index] = BaseAddress | AddressEncMask |\r
273 ((*PageEntry) & PAGE_PROGATE_BITS);\r
274\r
275 if (SplitTo != PageMin) {\r
276 NewPageEntry[Index] |= IA32_PG_PS;\r
277 }\r
278\r
053e878b 279 if (Recursively && (SplitTo > SplitAttribute)) {\r
0a0d5296
JW
280 SplitPage (&NewPageEntry[Index], SplitTo, SplitAttribute, Recursively);\r
281 }\r
282\r
283 BaseAddress += mPageAttributeTable[SplitTo].Length;\r
284 }\r
285\r
286 (*PageEntry) = (UINT64)(UINTN)NewPageEntry | AddressEncMask | PAGE_ATTRIBUTE_BITS;\r
287\r
288 return RETURN_SUCCESS;\r
289}\r
290\r
291/**\r
292 This function modifies the page attributes for the memory region specified\r
293 by BaseAddress and Length from their current attributes to the attributes\r
294 specified by Attributes.\r
295\r
296 Caller should make sure BaseAddress and Length is at page boundary.\r
297\r
298 @param[in] BaseAddress Start address of a memory region.\r
299 @param[in] Length Size in bytes of the memory region.\r
300 @param[in] Attributes Bit mask of attributes to modify.\r
301\r
302 @retval RETURN_SUCCESS The attributes were modified for the memory\r
303 region.\r
304 @retval RETURN_INVALID_PARAMETER Length is zero; or,\r
305 Attributes specified an illegal combination\r
306 of attributes that cannot be set together; or\r
307 Addressis not 4KB aligned.\r
308 @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify\r
309 the attributes.\r
310 @retval RETURN_UNSUPPORTED Cannot modify the attributes of given memory.\r
311\r
312**/\r
313RETURN_STATUS\r
314EFIAPI\r
315ConvertMemoryPageAttributes (\r
053e878b
MK
316 IN PHYSICAL_ADDRESS BaseAddress,\r
317 IN UINT64 Length,\r
318 IN UINT64 Attributes\r
0a0d5296
JW
319 )\r
320{\r
053e878b
MK
321 UINT64 *PageEntry;\r
322 PAGE_ATTRIBUTE PageAttribute;\r
323 RETURN_STATUS Status;\r
324 EFI_PHYSICAL_ADDRESS MaximumAddress;\r
325\r
326 if ((Length == 0) ||\r
327 ((BaseAddress & (SIZE_4KB - 1)) != 0) ||\r
328 ((Length & (SIZE_4KB - 1)) != 0))\r
329 {\r
0a0d5296
JW
330 ASSERT (Length > 0);\r
331 ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);\r
332 ASSERT ((Length & (SIZE_4KB - 1)) == 0);\r
333\r
334 return RETURN_INVALID_PARAMETER;\r
335 }\r
336\r
337 MaximumAddress = (EFI_PHYSICAL_ADDRESS)MAX_UINT32;\r
053e878b
MK
338 if ((BaseAddress > MaximumAddress) ||\r
339 (Length > MaximumAddress) ||\r
340 (BaseAddress > MaximumAddress - (Length - 1)))\r
341 {\r
0a0d5296
JW
342 return RETURN_UNSUPPORTED;\r
343 }\r
344\r
345 //\r
346 // Below logic is to check 2M/4K page to make sure we do not waste memory.\r
347 //\r
348 while (Length != 0) {\r
349 PageEntry = GetPageTableEntry (BaseAddress, &PageAttribute);\r
350 if (PageEntry == NULL) {\r
351 return RETURN_UNSUPPORTED;\r
352 }\r
353\r
354 if (PageAttribute != Page4K) {\r
355 Status = SplitPage (PageEntry, PageAttribute, Page4K, FALSE);\r
356 if (RETURN_ERROR (Status)) {\r
357 return Status;\r
358 }\r
053e878b 359\r
0a0d5296
JW
360 //\r
361 // Do it again until the page is 4K.\r
362 //\r
363 continue;\r
364 }\r
365\r
366 //\r
367 // Just take care of 'present' bit for Stack Guard.\r
368 //\r
369 if ((Attributes & IA32_PG_P) != 0) {\r
370 *PageEntry |= (UINT64)IA32_PG_P;\r
371 } else {\r
372 *PageEntry &= ~((UINT64)IA32_PG_P);\r
373 }\r
374\r
375 //\r
376 // Convert success, move to next\r
377 //\r
378 BaseAddress += SIZE_4KB;\r
053e878b 379 Length -= SIZE_4KB;\r
0a0d5296
JW
380 }\r
381\r
382 return RETURN_SUCCESS;\r
383}\r
384\r
385/**\r
386 Get maximum size of page memory supported by current processor.\r
387\r
388 @param[in] TopLevelType The type of top level page entry.\r
389\r
390 @retval Page1G If processor supports 1G page and PML4.\r
391 @retval Page2M For all other situations.\r
392\r
393**/\r
394PAGE_ATTRIBUTE\r
395GetMaxMemoryPage (\r
396 IN PAGE_ATTRIBUTE TopLevelType\r
397 )\r
398{\r
053e878b
MK
399 UINT32 RegEax;\r
400 UINT32 RegEdx;\r
0a0d5296
JW
401\r
402 if (TopLevelType == Page512G) {\r
403 AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);\r
404 if (RegEax >= CPUID_EXTENDED_CPU_SIG) {\r
405 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);\r
406 if ((RegEdx & BIT26) != 0) {\r
407 return Page1G;\r
408 }\r
409 }\r
410 }\r
411\r
412 return Page2M;\r
413}\r
414\r
415/**\r
416 Create PML4 or PAE page table.\r
417\r
418 @return The address of page table.\r
419\r
420**/\r
421UINTN\r
422CreatePageTable (\r
423 VOID\r
424 )\r
425{\r
053e878b
MK
426 RETURN_STATUS Status;\r
427 UINTN PhysicalAddressBits;\r
428 UINTN NumberOfEntries;\r
429 PAGE_ATTRIBUTE TopLevelPageAttr;\r
430 UINTN PageTable;\r
431 PAGE_ATTRIBUTE MaxMemoryPage;\r
432 UINTN Index;\r
433 UINT64 AddressEncMask;\r
434 UINT64 *PageEntry;\r
435 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
436\r
437 TopLevelPageAttr = (PAGE_ATTRIBUTE)GetPageTableTopLevelType ();\r
0a0d5296 438 PhysicalAddressBits = GetPhysicalAddressWidth ();\r
053e878b
MK
439 NumberOfEntries = (UINTN)1 << (PhysicalAddressBits -\r
440 mPageAttributeTable[TopLevelPageAttr].AddressBitOffset);\r
0a0d5296 441\r
053e878b 442 PageTable = (UINTN)AllocatePageTableMemory (1);\r
0a0d5296
JW
443 if (PageTable == 0) {\r
444 return 0;\r
445 }\r
446\r
053e878b 447 AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask);\r
0a0d5296 448 AddressEncMask &= mPageAttributeTable[TopLevelPageAttr].AddressMask;\r
053e878b
MK
449 MaxMemoryPage = GetMaxMemoryPage (TopLevelPageAttr);\r
450 PageEntry = (UINT64 *)PageTable;\r
0a0d5296
JW
451\r
452 PhysicalAddress = 0;\r
453 for (Index = 0; Index < NumberOfEntries; ++Index) {\r
454 *PageEntry = PhysicalAddress | AddressEncMask | PAGE_ATTRIBUTE_BITS;\r
455\r
456 //\r
457 // Split the top page table down to the maximum page size supported\r
458 //\r
459 if (MaxMemoryPage < TopLevelPageAttr) {\r
053e878b 460 Status = SplitPage (PageEntry, TopLevelPageAttr, MaxMemoryPage, TRUE);\r
0a0d5296
JW
461 ASSERT_EFI_ERROR (Status);\r
462 }\r
463\r
464 if (TopLevelPageAttr == Page1G) {\r
465 //\r
466 // PDPTE[2:1] (PAE Paging) must be 0. SplitPage() might change them to 1.\r
467 //\r
468 *PageEntry &= ~(UINT64)(IA32_PG_RW | IA32_PG_U);\r
469 }\r
470\r
053e878b 471 PageEntry += 1;\r
0a0d5296
JW
472 PhysicalAddress += mPageAttributeTable[TopLevelPageAttr].Length;\r
473 }\r
474\r
0a0d5296
JW
475 return PageTable;\r
476}\r
477\r
478/**\r
479 Setup page tables and make them work.\r
480\r
481**/\r
482VOID\r
483EnablePaging (\r
484 VOID\r
485 )\r
486{\r
053e878b 487 UINTN PageTable;\r
0a0d5296
JW
488\r
489 PageTable = CreatePageTable ();\r
490 ASSERT (PageTable != 0);\r
491 if (PageTable != 0) {\r
053e878b 492 AsmWriteCr3 (PageTable);\r
0a0d5296
JW
493 AsmWriteCr4 (AsmReadCr4 () | BIT5); // CR4.PAE\r
494 AsmWriteCr0 (AsmReadCr0 () | BIT31); // CR0.PG\r
495 }\r
496}\r
497\r
498/**\r
499 Get the base address of current AP's stack.\r
500\r
501 This function is called in AP's context and assumes that whole calling stacks\r
502 (till this function) consumed by AP's wakeup procedure will not exceed 4KB.\r
503\r
504 PcdCpuApStackSize must be configured with value taking the Guard page into\r
505 account.\r
506\r
507 @param[in,out] Buffer The pointer to private data buffer.\r
508\r
509**/\r
510VOID\r
511EFIAPI\r
512GetStackBase (\r
053e878b 513 IN OUT VOID *Buffer\r
0a0d5296
JW
514 )\r
515{\r
053e878b 516 EFI_PHYSICAL_ADDRESS StackBase;\r
0a0d5296 517\r
053e878b 518 StackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)&StackBase;\r
0a0d5296
JW
519 StackBase += BASE_4KB;\r
520 StackBase &= ~((EFI_PHYSICAL_ADDRESS)BASE_4KB - 1);\r
053e878b 521 StackBase -= PcdGet32 (PcdCpuApStackSize);\r
0a0d5296
JW
522\r
523 *(EFI_PHYSICAL_ADDRESS *)Buffer = StackBase;\r
524}\r
525\r
526/**\r
527 Setup stack Guard page at the stack base of each processor. BSP and APs have\r
528 different way to get stack base address.\r
529\r
530**/\r
531VOID\r
532SetupStackGuardPage (\r
533 VOID\r
534 )\r
535{\r
053e878b
MK
536 EFI_PEI_HOB_POINTERS Hob;\r
537 EFI_PHYSICAL_ADDRESS StackBase;\r
538 UINTN NumberOfProcessors;\r
539 UINTN Bsp;\r
540 UINTN Index;\r
0a0d5296
JW
541\r
542 //\r
543 // One extra page at the bottom of the stack is needed for Guard page.\r
544 //\r
053e878b 545 if (PcdGet32 (PcdCpuApStackSize) <= EFI_PAGE_SIZE) {\r
0a0d5296
JW
546 DEBUG ((DEBUG_ERROR, "PcdCpuApStackSize is not big enough for Stack Guard!\n"));\r
547 ASSERT (FALSE);\r
548 }\r
549\r
053e878b 550 MpInitLibGetNumberOfProcessors (&NumberOfProcessors, NULL);\r
0a0d5296
JW
551 MpInitLibWhoAmI (&Bsp);\r
552 for (Index = 0; Index < NumberOfProcessors; ++Index) {\r
2939283f
JW
553 StackBase = 0;\r
554\r
0a0d5296
JW
555 if (Index == Bsp) {\r
556 Hob.Raw = GetHobList ();\r
557 while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) {\r
053e878b
MK
558 if (CompareGuid (\r
559 &gEfiHobMemoryAllocStackGuid,\r
560 &(Hob.MemoryAllocationStack->AllocDescriptor.Name)\r
561 ))\r
562 {\r
0a0d5296
JW
563 StackBase = Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress;\r
564 break;\r
565 }\r
053e878b 566\r
0a0d5296
JW
567 Hob.Raw = GET_NEXT_HOB (Hob);\r
568 }\r
569 } else {\r
570 //\r
571 // Ask AP to return is stack base address.\r
572 //\r
053e878b 573 MpInitLibStartupThisAP (GetStackBase, Index, NULL, 0, (VOID *)&StackBase, NULL);\r
0a0d5296 574 }\r
053e878b 575\r
2939283f 576 ASSERT (StackBase != 0);\r
0a0d5296
JW
577 //\r
578 // Set Guard page at stack base address.\r
579 //\r
053e878b
MK
580 ConvertMemoryPageAttributes (StackBase, EFI_PAGE_SIZE, 0);\r
581 DEBUG ((\r
582 DEBUG_INFO,\r
583 "Stack Guard set at %lx [cpu%lu]!\n",\r
584 (UINT64)StackBase,\r
585 (UINT64)Index\r
586 ));\r
0a0d5296
JW
587 }\r
588\r
589 //\r
590 // Publish the changes of page table.\r
591 //\r
592 CpuFlushTlb ();\r
593}\r
594\r
595/**\r
92c19c68 596 Enable/setup stack guard for each processor if PcdCpuStackGuard is set to TRUE.\r
0a0d5296
JW
597\r
598 Doing this in the memory-discovered callback is to make sure the Stack Guard\r
599 feature to cover as most PEI code as possible.\r
600\r
601 @param[in] PeiServices General purpose services available to every PEIM.\r
602 @param[in] NotifyDescriptor The notification structure this PEIM registered on install.\r
603 @param[in] Ppi The memory discovered PPI. Not used.\r
604\r
605 @retval EFI_SUCCESS The function completed successfully.\r
606 @retval others There's error in MP initialization.\r
607**/\r
608EFI_STATUS\r
609EFIAPI\r
610MemoryDiscoveredPpiNotifyCallback (\r
611 IN EFI_PEI_SERVICES **PeiServices,\r
612 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
613 IN VOID *Ppi\r
614 )\r
615{\r
d7c9de51
GJ
616 EFI_STATUS Status;\r
617 BOOLEAN InitStackGuard;\r
d7c9de51
GJ
618 EDKII_MIGRATED_FV_INFO *MigratedFvInfo;\r
619 EFI_PEI_HOB_POINTERS Hob;\r
60b12e69 620\r
0a0d5296
JW
621 //\r
622 // Paging must be setup first. Otherwise the exception TSS setup during MP\r
623 // initialization later will not contain paging information and then fail\r
624 // the task switch (for the sake of stack switch).\r
625 //\r
626 InitStackGuard = FALSE;\r
053e878b 627 Hob.Raw = NULL;\r
d7c9de51 628 if (IsIa32PaeSupported ()) {\r
053e878b 629 Hob.Raw = GetFirstGuidHob (&gEdkiiMigratedFvInfoGuid);\r
d7c9de51
GJ
630 InitStackGuard = PcdGetBool (PcdCpuStackGuard);\r
631 }\r
632\r
053e878b 633 if (InitStackGuard || (Hob.Raw != NULL)) {\r
0a0d5296 634 EnablePaging ();\r
0a0d5296
JW
635 }\r
636\r
637 Status = InitializeCpuMpWorker ((CONST EFI_PEI_SERVICES **)PeiServices);\r
638 ASSERT_EFI_ERROR (Status);\r
639\r
640 if (InitStackGuard) {\r
641 SetupStackGuardPage ();\r
642 }\r
643\r
d7c9de51
GJ
644 while (Hob.Raw != NULL) {\r
645 MigratedFvInfo = GET_GUID_HOB_DATA (Hob);\r
646\r
647 //\r
648 // Enable #PF exception, so if the code access SPI after disable NEM, it will generate\r
649 // the exception to avoid potential vulnerability.\r
650 //\r
651 ConvertMemoryPageAttributes (MigratedFvInfo->FvOrgBase, MigratedFvInfo->FvLength, 0);\r
652\r
653 Hob.Raw = GET_NEXT_HOB (Hob);\r
654 Hob.Raw = GetNextGuidHob (&gEdkiiMigratedFvInfoGuid, Hob.Raw);\r
655 }\r
053e878b 656\r
d7c9de51
GJ
657 CpuFlushTlb ();\r
658\r
0a0d5296
JW
659 return Status;\r
660}\r