]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c
1. DxeIplPeim will locate Vector Handoff Table PPI and build GUIDed HOB if it has.
[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
57f360f2 4Copyright (c) 2006 - 2013, 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
91d92e25 59/**\r
60 Transfers control to DxeCore.\r
61\r
62 This function performs a CPU architecture specific operations to execute\r
63 the entry point of DxeCore with the parameters of HobList.\r
48557c65 64 It also installs EFI_END_OF_PEI_PPI to signal the end of PEI phase.\r
91d92e25 65\r
48557c65 66 @param DxeCoreEntryPoint The entry point of DxeCore.\r
91d92e25 67 @param HobList The start of HobList passed to DxeCore.\r
91d92e25 68\r
69**/\r
95276127 70VOID\r
71HandOffToDxeCore (\r
72 IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint,\r
9b937a73 73 IN EFI_PEI_HOB_POINTERS HobList\r
95276127 74 )\r
75{\r
76 EFI_STATUS Status;\r
77 EFI_PHYSICAL_ADDRESS BaseOfStack;\r
78 EFI_PHYSICAL_ADDRESS TopOfStack;\r
79 UINTN PageTables;\r
5d582956 80 X64_IDT_GATE_DESCRIPTOR *IdtTable;\r
81 UINTN SizeOfTemplate;\r
82 VOID *TemplateBase;\r
83 EFI_PHYSICAL_ADDRESS VectorAddress;\r
84 UINT32 Index;\r
bdfbe63e 85 X64_IDT_TABLE *IdtTableForX64;\r
57f360f2
JF
86 EFI_VECTOR_HANDOFF_INFO *VectorInfo;\r
87 EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;\r
95276127 88\r
89 Status = PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack);\r
90 ASSERT_EFI_ERROR (Status);\r
0cf27ce0 91\r
95276127 92 if (FeaturePcdGet(PcdDxeIplSwitchToLongMode)) {\r
93 //\r
0cf27ce0 94 // Compute the top of the stack we were allocated, which is used to load X64 dxe core.\r
95276127 95 // Pre-allocate a 32 bytes which confroms to x64 calling convention.\r
96 //\r
0cf27ce0 97 // The first four parameters to a function are passed in rcx, rdx, r8 and r9.\r
98 // Any further parameters are pushed on the stack. Furthermore, space (4 * 8bytes) for the\r
99 // register parameters is reserved on the stack, in case the called function\r
100 // wants to spill them; this is important if the function is variadic.\r
95276127 101 //\r
102 TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - 32;\r
103\r
104 //\r
b98da1b1 105 // x64 Calling Conventions requires that the stack must be aligned to 16 bytes\r
95276127 106 //\r
107 TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, 16);\r
108\r
109 //\r
110 // Load the GDT of Go64. Since the GDT of 32-bit Tiano locates in the BS_DATA\r
0cf27ce0 111 // memory, it may be corrupted when copying FV to high-end memory\r
95276127 112 //\r
113 AsmWriteGdtr (&gGdt);\r
114 //\r
115 // Create page table and save PageMapLevel4 to CR3\r
116 //\r
117 PageTables = CreateIdentityMappingPageTables ();\r
118\r
119 //\r
48557c65 120 // End of PEI phase signal\r
95276127 121 //\r
9b937a73 122 Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);\r
95276127 123 ASSERT_EFI_ERROR (Status);\r
0cf27ce0 124\r
95276127 125 AsmWriteCr3 (PageTables);\r
5d582956 126\r
30c8f861 127 //\r
128 // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.\r
0cf27ce0 129 //\r
30c8f861 130 UpdateStackHob (BaseOfStack, STACK_SIZE);\r
5d582956 131\r
4bfa7dc4 132 SizeOfTemplate = AsmGetVectorTemplatInfo (&TemplateBase);\r
133\r
134 Status = PeiServicesAllocatePages (\r
0cf27ce0 135 EfiBootServicesData,\r
bdfbe63e 136 EFI_SIZE_TO_PAGES(sizeof (X64_IDT_TABLE) + SizeOfTemplate * IDT_ENTRY_COUNT),\r
137 (EFI_PHYSICAL_ADDRESS *) &IdtTableForX64\r
4bfa7dc4 138 );\r
139 ASSERT_EFI_ERROR (Status);\r
140\r
bdfbe63e 141 //\r
142 // Store EFI_PEI_SERVICES** in the 4 bytes immediately preceding IDT to avoid that\r
143 // it may not be gotten correctly after IDT register is re-written.\r
144 //\r
145 IdtTableForX64->PeiService = GetPeiServicesTablePointer ();\r
146\r
147 VectorAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (IdtTableForX64 + 1);\r
148 IdtTable = IdtTableForX64->IdtTable;\r
e7af83ae 149 for (Index = 0; Index < IDT_ENTRY_COUNT; Index++) {\r
4bfa7dc4 150 IdtTable[Index].Ia32IdtEntry.Bits.GateType = 0x8e;\r
151 IdtTable[Index].Ia32IdtEntry.Bits.Reserved_0 = 0;\r
152 IdtTable[Index].Ia32IdtEntry.Bits.Selector = SYS_CODE64_SEL;\r
153\r
154 IdtTable[Index].Ia32IdtEntry.Bits.OffsetLow = (UINT16) VectorAddress;\r
155 IdtTable[Index].Ia32IdtEntry.Bits.OffsetHigh = (UINT16) (RShiftU64 (VectorAddress, 16));\r
156 IdtTable[Index].Offset32To63 = (UINT32) (RShiftU64 (VectorAddress, 32));\r
157 IdtTable[Index].Reserved = 0;\r
158\r
159 CopyMem ((VOID *) (UINTN) VectorAddress, TemplateBase, SizeOfTemplate);\r
160 AsmVectorFixup ((VOID *) (UINTN) VectorAddress, (UINT8) Index);\r
161\r
162 VectorAddress += SizeOfTemplate;\r
5d582956 163 }\r
4bfa7dc4 164\r
165 gLidtDescriptor.Base = (UINTN) IdtTable;\r
0cf27ce0 166\r
e7af83ae 167 //\r
168 // Disable interrupt of Debug timer, since new IDT table cannot handle it.\r
169 //\r
170 SaveAndSetDebugTimerInterrupt (FALSE);\r
171\r
4bfa7dc4 172 AsmWriteIdtr (&gLidtDescriptor);\r
173\r
5d582956 174 //\r
b98da1b1 175 // Go to Long Mode and transfer control to DxeCore.\r
176 // Interrupts will not get turned on until the CPU AP is loaded.\r
95276127 177 // Call x64 drivers passing in single argument, a pointer to the HOBs.\r
0cf27ce0 178 //\r
95276127 179 AsmEnablePaging64 (\r
180 SYS_CODE64_SEL,\r
181 DxeCoreEntryPoint,\r
182 (EFI_PHYSICAL_ADDRESS)(UINTN)(HobList.Raw),\r
183 0,\r
184 TopOfStack\r
185 );\r
186 } else {\r
57f360f2
JF
187 //\r
188 // Get Vector Hand-off Info PPI and build Guided HOB\r
189 //\r
190 Status = PeiServicesLocatePpi (\r
191 &gEfiVectorHandoffInfoPpiGuid,\r
192 0,\r
193 NULL,\r
194 (VOID **)&VectorHandoffInfoPpi\r
195 );\r
196 if (Status == EFI_SUCCESS) {\r
197 DEBUG ((EFI_D_INFO, "Vector Hand-off Info PPI is gotten, GUIDed HOB is created!\n"));\r
198 VectorInfo = VectorHandoffInfoPpi->Info;\r
199 Index = 1;\r
200 while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) {\r
201 VectorInfo ++;\r
202 Index ++;\r
203 }\r
204 BuildGuidDataHob (\r
205 &gEfiVectorHandoffInfoPpiGuid,\r
206 VectorHandoffInfoPpi->Info,\r
207 sizeof (EFI_VECTOR_HANDOFF_INFO) * Index\r
208 );\r
209 }\r
210\r
95276127 211 //\r
212 // Compute the top of the stack we were allocated. Pre-allocate a UINTN\r
213 // for safety.\r
214 //\r
215 TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT;\r
216 TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);\r
217\r
218 //\r
48557c65 219 // End of PEI phase signal\r
95276127 220 //\r
9b937a73 221 Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);\r
95276127 222 ASSERT_EFI_ERROR (Status);\r
223\r
30c8f861 224 //\r
225 // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.\r
0cf27ce0 226 //\r
30c8f861 227 UpdateStackHob (BaseOfStack, STACK_SIZE);\r
0cf27ce0 228\r
b98da1b1 229 //\r
230 // Transfer the control to the entry point of DxeCore.\r
231 //\r
95276127 232 SwitchStack (\r
233 (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,\r
234 HobList.Raw,\r
235 NULL,\r
236 (VOID *) (UINTN) TopOfStack\r
237 );\r
0cf27ce0 238 }\r
95276127 239}\r
240\r