VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.c@ 105670

Last change on this file since 105670 was 105670, checked in by vboxsync, 4 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • Property svn:eol-style set to native
File size: 15.8 KB
Line 
1/** @file
2
3 Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
5
6**/
7
8#include "UefiPayloadEntry.h"
9
10#define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
11 EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
12 EFI_RESOURCE_ATTRIBUTE_TESTED | \
13 EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED | \
14 EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED | \
15 EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \
16 EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED | \
17 EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \
18 EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \
19 EFI_RESOURCE_ATTRIBUTE_64_BIT_IO | \
20 EFI_RESOURCE_ATTRIBUTE_PERSISTENT )
21
22#define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
23 EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
24 EFI_RESOURCE_ATTRIBUTE_TESTED )
25
26extern VOID *mHobList;
27
28/**
29 Print all HOBs info from the HOB list.
30
31 @return The pointer to the HOB list.
32**/
33VOID
34PrintHob (
35 IN CONST VOID *HobStart
36 );
37
38/**
39 Some bootloader may pass a pcd database, and UPL also contain a PCD database.
40 Dxe PCD driver has the assumption that the two PCD database can be catenated and
41 the local token number should be successive.
42 This function will fix up the UPL PCD database to meet that assumption.
43
44 @param[in] DxeFv The FV where to find the Universal PCD database.
45
46 @retval EFI_SUCCESS If it completed successfully.
47 @retval other Failed to fix up.
48**/
49EFI_STATUS
50FixUpPcdDatabase (
51 IN EFI_FIRMWARE_VOLUME_HEADER *DxeFv
52 )
53{
54 EFI_STATUS Status;
55 EFI_FFS_FILE_HEADER *FileHeader;
56 VOID *PcdRawData;
57 PEI_PCD_DATABASE *PeiDatabase;
58 PEI_PCD_DATABASE *UplDatabase;
59 EFI_HOB_GUID_TYPE *GuidHob;
60 DYNAMICEX_MAPPING *ExMapTable;
61 UINTN Index;
62
63 GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid);
64 if (GuidHob == NULL) {
65 //
66 // No fix-up is needed.
67 //
68 return EFI_SUCCESS;
69 }
70
71 PeiDatabase = (PEI_PCD_DATABASE *)GET_GUID_HOB_DATA (GuidHob);
72 DEBUG ((DEBUG_INFO, "Find the Pei PCD data base, the total local token number is %d\n", PeiDatabase->LocalTokenCount));
73
74 Status = FvFindFileByTypeGuid (DxeFv, EFI_FV_FILETYPE_DRIVER, PcdGetPtr (PcdPcdDriverFile), &FileHeader);
75 ASSERT_EFI_ERROR (Status);
76 if (EFI_ERROR (Status)) {
77 return Status;
78 }
79
80 Status = FileFindSection (FileHeader, EFI_SECTION_RAW, &PcdRawData);
81 ASSERT_EFI_ERROR (Status);
82 if (EFI_ERROR (Status)) {
83 return Status;
84 }
85
86 UplDatabase = (PEI_PCD_DATABASE *)PcdRawData;
87 ExMapTable = (DYNAMICEX_MAPPING *)(UINTN)((UINTN)PcdRawData + UplDatabase->ExMapTableOffset);
88
89 for (Index = 0; Index < UplDatabase->ExTokenCount; Index++) {
90 ExMapTable[Index].TokenNumber += PeiDatabase->LocalTokenCount;
91 }
92
93 DEBUG ((DEBUG_INFO, "Fix up UPL PCD database successfully\n"));
94 return EFI_SUCCESS;
95}
96
97/**
98 Add HOB into HOB list
99
100 @param[in] Hob The HOB to be added into the HOB list.
101**/
102VOID
103AddNewHob (
104 IN EFI_PEI_HOB_POINTERS *Hob
105 )
106{
107 EFI_PEI_HOB_POINTERS NewHob;
108
109 if (Hob->Raw == NULL) {
110 return;
111 }
112
113 NewHob.Header = CreateHob (Hob->Header->HobType, Hob->Header->HobLength);
114 ASSERT (NewHob.Header != NULL);
115 if (NewHob.Header == NULL) {
116 return;
117 }
118
119 CopyMem (NewHob.Header + 1, Hob->Header + 1, Hob->Header->HobLength - sizeof (EFI_HOB_GENERIC_HEADER));
120}
121
122/**
123 Found the Resource Descriptor HOB that contains a range (Base, Top)
124
125 @param[in] HobList Hob start address
126 @param[in] Base Memory start address
127 @param[in] Top Memory end address.
128
129 @retval The pointer to the Resource Descriptor HOB.
130**/
131EFI_HOB_RESOURCE_DESCRIPTOR *
132FindResourceDescriptorByRange (
133 IN VOID *HobList,
134 IN EFI_PHYSICAL_ADDRESS Base,
135 IN EFI_PHYSICAL_ADDRESS Top
136 )
137{
138 EFI_PEI_HOB_POINTERS Hob;
139 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
140
141 for (Hob.Raw = (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
142 //
143 // Skip all HOBs except Resource Descriptor HOBs
144 //
145 if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
146 continue;
147 }
148
149 //
150 // Skip Resource Descriptor HOBs that do not describe tested system memory
151 //
152 ResourceHob = Hob.ResourceDescriptor;
153 if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
154 continue;
155 }
156
157 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
158 continue;
159 }
160
161 //
162 // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
163 //
164 if (Base < ResourceHob->PhysicalStart) {
165 continue;
166 }
167
168 if (Top > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) {
169 continue;
170 }
171
172 return ResourceHob;
173 }
174
175 return NULL;
176}
177
178/**
179 Find the highest below 4G memory resource descriptor, except the input Resource Descriptor.
180
181 @param[in] HobList Hob start address
182 @param[in] MinimalNeededSize Minimal needed size.
183 @param[in] ExceptResourceHob Ignore this Resource Descriptor.
184
185 @retval The pointer to the Resource Descriptor HOB.
186**/
187EFI_HOB_RESOURCE_DESCRIPTOR *
188FindAnotherHighestBelow4GResourceDescriptor (
189 IN VOID *HobList,
190 IN UINTN MinimalNeededSize,
191 IN EFI_HOB_RESOURCE_DESCRIPTOR *ExceptResourceHob
192 )
193{
194 EFI_PEI_HOB_POINTERS Hob;
195 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
196 EFI_HOB_RESOURCE_DESCRIPTOR *ReturnResourceHob;
197
198 ReturnResourceHob = NULL;
199
200 for (Hob.Raw = (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
201 //
202 // Skip all HOBs except Resource Descriptor HOBs
203 //
204 if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
205 continue;
206 }
207
208 //
209 // Skip Resource Descriptor HOBs that do not describe tested system memory
210 //
211 ResourceHob = Hob.ResourceDescriptor;
212 if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
213 continue;
214 }
215
216 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
217 continue;
218 }
219
220 //
221 // Skip if the Resource Descriptor HOB equals to ExceptResourceHob
222 //
223 if (ResourceHob == ExceptResourceHob) {
224 continue;
225 }
226
227 //
228 // Skip Resource Descriptor HOBs that are beyond 4G
229 //
230 if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > BASE_4GB) {
231 continue;
232 }
233
234 //
235 // Skip Resource Descriptor HOBs that are too small
236 //
237 if (ResourceHob->ResourceLength < MinimalNeededSize) {
238 continue;
239 }
240
241 //
242 // Return the topest Resource Descriptor
243 //
244 if (ReturnResourceHob == NULL) {
245 ReturnResourceHob = ResourceHob;
246 } else {
247 if (ReturnResourceHob->PhysicalStart < ResourceHob->PhysicalStart) {
248 ReturnResourceHob = ResourceHob;
249 }
250 }
251 }
252
253 return ReturnResourceHob;
254}
255
256/**
257 Check the HOB and decide if it is need inside Payload
258
259 Payload maintainer may make decision which HOB is need or needn't
260 Then add the check logic in the function.
261
262 @param[in] Hob The HOB to check
263
264 @retval TRUE If HOB is need inside Payload
265 @retval FALSE If HOB is needn't inside Payload
266**/
267BOOLEAN
268IsHobNeed (
269 EFI_PEI_HOB_POINTERS Hob
270 )
271{
272 if (Hob.Header->HobType == EFI_HOB_TYPE_HANDOFF) {
273 return FALSE;
274 }
275
276 if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
277 if (CompareGuid (&Hob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
278 return FALSE;
279 }
280 }
281
282 // Arrive here mean the HOB is need
283 return TRUE;
284}
285
286/**
287 It will build HOBs based on information from bootloaders.
288
289 @param[in] BootloaderParameter The starting memory address of bootloader parameter block.
290 @param[out] DxeFv The pointer to the DXE FV in memory.
291
292 @retval EFI_SUCCESS If it completed successfully.
293 @retval Others If it failed to build required HOBs.
294**/
295EFI_STATUS
296BuildHobs (
297 IN UINTN BootloaderParameter,
298 OUT EFI_FIRMWARE_VOLUME_HEADER **DxeFv
299 )
300{
301 EFI_PEI_HOB_POINTERS Hob;
302 UINTN MinimalNeededSize;
303 EFI_PHYSICAL_ADDRESS FreeMemoryBottom;
304 EFI_PHYSICAL_ADDRESS FreeMemoryTop;
305 EFI_PHYSICAL_ADDRESS MemoryBottom;
306 EFI_PHYSICAL_ADDRESS MemoryTop;
307 EFI_HOB_RESOURCE_DESCRIPTOR *PhitResourceHob;
308 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
309 UNIVERSAL_PAYLOAD_EXTRA_DATA *ExtraData;
310 UINT8 *GuidHob;
311 EFI_HOB_FIRMWARE_VOLUME *FvHob;
312 UNIVERSAL_PAYLOAD_ACPI_TABLE *AcpiTable;
313 ACPI_BOARD_INFO *AcpiBoardInfo;
314 EFI_HOB_HANDOFF_INFO_TABLE *HobInfo;
315 UINT8 Idx;
316
317 Hob.Raw = (UINT8 *)BootloaderParameter;
318 MinimalNeededSize = FixedPcdGet32 (PcdSystemMemoryUefiRegionSize);
319
320 ASSERT (Hob.Raw != NULL);
321 ASSERT ((UINTN)Hob.HandoffInformationTable->EfiFreeMemoryTop == Hob.HandoffInformationTable->EfiFreeMemoryTop);
322 ASSERT ((UINTN)Hob.HandoffInformationTable->EfiMemoryTop == Hob.HandoffInformationTable->EfiMemoryTop);
323 ASSERT ((UINTN)Hob.HandoffInformationTable->EfiFreeMemoryBottom == Hob.HandoffInformationTable->EfiFreeMemoryBottom);
324 ASSERT ((UINTN)Hob.HandoffInformationTable->EfiMemoryBottom == Hob.HandoffInformationTable->EfiMemoryBottom);
325
326 //
327 // Try to find Resource Descriptor HOB that contains Hob range EfiMemoryBottom..EfiMemoryTop
328 //
329 PhitResourceHob = FindResourceDescriptorByRange (Hob.Raw, Hob.HandoffInformationTable->EfiMemoryBottom, Hob.HandoffInformationTable->EfiMemoryTop);
330 if (PhitResourceHob == NULL) {
331 //
332 // Boot loader's Phit Hob is not in an available Resource Descriptor, find another Resource Descriptor for new Phit Hob
333 //
334 ResourceHob = FindAnotherHighestBelow4GResourceDescriptor (Hob.Raw, MinimalNeededSize, NULL);
335 if (ResourceHob == NULL) {
336 return EFI_NOT_FOUND;
337 }
338
339 MemoryBottom = ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MinimalNeededSize;
340 FreeMemoryBottom = MemoryBottom;
341 FreeMemoryTop = ResourceHob->PhysicalStart + ResourceHob->ResourceLength;
342 MemoryTop = FreeMemoryTop;
343 } else if (PhitResourceHob->PhysicalStart + PhitResourceHob->ResourceLength - Hob.HandoffInformationTable->EfiMemoryTop >= MinimalNeededSize) {
344 //
345 // New availiable Memory range in new hob is right above memory top in old hob.
346 //
347 MemoryBottom = Hob.HandoffInformationTable->EfiFreeMemoryTop;
348 FreeMemoryBottom = Hob.HandoffInformationTable->EfiMemoryTop;
349 FreeMemoryTop = FreeMemoryBottom + MinimalNeededSize;
350 MemoryTop = FreeMemoryTop;
351 } else if (Hob.HandoffInformationTable->EfiMemoryBottom - PhitResourceHob->PhysicalStart >= MinimalNeededSize) {
352 //
353 // New availiable Memory range in new hob is right below memory bottom in old hob.
354 //
355 MemoryBottom = Hob.HandoffInformationTable->EfiMemoryBottom - MinimalNeededSize;
356 FreeMemoryBottom = MemoryBottom;
357 FreeMemoryTop = Hob.HandoffInformationTable->EfiMemoryBottom;
358 MemoryTop = Hob.HandoffInformationTable->EfiMemoryTop;
359 } else {
360 //
361 // In the Resource Descriptor HOB contains boot loader Hob, there is no enough free memory size for payload hob
362 // Find another Resource Descriptor Hob
363 //
364 ResourceHob = FindAnotherHighestBelow4GResourceDescriptor (Hob.Raw, MinimalNeededSize, PhitResourceHob);
365 if (ResourceHob == NULL) {
366 return EFI_NOT_FOUND;
367 }
368
369 MemoryBottom = ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MinimalNeededSize;
370 FreeMemoryBottom = MemoryBottom;
371 FreeMemoryTop = ResourceHob->PhysicalStart + ResourceHob->ResourceLength;
372 MemoryTop = FreeMemoryTop;
373 }
374
375 HobInfo = HobConstructor ((VOID *)(UINTN)MemoryBottom, (VOID *)(UINTN)MemoryTop, (VOID *)(UINTN)FreeMemoryBottom, (VOID *)(UINTN)FreeMemoryTop);
376 HobInfo->BootMode = Hob.HandoffInformationTable->BootMode;
377 //
378 // From now on, mHobList will point to the new Hob range.
379 //
380
381 //
382 // Create an empty FvHob for the DXE FV that contains DXE core.
383 //
384 BuildFvHob ((EFI_PHYSICAL_ADDRESS)0, 0);
385 //
386 // Since payload created new Hob, move all hobs except PHIT from boot loader hob list.
387 //
388 while (!END_OF_HOB_LIST (Hob)) {
389 if (IsHobNeed (Hob)) {
390 // Add this hob to payload HOB
391 AddNewHob (&Hob);
392 }
393
394 Hob.Raw = GET_NEXT_HOB (Hob);
395 }
396
397 //
398 // Get DXE FV location
399 //
400 GuidHob = GetFirstGuidHob (&gUniversalPayloadExtraDataGuid);
401 ASSERT (GuidHob != NULL);
402 ExtraData = (UNIVERSAL_PAYLOAD_EXTRA_DATA *)GET_GUID_HOB_DATA (GuidHob);
403 DEBUG ((DEBUG_INFO, "Multiple Fv Count=%d\n", ExtraData->Count));
404 ASSERT (AsciiStrCmp (ExtraData->Entry[0].Identifier, "uefi_fv") == 0);
405
406 *DxeFv = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)ExtraData->Entry[0].Base;
407 ASSERT ((*DxeFv)->FvLength == ExtraData->Entry[0].Size);
408 //
409 // support multiple FVs provided by UPL
410 //
411 for (Idx = 1; Idx < ExtraData->Count; Idx++) {
412 BuildFvHob (ExtraData->Entry[Idx].Base, ExtraData->Entry[Idx].Size);
413 DEBUG ((
414 DEBUG_INFO,
415 "UPL Multiple fv[%d], Base=0x%x, size=0x%x\n",
416 Idx,
417 ExtraData->Entry[Idx].Base,
418 ExtraData->Entry[Idx].Size
419 ));
420 }
421
422 //
423 // Create guid hob for acpi board information
424 //
425 GuidHob = GetFirstGuidHob (&gUniversalPayloadAcpiTableGuid);
426 if (GuidHob != NULL) {
427 AcpiTable = (UNIVERSAL_PAYLOAD_ACPI_TABLE *)GET_GUID_HOB_DATA (GuidHob);
428 GuidHob = GetFirstGuidHob (&gUefiAcpiBoardInfoGuid);
429 if (GuidHob == NULL) {
430 AcpiBoardInfo = BuildHobFromAcpi ((UINT64)AcpiTable->Rsdp);
431 ASSERT (AcpiBoardInfo != NULL);
432 }
433 }
434
435 //
436 // Update DXE FV information to first fv hob in the hob list, which
437 // is the empty FvHob created before.
438 //
439 FvHob = GetFirstHob (EFI_HOB_TYPE_FV);
440 FvHob->BaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)*DxeFv;
441 FvHob->Length = (*DxeFv)->FvLength;
442 return EFI_SUCCESS;
443}
444
445/**
446 Entry point to the C language phase of UEFI payload.
447
448 @param[in] BootloaderParameter The starting address of bootloader parameter block.
449
450 @retval It will not return if SUCCESS, and return error when passing bootloader parameter.
451**/
452EFI_STATUS
453EFIAPI
454_ModuleEntryPoint (
455 IN UINTN BootloaderParameter
456 )
457{
458 EFI_STATUS Status;
459 PHYSICAL_ADDRESS DxeCoreEntryPoint;
460 EFI_PEI_HOB_POINTERS Hob;
461 EFI_FIRMWARE_VOLUME_HEADER *DxeFv;
462
463 mHobList = (VOID *)BootloaderParameter;
464 DxeFv = NULL;
465 // Call constructor for all libraries
466 ProcessLibraryConstructorList ();
467
468 DEBUG ((DEBUG_INFO, "Entering Universal Payload...\n"));
469 DEBUG ((DEBUG_INFO, "sizeof(UINTN) = 0x%x\n", sizeof (UINTN)));
470
471 DEBUG_CODE (
472 //
473 // Dump the Hobs from boot loader
474 //
475 PrintHob (mHobList);
476 );
477
478 // Initialize floating point operating environment to be compliant with UEFI spec.
479 InitializeFloatingPointUnits ();
480
481 // Build HOB based on information from Bootloader
482 Status = BuildHobs (BootloaderParameter, &DxeFv);
483 ASSERT_EFI_ERROR (Status);
484
485 FixUpPcdDatabase (DxeFv);
486 Status = UniversalLoadDxeCore (DxeFv, &DxeCoreEntryPoint);
487 ASSERT_EFI_ERROR (Status);
488
489 //
490 // Mask off all legacy 8259 interrupt sources
491 //
492 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0xFF);
493 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0xFF);
494
495 Hob.HandoffInformationTable = (EFI_HOB_HANDOFF_INFO_TABLE *)GetFirstHob (EFI_HOB_TYPE_HANDOFF);
496 HandOffToDxeCore (DxeCoreEntryPoint, Hob);
497
498 // Should not get here
499 CpuDeadLoop ();
500 return EFI_SUCCESS;
501}
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