]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Library/PeilessStartupLib/DxeLoad.c
OvmfPkg/PeilessStartupLib: Find NCCFV in non-td guest
[mirror_edk2.git] / OvmfPkg / Library / PeilessStartupLib / DxeLoad.c
CommitLineData
4fe26784
MX
1/** @file\r
2 Responsibility of this file is to load the DXE Core from a Firmware Volume.\r
3\r
4Copyright (c) 2016 HP Development Company, L.P.\r
5Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>\r
6SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include "PeilessStartupInternal.h"\r
11#include <Library/DebugLib.h>\r
12#include <Library/BaseLib.h>\r
13#include <Library/BaseMemoryLib.h>\r
14#include <Library/MemoryAllocationLib.h>\r
15#include <Library/PcdLib.h>\r
16#include <Guid/MemoryTypeInformation.h>\r
17#include <Guid/MemoryAllocationHob.h>\r
18#include <Guid/PcdDataBaseSignatureGuid.h>\r
19#include <Register/Intel/Cpuid.h>\r
20#include <Library/PrePiLib.h>\r
21#include "X64/PageTables.h"\r
22#include <Library/ReportStatusCodeLib.h>\r
23\r
24#define STACK_SIZE 0x20000\r
70d1481b 25extern EFI_GUID gEfiNonCcFvGuid;\r
4fe26784
MX
26\r
27/**\r
28 Transfers control to DxeCore.\r
29\r
30 This function performs a CPU architecture specific operations to execute\r
31 the entry point of DxeCore\r
32\r
33 @param DxeCoreEntryPoint The entry point of DxeCore.\r
34\r
35**/\r
36VOID\r
37HandOffToDxeCore (\r
38 IN EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint\r
39 )\r
40{\r
41 VOID *BaseOfStack;\r
42 VOID *TopOfStack;\r
43 UINTN PageTables;\r
44\r
45 //\r
46 // Clear page 0 and mark it as allocated if NULL pointer detection is enabled.\r
47 //\r
48 if (IsNullDetectionEnabled ()) {\r
49 ClearFirst4KPage (GetHobList ());\r
50 BuildMemoryAllocationHob (0, EFI_PAGES_TO_SIZE (1), EfiBootServicesData);\r
51 }\r
52\r
53 //\r
54 // Allocate 128KB for the Stack\r
55 //\r
56 BaseOfStack = AllocatePages (EFI_SIZE_TO_PAGES (STACK_SIZE));\r
57 ASSERT (BaseOfStack != NULL);\r
58\r
59 //\r
60 // Compute the top of the stack we were allocated. Pre-allocate a UINTN\r
61 // for safety.\r
62 //\r
63 TopOfStack = (VOID *)((UINTN)BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - CPU_STACK_ALIGNMENT);\r
64 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);\r
65\r
66 DEBUG ((DEBUG_INFO, "BaseOfStack=0x%x, TopOfStack=0x%x\n", BaseOfStack, TopOfStack));\r
67\r
68 //\r
69 // Create page table and save PageMapLevel4 to CR3\r
70 //\r
71 PageTables = CreateIdentityMappingPageTables (\r
72 (EFI_PHYSICAL_ADDRESS)(UINTN)BaseOfStack,\r
73 STACK_SIZE\r
74 );\r
75 if (PageTables == 0) {\r
76 DEBUG ((DEBUG_ERROR, "Failed to create idnetity mapping page tables.\n"));\r
77 CpuDeadLoop ();\r
78 }\r
79\r
80 AsmWriteCr3 (PageTables);\r
81\r
82 //\r
83 // Update the contents of BSP stack HOB to reflect the real stack info passed to DxeCore.\r
84 //\r
85 UpdateStackHob ((EFI_PHYSICAL_ADDRESS)(UINTN)BaseOfStack, STACK_SIZE);\r
86\r
87 DEBUG ((DEBUG_INFO, "SwitchStack then Jump to DxeCore\n"));\r
88 //\r
89 // Transfer the control to the entry point of DxeCore.\r
90 //\r
91 SwitchStack (\r
92 (SWITCH_STACK_ENTRY_POINT)(UINTN)DxeCoreEntryPoint,\r
93 GetHobList (),\r
94 NULL,\r
95 TopOfStack\r
96 );\r
97}\r
98\r
99/**\r
100 Searches DxeCore in all firmware Volumes and loads the first\r
101 instance that contains DxeCore.\r
102\r
103 @return FileHandle of DxeCore to load DxeCore.\r
104\r
105**/\r
106EFI_STATUS\r
107FindDxeCore (\r
108 IN INTN FvInstance,\r
109 IN OUT EFI_PEI_FILE_HANDLE *FileHandle\r
110 )\r
111{\r
112 EFI_STATUS Status;\r
113 EFI_PEI_FV_HANDLE VolumeHandle;\r
114\r
115 if (FileHandle == NULL) {\r
116 ASSERT (FALSE);\r
117 return EFI_INVALID_PARAMETER;\r
118 }\r
119\r
120 *FileHandle = NULL;\r
121\r
122 //\r
123 // Caller passed in a specific FV to try, so only try that one\r
124 //\r
125 Status = FfsFindNextVolume (FvInstance, &VolumeHandle);\r
126 if (!EFI_ERROR (Status)) {\r
127 Status = FfsFindNextFile (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, VolumeHandle, FileHandle);\r
128 if (*FileHandle) {\r
129 // Assume the FV that contains multiple compressed FVs.\r
130 // So decompress the compressed FVs\r
131 Status = FfsProcessFvFile (*FileHandle);\r
132 ASSERT_EFI_ERROR (Status);\r
133 Status = FfsAnyFvFindFirstFile (EFI_FV_FILETYPE_DXE_CORE, &VolumeHandle, FileHandle);\r
134 }\r
135 }\r
136\r
137 return Status;\r
138}\r
139\r
70d1481b
MX
140/**\r
141 * This is a FFS_CHECK_SECTION_HOOK which is defined by caller to check\r
142 * if the section is an EFI_SECTION_FIRMWARE_VOLUME_IMAGE and if it is\r
143 * a NonCc FV.\r
144 *\r
145 * @param Section The section in which we're checking for the NonCc FV.\r
146 * @return EFI_STATUS The section is the NonCc FV.\r
147 */\r
148EFI_STATUS\r
149EFIAPI\r
150CheckSectionHookForDxeNonCc (\r
151 IN EFI_COMMON_SECTION_HEADER *Section\r
152 )\r
153{\r
154 VOID *Buffer;\r
155 EFI_STATUS Status;\r
156 EFI_FV_INFO FvImageInfo;\r
157\r
158 if (Section->Type != EFI_SECTION_FIRMWARE_VOLUME_IMAGE) {\r
159 return EFI_INVALID_PARAMETER;\r
160 }\r
161\r
162 if (IS_SECTION2 (Section)) {\r
163 Buffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER2));\r
164 } else {\r
165 Buffer = (VOID *)((UINT8 *)Section + sizeof (EFI_COMMON_SECTION_HEADER));\r
166 }\r
167\r
168 ZeroMem (&FvImageInfo, sizeof (FvImageInfo));\r
169 Status = FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE)(UINTN)Buffer, &FvImageInfo);\r
170 if (EFI_ERROR (Status)) {\r
171 DEBUG ((DEBUG_INFO, "Cannot get volume info! %r\n", Status));\r
172 return Status;\r
173 }\r
174\r
175 return CompareGuid (&FvImageInfo.FvName, &gEfiNonCcFvGuid) ? EFI_SUCCESS : EFI_NOT_FOUND;\r
176}\r
177\r
178/**\r
179 * Find the NonCc FV.\r
180 *\r
181 * @param FvInstance The FvInstance number.\r
182 * @return EFI_STATUS Successfuly find the NonCc FV.\r
183 */\r
184EFI_STATUS\r
185EFIAPI\r
186FindDxeNonCc (\r
187 IN INTN FvInstance\r
188 )\r
189{\r
190 EFI_STATUS Status;\r
191 EFI_PEI_FV_HANDLE VolumeHandle;\r
192 EFI_PEI_FILE_HANDLE FileHandle;\r
193 EFI_PEI_FV_HANDLE FvImageHandle;\r
194 EFI_FV_INFO FvImageInfo;\r
195 UINT32 FvAlignment;\r
196 VOID *FvBuffer;\r
197\r
198 FileHandle = NULL;\r
199\r
200 //\r
201 // Caller passed in a specific FV to try, so only try that one\r
202 //\r
203 Status = FfsFindNextVolume (FvInstance, &VolumeHandle);\r
204 ASSERT (Status == EFI_SUCCESS);\r
205\r
206 Status = FfsFindNextFile (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, VolumeHandle, &FileHandle);\r
207 ASSERT (FileHandle != NULL);\r
208\r
209 //\r
210 // Find FvImage in FvFile\r
211 //\r
212 Status = FfsFindSectionData (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, CheckSectionHookForDxeNonCc, FileHandle, (VOID **)&FvImageHandle);\r
213 if (EFI_ERROR (Status)) {\r
214 return Status;\r
215 }\r
216\r
217 //\r
218 // Collect FvImage Info.\r
219 //\r
220 ZeroMem (&FvImageInfo, sizeof (FvImageInfo));\r
221 Status = FfsGetVolumeInfo (FvImageHandle, &FvImageInfo);\r
222 ASSERT_EFI_ERROR (Status);\r
223\r
224 //\r
225 // FvAlignment must be more than 8 bytes required by FvHeader structure.\r
226 //\r
227 FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16);\r
228 if (FvAlignment < 8) {\r
229 FvAlignment = 8;\r
230 }\r
231\r
232 //\r
233 // Check FvImage\r
234 //\r
235 if ((UINTN)FvImageInfo.FvStart % FvAlignment != 0) {\r
236 FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32)FvImageInfo.FvSize), FvAlignment);\r
237 if (FvBuffer == NULL) {\r
238 return EFI_OUT_OF_RESOURCES;\r
239 }\r
240\r
241 CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN)FvImageInfo.FvSize);\r
242 //\r
243 // Update FvImageInfo after reload FvImage to new aligned memory\r
244 //\r
245 FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE)FvBuffer, &FvImageInfo);\r
246 }\r
247\r
248 //\r
249 // Inform HOB consumer phase, i.e. DXE core, the existence of this FV\r
250 //\r
251 BuildFvHob ((EFI_PHYSICAL_ADDRESS)(UINTN)FvImageInfo.FvStart, FvImageInfo.FvSize);\r
252\r
253 //\r
254 // Makes the encapsulated volume show up in DXE phase to skip processing of\r
255 // encapsulated file again.\r
256 //\r
257 BuildFv2Hob (\r
258 (EFI_PHYSICAL_ADDRESS)(UINTN)FvImageInfo.FvStart,\r
259 FvImageInfo.FvSize,\r
260 &FvImageInfo.FvName,\r
261 &(((EFI_FFS_FILE_HEADER *)FileHandle)->Name)\r
262 );\r
263\r
264 return Status;\r
265}\r
266\r
4fe26784
MX
267/**\r
268 This function finds DXE Core in the firmware volume and transfer the control to\r
269 DXE core.\r
270\r
271 @return EFI_SUCCESS DXE core was successfully loaded.\r
272 @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core.\r
273\r
274**/\r
275EFI_STATUS\r
276EFIAPI\r
277DxeLoadCore (\r
278 IN INTN FvInstance\r
279 )\r
280{\r
281 EFI_STATUS Status;\r
282 EFI_FV_FILE_INFO DxeCoreFileInfo;\r
283 EFI_PHYSICAL_ADDRESS DxeCoreAddress;\r
284 UINT64 DxeCoreSize;\r
285 EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint;\r
286 EFI_PEI_FILE_HANDLE FileHandle;\r
287 VOID *PeCoffImage;\r
288\r
289 //\r
290 // Look in all the FVs present and find the DXE Core FileHandle\r
291 //\r
292 Status = FindDxeCore (FvInstance, &FileHandle);\r
293\r
294 if (EFI_ERROR (Status)) {\r
295 ASSERT (FALSE);\r
296 return Status;\r
297 }\r
298\r
70d1481b
MX
299 if (!TdIsEnabled ()) {\r
300 FindDxeNonCc (FvInstance);\r
301 }\r
302\r
4fe26784
MX
303 //\r
304 // Load the DXE Core from a Firmware Volume.\r
305 //\r
70d1481b 306 Status = FfsFindSectionData (EFI_SECTION_PE32, NULL, FileHandle, &PeCoffImage);\r
4fe26784
MX
307 if (EFI_ERROR (Status)) {\r
308 return Status;\r
309 }\r
310\r
311 Status = LoadPeCoffImage (PeCoffImage, &DxeCoreAddress, &DxeCoreSize, &DxeCoreEntryPoint);\r
312 ASSERT_EFI_ERROR (Status);\r
313\r
314 //\r
315 // Extract the DxeCore GUID file name.\r
316 //\r
317 Status = FfsGetFileInfo (FileHandle, &DxeCoreFileInfo);\r
318 ASSERT_EFI_ERROR (Status);\r
319\r
320 //\r
321 // Add HOB for the DXE Core\r
322 //\r
323 BuildModuleHob (\r
324 &DxeCoreFileInfo.FileName,\r
325 DxeCoreAddress,\r
326 ALIGN_VALUE (DxeCoreSize, EFI_PAGE_SIZE),\r
327 DxeCoreEntryPoint\r
328 );\r
329\r
330 DEBUG ((\r
331 DEBUG_INFO | DEBUG_LOAD,\r
332 "Loading DXE CORE at 0x%11p EntryPoint=0x%11p\n",\r
333 (VOID *)(UINTN)DxeCoreAddress,\r
334 FUNCTION_ENTRY_POINT (DxeCoreEntryPoint)\r
335 ));\r
336\r
337 // Transfer control to the DXE Core\r
338 // The hand off state is simply a pointer to the HOB list\r
339 //\r
340 HandOffToDxeCore (DxeCoreEntryPoint);\r
341\r
342 //\r
343 // If we get here, then the DXE Core returned. This is an error\r
344 // DxeCore should not return.\r
345 //\r
346 ASSERT (FALSE);\r
347 CpuDeadLoop ();\r
348\r
349 return EFI_OUT_OF_RESOURCES;\r
350}\r