2 Ia32-specific functionality for DxeLoad.
4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "VirtualMemory.h"
18 #define IDT_ENTRY_COUNT 32
20 typedef struct _X64_IDT_TABLE
{
22 // Reserved 4 bytes preceding PeiService and IdtTable,
23 // since IDT base address should be 8-byte alignment.
26 CONST EFI_PEI_SERVICES
**PeiService
;
27 X64_IDT_GATE_DESCRIPTOR IdtTable
[IDT_ENTRY_COUNT
];
31 // Global Descriptor Table (GDT)
33 GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT gGdtEntries
[] = {
34 /* selector { Global Segment Descriptor } */
35 /* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //null descriptor
36 /* 0x08 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear data segment descriptor
37 /* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear code segment descriptor
38 /* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
39 /* 0x20 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system code segment descriptor
40 /* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
41 /* 0x30 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
42 /* 0x38 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, //system code segment descriptor
43 /* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
49 GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR gGdt
= {
50 sizeof (gGdtEntries
) - 1,
54 GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR gLidtDescriptor
= {
55 sizeof (X64_IDT_GATE_DESCRIPTOR
) * IDT_ENTRY_COUNT
- 1,
60 Allocates and fills in the Page Directory and Page Table Entries to
61 establish a 4G page table.
63 @param[in] StackBase Stack base address.
64 @param[in] StackSize Stack size.
66 @return The address of page table.
70 Create4GPageTablesIa32Pae (
71 IN EFI_PHYSICAL_ADDRESS StackBase
,
75 UINT8 PhysicalAddressBits
;
76 EFI_PHYSICAL_ADDRESS PhysicalAddress
;
77 UINTN IndexOfPdpEntries
;
78 UINTN IndexOfPageDirectoryEntries
;
79 UINT32 NumberOfPdpEntriesNeeded
;
80 PAGE_MAP_AND_DIRECTORY_POINTER
*PageMap
;
81 PAGE_MAP_AND_DIRECTORY_POINTER
*PageDirectoryPointerEntry
;
82 PAGE_TABLE_ENTRY
*PageDirectoryEntry
;
86 PhysicalAddressBits
= 32;
89 // Calculate the table entries needed.
91 NumberOfPdpEntriesNeeded
= (UINT32
) LShiftU64 (1, (PhysicalAddressBits
- 30));
93 TotalPagesNum
= NumberOfPdpEntriesNeeded
+ 1;
94 PageAddress
= (UINTN
) AllocatePages (TotalPagesNum
);
95 ASSERT (PageAddress
!= 0);
97 PageMap
= (VOID
*) PageAddress
;
98 PageAddress
+= SIZE_4KB
;
100 PageDirectoryPointerEntry
= PageMap
;
103 for (IndexOfPdpEntries
= 0; IndexOfPdpEntries
< NumberOfPdpEntriesNeeded
; IndexOfPdpEntries
++, PageDirectoryPointerEntry
++) {
105 // Each Directory Pointer entries points to a page of Page Directory entires.
106 // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
108 PageDirectoryEntry
= (VOID
*) PageAddress
;
109 PageAddress
+= SIZE_4KB
;
112 // Fill in a Page Directory Pointer Entries
114 PageDirectoryPointerEntry
->Uint64
= (UINT64
) (UINTN
) PageDirectoryEntry
;
115 PageDirectoryPointerEntry
->Bits
.Present
= 1;
117 for (IndexOfPageDirectoryEntries
= 0; IndexOfPageDirectoryEntries
< 512; IndexOfPageDirectoryEntries
++, PageDirectoryEntry
++, PhysicalAddress
+= SIZE_2MB
) {
118 if ((PhysicalAddress
< StackBase
+ StackSize
) && ((PhysicalAddress
+ SIZE_2MB
) > StackBase
)) {
120 // Need to split this 2M page that covers stack range.
122 Split2MPageTo4K (PhysicalAddress
, (UINT64
*) PageDirectoryEntry
, StackBase
, StackSize
);
125 // Fill in the Page Directory entries
127 PageDirectoryEntry
->Uint64
= (UINT64
) PhysicalAddress
;
128 PageDirectoryEntry
->Bits
.ReadWrite
= 1;
129 PageDirectoryEntry
->Bits
.Present
= 1;
130 PageDirectoryEntry
->Bits
.MustBe1
= 1;
135 for (; IndexOfPdpEntries
< 512; IndexOfPdpEntries
++, PageDirectoryPointerEntry
++) {
137 PageDirectoryPointerEntry
,
138 sizeof (PAGE_MAP_AND_DIRECTORY_POINTER
)
142 return (UINTN
) PageMap
;
146 The function will check if IA32 PAE is supported.
148 @retval TRUE IA32 PAE is supported.
149 @retval FALSE IA32 PAE is not supported.
159 BOOLEAN Ia32PaeSupport
;
161 Ia32PaeSupport
= FALSE
;
162 AsmCpuid (0x0, &RegEax
, NULL
, NULL
, NULL
);
164 AsmCpuid (0x1, NULL
, NULL
, NULL
, &RegEdx
);
165 if ((RegEdx
& BIT6
) != 0) {
166 Ia32PaeSupport
= TRUE
;
170 return Ia32PaeSupport
;
174 The function will check if Execute Disable Bit is available.
176 @retval TRUE Execute Disable Bit is available.
177 @retval FALSE Execute Disable Bit is not available.
181 IsExecuteDisableBitAvailable (
190 AsmCpuid (0x80000000, &RegEax
, NULL
, NULL
, NULL
);
191 if (RegEax
>= 0x80000001) {
192 AsmCpuid (0x80000001, NULL
, NULL
, NULL
, &RegEdx
);
193 if ((RegEdx
& BIT20
) != 0) {
195 // Bit 20: Execute Disable Bit available.
205 Transfers control to DxeCore.
207 This function performs a CPU architecture specific operations to execute
208 the entry point of DxeCore with the parameters of HobList.
209 It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase.
211 @param DxeCoreEntryPoint The entry point of DxeCore.
212 @param HobList The start of HobList passed to DxeCore.
217 IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint
,
218 IN EFI_PEI_HOB_POINTERS HobList
222 EFI_PHYSICAL_ADDRESS BaseOfStack
;
223 EFI_PHYSICAL_ADDRESS TopOfStack
;
225 X64_IDT_GATE_DESCRIPTOR
*IdtTable
;
226 UINTN SizeOfTemplate
;
228 EFI_PHYSICAL_ADDRESS VectorAddress
;
230 X64_IDT_TABLE
*IdtTableForX64
;
231 EFI_VECTOR_HANDOFF_INFO
*VectorInfo
;
232 EFI_PEI_VECTOR_HANDOFF_INFO_PPI
*VectorHandoffInfoPpi
;
233 BOOLEAN BuildPageTablesIa32Pae
;
235 Status
= PeiServicesAllocatePages (EfiBootServicesData
, EFI_SIZE_TO_PAGES (STACK_SIZE
), &BaseOfStack
);
236 ASSERT_EFI_ERROR (Status
);
238 if (FeaturePcdGet(PcdDxeIplSwitchToLongMode
)) {
240 // Compute the top of the stack we were allocated, which is used to load X64 dxe core.
241 // Pre-allocate a 32 bytes which confroms to x64 calling convention.
243 // The first four parameters to a function are passed in rcx, rdx, r8 and r9.
244 // Any further parameters are pushed on the stack. Furthermore, space (4 * 8bytes) for the
245 // register parameters is reserved on the stack, in case the called function
246 // wants to spill them; this is important if the function is variadic.
248 TopOfStack
= BaseOfStack
+ EFI_SIZE_TO_PAGES (STACK_SIZE
) * EFI_PAGE_SIZE
- 32;
251 // x64 Calling Conventions requires that the stack must be aligned to 16 bytes
253 TopOfStack
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) ALIGN_POINTER (TopOfStack
, 16);
256 // Load the GDT of Go64. Since the GDT of 32-bit Tiano locates in the BS_DATA
257 // memory, it may be corrupted when copying FV to high-end memory
259 AsmWriteGdtr (&gGdt
);
261 // Create page table and save PageMapLevel4 to CR3
263 PageTables
= CreateIdentityMappingPageTables (BaseOfStack
, STACK_SIZE
);
266 // End of PEI phase signal
268 Status
= PeiServicesInstallPpi (&gEndOfPeiSignalPpi
);
269 ASSERT_EFI_ERROR (Status
);
271 AsmWriteCr3 (PageTables
);
274 // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.
276 UpdateStackHob (BaseOfStack
, STACK_SIZE
);
278 SizeOfTemplate
= AsmGetVectorTemplatInfo (&TemplateBase
);
280 Status
= PeiServicesAllocatePages (
282 EFI_SIZE_TO_PAGES(sizeof (X64_IDT_TABLE
) + SizeOfTemplate
* IDT_ENTRY_COUNT
),
283 (EFI_PHYSICAL_ADDRESS
*) &IdtTableForX64
285 ASSERT_EFI_ERROR (Status
);
288 // Store EFI_PEI_SERVICES** in the 4 bytes immediately preceding IDT to avoid that
289 // it may not be gotten correctly after IDT register is re-written.
291 IdtTableForX64
->PeiService
= GetPeiServicesTablePointer ();
293 VectorAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) (IdtTableForX64
+ 1);
294 IdtTable
= IdtTableForX64
->IdtTable
;
295 for (Index
= 0; Index
< IDT_ENTRY_COUNT
; Index
++) {
296 IdtTable
[Index
].Ia32IdtEntry
.Bits
.GateType
= 0x8e;
297 IdtTable
[Index
].Ia32IdtEntry
.Bits
.Reserved_0
= 0;
298 IdtTable
[Index
].Ia32IdtEntry
.Bits
.Selector
= SYS_CODE64_SEL
;
300 IdtTable
[Index
].Ia32IdtEntry
.Bits
.OffsetLow
= (UINT16
) VectorAddress
;
301 IdtTable
[Index
].Ia32IdtEntry
.Bits
.OffsetHigh
= (UINT16
) (RShiftU64 (VectorAddress
, 16));
302 IdtTable
[Index
].Offset32To63
= (UINT32
) (RShiftU64 (VectorAddress
, 32));
303 IdtTable
[Index
].Reserved
= 0;
305 CopyMem ((VOID
*) (UINTN
) VectorAddress
, TemplateBase
, SizeOfTemplate
);
306 AsmVectorFixup ((VOID
*) (UINTN
) VectorAddress
, (UINT8
) Index
);
308 VectorAddress
+= SizeOfTemplate
;
311 gLidtDescriptor
.Base
= (UINTN
) IdtTable
;
314 // Disable interrupt of Debug timer, since new IDT table cannot handle it.
316 SaveAndSetDebugTimerInterrupt (FALSE
);
318 AsmWriteIdtr (&gLidtDescriptor
);
321 // Go to Long Mode and transfer control to DxeCore.
322 // Interrupts will not get turned on until the CPU AP is loaded.
323 // Call x64 drivers passing in single argument, a pointer to the HOBs.
328 (EFI_PHYSICAL_ADDRESS
)(UINTN
)(HobList
.Raw
),
334 // Get Vector Hand-off Info PPI and build Guided HOB
336 Status
= PeiServicesLocatePpi (
337 &gEfiVectorHandoffInfoPpiGuid
,
340 (VOID
**)&VectorHandoffInfoPpi
342 if (Status
== EFI_SUCCESS
) {
343 DEBUG ((EFI_D_INFO
, "Vector Hand-off Info PPI is gotten, GUIDed HOB is created!\n"));
344 VectorInfo
= VectorHandoffInfoPpi
->Info
;
346 while (VectorInfo
->Attribute
!= EFI_VECTOR_HANDOFF_LAST_ENTRY
) {
351 &gEfiVectorHandoffInfoPpiGuid
,
352 VectorHandoffInfoPpi
->Info
,
353 sizeof (EFI_VECTOR_HANDOFF_INFO
) * Index
358 // Compute the top of the stack we were allocated. Pre-allocate a UINTN
361 TopOfStack
= BaseOfStack
+ EFI_SIZE_TO_PAGES (STACK_SIZE
) * EFI_PAGE_SIZE
- CPU_STACK_ALIGNMENT
;
362 TopOfStack
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) ALIGN_POINTER (TopOfStack
, CPU_STACK_ALIGNMENT
);
364 BuildPageTablesIa32Pae
= (BOOLEAN
) (PcdGetBool (PcdSetNxForStack
) && IsIa32PaeSupport () && IsExecuteDisableBitAvailable ());
365 if (BuildPageTablesIa32Pae
) {
366 PageTables
= Create4GPageTablesIa32Pae (BaseOfStack
, STACK_SIZE
);
367 EnableExecuteDisableBit ();
371 // End of PEI phase signal
373 Status
= PeiServicesInstallPpi (&gEndOfPeiSignalPpi
);
374 ASSERT_EFI_ERROR (Status
);
376 if (BuildPageTablesIa32Pae
) {
377 AsmWriteCr3 (PageTables
);
379 // Set Physical Address Extension (bit 5 of CR4).
381 AsmWriteCr4 (AsmReadCr4 () | BIT5
);
385 // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.
387 UpdateStackHob (BaseOfStack
, STACK_SIZE
);
390 // Transfer the control to the entry point of DxeCore.
392 if (BuildPageTablesIa32Pae
) {
394 (SWITCH_STACK_ENTRY_POINT
)(UINTN
)DxeCoreEntryPoint
,
397 (VOID
*) (UINTN
) TopOfStack
401 (SWITCH_STACK_ENTRY_POINT
)(UINTN
)DxeCoreEntryPoint
,
404 (VOID
*) (UINTN
) TopOfStack