TianoCore EDK2 master
Loading...
Searching...
No Matches
DxeLoadFuncFit.c
Go to the documentation of this file.
1
9#include <PiPei.h>
10#include <Library/BaseLib.h>
11#include <Library/DebugLib.h>
14#include <Library/PcdLib.h>
15#include <Library/HobLib.h>
16#include <Library/FdtLib.h>
17#include "VirtualMemory.h"
18#include "UefiPayloadEntry.h"
19
20#define STACK_SIZE 0x20000
21#define IDT_ENTRY_COUNT 32
22
23extern VOID *mHobList;
24
25typedef struct _X64_IDT_TABLE {
26 //
27 // Reserved 4 bytes preceding PeiService and IdtTable,
28 // since IDT base address should be 8-byte alignment.
29 //
30 UINT32 Reserved;
31 CONST EFI_PEI_SERVICES **PeiService;
32 X64_IDT_GATE_DESCRIPTOR IdtTable[IDT_ENTRY_COUNT];
34
35//
36// Global Descriptor Table (GDT)
37//
39 /* selector { Global Segment Descriptor } */
40 /* 0x00 */ {
41 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
42 }, // null descriptor
43 /* 0x08 */ {
44 { 0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
45 }, // linear data segment descriptor
46 /* 0x10 */ {
47 { 0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
48 }, // linear code segment descriptor
49 /* 0x18 */ {
50 { 0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
51 }, // system data segment descriptor
52 /* 0x20 */ {
53 { 0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
54 }, // system code segment descriptor
55 /* 0x28 */ {
56 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
57 }, // spare segment descriptor
58 /* 0x30 */ {
59 { 0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0 }
60 }, // system data segment descriptor
61 /* 0x38 */ {
62 { 0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 1, 0, 1, 0 }
63 }, // system code segment descriptor
64 /* 0x40 */ {
65 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
66 }, // spare segment descriptor
67};
68
69//
70// IA32 Gdt register
71//
72GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR gGdt = {
73 sizeof (gGdtEntries) - 1,
74 (UINTN)gGdtEntries
75};
76
77GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR gLidtDescriptor = {
78 sizeof (X64_IDT_GATE_DESCRIPTOR) * IDT_ENTRY_COUNT - 1,
79 0
80};
81
94 IN EFI_PHYSICAL_ADDRESS StackBase,
95 IN UINTN StackSize
96 )
97{
98 UINT8 PhysicalAddressBits;
99 EFI_PHYSICAL_ADDRESS PhysicalAddress;
100 UINTN IndexOfPdpEntries;
101 UINTN IndexOfPageDirectoryEntries;
102 UINT32 NumberOfPdpEntriesNeeded;
104 PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;
105 PAGE_TABLE_ENTRY *PageDirectoryEntry;
106 UINTN TotalPagesNum;
107 UINTN PageAddress;
108 UINT64 AddressEncMask;
109
110 //
111 // Make sure AddressEncMask is contained to smallest supported address field
112 //
113 AddressEncMask = PcdGet64 (PcdPteMemoryEncryptionAddressOrMask) & PAGING_1G_ADDRESS_MASK_64;
114
115 PhysicalAddressBits = 32;
116
117 //
118 // Calculate the table entries needed.
119 //
120 NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
121
122 TotalPagesNum = NumberOfPdpEntriesNeeded + 1;
123 PageAddress = (UINTN)AllocatePageTableMemory (TotalPagesNum);
124 ASSERT (PageAddress != 0);
125
126 PageMap = (VOID *)PageAddress;
127 PageAddress += SIZE_4KB;
128
129 PageDirectoryPointerEntry = PageMap;
130 PhysicalAddress = 0;
131
132 for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
133 //
134 // Each Directory Pointer entries points to a page of Page Directory entires.
135 // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
136 //
137 PageDirectoryEntry = (VOID *)PageAddress;
138 PageAddress += SIZE_4KB;
139
140 //
141 // Fill in a Page Directory Pointer Entries
142 //
143 PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry | AddressEncMask;
144 PageDirectoryPointerEntry->Bits.Present = 1;
145
146 for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PhysicalAddress += SIZE_2MB) {
147 if ( (IsNullDetectionEnabled () && (PhysicalAddress == 0))
148 || ( (PhysicalAddress < StackBase + StackSize)
149 && ((PhysicalAddress + SIZE_2MB) > StackBase)))
150 {
151 //
152 // Need to split this 2M page that covers stack range.
153 //
154 Split2MPageTo4K (PhysicalAddress, (UINT64 *)PageDirectoryEntry, StackBase, StackSize, 0, 0);
155 } else {
156 //
157 // Fill in the Page Directory entries
158 //
159 PageDirectoryEntry->Uint64 = (UINT64)PhysicalAddress | AddressEncMask;
160 PageDirectoryEntry->Bits.ReadWrite = 1;
161 PageDirectoryEntry->Bits.Present = 1;
162 PageDirectoryEntry->Bits.MustBe1 = 1;
163 }
164 }
165 }
166
167 for ( ; IndexOfPdpEntries < 512; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
168 ZeroMem (
169 PageDirectoryPointerEntry,
171 );
172 }
173
174 //
175 // Protect the page table by marking the memory used for page table to be
176 // read-only.
177 //
179
180 return (UINTN)PageMap;
181}
182
190BOOLEAN
192 VOID
193 )
194{
195 UINT32 RegEax;
196 UINT32 RegEdx;
197 BOOLEAN Ia32PaeSupport;
198
199 Ia32PaeSupport = FALSE;
200 AsmCpuid (0x0, &RegEax, NULL, NULL, NULL);
201 if (RegEax >= 0x1) {
202 AsmCpuid (0x1, NULL, NULL, NULL, &RegEdx);
203 if ((RegEdx & BIT6) != 0) {
204 Ia32PaeSupport = TRUE;
205 }
206 }
207
208 return Ia32PaeSupport;
209}
210
218BOOLEAN
220 VOID
221 )
222{
223 if (!IsIa32PaeSupport ()) {
224 return FALSE;
225 }
226
227 if (IsNullDetectionEnabled ()) {
228 return TRUE;
229 }
230
231 if (PcdGet8 (PcdHeapGuardPropertyMask) != 0) {
232 return TRUE;
233 }
234
235 if (PcdGetBool (PcdCpuStackGuard)) {
236 return TRUE;
237 }
238
239 if (IsEnableNonExecNeeded ()) {
240 return TRUE;
241 }
242
243 return FALSE;
244}
245
256VOID
258 IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint,
260 )
261{
262 EFI_PHYSICAL_ADDRESS BaseOfStack;
263 EFI_PHYSICAL_ADDRESS TopOfStack;
264 UINTN PageTables;
265 X64_IDT_GATE_DESCRIPTOR *IdtTable;
266 UINTN SizeOfTemplate;
267 VOID *TemplateBase;
268 EFI_PHYSICAL_ADDRESS VectorAddress;
269 UINT32 Index;
270 X64_IDT_TABLE *IdtTableForX64;
271
272 // Initialize floating point operating environment to be compliant with UEFI spec.
274
275 //
276 // Mask off all legacy 8259 interrupt sources
277 //
278 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0xFF);
279 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0xFF);
280
281 //
282 // Clear page 0 and mark it as allocated if NULL pointer detection is enabled.
283 //
284 if (IsNullDetectionEnabled ()) {
285 ClearFirst4KPage (HobList.Raw);
287 }
288
289 BaseOfStack = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (STACK_SIZE));
290 ASSERT (BaseOfStack != 0);
291
292 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
293 //
294 // Compute the top of the stack we were allocated, which is used to load X64 dxe core.
295 // Pre-allocate a 32 bytes which confroms to x64 calling convention.
296 //
297 // The first four parameters to a function are passed in rcx, rdx, r8 and r9.
298 // Any further parameters are pushed on the stack. Furthermore, space (4 * 8bytes) for the
299 // register parameters is reserved on the stack, in case the called function
300 // wants to spill them; this is important if the function is variadic.
301 //
302 TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - 32;
303
304 //
305 // x64 Calling Conventions requires that the stack must be aligned to 16 bytes
306 //
307 TopOfStack = (EFI_PHYSICAL_ADDRESS)(UINTN)ALIGN_POINTER (TopOfStack, 16);
308
309 //
310 // Load the GDT of Go64. Since the GDT of 32-bit Tiano locates in the BS_DATA
311 // memory, it may be corrupted when copying FV to high-end memory
312 //
313 AsmWriteGdtr (&gGdt);
314 //
315 // Create page table and save PageMapLevel4 to CR3
316 //
317 PageTables = CreateIdentityMappingPageTables (BaseOfStack, STACK_SIZE, 0, 0);
318
319 //
320 // Paging might be already enabled. To avoid conflict configuration,
321 // disable paging first anyway.
322 //
323 AsmWriteCr0 (AsmReadCr0 () & (~BIT31));
324 AsmWriteCr3 (PageTables);
325
326 //
327 // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.
328 //
329 UpdateStackHob (BaseOfStack, STACK_SIZE);
330
331 SizeOfTemplate = AsmGetVectorTemplatInfo (&TemplateBase);
332
333 VectorAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (sizeof (X64_IDT_TABLE) + SizeOfTemplate * IDT_ENTRY_COUNT));
334 ASSERT (VectorAddress != 0);
335
336 //
337 // Store EFI_PEI_SERVICES** in the 4 bytes immediately preceding IDT to avoid that
338 // it may not be gotten correctly after IDT register is re-written.
339 //
340 IdtTableForX64 = (X64_IDT_TABLE *)(UINTN)VectorAddress;
341 IdtTableForX64->PeiService = NULL;
342
343 VectorAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)(IdtTableForX64 + 1);
344 IdtTable = IdtTableForX64->IdtTable;
345 for (Index = 0; Index < IDT_ENTRY_COUNT; Index++) {
346 IdtTable[Index].Ia32IdtEntry.Bits.GateType = 0x8e;
347 IdtTable[Index].Ia32IdtEntry.Bits.Reserved_0 = 0;
348 IdtTable[Index].Ia32IdtEntry.Bits.Selector = SYS_CODE64_SEL;
349
350 IdtTable[Index].Ia32IdtEntry.Bits.OffsetLow = (UINT16)VectorAddress;
351 IdtTable[Index].Ia32IdtEntry.Bits.OffsetHigh = (UINT16)(RShiftU64 (VectorAddress, 16));
352 IdtTable[Index].Offset32To63 = (UINT32)(RShiftU64 (VectorAddress, 32));
353 IdtTable[Index].Reserved = 0;
354
355 CopyMem ((VOID *)(UINTN)VectorAddress, TemplateBase, SizeOfTemplate);
356 AsmVectorFixup ((VOID *)(UINTN)VectorAddress, (UINT8)Index);
357
358 VectorAddress += SizeOfTemplate;
359 }
360
361 gLidtDescriptor.Base = (UINTN)IdtTable;
362
363 AsmWriteIdtr (&gLidtDescriptor);
364
365 DEBUG ((
366 DEBUG_INFO,
367 "%a() Stack Base: 0x%lx, Stack Size: 0x%x\n",
368 __func__,
369 BaseOfStack,
370 STACK_SIZE
371 ));
372
373 //
374 // Go to Long Mode and transfer control to DxeCore.
375 // Interrupts will not get turned on until the CPU AP is loaded.
376 // Call x64 drivers passing in single argument, a pointer to the HOBs.
377 //
379 SYS_CODE64_SEL,
380 DxeCoreEntryPoint,
381 (EFI_PHYSICAL_ADDRESS)(UINTN)(HobList.Raw),
382 0,
383 TopOfStack
384 );
385 } else {
386 // 32bit UEFI payload could be supported if required later.
387 DEBUG ((DEBUG_ERROR, "NOT support 32bit UEFI payload\n"));
388 ASSERT (FALSE);
389 CpuDeadLoop ();
390 }
391}
392
399EFIAPI
401 IN UINTN BootloaderParameter
402 )
403{
404 return FitUplEntryPoint (BootloaderParameter);
405}
UINT64 UINTN
VOID EFIAPI BuildMemoryAllocationHob(IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length, IN EFI_MEMORY_TYPE MemoryType)
Definition: HobLib.c:601
VOID EFIAPI CpuDeadLoop(VOID)
Definition: CpuDeadLoop.c:25
UINT64 EFIAPI RShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: RShiftU64.c:28
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: LShiftU64.c:28
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_STATUS EFIAPI FitUplEntryPoint(IN UINTN BootloaderParameter)
BOOLEAN IsIa32PaeSupport(VOID)
VOID HandOffToDxeCore(IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint, IN EFI_PEI_HOB_POINTERS HobList)
UINTN Create4GPageTablesIa32Pae(IN EFI_PHYSICAL_ADDRESS StackBase, IN UINTN StackSize)
BOOLEAN ToBuildPageTable(VOID)
EFI_STATUS EFIAPI _ModuleEntryPoint(IN UINTN BootloaderParameter)
UINTN EFIAPI AsmWriteCr3(UINTN Cr3)
UINTN EFIAPI AsmReadCr0(VOID)
UINTN EFIAPI AsmWriteCr0(UINTN Cr0)
UINT8 EFIAPI IoWrite8(IN UINTN Port, IN UINT8 Value)
Definition: IoLibArmVirt.c:200
VOID Split2MPageTo4K(IN EFI_PHYSICAL_ADDRESS PhysicalAddress, IN OUT UINT64 *PageEntry2M, IN EFI_PHYSICAL_ADDRESS StackBase, IN UINTN StackSize, IN EFI_PHYSICAL_ADDRESS GhcbBase, IN UINTN GhcbSize)
BOOLEAN IsEnableNonExecNeeded(VOID)
VOID ClearFirst4KPage(IN VOID *HobStart)
Definition: VirtualMemory.c:44
VOID EnablePageTableProtection(IN UINTN PageTableBase, IN BOOLEAN Level4Paging)
VOID * AllocatePageTableMemory(IN UINTN Pages)
UINTN CreateIdentityMappingPageTables(IN EFI_PHYSICAL_ADDRESS StackBase, IN UINTN StackSize, IN EFI_PHYSICAL_ADDRESS GhcbBase, IN UINTN GhcbSize)
BOOLEAN IsNullDetectionEnabled(VOID)
VOID EFIAPI AsmVectorFixup(VOID *VectorBase, UINT8 VectorNum)
UINTN EFIAPI AsmGetVectorTemplatInfo(OUT VOID **TemplateBase)
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define ALIGN_POINTER(Pointer, Alignment)
Definition: Base.h:963
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define GLOBAL_REMOVE_IF_UNREFERENCED
Definition: Base.h:48
#define DEBUG(Expression)
Definition: DebugLib.h:434
UINT32 EFIAPI AsmCpuid(IN UINT32 Index, OUT UINT32 *RegisterEax OPTIONAL, OUT UINT32 *RegisterEbx OPTIONAL, OUT UINT32 *RegisterEcx OPTIONAL, OUT UINT32 *RegisterEdx OPTIONAL)
Definition: CpuId.c:36
#define PcdGet64(TokenName)
Definition: PcdLib.h:375
#define PcdGet8(TokenName)
Definition: PcdLib.h:336
#define PcdGetBool(TokenName)
Definition: PcdLib.h:401
#define FeaturePcdGet(TokenName)
Definition: PcdLib.h:50
VOID *EFIAPI AllocatePages(IN UINTN Pages)
VOID UpdateStackHob(IN EFI_PHYSICAL_ADDRESS BaseAddress, IN UINT64 Length)
Definition: Hob.c:731
UINT64 EFI_PHYSICAL_ADDRESS
Definition: UefiBaseType.h:50
#define EFI_PAGES_TO_SIZE(Pages)
Definition: UefiBaseType.h:213
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SIZE_TO_PAGES(Size)
Definition: UefiBaseType.h:200
@ EfiBootServicesData
VOID EFIAPI InitializeFloatingPointUnits(VOID)
VOID EFIAPI AsmEnablePaging64(IN UINT16 Cs, IN UINT64 EntryPoint, IN UINT64 Context1 OPTIONAL, IN UINT64 Context2 OPTIONAL, IN UINT64 NewStack)
VOID EFIAPI AsmWriteGdtr(IN CONST IA32_DESCRIPTOR *Gdtr)
VOID EFIAPI AsmWriteIdtr(IN CONST IA32_DESCRIPTOR *Idtr)