VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/OvmfPkg/Library/PeilessStartupLib/DxeLoad.c

Last change on this file was 99404, checked in by vboxsync, 22 months ago

Devices/EFI/FirmwareNew: Update to edk2-stable202302 and make it build, bugref:4643

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette