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 Some bootloader may pass a pcd database, and UPL also contain a PCD database.
30 Dxe PCD driver has the assumption that the two PCD database can be catenated and
31 the local token number should be successive。
32 This function will fix up the UPL PCD database to meet that assumption.
34 @param[in] DxeFv The FV where to find the Universal PCD database.
36 @retval EFI_SUCCESS If it completed successfully.
37 @retval other Failed to fix up.
41 IN EFI_FIRMWARE_VOLUME_HEADER
*DxeFv
45 EFI_FFS_FILE_HEADER
*FileHeader
;
47 PEI_PCD_DATABASE
*PeiDatabase
;
48 PEI_PCD_DATABASE
*UplDatabase
;
49 EFI_HOB_GUID_TYPE
*GuidHob
;
50 DYNAMICEX_MAPPING
*ExMapTable
;
53 GuidHob
= GetFirstGuidHob (&gPcdDataBaseHobGuid
);
54 if (GuidHob
== NULL
) {
56 // No fix-up is needed.
60 PeiDatabase
= (PEI_PCD_DATABASE
*) GET_GUID_HOB_DATA (GuidHob
);
61 DEBUG ((DEBUG_INFO
, "Find the Pei PCD data base, the total local token number is %d\n", PeiDatabase
->LocalTokenCount
));
63 Status
= FvFindFileByTypeGuid (DxeFv
, EFI_FV_FILETYPE_DRIVER
, PcdGetPtr (PcdPcdDriverFile
), &FileHeader
);
64 ASSERT_EFI_ERROR (Status
);
65 if (EFI_ERROR (Status
)) {
68 Status
= FileFindSection (FileHeader
, EFI_SECTION_RAW
, &PcdRawData
);
69 ASSERT_EFI_ERROR (Status
);
70 if (EFI_ERROR (Status
)) {
74 UplDatabase
= (PEI_PCD_DATABASE
*) PcdRawData
;
75 ExMapTable
= (DYNAMICEX_MAPPING
*) (UINTN
) ((UINTN
) PcdRawData
+ UplDatabase
->ExMapTableOffset
);
77 for (Index
= 0; Index
< UplDatabase
->ExTokenCount
; Index
++) {
78 ExMapTable
[Index
].TokenNumber
+= PeiDatabase
->LocalTokenCount
;
80 DEBUG ((DEBUG_INFO
, "Fix up UPL PCD database successfully\n"));
87 @param[in] Hob The HOB to be added into the HOB list.
91 IN EFI_PEI_HOB_POINTERS
*Hob
94 EFI_PEI_HOB_POINTERS NewHob
;
96 if (Hob
->Raw
== NULL
) {
99 NewHob
.Header
= CreateHob (Hob
->Header
->HobType
, Hob
->Header
->HobLength
);
101 if (NewHob
.Header
!= NULL
) {
102 CopyMem (NewHob
.Header
+ 1, Hob
->Header
+ 1, Hob
->Header
->HobLength
- sizeof (EFI_HOB_GENERIC_HEADER
));
107 Found the Resource Descriptor HOB that contains a range
109 @param[in] Base Memory start address
110 @param[in] Top Memory Top.
112 @return The pointer to the Resource Descriptor HOB.
114 EFI_HOB_RESOURCE_DESCRIPTOR
*
115 FindResourceDescriptorByRange (
117 EFI_PHYSICAL_ADDRESS Base
,
118 EFI_PHYSICAL_ADDRESS Top
121 EFI_PEI_HOB_POINTERS Hob
;
122 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
124 for (Hob
.Raw
= (UINT8
*) HobList
; !END_OF_HOB_LIST(Hob
); Hob
.Raw
= GET_NEXT_HOB(Hob
)) {
126 // Skip all HOBs except Resource Descriptor HOBs
128 if (GET_HOB_TYPE (Hob
) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
133 // Skip Resource Descriptor HOBs that do not describe tested system memory
135 ResourceHob
= Hob
.ResourceDescriptor
;
136 if (ResourceHob
->ResourceType
!= EFI_RESOURCE_SYSTEM_MEMORY
) {
139 if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) != TESTED_MEMORY_ATTRIBUTES
) {
144 // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
146 if (Base
< ResourceHob
->PhysicalStart
) {
149 if (Top
> (ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
)) {
158 Find the highest below 4G memory resource descriptor, except the input Resource Descriptor.
160 @param[in] HobList Hob start address
161 @param[in] MinimalNeededSize Minimal needed size.
162 @param[in] ExceptResourceHob Ignore this Resource Descriptor.
164 @return The pointer to the Resource Descriptor HOB.
166 EFI_HOB_RESOURCE_DESCRIPTOR
*
167 FindAnotherHighestBelow4GResourceDescriptor (
169 IN UINTN MinimalNeededSize
,
170 IN EFI_HOB_RESOURCE_DESCRIPTOR
*ExceptResourceHob
173 EFI_PEI_HOB_POINTERS Hob
;
174 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
175 EFI_HOB_RESOURCE_DESCRIPTOR
*ReturnResourceHob
;
176 ReturnResourceHob
= NULL
;
178 for (Hob
.Raw
= (UINT8
*) HobList
; !END_OF_HOB_LIST(Hob
); Hob
.Raw
= GET_NEXT_HOB(Hob
)) {
180 // Skip all HOBs except Resource Descriptor HOBs
182 if (GET_HOB_TYPE (Hob
) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
187 // Skip Resource Descriptor HOBs that do not describe tested system memory
189 ResourceHob
= Hob
.ResourceDescriptor
;
190 if (ResourceHob
->ResourceType
!= EFI_RESOURCE_SYSTEM_MEMORY
) {
193 if ((ResourceHob
->ResourceAttribute
& MEMORY_ATTRIBUTE_MASK
) != TESTED_MEMORY_ATTRIBUTES
) {
198 // Skip if the Resource Descriptor HOB equals to ExceptResourceHob
200 if (ResourceHob
== ExceptResourceHob
) {
204 // Skip Resource Descriptor HOBs that are beyond 4G
206 if ((ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
) > BASE_4GB
) {
210 // Skip Resource Descriptor HOBs that are too small
212 if (ResourceHob
->ResourceLength
< MinimalNeededSize
) {
217 // Return the topest Resource Descriptor
219 if (ReturnResourceHob
== NULL
) {
220 ReturnResourceHob
= ResourceHob
;
222 if (ReturnResourceHob
->PhysicalStart
< ResourceHob
->PhysicalStart
) {
223 ReturnResourceHob
= ResourceHob
;
227 return ReturnResourceHob
;
231 It will build HOBs based on information from bootloaders.
233 @retval EFI_SUCCESS If it completed successfully.
234 @retval Others If it failed to build required HOBs.
238 IN UINTN BootloaderParameter
,
239 OUT EFI_FIRMWARE_VOLUME_HEADER
**DxeFv
242 EFI_PEI_HOB_POINTERS Hob
;
243 UINTN MinimalNeededSize
;
244 EFI_PHYSICAL_ADDRESS FreeMemoryBottom
;
245 EFI_PHYSICAL_ADDRESS FreeMemoryTop
;
246 EFI_PHYSICAL_ADDRESS MemoryBottom
;
247 EFI_PHYSICAL_ADDRESS MemoryTop
;
248 EFI_HOB_RESOURCE_DESCRIPTOR
*PhitResourceHob
;
249 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
250 UNIVERSAL_PAYLOAD_EXTRA_DATA
*ExtraData
;
252 EFI_HOB_FIRMWARE_VOLUME
*FvHob
;
254 Hob
.Raw
= (UINT8
*) BootloaderParameter
;
255 MinimalNeededSize
= FixedPcdGet32 (PcdSystemMemoryUefiRegionSize
);
257 ASSERT (Hob
.Raw
!= NULL
);
258 ASSERT ((UINTN
) Hob
.HandoffInformationTable
->EfiFreeMemoryTop
== Hob
.HandoffInformationTable
->EfiFreeMemoryTop
);
259 ASSERT ((UINTN
) Hob
.HandoffInformationTable
->EfiMemoryTop
== Hob
.HandoffInformationTable
->EfiMemoryTop
);
260 ASSERT ((UINTN
) Hob
.HandoffInformationTable
->EfiFreeMemoryBottom
== Hob
.HandoffInformationTable
->EfiFreeMemoryBottom
);
261 ASSERT ((UINTN
) Hob
.HandoffInformationTable
->EfiMemoryBottom
== Hob
.HandoffInformationTable
->EfiMemoryBottom
);
265 // Try to find Resource Descriptor HOB that contains Hob range EfiMemoryBottom..EfiMemoryTop
267 PhitResourceHob
= FindResourceDescriptorByRange(Hob
.Raw
, Hob
.HandoffInformationTable
->EfiMemoryBottom
, Hob
.HandoffInformationTable
->EfiMemoryTop
);
268 if (PhitResourceHob
== NULL
) {
270 // Boot loader's Phit Hob is not in an available Resource Descriptor, find another Resource Descriptor for new Phit Hob
272 ResourceHob
= FindAnotherHighestBelow4GResourceDescriptor(Hob
.Raw
, MinimalNeededSize
, NULL
);
273 if (ResourceHob
== NULL
) {
274 return EFI_NOT_FOUND
;
277 MemoryBottom
= ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
- MinimalNeededSize
;
278 FreeMemoryBottom
= MemoryBottom
;
279 FreeMemoryTop
= ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
;
280 MemoryTop
= FreeMemoryTop
;
281 } else if (PhitResourceHob
->PhysicalStart
+ PhitResourceHob
->ResourceLength
- Hob
.HandoffInformationTable
->EfiMemoryTop
>= MinimalNeededSize
) {
283 // New availiable Memory range in new hob is right above memory top in old hob.
285 MemoryBottom
= Hob
.HandoffInformationTable
->EfiFreeMemoryTop
;
286 FreeMemoryBottom
= Hob
.HandoffInformationTable
->EfiMemoryTop
;
287 FreeMemoryTop
= FreeMemoryBottom
+ MinimalNeededSize
;
288 MemoryTop
= FreeMemoryTop
;
289 } else if (Hob
.HandoffInformationTable
->EfiMemoryBottom
- PhitResourceHob
->PhysicalStart
>= MinimalNeededSize
) {
291 // New availiable Memory range in new hob is right below memory bottom in old hob.
293 MemoryBottom
= Hob
.HandoffInformationTable
->EfiMemoryBottom
- MinimalNeededSize
;
294 FreeMemoryBottom
= MemoryBottom
;
295 FreeMemoryTop
= Hob
.HandoffInformationTable
->EfiMemoryBottom
;
296 MemoryTop
= Hob
.HandoffInformationTable
->EfiMemoryTop
;
299 // In the Resource Descriptor HOB contains boot loader Hob, there is no enough free memory size for payload hob
300 // Find another Resource Descriptor Hob
302 ResourceHob
= FindAnotherHighestBelow4GResourceDescriptor(Hob
.Raw
, MinimalNeededSize
, PhitResourceHob
);
303 if (ResourceHob
== NULL
) {
304 return EFI_NOT_FOUND
;
307 MemoryBottom
= ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
- MinimalNeededSize
;
308 FreeMemoryBottom
= MemoryBottom
;
309 FreeMemoryTop
= ResourceHob
->PhysicalStart
+ ResourceHob
->ResourceLength
;
310 MemoryTop
= FreeMemoryTop
;
312 HobConstructor ((VOID
*) (UINTN
) MemoryBottom
, (VOID
*) (UINTN
) MemoryTop
, (VOID
*) (UINTN
) FreeMemoryBottom
, (VOID
*) (UINTN
) FreeMemoryTop
);
314 // From now on, mHobList will point to the new Hob range.
318 // Create an empty FvHob for the DXE FV that contains DXE core.
320 BuildFvHob ((EFI_PHYSICAL_ADDRESS
) 0, 0);
322 // Since payload created new Hob, move all hobs except PHIT from boot loader hob list.
324 while (!END_OF_HOB_LIST (Hob
)) {
325 if (Hob
.Header
->HobType
!= EFI_HOB_TYPE_HANDOFF
) {
326 // Add this hob to payload HOB
329 Hob
.Raw
= GET_NEXT_HOB (Hob
);
333 // Get DXE FV location
335 GuidHob
= GetFirstGuidHob(&gUniversalPayloadExtraDataGuid
);
336 ASSERT (GuidHob
!= NULL
);
337 ExtraData
= (UNIVERSAL_PAYLOAD_EXTRA_DATA
*) GET_GUID_HOB_DATA (GuidHob
);
338 ASSERT (ExtraData
->Count
== 1);
339 ASSERT (AsciiStrCmp (ExtraData
->Entry
[0].Identifier
, "uefi_fv") == 0);
341 *DxeFv
= (EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) ExtraData
->Entry
[0].Base
;
342 ASSERT ((*DxeFv
)->FvLength
== ExtraData
->Entry
[0].Size
);
345 // Update DXE FV information to first fv hob in the hob list, which
346 // is the empty FvHob created before.
348 FvHob
= GetFirstHob (EFI_HOB_TYPE_FV
);
349 FvHob
->BaseAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) *DxeFv
;
350 FvHob
->Length
= (*DxeFv
)->FvLength
;
355 Entry point to the C language phase of UEFI payload.
357 @retval It will not return if SUCCESS, and return error when passing bootloader parameter.
362 IN UINTN BootloaderParameter
366 PHYSICAL_ADDRESS DxeCoreEntryPoint
;
367 EFI_PEI_HOB_POINTERS Hob
;
368 EFI_FIRMWARE_VOLUME_HEADER
*DxeFv
;
370 mHobList
= (VOID
*) BootloaderParameter
;
372 // Call constructor for all libraries
373 ProcessLibraryConstructorList ();
375 DEBUG ((DEBUG_INFO
, "Entering Universal Payload...\n"));
376 DEBUG ((DEBUG_INFO
, "sizeof(UINTN) = 0x%x\n", sizeof(UINTN
)));
378 // Initialize floating point operating environment to be compliant with UEFI spec.
379 InitializeFloatingPointUnits ();
381 // Build HOB based on information from Bootloader
382 Status
= BuildHobs (BootloaderParameter
, &DxeFv
);
383 ASSERT_EFI_ERROR (Status
);
385 FixUpPcdDatabase (DxeFv
);
386 Status
= UniversalLoadDxeCore (DxeFv
, &DxeCoreEntryPoint
);
387 ASSERT_EFI_ERROR (Status
);
390 // Mask off all legacy 8259 interrupt sources
392 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER
, 0xFF);
393 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE
, 0xFF);
395 Hob
.HandoffInformationTable
= (EFI_HOB_HANDOFF_INFO_TABLE
*) GetFirstHob(EFI_HOB_TYPE_HANDOFF
);
396 HandOffToDxeCore (DxeCoreEntryPoint
, Hob
);
398 // Should not get here