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