]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
MdeModulePkg/DxeIpl: Enable paging for heap guard
[mirror_edk2.git] / MdeModulePkg / Core / DxeIplPeim / Ia32 / DxeLoadFunc.c
CommitLineData
96226baa 1/** @file\r
48557c65 2 Ia32-specific functionality for DxeLoad.\r
95276127 3\r
5630cdfe 4Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
5997daf7
LD
5Copyright (c) 2017, AMD Incorporated. All rights reserved.<BR>\r
6\r
cd5ebaa0 7This program and the accompanying materials\r
95276127 8are licensed and made available under the terms and conditions of the BSD License\r
9which accompanies this distribution. The full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
96226baa 15**/\r
95276127 16\r
95276127 17#include "DxeIpl.h"\r
18#include "VirtualMemory.h"\r
19\r
df7aaeb9 20#define IDT_ENTRY_COUNT 32\r
e7af83ae 21\r
bdfbe63e 22typedef struct _X64_IDT_TABLE {\r
23 //\r
24 // Reserved 4 bytes preceding PeiService and IdtTable,\r
25 // since IDT base address should be 8-byte alignment.\r
26 //\r
27 UINT32 Reserved;\r
28 CONST EFI_PEI_SERVICES **PeiService;\r
29 X64_IDT_GATE_DESCRIPTOR IdtTable[IDT_ENTRY_COUNT];\r
30} X64_IDT_TABLE;\r
31\r
95276127 32//\r
33// Global Descriptor Table (GDT)\r
34//\r
b98da1b1 35GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT gGdtEntries[] = {\r
0cf27ce0 36/* selector { Global Segment Descriptor } */\r
37/* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //null descriptor\r
95276127 38/* 0x08 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear data segment descriptor\r
39/* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear code segment descriptor\r
40/* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor\r
41/* 0x20 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system code segment descriptor\r
42/* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor\r
43/* 0x30 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor\r
44/* 0x38 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, //system code segment descriptor\r
45/* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor\r
46};\r
47\r
48//\r
49// IA32 Gdt register\r
50//\r
51GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR gGdt = {\r
52 sizeof (gGdtEntries) - 1,\r
53 (UINTN) gGdtEntries\r
54 };\r
55\r
5d582956 56GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR gLidtDescriptor = {\r
e7af83ae 57 sizeof (X64_IDT_GATE_DESCRIPTOR) * IDT_ENTRY_COUNT - 1,\r
5d582956 58 0\r
59};\r
60\r
5630cdfe
SZ
61/**\r
62 Allocates and fills in the Page Directory and Page Table Entries to\r
63 establish a 4G page table.\r
64\r
65 @param[in] StackBase Stack base address.\r
66 @param[in] StackSize Stack size.\r
67\r
68 @return The address of page table.\r
69\r
70**/\r
71UINTN\r
72Create4GPageTablesIa32Pae (\r
73 IN EFI_PHYSICAL_ADDRESS StackBase,\r
74 IN UINTN StackSize\r
75 )\r
76{ \r
77 UINT8 PhysicalAddressBits;\r
78 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
79 UINTN IndexOfPdpEntries;\r
80 UINTN IndexOfPageDirectoryEntries;\r
81 UINT32 NumberOfPdpEntriesNeeded;\r
82 PAGE_MAP_AND_DIRECTORY_POINTER *PageMap;\r
83 PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;\r
84 PAGE_TABLE_ENTRY *PageDirectoryEntry;\r
85 UINTN TotalPagesNum;\r
86 UINTN PageAddress;\r
5997daf7
LD
87 UINT64 AddressEncMask;\r
88\r
89 //\r
90 // Make sure AddressEncMask is contained to smallest supported address field\r
91 //\r
92 AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;\r
5630cdfe
SZ
93\r
94 PhysicalAddressBits = 32;\r
95\r
96 //\r
97 // Calculate the table entries needed.\r
98 //\r
99 NumberOfPdpEntriesNeeded = (UINT32) LShiftU64 (1, (PhysicalAddressBits - 30));\r
100\r
101 TotalPagesNum = NumberOfPdpEntriesNeeded + 1;\r
102 PageAddress = (UINTN) AllocatePages (TotalPagesNum);\r
103 ASSERT (PageAddress != 0);\r
104\r
105 PageMap = (VOID *) PageAddress;\r
106 PageAddress += SIZE_4KB;\r
107\r
108 PageDirectoryPointerEntry = PageMap;\r
109 PhysicalAddress = 0;\r
110\r
111 for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {\r
112 //\r
113 // Each Directory Pointer entries points to a page of Page Directory entires.\r
114 // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.\r
115 // \r
116 PageDirectoryEntry = (VOID *) PageAddress;\r
117 PageAddress += SIZE_4KB;\r
118\r
119 //\r
120 // Fill in a Page Directory Pointer Entries\r
121 //\r
5997daf7 122 PageDirectoryPointerEntry->Uint64 = (UINT64) (UINTN) PageDirectoryEntry | AddressEncMask;\r
5630cdfe
SZ
123 PageDirectoryPointerEntry->Bits.Present = 1;\r
124\r
125 for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress += SIZE_2MB) {\r
9189ec20
JW
126 if ((IsNullDetectionEnabled () && PhysicalAddress == 0)\r
127 || ((PhysicalAddress < StackBase + StackSize)\r
128 && ((PhysicalAddress + SIZE_2MB) > StackBase))) {\r
5630cdfe
SZ
129 //\r
130 // Need to split this 2M page that covers stack range.\r
131 //\r
132 Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);\r
133 } else {\r
134 //\r
135 // Fill in the Page Directory entries\r
136 //\r
5997daf7 137 PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress | AddressEncMask;\r
5630cdfe
SZ
138 PageDirectoryEntry->Bits.ReadWrite = 1;\r
139 PageDirectoryEntry->Bits.Present = 1;\r
140 PageDirectoryEntry->Bits.MustBe1 = 1;\r
141 }\r
142 }\r
143 }\r
144\r
145 for (; IndexOfPdpEntries < 512; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {\r
146 ZeroMem (\r
147 PageDirectoryPointerEntry,\r
148 sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)\r
149 );\r
150 }\r
151\r
152 return (UINTN) PageMap;\r
153}\r
154\r
155/**\r
156 The function will check if IA32 PAE is supported.\r
157\r
158 @retval TRUE IA32 PAE is supported.\r
159 @retval FALSE IA32 PAE is not supported.\r
160\r
161**/\r
162BOOLEAN\r
163IsIa32PaeSupport (\r
164 VOID\r
165 )\r
166{\r
167 UINT32 RegEax;\r
168 UINT32 RegEdx;\r
169 BOOLEAN Ia32PaeSupport;\r
170\r
171 Ia32PaeSupport = FALSE;\r
172 AsmCpuid (0x0, &RegEax, NULL, NULL, NULL);\r
173 if (RegEax >= 0x1) {\r
174 AsmCpuid (0x1, NULL, NULL, NULL, &RegEdx);\r
175 if ((RegEdx & BIT6) != 0) {\r
176 Ia32PaeSupport = TRUE;\r
177 }\r
178 }\r
179\r
180 return Ia32PaeSupport;\r
181}\r
182\r
183/**\r
184 The function will check if Execute Disable Bit is available.\r
185\r
186 @retval TRUE Execute Disable Bit is available.\r
187 @retval FALSE Execute Disable Bit is not available.\r
188\r
189**/\r
190BOOLEAN\r
191IsExecuteDisableBitAvailable (\r
192 VOID\r
193 )\r
194{\r
195 UINT32 RegEax;\r
196 UINT32 RegEdx;\r
197 BOOLEAN Available;\r
198\r
199 Available = FALSE;\r
200 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
201 if (RegEax >= 0x80000001) {\r
202 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
203 if ((RegEdx & BIT20) != 0) {\r
204 //\r
205 // Bit 20: Execute Disable Bit available.\r
206 //\r
207 Available = TRUE;\r
208 }\r
209 }\r
210\r
211 return Available;\r
212}\r
213\r
99cc7b95
JW
214/**
215 The function will check if page table should be setup or not.
216
217 @retval TRUE Page table should be created.
218 @retval FALSE Page table should not be created.
219
220**/
221BOOLEAN
222ToBuildPageTable (
223 VOID
224 )
225{
226 if (!IsIa32PaeSupport ()) {
227 return FALSE;
228 }
229
230 if (IsNullDetectionEnabled ()) {
231 return TRUE;
232 }
233
234 if (PcdGet8 (PcdHeapGuardPropertyMask) != 0) {
235 return TRUE;
236 }
237
238 if (PcdGetBool (PcdSetNxForStack) && IsExecuteDisableBitAvailable ()) {
239 return TRUE;
240 }
241
242 return FALSE;
243}
244
91d92e25 245/**\r
246 Transfers control to DxeCore.\r
247\r
248 This function performs a CPU architecture specific operations to execute\r
249 the entry point of DxeCore with the parameters of HobList.\r
48557c65 250 It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase.\r
91d92e25 251\r
48557c65 252 @param DxeCoreEntryPoint The entry point of DxeCore.\r
91d92e25 253 @param HobList The start of HobList passed to DxeCore.\r
91d92e25 254\r
255**/\r
95276127 256VOID\r
257HandOffToDxeCore (\r
258 IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint,\r
9b937a73 259 IN EFI_PEI_HOB_POINTERS HobList\r
95276127 260 )\r
261{\r
262 EFI_STATUS Status;\r
263 EFI_PHYSICAL_ADDRESS BaseOfStack;\r
264 EFI_PHYSICAL_ADDRESS TopOfStack;\r
265 UINTN PageTables;\r
5d582956 266 X64_IDT_GATE_DESCRIPTOR *IdtTable;\r
267 UINTN SizeOfTemplate;\r
268 VOID *TemplateBase;\r
269 EFI_PHYSICAL_ADDRESS VectorAddress;\r
270 UINT32 Index;\r
bdfbe63e 271 X64_IDT_TABLE *IdtTableForX64;\r
57f360f2
JF
272 EFI_VECTOR_HANDOFF_INFO *VectorInfo;\r
273 EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;\r
5630cdfe 274 BOOLEAN BuildPageTablesIa32Pae;\r
95276127 275\r
9189ec20
JW
276 if (IsNullDetectionEnabled ()) {\r
277 ClearFirst4KPage (HobList.Raw);\r
278 }\r
279\r
95276127 280 Status = PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack);\r
281 ASSERT_EFI_ERROR (Status);\r
0cf27ce0 282\r
95276127 283 if (FeaturePcdGet(PcdDxeIplSwitchToLongMode)) {\r
284 //\r
0cf27ce0 285 // Compute the top of the stack we were allocated, which is used to load X64 dxe core.\r
95276127 286 // Pre-allocate a 32 bytes which confroms to x64 calling convention.\r
287 //\r
0cf27ce0 288 // The first four parameters to a function are passed in rcx, rdx, r8 and r9.\r
289 // Any further parameters are pushed on the stack. Furthermore, space (4 * 8bytes) for the\r
290 // register parameters is reserved on the stack, in case the called function\r
291 // wants to spill them; this is important if the function is variadic.\r
95276127 292 //\r
293 TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - 32;\r
294\r
295 //\r
b98da1b1 296 // x64 Calling Conventions requires that the stack must be aligned to 16 bytes\r
95276127 297 //\r
298 TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, 16);\r
299\r
300 //\r
301 // Load the GDT of Go64. Since the GDT of 32-bit Tiano locates in the BS_DATA\r
0cf27ce0 302 // memory, it may be corrupted when copying FV to high-end memory\r
95276127 303 //\r
304 AsmWriteGdtr (&gGdt);\r
305 //\r
306 // Create page table and save PageMapLevel4 to CR3\r
307 //\r
5630cdfe 308 PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE);\r
95276127 309\r
310 //\r
48557c65 311 // End of PEI phase signal\r
95276127 312 //\r
9b937a73 313 Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);\r
95276127 314 ASSERT_EFI_ERROR (Status);\r
0cf27ce0 315\r
95276127 316 AsmWriteCr3 (PageTables);\r
5d582956 317\r
30c8f861 318 //\r
319 // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.\r
0cf27ce0 320 //\r
30c8f861 321 UpdateStackHob (BaseOfStack, STACK_SIZE);\r
5d582956 322\r
4bfa7dc4 323 SizeOfTemplate = AsmGetVectorTemplatInfo (&TemplateBase);\r
324\r
325 Status = PeiServicesAllocatePages (\r
0cf27ce0 326 EfiBootServicesData,\r
bdfbe63e 327 EFI_SIZE_TO_PAGES(sizeof (X64_IDT_TABLE) + SizeOfTemplate * IDT_ENTRY_COUNT),\r
b028c102 328 &VectorAddress\r
4bfa7dc4 329 );\r
330 ASSERT_EFI_ERROR (Status);\r
331\r
bdfbe63e 332 //\r
333 // Store EFI_PEI_SERVICES** in the 4 bytes immediately preceding IDT to avoid that\r
334 // it may not be gotten correctly after IDT register is re-written.\r
335 //\r
b028c102 336 IdtTableForX64 = (X64_IDT_TABLE *) (UINTN) VectorAddress;\r
bdfbe63e 337 IdtTableForX64->PeiService = GetPeiServicesTablePointer ();\r
338\r
339 VectorAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (IdtTableForX64 + 1);\r
340 IdtTable = IdtTableForX64->IdtTable;\r
e7af83ae 341 for (Index = 0; Index < IDT_ENTRY_COUNT; Index++) {\r
4bfa7dc4 342 IdtTable[Index].Ia32IdtEntry.Bits.GateType = 0x8e;\r
343 IdtTable[Index].Ia32IdtEntry.Bits.Reserved_0 = 0;\r
344 IdtTable[Index].Ia32IdtEntry.Bits.Selector = SYS_CODE64_SEL;\r
345\r
346 IdtTable[Index].Ia32IdtEntry.Bits.OffsetLow = (UINT16) VectorAddress;\r
347 IdtTable[Index].Ia32IdtEntry.Bits.OffsetHigh = (UINT16) (RShiftU64 (VectorAddress, 16));\r
348 IdtTable[Index].Offset32To63 = (UINT32) (RShiftU64 (VectorAddress, 32));\r
349 IdtTable[Index].Reserved = 0;\r
350\r
351 CopyMem ((VOID *) (UINTN) VectorAddress, TemplateBase, SizeOfTemplate);\r
352 AsmVectorFixup ((VOID *) (UINTN) VectorAddress, (UINT8) Index);\r
353\r
354 VectorAddress += SizeOfTemplate;\r
5d582956 355 }\r
4bfa7dc4 356\r
357 gLidtDescriptor.Base = (UINTN) IdtTable;\r
0cf27ce0 358\r
e7af83ae 359 //\r
360 // Disable interrupt of Debug timer, since new IDT table cannot handle it.\r
361 //\r
362 SaveAndSetDebugTimerInterrupt (FALSE);\r
363\r
4bfa7dc4 364 AsmWriteIdtr (&gLidtDescriptor);\r
365\r
6fb389d0
JF
366 DEBUG ((\r
367 DEBUG_INFO,\r
368 "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n",\r
369 __FUNCTION__,\r
370 BaseOfStack,\r
371 STACK_SIZE\r
372 ));\r
373\r
5d582956 374 //\r
b98da1b1 375 // Go to Long Mode and transfer control to DxeCore.\r
376 // Interrupts will not get turned on until the CPU AP is loaded.\r
95276127 377 // Call x64 drivers passing in single argument, a pointer to the HOBs.\r
0cf27ce0 378 //\r
95276127 379 AsmEnablePaging64 (\r
380 SYS_CODE64_SEL,\r
381 DxeCoreEntryPoint,\r
382 (EFI_PHYSICAL_ADDRESS)(UINTN)(HobList.Raw),\r
383 0,\r
384 TopOfStack\r
385 );\r
386 } else {\r
57f360f2
JF
387 //\r
388 // Get Vector Hand-off Info PPI and build Guided HOB\r
389 //\r
390 Status = PeiServicesLocatePpi (\r
391 &gEfiVectorHandoffInfoPpiGuid,\r
392 0,\r
393 NULL,\r
394 (VOID **)&VectorHandoffInfoPpi\r
395 );\r
396 if (Status == EFI_SUCCESS) {\r
397 DEBUG ((EFI_D_INFO, "Vector Hand-off Info PPI is gotten, GUIDed HOB is created!\n"));\r
398 VectorInfo = VectorHandoffInfoPpi->Info;\r
399 Index = 1;\r
400 while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) {\r
401 VectorInfo ++;\r
402 Index ++;\r
403 }\r
404 BuildGuidDataHob (\r
405 &gEfiVectorHandoffInfoPpiGuid,\r
406 VectorHandoffInfoPpi->Info,\r
407 sizeof (EFI_VECTOR_HANDOFF_INFO) * Index\r
408 );\r
409 }\r
410\r
95276127 411 //\r
412 // Compute the top of the stack we were allocated. Pre-allocate a UINTN\r
413 // for safety.\r
414 //\r
415 TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT;\r
416 TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);\r
417\r
09e4a8fd 418 PageTables = 0;\r
99cc7b95 419 BuildPageTablesIa32Pae = ToBuildPageTable ();
5630cdfe
SZ
420 if (BuildPageTablesIa32Pae) {\r
421 PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE);\r
9189ec20
JW
422 if (IsExecuteDisableBitAvailable ()) {\r
423 EnableExecuteDisableBit();\r
424 }\r
5630cdfe
SZ
425 }\r
426\r
95276127 427 //\r
48557c65 428 // End of PEI phase signal\r
95276127 429 //\r
9b937a73 430 Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);\r
95276127 431 ASSERT_EFI_ERROR (Status);\r
432\r
5630cdfe
SZ
433 if (BuildPageTablesIa32Pae) {\r
434 AsmWriteCr3 (PageTables);\r
435 //\r
436 // Set Physical Address Extension (bit 5 of CR4).\r
437 //\r
438 AsmWriteCr4 (AsmReadCr4 () | BIT5);\r
439 }\r
440\r
30c8f861 441 //\r
442 // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.\r
0cf27ce0 443 //\r
30c8f861 444 UpdateStackHob (BaseOfStack, STACK_SIZE);\r
0cf27ce0 445\r
6fb389d0
JF
446 DEBUG ((\r
447 DEBUG_INFO,\r
448 "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n",\r
449 __FUNCTION__,\r
450 BaseOfStack,\r
451 STACK_SIZE\r
452 ));\r
453\r
b98da1b1 454 //\r
455 // Transfer the control to the entry point of DxeCore.\r
456 //\r
5630cdfe
SZ
457 if (BuildPageTablesIa32Pae) {\r
458 AsmEnablePaging32 (\r
459 (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,\r
460 HobList.Raw,\r
461 NULL,\r
462 (VOID *) (UINTN) TopOfStack\r
463 );\r
464 } else {\r
465 SwitchStack (\r
466 (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,\r
467 HobList.Raw,\r
468 NULL,\r
469 (VOID *) (UINTN) TopOfStack\r
470 );\r
471 }\r
0cf27ce0 472 }\r
95276127 473}\r
474\r