95276127 |
1 | /*++\r |
2 | \r |
3 | Copyright (c) 2006, Intel Corporation\r |
4 | All rights reserved. This program and the accompanying materials\r |
5 | are licensed and made available under the terms and conditions of the BSD License\r |
6 | which accompanies this distribution. The full text of the license may be found at\r |
7 | http://opensource.org/licenses/bsd-license.php\r |
8 | \r |
9 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r |
10 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r |
11 | \r |
12 | Module Name:\r |
13 | \r |
14 | DxeLoadFunc.c\r |
15 | \r |
16 | Abstract:\r |
17 | \r |
18 | Ia32-specifc functionality for DxeLoad.\r |
19 | \r |
20 | --*/\r |
21 | \r |
22 | //\r |
23 | // Include common header file for this module.\r |
24 | //\r |
25 | #include "CommonHeader.h"\r |
26 | \r |
27 | #include "DxeIpl.h"\r |
28 | #include "VirtualMemory.h"\r |
29 | \r |
30 | //\r |
31 | // Global Descriptor Table (GDT)\r |
32 | //\r |
33 | GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT gGdtEntries [] = {\r |
34 | /* selector { Global Segment Descriptor } */ \r |
35 | /* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //null descriptor \r |
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 |
49 | GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR gGdt = {\r |
50 | sizeof (gGdtEntries) - 1,\r |
51 | (UINTN) gGdtEntries\r |
52 | };\r |
53 | \r |
54 | VOID\r |
55 | HandOffToDxeCore (\r |
56 | IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint,\r |
57 | IN EFI_PEI_HOB_POINTERS HobList,\r |
58 | IN EFI_PEI_PPI_DESCRIPTOR *EndOfPeiSignal\r |
59 | )\r |
60 | {\r |
61 | EFI_STATUS Status;\r |
62 | EFI_PHYSICAL_ADDRESS BaseOfStack;\r |
63 | EFI_PHYSICAL_ADDRESS TopOfStack;\r |
64 | UINTN PageTables;\r |
65 | \r |
66 | Status = PeiServicesAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack);\r |
67 | ASSERT_EFI_ERROR (Status);\r |
68 | \r |
69 | if (FeaturePcdGet(PcdDxeIplSwitchToLongMode)) {\r |
70 | //\r |
71 | // Compute the top of the stack we were allocated, which is used to load X64 dxe core. \r |
72 | // Pre-allocate a 32 bytes which confroms to x64 calling convention.\r |
73 | //\r |
74 | // The first four parameters to a function are passed in rcx, rdx, r8 and r9. \r |
75 | // Any further parameters are pushed on the stack. Furthermore, space (4 * 8bytes) for the \r |
76 | // register parameters is reserved on the stack, in case the called function \r |
77 | // wants to spill them; this is important if the function is variadic. \r |
78 | //\r |
79 | TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - 32;\r |
80 | \r |
81 | //\r |
82 | // X64 Calling Conventions requires that the stack must be aligned to 16 bytes\r |
83 | //\r |
84 | TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, 16);\r |
85 | \r |
86 | //\r |
87 | // Load the GDT of Go64. Since the GDT of 32-bit Tiano locates in the BS_DATA\r |
88 | // memory, it may be corrupted when copying FV to high-end memory \r |
89 | //\r |
90 | AsmWriteGdtr (&gGdt);\r |
91 | //\r |
92 | // Create page table and save PageMapLevel4 to CR3\r |
93 | //\r |
94 | PageTables = CreateIdentityMappingPageTables ();\r |
95 | \r |
96 | //\r |
97 | // End of PEI phase singal\r |
98 | //\r |
99 | Status = PeiServicesInstallPpi (EndOfPeiSignal);\r |
100 | ASSERT_EFI_ERROR (Status);\r |
101 | \r |
102 | AsmWriteCr3 (PageTables);\r |
103 | //\r |
104 | // Go to Long Mode. Interrupts will not get turned on until the CPU AP is loaded.\r |
105 | // Call x64 drivers passing in single argument, a pointer to the HOBs.\r |
106 | // \r |
107 | AsmEnablePaging64 (\r |
108 | SYS_CODE64_SEL,\r |
109 | DxeCoreEntryPoint,\r |
110 | (EFI_PHYSICAL_ADDRESS)(UINTN)(HobList.Raw),\r |
111 | 0,\r |
112 | TopOfStack\r |
113 | );\r |
114 | } else {\r |
115 | //\r |
116 | // Compute the top of the stack we were allocated. Pre-allocate a UINTN\r |
117 | // for safety.\r |
118 | //\r |
119 | TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT;\r |
120 | TopOfStack = (EFI_PHYSICAL_ADDRESS) (UINTN) ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);\r |
121 | \r |
122 | //\r |
123 | // End of PEI phase singal\r |
124 | //\r |
125 | Status = PeiServicesInstallPpi (EndOfPeiSignal);\r |
126 | ASSERT_EFI_ERROR (Status);\r |
127 | \r |
128 | SwitchStack (\r |
129 | (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,\r |
130 | HobList.Raw,\r |
131 | NULL,\r |
132 | (VOID *) (UINTN) TopOfStack\r |
133 | );\r |
134 | } \r |
135 | }\r |
136 | \r |