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.
70 PeiDatabase
= (PEI_PCD_DATABASE
*) GET_GUID_HOB_DATA (GuidHob
);
71 DEBUG ((DEBUG_INFO
, "Find the Pei PCD data base, the total local token number is %d\n", PeiDatabase
->LocalTokenCount
));
73 Status
= FvFindFileByTypeGuid (DxeFv
, EFI_FV_FILETYPE_DRIVER
, PcdGetPtr (PcdPcdDriverFile
), &FileHeader
);
74 ASSERT_EFI_ERROR (Status
);
75 if (EFI_ERROR (Status
)) {
78 Status
= FileFindSection (FileHeader
, EFI_SECTION_RAW
, &PcdRawData
);
79 ASSERT_EFI_ERROR (Status
);
80 if (EFI_ERROR (Status
)) {
84 UplDatabase
= (PEI_PCD_DATABASE
*) PcdRawData
;
85 ExMapTable
= (DYNAMICEX_MAPPING
*) (UINTN
) ((UINTN
) PcdRawData
+ UplDatabase
->ExMapTableOffset
);
87 for (Index
= 0; Index
< UplDatabase
->ExTokenCount
; Index
++) {
88 ExMapTable
[Index
].TokenNumber
+= PeiDatabase
->LocalTokenCount
;
90 DEBUG ((DEBUG_INFO
, "Fix up UPL PCD database successfully\n"));
97 @param[in] Hob The HOB to be added into the HOB list.
101 IN EFI_PEI_HOB_POINTERS
*Hob
104 EFI_PEI_HOB_POINTERS NewHob
;
106 if (Hob
->Raw
== NULL
) {
109 NewHob
.Header
= CreateHob (Hob
->Header
->HobType
, Hob
->Header
->HobLength
);
111 if (NewHob
.Header
!= NULL
) {
112 CopyMem (NewHob
.Header
+ 1, Hob
->Header
+ 1, Hob
->Header
->HobLength
- sizeof (EFI_HOB_GENERIC_HEADER
));
117 Found the Resource Descriptor HOB that contains a range
119 @param[in] Base Memory start address
120 @param[in] Top Memory Top.
122 @return The pointer to the Resource Descriptor HOB.
124 EFI_HOB_RESOURCE_DESCRIPTOR
*
125 FindResourceDescriptorByRange (
127 EFI_PHYSICAL_ADDRESS Base
,
128 EFI_PHYSICAL_ADDRESS Top
131 EFI_PEI_HOB_POINTERS Hob
;
132 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
134 for (Hob
.Raw
= (UINT8
*) HobList
; !END_OF_HOB_LIST(Hob
); Hob
.Raw
= GET_NEXT_HOB(Hob
)) {
136 // Skip all HOBs except Resource Descriptor HOBs
138 if (GET_HOB_TYPE (Hob
) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
143 // Skip Resource Descriptor HOBs that do not describe tested system memory
145 ResourceHob
= Hob
.ResourceDescriptor
;
146 if (ResourceHob
->ResourceType
!= EFI_RESOURCE_SYSTEM_MEMORY
) {
149 if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) != TESTED_MEMORY_ATTRIBUTES
) {
154 // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
156 if (Base
< ResourceHob
->PhysicalStart
) {
159 if (Top
> (ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
)) {
168 Find the highest below 4G memory resource descriptor, except the input Resource Descriptor.
170 @param[in] HobList Hob start address
171 @param[in] MinimalNeededSize Minimal needed size.
172 @param[in] ExceptResourceHob Ignore this Resource Descriptor.
174 @return The pointer to the Resource Descriptor HOB.
176 EFI_HOB_RESOURCE_DESCRIPTOR
*
177 FindAnotherHighestBelow4GResourceDescriptor (
179 IN UINTN MinimalNeededSize
,
180 IN EFI_HOB_RESOURCE_DESCRIPTOR
*ExceptResourceHob
183 EFI_PEI_HOB_POINTERS Hob
;
184 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
185 EFI_HOB_RESOURCE_DESCRIPTOR
*ReturnResourceHob
;
186 ReturnResourceHob
= NULL
;
188 for (Hob
.Raw
= (UINT8
*) HobList
; !END_OF_HOB_LIST(Hob
); Hob
.Raw
= GET_NEXT_HOB(Hob
)) {
190 // Skip all HOBs except Resource Descriptor HOBs
192 if (GET_HOB_TYPE (Hob
) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
197 // Skip Resource Descriptor HOBs that do not describe tested system memory
199 ResourceHob
= Hob
.ResourceDescriptor
;
200 if (ResourceHob
->ResourceType
!= EFI_RESOURCE_SYSTEM_MEMORY
) {
203 if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) != TESTED_MEMORY_ATTRIBUTES
) {
208 // Skip if the Resource Descriptor HOB equals to ExceptResourceHob
210 if (ResourceHob
== ExceptResourceHob
) {
214 // Skip Resource Descriptor HOBs that are beyond 4G
216 if ((ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
) > BASE_4GB
) {
220 // Skip Resource Descriptor HOBs that are too small
222 if (ResourceHob
->ResourceLength
< MinimalNeededSize
) {
227 // Return the topest Resource Descriptor
229 if (ReturnResourceHob
== NULL
) {
230 ReturnResourceHob
= ResourceHob
;
232 if (ReturnResourceHob
->PhysicalStart
< ResourceHob
->PhysicalStart
) {
233 ReturnResourceHob
= ResourceHob
;
237 return ReturnResourceHob
;
241 It will build HOBs based on information from bootloaders.
243 @retval EFI_SUCCESS If it completed successfully.
244 @retval Others If it failed to build required HOBs.
248 IN UINTN BootloaderParameter
,
249 OUT EFI_FIRMWARE_VOLUME_HEADER
**DxeFv
252 EFI_PEI_HOB_POINTERS Hob
;
253 UINTN MinimalNeededSize
;
254 EFI_PHYSICAL_ADDRESS FreeMemoryBottom
;
255 EFI_PHYSICAL_ADDRESS FreeMemoryTop
;
256 EFI_PHYSICAL_ADDRESS MemoryBottom
;
257 EFI_PHYSICAL_ADDRESS MemoryTop
;
258 EFI_HOB_RESOURCE_DESCRIPTOR
*PhitResourceHob
;
259 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
260 UNIVERSAL_PAYLOAD_EXTRA_DATA
*ExtraData
;
262 EFI_HOB_FIRMWARE_VOLUME
*FvHob
;
264 Hob
.Raw
= (UINT8
*) BootloaderParameter
;
265 MinimalNeededSize
= FixedPcdGet32 (PcdSystemMemoryUefiRegionSize
);
267 ASSERT (Hob
.Raw
!= NULL
);
268 ASSERT ((UINTN
) Hob
.HandoffInformationTable
->EfiFreeMemoryTop
== Hob
.HandoffInformationTable
->EfiFreeMemoryTop
);
269 ASSERT ((UINTN
) Hob
.HandoffInformationTable
->EfiMemoryTop
== Hob
.HandoffInformationTable
->EfiMemoryTop
);
270 ASSERT ((UINTN
) Hob
.HandoffInformationTable
->EfiFreeMemoryBottom
== Hob
.HandoffInformationTable
->EfiFreeMemoryBottom
);
271 ASSERT ((UINTN
) Hob
.HandoffInformationTable
->EfiMemoryBottom
== Hob
.HandoffInformationTable
->EfiMemoryBottom
);
275 // Try to find Resource Descriptor HOB that contains Hob range EfiMemoryBottom..EfiMemoryTop
277 PhitResourceHob
= FindResourceDescriptorByRange(Hob
.Raw
, Hob
.HandoffInformationTable
->EfiMemoryBottom
, Hob
.HandoffInformationTable
->EfiMemoryTop
);
278 if (PhitResourceHob
== NULL
) {
280 // Boot loader's Phit Hob is not in an available Resource Descriptor, find another Resource Descriptor for new Phit Hob
282 ResourceHob
= FindAnotherHighestBelow4GResourceDescriptor(Hob
.Raw
, MinimalNeededSize
, NULL
);
283 if (ResourceHob
== NULL
) {
284 return EFI_NOT_FOUND
;
287 MemoryBottom
= ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
- MinimalNeededSize
;
288 FreeMemoryBottom
= MemoryBottom
;
289 FreeMemoryTop
= ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
;
290 MemoryTop
= FreeMemoryTop
;
291 } else if (PhitResourceHob
->PhysicalStart
+ PhitResourceHob
->ResourceLength
- Hob
.HandoffInformationTable
->EfiMemoryTop
>= MinimalNeededSize
) {
293 // New availiable Memory range in new hob is right above memory top in old hob.
295 MemoryBottom
= Hob
.HandoffInformationTable
->EfiFreeMemoryTop
;
296 FreeMemoryBottom
= Hob
.HandoffInformationTable
->EfiMemoryTop
;
297 FreeMemoryTop
= FreeMemoryBottom
+ MinimalNeededSize
;
298 MemoryTop
= FreeMemoryTop
;
299 } else if (Hob
.HandoffInformationTable
->EfiMemoryBottom
- PhitResourceHob
->PhysicalStart
>= MinimalNeededSize
) {
301 // New availiable Memory range in new hob is right below memory bottom in old hob.
303 MemoryBottom
= Hob
.HandoffInformationTable
->EfiMemoryBottom
- MinimalNeededSize
;
304 FreeMemoryBottom
= MemoryBottom
;
305 FreeMemoryTop
= Hob
.HandoffInformationTable
->EfiMemoryBottom
;
306 MemoryTop
= Hob
.HandoffInformationTable
->EfiMemoryTop
;
309 // In the Resource Descriptor HOB contains boot loader Hob, there is no enough free memory size for payload hob
310 // Find another Resource Descriptor Hob
312 ResourceHob
= FindAnotherHighestBelow4GResourceDescriptor(Hob
.Raw
, MinimalNeededSize
, PhitResourceHob
);
313 if (ResourceHob
== NULL
) {
314 return EFI_NOT_FOUND
;
317 MemoryBottom
= ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
- MinimalNeededSize
;
318 FreeMemoryBottom
= MemoryBottom
;
319 FreeMemoryTop
= ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
;
320 MemoryTop
= FreeMemoryTop
;
322 HobConstructor ((VOID
*) (UINTN
) MemoryBottom
, (VOID
*) (UINTN
) MemoryTop
, (VOID
*) (UINTN
) FreeMemoryBottom
, (VOID
*) (UINTN
) FreeMemoryTop
);
324 // From now on, mHobList will point to the new Hob range.
328 // Create an empty FvHob for the DXE FV that contains DXE core.
330 BuildFvHob ((EFI_PHYSICAL_ADDRESS
) 0, 0);
332 // Since payload created new Hob, move all hobs except PHIT from boot loader hob list.
334 while (!END_OF_HOB_LIST (Hob
)) {
335 if (Hob
.Header
->HobType
!= EFI_HOB_TYPE_HANDOFF
) {
336 // Add this hob to payload HOB
339 Hob
.Raw
= GET_NEXT_HOB (Hob
);
343 // Get DXE FV location
345 GuidHob
= GetFirstGuidHob(&gUniversalPayloadExtraDataGuid
);
346 ASSERT (GuidHob
!= NULL
);
347 ExtraData
= (UNIVERSAL_PAYLOAD_EXTRA_DATA
*) GET_GUID_HOB_DATA (GuidHob
);
348 ASSERT (ExtraData
->Count
== 1);
349 ASSERT (AsciiStrCmp (ExtraData
->Entry
[0].Identifier
, "uefi_fv") == 0);
351 *DxeFv
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) ExtraData
->Entry
[0].Base
;
352 ASSERT ((*DxeFv
)->FvLength
== ExtraData
->Entry
[0].Size
);
355 // Update DXE FV information to first fv hob in the hob list, which
356 // is the empty FvHob created before.
358 FvHob
= GetFirstHob (EFI_HOB_TYPE_FV
);
359 FvHob
->BaseAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) *DxeFv
;
360 FvHob
->Length
= (*DxeFv
)->FvLength
;
365 Entry point to the C language phase of UEFI payload.
367 @retval It will not return if SUCCESS, and return error when passing bootloader parameter.
372 IN UINTN BootloaderParameter
376 PHYSICAL_ADDRESS DxeCoreEntryPoint
;
377 EFI_PEI_HOB_POINTERS Hob
;
378 EFI_FIRMWARE_VOLUME_HEADER
*DxeFv
;
380 mHobList
= (VOID
*) BootloaderParameter
;
382 // Call constructor for all libraries
383 ProcessLibraryConstructorList ();
385 DEBUG ((DEBUG_INFO
, "Entering Universal Payload...\n"));
386 DEBUG ((DEBUG_INFO
, "sizeof(UINTN) = 0x%x\n", sizeof(UINTN
)));
390 // Dump the Hobs from boot loader
395 // Initialize floating point operating environment to be compliant with UEFI spec.
396 InitializeFloatingPointUnits ();
398 // Build HOB based on information from Bootloader
399 Status
= BuildHobs (BootloaderParameter
, &DxeFv
);
400 ASSERT_EFI_ERROR (Status
);
402 FixUpPcdDatabase (DxeFv
);
403 Status
= UniversalLoadDxeCore (DxeFv
, &DxeCoreEntryPoint
);
404 ASSERT_EFI_ERROR (Status
);
407 // Mask off all legacy 8259 interrupt sources
409 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, 0xFF);
410 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, 0xFF);
412 Hob
.HandoffInformationTable
= (EFI_HOB_HANDOFF_INFO_TABLE
*) GetFirstHob(EFI_HOB_TYPE_HANDOFF
);
413 HandOffToDxeCore (DxeCoreEntryPoint
, Hob
);
415 // Should not get here