]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
MdeModulePkg/Core/DxeIplPeim: Add support for PCD PcdPteMemoryEncryptionAddressOrMask
[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
126 if ((PhysicalAddress < StackBase + StackSize) && ((PhysicalAddress + SIZE_2MB) > StackBase)) {\r
127 //\r
128 // Need to split this 2M page that covers stack range.\r
129 //\r
130 Split2MPageTo4K (PhysicalAddress, (UINT64 *) PageDirectoryEntry, StackBase, StackSize);\r
131 } else {\r
132 //\r
133 // Fill in the Page Directory entries\r
134 //\r
5997daf7 135 PageDirectoryEntry->Uint64 = (UINT64) PhysicalAddress | AddressEncMask;\r
5630cdfe
SZ
136 PageDirectoryEntry->Bits.ReadWrite = 1;\r
137 PageDirectoryEntry->Bits.Present = 1;\r
138 PageDirectoryEntry->Bits.MustBe1 = 1;\r
139 }\r
140 }\r
141 }\r
142\r
143 for (; IndexOfPdpEntries < 512; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {\r
144 ZeroMem (\r
145 PageDirectoryPointerEntry,\r
146 sizeof (PAGE_MAP_AND_DIRECTORY_POINTER)\r
147 );\r
148 }\r
149\r
150 return (UINTN) PageMap;\r
151}\r
152\r
153/**\r
154 The function will check if IA32 PAE is supported.\r
155\r
156 @retval TRUE IA32 PAE is supported.\r
157 @retval FALSE IA32 PAE is not supported.\r
158\r
159**/\r
160BOOLEAN\r
161IsIa32PaeSupport (\r
162 VOID\r
163 )\r
164{\r
165 UINT32 RegEax;\r
166 UINT32 RegEdx;\r
167 BOOLEAN Ia32PaeSupport;\r
168\r
169 Ia32PaeSupport = FALSE;\r
170 AsmCpuid (0x0, &RegEax, NULL, NULL, NULL);\r
171 if (RegEax >= 0x1) {\r
172 AsmCpuid (0x1, NULL, NULL, NULL, &RegEdx);\r
173 if ((RegEdx & BIT6) != 0) {\r
174 Ia32PaeSupport = TRUE;\r
175 }\r
176 }\r
177\r
178 return Ia32PaeSupport;\r
179}\r
180\r
181/**\r
182 The function will check if Execute Disable Bit is available.\r
183\r
184 @retval TRUE Execute Disable Bit is available.\r
185 @retval FALSE Execute Disable Bit is not available.\r
186\r
187**/\r
188BOOLEAN\r
189IsExecuteDisableBitAvailable (\r
190 VOID\r
191 )\r
192{\r
193 UINT32 RegEax;\r
194 UINT32 RegEdx;\r
195 BOOLEAN Available;\r
196\r
197 Available = FALSE;\r
198 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
199 if (RegEax >= 0x80000001) {\r
200 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
201 if ((RegEdx & BIT20) != 0) {\r
202 //\r
203 // Bit 20: Execute Disable Bit available.\r
204 //\r
205 Available = TRUE;\r
206 }\r
207 }\r
208\r
209 return Available;\r
210}\r
211\r
91d92e25 212/**\r
213 Transfers control to DxeCore.\r
214\r
215 This function performs a CPU architecture specific operations to execute\r
216 the entry point of DxeCore with the parameters of HobList.\r
48557c65 217 It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase.\r
91d92e25 218\r
48557c65 219 @param DxeCoreEntryPoint The entry point of DxeCore.\r
91d92e25 220 @param HobList The start of HobList passed to DxeCore.\r
91d92e25 221\r
222**/\r
95276127 223VOID\r
224HandOffToDxeCore (\r
225 IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint,\r
9b937a73 226 IN EFI_PEI_HOB_POINTERS HobList\r
95276127 227 )\r
228{\r
229 EFI_STATUS Status;\r
230 EFI_PHYSICAL_ADDRESS BaseOfStack;\r
231 EFI_PHYSICAL_ADDRESS TopOfStack;\r
232 UINTN PageTables;\r
5d582956 233 X64_IDT_GATE_DESCRIPTOR *IdtTable;\r
234 UINTN SizeOfTemplate;\r
235 VOID *TemplateBase;\r
236 EFI_PHYSICAL_ADDRESS VectorAddress;\r
237 UINT32 Index;\r
bdfbe63e 238 X64_IDT_TABLE *IdtTableForX64;\r
57f360f2
JF
239 EFI_VECTOR_HANDOFF_INFO *VectorInfo;\r
240 EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;\r
5630cdfe 241 BOOLEAN BuildPageTablesIa32Pae;\r
95276127 242\r
243 Status = PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack);\r
244 ASSERT_EFI_ERROR (Status);\r
0cf27ce0 245\r
95276127 246 if (FeaturePcdGet(PcdDxeIplSwitchToLongMode)) {\r
247 //\r
0cf27ce0 248 // Compute the top of the stack we were allocated, which is used to load X64 dxe core.\r
95276127 249 // Pre-allocate a 32 bytes which confroms to x64 calling convention.\r
250 //\r
0cf27ce0 251 // The first four parameters to a function are passed in rcx, rdx, r8 and r9.\r
252 // Any further parameters are pushed on the stack. Furthermore, space (4 * 8bytes) for the\r
253 // register parameters is reserved on the stack, in case the called function\r
254 // wants to spill them; this is important if the function is variadic.\r
95276127 255 //\r
256 TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - 32;\r
257\r
258 //\r
b98da1b1 259 // x64 Calling Conventions requires that the stack must be aligned to 16 bytes\r
95276127 260 //\r
261 TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, 16);\r
262\r
263 //\r
264 // Load the GDT of Go64. Since the GDT of 32-bit Tiano locates in the BS_DATA\r
0cf27ce0 265 // memory, it may be corrupted when copying FV to high-end memory\r
95276127 266 //\r
267 AsmWriteGdtr (&gGdt);\r
268 //\r
269 // Create page table and save PageMapLevel4 to CR3\r
270 //\r
5630cdfe 271 PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE);\r
95276127 272\r
273 //\r
48557c65 274 // End of PEI phase signal\r
95276127 275 //\r
9b937a73 276 Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);\r
95276127 277 ASSERT_EFI_ERROR (Status);\r
0cf27ce0 278\r
95276127 279 AsmWriteCr3 (PageTables);\r
5d582956 280\r
30c8f861 281 //\r
282 // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.\r
0cf27ce0 283 //\r
30c8f861 284 UpdateStackHob (BaseOfStack, STACK_SIZE);\r
5d582956 285\r
4bfa7dc4 286 SizeOfTemplate = AsmGetVectorTemplatInfo (&TemplateBase);\r
287\r
288 Status = PeiServicesAllocatePages (\r
0cf27ce0 289 EfiBootServicesData,\r
bdfbe63e 290 EFI_SIZE_TO_PAGES(sizeof (X64_IDT_TABLE) + SizeOfTemplate * IDT_ENTRY_COUNT),\r
b028c102 291 &VectorAddress\r
4bfa7dc4 292 );\r
293 ASSERT_EFI_ERROR (Status);\r
294\r
bdfbe63e 295 //\r
296 // Store EFI_PEI_SERVICES** in the 4 bytes immediately preceding IDT to avoid that\r
297 // it may not be gotten correctly after IDT register is re-written.\r
298 //\r
b028c102 299 IdtTableForX64 = (X64_IDT_TABLE *) (UINTN) VectorAddress;\r
bdfbe63e 300 IdtTableForX64->PeiService = GetPeiServicesTablePointer ();\r
301\r
302 VectorAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (IdtTableForX64 + 1);\r
303 IdtTable = IdtTableForX64->IdtTable;\r
e7af83ae 304 for (Index = 0; Index < IDT_ENTRY_COUNT; Index++) {\r
4bfa7dc4 305 IdtTable[Index].Ia32IdtEntry.Bits.GateType = 0x8e;\r
306 IdtTable[Index].Ia32IdtEntry.Bits.Reserved_0 = 0;\r
307 IdtTable[Index].Ia32IdtEntry.Bits.Selector = SYS_CODE64_SEL;\r
308\r
309 IdtTable[Index].Ia32IdtEntry.Bits.OffsetLow = (UINT16) VectorAddress;\r
310 IdtTable[Index].Ia32IdtEntry.Bits.OffsetHigh = (UINT16) (RShiftU64 (VectorAddress, 16));\r
311 IdtTable[Index].Offset32To63 = (UINT32) (RShiftU64 (VectorAddress, 32));\r
312 IdtTable[Index].Reserved = 0;\r
313\r
314 CopyMem ((VOID *) (UINTN) VectorAddress, TemplateBase, SizeOfTemplate);\r
315 AsmVectorFixup ((VOID *) (UINTN) VectorAddress, (UINT8) Index);\r
316\r
317 VectorAddress += SizeOfTemplate;\r
5d582956 318 }\r
4bfa7dc4 319\r
320 gLidtDescriptor.Base = (UINTN) IdtTable;\r
0cf27ce0 321\r
e7af83ae 322 //\r
323 // Disable interrupt of Debug timer, since new IDT table cannot handle it.\r
324 //\r
325 SaveAndSetDebugTimerInterrupt (FALSE);\r
326\r
4bfa7dc4 327 AsmWriteIdtr (&gLidtDescriptor);\r
328\r
6fb389d0
JF
329 DEBUG ((\r
330 DEBUG_INFO,\r
331 "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n",\r
332 __FUNCTION__,\r
333 BaseOfStack,\r
334 STACK_SIZE\r
335 ));\r
336\r
5d582956 337 //\r
b98da1b1 338 // Go to Long Mode and transfer control to DxeCore.\r
339 // Interrupts will not get turned on until the CPU AP is loaded.\r
95276127 340 // Call x64 drivers passing in single argument, a pointer to the HOBs.\r
0cf27ce0 341 //\r
95276127 342 AsmEnablePaging64 (\r
343 SYS_CODE64_SEL,\r
344 DxeCoreEntryPoint,\r
345 (EFI_PHYSICAL_ADDRESS)(UINTN)(HobList.Raw),\r
346 0,\r
347 TopOfStack\r
348 );\r
349 } else {\r
57f360f2
JF
350 //\r
351 // Get Vector Hand-off Info PPI and build Guided HOB\r
352 //\r
353 Status = PeiServicesLocatePpi (\r
354 &gEfiVectorHandoffInfoPpiGuid,\r
355 0,\r
356 NULL,\r
357 (VOID **)&VectorHandoffInfoPpi\r
358 );\r
359 if (Status == EFI_SUCCESS) {\r
360 DEBUG ((EFI_D_INFO, "Vector Hand-off Info PPI is gotten, GUIDed HOB is created!\n"));\r
361 VectorInfo = VectorHandoffInfoPpi->Info;\r
362 Index = 1;\r
363 while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) {\r
364 VectorInfo ++;\r
365 Index ++;\r
366 }\r
367 BuildGuidDataHob (\r
368 &gEfiVectorHandoffInfoPpiGuid,\r
369 VectorHandoffInfoPpi->Info,\r
370 sizeof (EFI_VECTOR_HANDOFF_INFO) * Index\r
371 );\r
372 }\r
373\r
95276127 374 //\r
375 // Compute the top of the stack we were allocated. Pre-allocate a UINTN\r
376 // for safety.\r
377 //\r
378 TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT;\r
379 TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);\r
380\r
09e4a8fd 381 PageTables = 0;\r
5630cdfe
SZ
382 BuildPageTablesIa32Pae = (BOOLEAN) (PcdGetBool (PcdSetNxForStack) && IsIa32PaeSupport () && IsExecuteDisableBitAvailable ());\r
383 if (BuildPageTablesIa32Pae) {\r
384 PageTables = Create4GPageTablesIa32Pae (BaseOfStack, STACK_SIZE);\r
385 EnableExecuteDisableBit ();\r
386 }\r
387\r
95276127 388 //\r
48557c65 389 // End of PEI phase signal\r
95276127 390 //\r
9b937a73 391 Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);\r
95276127 392 ASSERT_EFI_ERROR (Status);\r
393\r
5630cdfe
SZ
394 if (BuildPageTablesIa32Pae) {\r
395 AsmWriteCr3 (PageTables);\r
396 //\r
397 // Set Physical Address Extension (bit 5 of CR4).\r
398 //\r
399 AsmWriteCr4 (AsmReadCr4 () | BIT5);\r
400 }\r
401\r
30c8f861 402 //\r
403 // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.\r
0cf27ce0 404 //\r
30c8f861 405 UpdateStackHob (BaseOfStack, STACK_SIZE);\r
0cf27ce0 406\r
6fb389d0
JF
407 DEBUG ((\r
408 DEBUG_INFO,\r
409 "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n",\r
410 __FUNCTION__,\r
411 BaseOfStack,\r
412 STACK_SIZE\r
413 ));\r
414\r
b98da1b1 415 //\r
416 // Transfer the control to the entry point of DxeCore.\r
417 //\r
5630cdfe
SZ
418 if (BuildPageTablesIa32Pae) {\r
419 AsmEnablePaging32 (\r
420 (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,\r
421 HobList.Raw,\r
422 NULL,\r
423 (VOID *) (UINTN) TopOfStack\r
424 );\r
425 } else {\r
426 SwitchStack (\r
427 (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,\r
428 HobList.Raw,\r
429 NULL,\r
430 (VOID *) (UINTN) TopOfStack\r
431 );\r
432 }\r
0cf27ce0 433 }\r
95276127 434}\r
435\r