3 Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
4 SPDX-License-Identifier: BSD-2-Clause-Patent
8 #include "UefiPayloadEntry.h"
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 )
22 #define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
23 EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
24 EFI_RESOURCE_ATTRIBUTE_TESTED )
26 extern VOID
*mHobList
;
29 Print all HOBs info from the HOB list.
31 @return The pointer to the HOB list.
35 IN CONST VOID
*HobStart
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.
44 @param[in] DxeFv The FV where to find the Universal PCD database.
46 @retval EFI_SUCCESS If it completed successfully.
47 @retval other Failed to fix up.
51 IN EFI_FIRMWARE_VOLUME_HEADER
*DxeFv
55 EFI_FFS_FILE_HEADER
*FileHeader
;
57 PEI_PCD_DATABASE
*PeiDatabase
;
58 PEI_PCD_DATABASE
*UplDatabase
;
59 EFI_HOB_GUID_TYPE
*GuidHob
;
60 DYNAMICEX_MAPPING
*ExMapTable
;
63 GuidHob
= GetFirstGuidHob (&gPcdDataBaseHobGuid
);
64 if (GuidHob
== NULL
) {
66 // No fix-up is needed.
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
));
74 Status
= FvFindFileByTypeGuid (DxeFv
, EFI_FV_FILETYPE_DRIVER
, PcdGetPtr (PcdPcdDriverFile
), &FileHeader
);
75 ASSERT_EFI_ERROR (Status
);
76 if (EFI_ERROR (Status
)) {
80 Status
= FileFindSection (FileHeader
, EFI_SECTION_RAW
, &PcdRawData
);
81 ASSERT_EFI_ERROR (Status
);
82 if (EFI_ERROR (Status
)) {
86 UplDatabase
= (PEI_PCD_DATABASE
*)PcdRawData
;
87 ExMapTable
= (DYNAMICEX_MAPPING
*)(UINTN
)((UINTN
)PcdRawData
+ UplDatabase
->ExMapTableOffset
);
89 for (Index
= 0; Index
< UplDatabase
->ExTokenCount
; Index
++) {
90 ExMapTable
[Index
].TokenNumber
+= PeiDatabase
->LocalTokenCount
;
93 DEBUG ((DEBUG_INFO
, "Fix up UPL PCD database successfully\n"));
100 @param[in] Hob The HOB to be added into the HOB list.
104 IN EFI_PEI_HOB_POINTERS
*Hob
107 EFI_PEI_HOB_POINTERS NewHob
;
109 if (Hob
->Raw
== NULL
) {
113 NewHob
.Header
= CreateHob (Hob
->Header
->HobType
, Hob
->Header
->HobLength
);
115 if (NewHob
.Header
!= NULL
) {
116 CopyMem (NewHob
.Header
+ 1, Hob
->Header
+ 1, Hob
->Header
->HobLength
- sizeof (EFI_HOB_GENERIC_HEADER
));
121 Found the Resource Descriptor HOB that contains a range (Base, Top)
123 @param[in] HobList Hob start address
124 @param[in] Base Memory start address
125 @param[in] Top Memory end address.
127 @retval The pointer to the Resource Descriptor HOB.
129 EFI_HOB_RESOURCE_DESCRIPTOR
*
130 FindResourceDescriptorByRange (
132 IN EFI_PHYSICAL_ADDRESS Base
,
133 IN EFI_PHYSICAL_ADDRESS Top
136 EFI_PEI_HOB_POINTERS Hob
;
137 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
139 for (Hob
.Raw
= (UINT8
*)HobList
; !END_OF_HOB_LIST (Hob
); Hob
.Raw
= GET_NEXT_HOB (Hob
)) {
141 // Skip all HOBs except Resource Descriptor HOBs
143 if (GET_HOB_TYPE (Hob
) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
148 // Skip Resource Descriptor HOBs that do not describe tested system memory
150 ResourceHob
= Hob
.ResourceDescriptor
;
151 if (ResourceHob
->ResourceType
!= EFI_RESOURCE_SYSTEM_MEMORY
) {
155 if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) != TESTED_MEMORY_ATTRIBUTES
) {
160 // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
162 if (Base
< ResourceHob
->PhysicalStart
) {
166 if (Top
> (ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
)) {
177 Find the highest below 4G memory resource descriptor, except the input Resource Descriptor.
179 @param[in] HobList Hob start address
180 @param[in] MinimalNeededSize Minimal needed size.
181 @param[in] ExceptResourceHob Ignore this Resource Descriptor.
183 @retval The pointer to the Resource Descriptor HOB.
185 EFI_HOB_RESOURCE_DESCRIPTOR
*
186 FindAnotherHighestBelow4GResourceDescriptor (
188 IN UINTN MinimalNeededSize
,
189 IN EFI_HOB_RESOURCE_DESCRIPTOR
*ExceptResourceHob
192 EFI_PEI_HOB_POINTERS Hob
;
193 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
194 EFI_HOB_RESOURCE_DESCRIPTOR
*ReturnResourceHob
;
196 ReturnResourceHob
= NULL
;
198 for (Hob
.Raw
= (UINT8
*)HobList
; !END_OF_HOB_LIST (Hob
); Hob
.Raw
= GET_NEXT_HOB (Hob
)) {
200 // Skip all HOBs except Resource Descriptor HOBs
202 if (GET_HOB_TYPE (Hob
) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
207 // Skip Resource Descriptor HOBs that do not describe tested system memory
209 ResourceHob
= Hob
.ResourceDescriptor
;
210 if (ResourceHob
->ResourceType
!= EFI_RESOURCE_SYSTEM_MEMORY
) {
214 if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) != TESTED_MEMORY_ATTRIBUTES
) {
219 // Skip if the Resource Descriptor HOB equals to ExceptResourceHob
221 if (ResourceHob
== ExceptResourceHob
) {
226 // Skip Resource Descriptor HOBs that are beyond 4G
228 if ((ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
) > BASE_4GB
) {
233 // Skip Resource Descriptor HOBs that are too small
235 if (ResourceHob
->ResourceLength
< MinimalNeededSize
) {
240 // Return the topest Resource Descriptor
242 if (ReturnResourceHob
== NULL
) {
243 ReturnResourceHob
= ResourceHob
;
245 if (ReturnResourceHob
->PhysicalStart
< ResourceHob
->PhysicalStart
) {
246 ReturnResourceHob
= ResourceHob
;
251 return ReturnResourceHob
;
255 Check the HOB and decide if it is need inside Payload
257 Payload maintainer may make decision which HOB is need or needn't
258 Then add the check logic in the function.
260 @param[in] Hob The HOB to check
262 @retval TRUE If HOB is need inside Payload
263 @retval FALSE If HOB is needn't inside Payload
267 EFI_PEI_HOB_POINTERS Hob
270 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_HANDOFF
) {
274 if (Hob
.Header
->HobType
== EFI_HOB_TYPE_MEMORY_ALLOCATION
) {
275 if (CompareGuid (&Hob
.MemoryAllocationModule
->MemoryAllocationHeader
.Name
, &gEfiHobMemoryAllocModuleGuid
)) {
280 // Arrive here mean the HOB is need
285 It will build HOBs based on information from bootloaders.
287 @param[in] BootloaderParameter The starting memory address of bootloader parameter block.
288 @param[out] DxeFv The pointer to the DXE FV in memory.
290 @retval EFI_SUCCESS If it completed successfully.
291 @retval Others If it failed to build required HOBs.
295 IN UINTN BootloaderParameter
,
296 OUT EFI_FIRMWARE_VOLUME_HEADER
**DxeFv
299 EFI_PEI_HOB_POINTERS Hob
;
300 UINTN MinimalNeededSize
;
301 EFI_PHYSICAL_ADDRESS FreeMemoryBottom
;
302 EFI_PHYSICAL_ADDRESS FreeMemoryTop
;
303 EFI_PHYSICAL_ADDRESS MemoryBottom
;
304 EFI_PHYSICAL_ADDRESS MemoryTop
;
305 EFI_HOB_RESOURCE_DESCRIPTOR
*PhitResourceHob
;
306 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
307 UNIVERSAL_PAYLOAD_EXTRA_DATA
*ExtraData
;
309 EFI_HOB_FIRMWARE_VOLUME
*FvHob
;
310 UNIVERSAL_PAYLOAD_ACPI_TABLE
*AcpiTable
;
311 ACPI_BOARD_INFO
*AcpiBoardInfo
;
313 Hob
.Raw
= (UINT8
*)BootloaderParameter
;
314 MinimalNeededSize
= FixedPcdGet32 (PcdSystemMemoryUefiRegionSize
);
316 ASSERT (Hob
.Raw
!= NULL
);
317 ASSERT ((UINTN
)Hob
.HandoffInformationTable
->EfiFreeMemoryTop
== Hob
.HandoffInformationTable
->EfiFreeMemoryTop
);
318 ASSERT ((UINTN
)Hob
.HandoffInformationTable
->EfiMemoryTop
== Hob
.HandoffInformationTable
->EfiMemoryTop
);
319 ASSERT ((UINTN
)Hob
.HandoffInformationTable
->EfiFreeMemoryBottom
== Hob
.HandoffInformationTable
->EfiFreeMemoryBottom
);
320 ASSERT ((UINTN
)Hob
.HandoffInformationTable
->EfiMemoryBottom
== Hob
.HandoffInformationTable
->EfiMemoryBottom
);
323 // Try to find Resource Descriptor HOB that contains Hob range EfiMemoryBottom..EfiMemoryTop
325 PhitResourceHob
= FindResourceDescriptorByRange (Hob
.Raw
, Hob
.HandoffInformationTable
->EfiMemoryBottom
, Hob
.HandoffInformationTable
->EfiMemoryTop
);
326 if (PhitResourceHob
== NULL
) {
328 // Boot loader's Phit Hob is not in an available Resource Descriptor, find another Resource Descriptor for new Phit Hob
330 ResourceHob
= FindAnotherHighestBelow4GResourceDescriptor (Hob
.Raw
, MinimalNeededSize
, NULL
);
331 if (ResourceHob
== NULL
) {
332 return EFI_NOT_FOUND
;
335 MemoryBottom
= ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
- MinimalNeededSize
;
336 FreeMemoryBottom
= MemoryBottom
;
337 FreeMemoryTop
= ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
;
338 MemoryTop
= FreeMemoryTop
;
339 } else if (PhitResourceHob
->PhysicalStart
+ PhitResourceHob
->ResourceLength
- Hob
.HandoffInformationTable
->EfiMemoryTop
>= MinimalNeededSize
) {
341 // New availiable Memory range in new hob is right above memory top in old hob.
343 MemoryBottom
= Hob
.HandoffInformationTable
->EfiFreeMemoryTop
;
344 FreeMemoryBottom
= Hob
.HandoffInformationTable
->EfiMemoryTop
;
345 FreeMemoryTop
= FreeMemoryBottom
+ MinimalNeededSize
;
346 MemoryTop
= FreeMemoryTop
;
347 } else if (Hob
.HandoffInformationTable
->EfiMemoryBottom
- PhitResourceHob
->PhysicalStart
>= MinimalNeededSize
) {
349 // New availiable Memory range in new hob is right below memory bottom in old hob.
351 MemoryBottom
= Hob
.HandoffInformationTable
->EfiMemoryBottom
- MinimalNeededSize
;
352 FreeMemoryBottom
= MemoryBottom
;
353 FreeMemoryTop
= Hob
.HandoffInformationTable
->EfiMemoryBottom
;
354 MemoryTop
= Hob
.HandoffInformationTable
->EfiMemoryTop
;
357 // In the Resource Descriptor HOB contains boot loader Hob, there is no enough free memory size for payload hob
358 // Find another Resource Descriptor Hob
360 ResourceHob
= FindAnotherHighestBelow4GResourceDescriptor (Hob
.Raw
, MinimalNeededSize
, PhitResourceHob
);
361 if (ResourceHob
== NULL
) {
362 return EFI_NOT_FOUND
;
365 MemoryBottom
= ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
- MinimalNeededSize
;
366 FreeMemoryBottom
= MemoryBottom
;
367 FreeMemoryTop
= ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
;
368 MemoryTop
= FreeMemoryTop
;
371 HobConstructor ((VOID
*)(UINTN
)MemoryBottom
, (VOID
*)(UINTN
)MemoryTop
, (VOID
*)(UINTN
)FreeMemoryBottom
, (VOID
*)(UINTN
)FreeMemoryTop
);
373 // From now on, mHobList will point to the new Hob range.
377 // Create an empty FvHob for the DXE FV that contains DXE core.
379 BuildFvHob ((EFI_PHYSICAL_ADDRESS
)0, 0);
381 // Since payload created new Hob, move all hobs except PHIT from boot loader hob list.
383 while (!END_OF_HOB_LIST (Hob
)) {
384 if (IsHobNeed (Hob
)) {
385 // Add this hob to payload HOB
389 Hob
.Raw
= GET_NEXT_HOB (Hob
);
393 // Get DXE FV location
395 GuidHob
= GetFirstGuidHob (&gUniversalPayloadExtraDataGuid
);
396 ASSERT (GuidHob
!= NULL
);
397 ExtraData
= (UNIVERSAL_PAYLOAD_EXTRA_DATA
*)GET_GUID_HOB_DATA (GuidHob
);
398 ASSERT (ExtraData
->Count
== 1);
399 ASSERT (AsciiStrCmp (ExtraData
->Entry
[0].Identifier
, "uefi_fv") == 0);
401 *DxeFv
= (EFI_FIRMWARE_VOLUME_HEADER
*)(UINTN
)ExtraData
->Entry
[0].Base
;
402 ASSERT ((*DxeFv
)->FvLength
== ExtraData
->Entry
[0].Size
);
405 // Create guid hob for acpi board information
407 GuidHob
= GetFirstGuidHob (&gUniversalPayloadAcpiTableGuid
);
408 if (GuidHob
!= NULL
) {
409 AcpiTable
= (UNIVERSAL_PAYLOAD_ACPI_TABLE
*)GET_GUID_HOB_DATA (GuidHob
);
410 AcpiBoardInfo
= BuildHobFromAcpi ((UINT64
)AcpiTable
->Rsdp
);
411 ASSERT (AcpiBoardInfo
!= NULL
);
415 // Update DXE FV information to first fv hob in the hob list, which
416 // is the empty FvHob created before.
418 FvHob
= GetFirstHob (EFI_HOB_TYPE_FV
);
419 FvHob
->BaseAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)*DxeFv
;
420 FvHob
->Length
= (*DxeFv
)->FvLength
;
425 Entry point to the C language phase of UEFI payload.
427 @param[in] BootloaderParameter The starting address of bootloader parameter block.
429 @retval It will not return if SUCCESS, and return error when passing bootloader parameter.
434 IN UINTN BootloaderParameter
438 PHYSICAL_ADDRESS DxeCoreEntryPoint
;
439 EFI_PEI_HOB_POINTERS Hob
;
440 EFI_FIRMWARE_VOLUME_HEADER
*DxeFv
;
442 mHobList
= (VOID
*)BootloaderParameter
;
444 // Call constructor for all libraries
445 ProcessLibraryConstructorList ();
447 DEBUG ((DEBUG_INFO
, "Entering Universal Payload...\n"));
448 DEBUG ((DEBUG_INFO
, "sizeof(UINTN) = 0x%x\n", sizeof (UINTN
)));
452 // Dump the Hobs from boot loader
457 // Initialize floating point operating environment to be compliant with UEFI spec.
458 InitializeFloatingPointUnits ();
460 // Build HOB based on information from Bootloader
461 Status
= BuildHobs (BootloaderParameter
, &DxeFv
);
462 ASSERT_EFI_ERROR (Status
);
464 FixUpPcdDatabase (DxeFv
);
465 Status
= UniversalLoadDxeCore (DxeFv
, &DxeCoreEntryPoint
);
466 ASSERT_EFI_ERROR (Status
);
469 // Mask off all legacy 8259 interrupt sources
471 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, 0xFF);
472 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, 0xFF);
474 Hob
.HandoffInformationTable
= (EFI_HOB_HANDOFF_INFO_TABLE
*)GetFirstHob (EFI_HOB_TYPE_HANDOFF
);
475 HandOffToDxeCore (DxeCoreEntryPoint
, Hob
);
477 // Should not get here