]> git.proxmox.com Git - mirror_edk2.git/blob - UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.c
4d1096b323215fdb591a4e1588d127961a42edb6
[mirror_edk2.git] / UefiPayloadPkg / UefiPayloadEntry / UniversalPayloadEntry.c
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
26 extern VOID *mHobList;
27
28 /**
29 Print all HOBs info from the HOB list.
30
31 @return The pointer to the HOB list.
32 **/
33 VOID
34 PrintHob (
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 **/
49 EFI_STATUS
50 FixUpPcdDatabase (
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 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));
72
73 Status = FvFindFileByTypeGuid (DxeFv, EFI_FV_FILETYPE_DRIVER, PcdGetPtr (PcdPcdDriverFile), &FileHeader);
74 ASSERT_EFI_ERROR (Status);
75 if (EFI_ERROR (Status)) {
76 return Status;
77 }
78 Status = FileFindSection (FileHeader, EFI_SECTION_RAW, &PcdRawData);
79 ASSERT_EFI_ERROR (Status);
80 if (EFI_ERROR (Status)) {
81 return Status;
82 }
83
84 UplDatabase = (PEI_PCD_DATABASE *) PcdRawData;
85 ExMapTable = (DYNAMICEX_MAPPING *) (UINTN) ((UINTN) PcdRawData + UplDatabase->ExMapTableOffset);
86
87 for (Index = 0; Index < UplDatabase->ExTokenCount; Index++) {
88 ExMapTable[Index].TokenNumber += PeiDatabase->LocalTokenCount;
89 }
90 DEBUG ((DEBUG_INFO, "Fix up UPL PCD database successfully\n"));
91 return EFI_SUCCESS;
92 }
93
94 /**
95 Add HOB into HOB list
96
97 @param[in] Hob The HOB to be added into the HOB list.
98 **/
99 VOID
100 AddNewHob (
101 IN EFI_PEI_HOB_POINTERS *Hob
102 )
103 {
104 EFI_PEI_HOB_POINTERS NewHob;
105
106 if (Hob->Raw == NULL) {
107 return;
108 }
109 NewHob.Header = CreateHob (Hob->Header->HobType, Hob->Header->HobLength);
110
111 if (NewHob.Header != NULL) {
112 CopyMem (NewHob.Header + 1, Hob->Header + 1, Hob->Header->HobLength - sizeof (EFI_HOB_GENERIC_HEADER));
113 }
114 }
115
116 /**
117 Found the Resource Descriptor HOB that contains a range (Base, Top)
118
119 @param[in] HobList Hob start address
120 @param[in] Base Memory start address
121 @param[in] Top Memory end address.
122
123 @retval The pointer to the Resource Descriptor HOB.
124 **/
125 EFI_HOB_RESOURCE_DESCRIPTOR *
126 FindResourceDescriptorByRange (
127 IN VOID *HobList,
128 IN EFI_PHYSICAL_ADDRESS Base,
129 IN EFI_PHYSICAL_ADDRESS Top
130 )
131 {
132 EFI_PEI_HOB_POINTERS Hob;
133 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
134
135 for (Hob.Raw = (UINT8 *) HobList; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
136 //
137 // Skip all HOBs except Resource Descriptor HOBs
138 //
139 if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
140 continue;
141 }
142
143 //
144 // Skip Resource Descriptor HOBs that do not describe tested system memory
145 //
146 ResourceHob = Hob.ResourceDescriptor;
147 if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
148 continue;
149 }
150 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
151 continue;
152 }
153
154 //
155 // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
156 //
157 if (Base < ResourceHob->PhysicalStart) {
158 continue;
159 }
160 if (Top > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) {
161 continue;
162 }
163 return ResourceHob;
164 }
165 return NULL;
166 }
167
168 /**
169 Find the highest below 4G memory resource descriptor, except the input Resource Descriptor.
170
171 @param[in] HobList Hob start address
172 @param[in] MinimalNeededSize Minimal needed size.
173 @param[in] ExceptResourceHob Ignore this Resource Descriptor.
174
175 @retval The pointer to the Resource Descriptor HOB.
176 **/
177 EFI_HOB_RESOURCE_DESCRIPTOR *
178 FindAnotherHighestBelow4GResourceDescriptor (
179 IN VOID *HobList,
180 IN UINTN MinimalNeededSize,
181 IN EFI_HOB_RESOURCE_DESCRIPTOR *ExceptResourceHob
182 )
183 {
184 EFI_PEI_HOB_POINTERS Hob;
185 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
186 EFI_HOB_RESOURCE_DESCRIPTOR *ReturnResourceHob;
187 ReturnResourceHob = NULL;
188
189 for (Hob.Raw = (UINT8 *) HobList; !END_OF_HOB_LIST(Hob); Hob.Raw = GET_NEXT_HOB(Hob)) {
190 //
191 // Skip all HOBs except Resource Descriptor HOBs
192 //
193 if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
194 continue;
195 }
196
197 //
198 // Skip Resource Descriptor HOBs that do not describe tested system memory
199 //
200 ResourceHob = Hob.ResourceDescriptor;
201 if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
202 continue;
203 }
204 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
205 continue;
206 }
207
208 //
209 // Skip if the Resource Descriptor HOB equals to ExceptResourceHob
210 //
211 if (ResourceHob == ExceptResourceHob) {
212 continue;
213 }
214 //
215 // Skip Resource Descriptor HOBs that are beyond 4G
216 //
217 if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > BASE_4GB) {
218 continue;
219 }
220 //
221 // Skip Resource Descriptor HOBs that are too small
222 //
223 if (ResourceHob->ResourceLength < MinimalNeededSize) {
224 continue;
225 }
226
227 //
228 // Return the topest Resource Descriptor
229 //
230 if (ReturnResourceHob == NULL) {
231 ReturnResourceHob = ResourceHob;
232 } else {
233 if (ReturnResourceHob->PhysicalStart < ResourceHob->PhysicalStart) {
234 ReturnResourceHob = ResourceHob;
235 }
236 }
237 }
238 return ReturnResourceHob;
239 }
240
241 /**
242 It will build HOBs based on information from bootloaders.
243
244 @param[in] BootloaderParameter The starting memory address of bootloader parameter block.
245 @param[out] DxeFv The pointer to the DXE FV in memory.
246
247 @retval EFI_SUCCESS If it completed successfully.
248 @retval Others If it failed to build required HOBs.
249 **/
250 EFI_STATUS
251 BuildHobs (
252 IN UINTN BootloaderParameter,
253 OUT EFI_FIRMWARE_VOLUME_HEADER **DxeFv
254 )
255 {
256 EFI_PEI_HOB_POINTERS Hob;
257 UINTN MinimalNeededSize;
258 EFI_PHYSICAL_ADDRESS FreeMemoryBottom;
259 EFI_PHYSICAL_ADDRESS FreeMemoryTop;
260 EFI_PHYSICAL_ADDRESS MemoryBottom;
261 EFI_PHYSICAL_ADDRESS MemoryTop;
262 EFI_HOB_RESOURCE_DESCRIPTOR *PhitResourceHob;
263 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
264 UNIVERSAL_PAYLOAD_EXTRA_DATA *ExtraData;
265 UINT8 *GuidHob;
266 EFI_HOB_FIRMWARE_VOLUME *FvHob;
267 UNIVERSAL_PAYLOAD_ACPI_TABLE *AcpiTable;
268 ACPI_BOARD_INFO *AcpiBoardInfo;
269
270 Hob.Raw = (UINT8 *) BootloaderParameter;
271 MinimalNeededSize = FixedPcdGet32 (PcdSystemMemoryUefiRegionSize);
272
273 ASSERT (Hob.Raw != NULL);
274 ASSERT ((UINTN) Hob.HandoffInformationTable->EfiFreeMemoryTop == Hob.HandoffInformationTable->EfiFreeMemoryTop);
275 ASSERT ((UINTN) Hob.HandoffInformationTable->EfiMemoryTop == Hob.HandoffInformationTable->EfiMemoryTop);
276 ASSERT ((UINTN) Hob.HandoffInformationTable->EfiFreeMemoryBottom == Hob.HandoffInformationTable->EfiFreeMemoryBottom);
277 ASSERT ((UINTN) Hob.HandoffInformationTable->EfiMemoryBottom == Hob.HandoffInformationTable->EfiMemoryBottom);
278
279
280 //
281 // Try to find Resource Descriptor HOB that contains Hob range EfiMemoryBottom..EfiMemoryTop
282 //
283 PhitResourceHob = FindResourceDescriptorByRange(Hob.Raw, Hob.HandoffInformationTable->EfiMemoryBottom, Hob.HandoffInformationTable->EfiMemoryTop);
284 if (PhitResourceHob == NULL) {
285 //
286 // Boot loader's Phit Hob is not in an available Resource Descriptor, find another Resource Descriptor for new Phit Hob
287 //
288 ResourceHob = FindAnotherHighestBelow4GResourceDescriptor(Hob.Raw, MinimalNeededSize, NULL);
289 if (ResourceHob == NULL) {
290 return EFI_NOT_FOUND;
291 }
292
293 MemoryBottom = ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MinimalNeededSize;
294 FreeMemoryBottom = MemoryBottom;
295 FreeMemoryTop = ResourceHob->PhysicalStart + ResourceHob->ResourceLength;
296 MemoryTop = FreeMemoryTop;
297 } else if (PhitResourceHob->PhysicalStart + PhitResourceHob->ResourceLength - Hob.HandoffInformationTable->EfiMemoryTop >= MinimalNeededSize) {
298 //
299 // New availiable Memory range in new hob is right above memory top in old hob.
300 //
301 MemoryBottom = Hob.HandoffInformationTable->EfiFreeMemoryTop;
302 FreeMemoryBottom = Hob.HandoffInformationTable->EfiMemoryTop;
303 FreeMemoryTop = FreeMemoryBottom + MinimalNeededSize;
304 MemoryTop = FreeMemoryTop;
305 } else if (Hob.HandoffInformationTable->EfiMemoryBottom - PhitResourceHob->PhysicalStart >= MinimalNeededSize) {
306 //
307 // New availiable Memory range in new hob is right below memory bottom in old hob.
308 //
309 MemoryBottom = Hob.HandoffInformationTable->EfiMemoryBottom - MinimalNeededSize;
310 FreeMemoryBottom = MemoryBottom;
311 FreeMemoryTop = Hob.HandoffInformationTable->EfiMemoryBottom;
312 MemoryTop = Hob.HandoffInformationTable->EfiMemoryTop;
313 } else {
314 //
315 // In the Resource Descriptor HOB contains boot loader Hob, there is no enough free memory size for payload hob
316 // Find another Resource Descriptor Hob
317 //
318 ResourceHob = FindAnotherHighestBelow4GResourceDescriptor(Hob.Raw, MinimalNeededSize, PhitResourceHob);
319 if (ResourceHob == NULL) {
320 return EFI_NOT_FOUND;
321 }
322
323 MemoryBottom = ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MinimalNeededSize;
324 FreeMemoryBottom = MemoryBottom;
325 FreeMemoryTop = ResourceHob->PhysicalStart + ResourceHob->ResourceLength;
326 MemoryTop = FreeMemoryTop;
327 }
328 HobConstructor ((VOID *) (UINTN) MemoryBottom, (VOID *) (UINTN) MemoryTop, (VOID *) (UINTN) FreeMemoryBottom, (VOID *) (UINTN) FreeMemoryTop);
329 //
330 // From now on, mHobList will point to the new Hob range.
331 //
332
333 //
334 // Create an empty FvHob for the DXE FV that contains DXE core.
335 //
336 BuildFvHob ((EFI_PHYSICAL_ADDRESS) 0, 0);
337 //
338 // Since payload created new Hob, move all hobs except PHIT from boot loader hob list.
339 //
340 while (!END_OF_HOB_LIST (Hob)) {
341 if (Hob.Header->HobType != EFI_HOB_TYPE_HANDOFF) {
342 // Add this hob to payload HOB
343 AddNewHob (&Hob);
344 }
345 Hob.Raw = GET_NEXT_HOB (Hob);
346 }
347
348 //
349 // Get DXE FV location
350 //
351 GuidHob = GetFirstGuidHob(&gUniversalPayloadExtraDataGuid);
352 ASSERT (GuidHob != NULL);
353 ExtraData = (UNIVERSAL_PAYLOAD_EXTRA_DATA *) GET_GUID_HOB_DATA (GuidHob);
354 ASSERT (ExtraData->Count == 1);
355 ASSERT (AsciiStrCmp (ExtraData->Entry[0].Identifier, "uefi_fv") == 0);
356
357 *DxeFv = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) ExtraData->Entry[0].Base;
358 ASSERT ((*DxeFv)->FvLength == ExtraData->Entry[0].Size);
359
360 //
361 // Create guid hob for acpi board information
362 //
363 GuidHob = GetFirstGuidHob(&gUniversalPayloadAcpiTableGuid);
364 if (GuidHob != NULL) {
365 AcpiTable = (UNIVERSAL_PAYLOAD_ACPI_TABLE *) GET_GUID_HOB_DATA (GuidHob);
366 AcpiBoardInfo = BuildHobFromAcpi ((UINT64)AcpiTable->Rsdp);
367 ASSERT (AcpiBoardInfo != NULL);
368 }
369
370 //
371 // Update DXE FV information to first fv hob in the hob list, which
372 // is the empty FvHob created before.
373 //
374 FvHob = GetFirstHob (EFI_HOB_TYPE_FV);
375 FvHob->BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) *DxeFv;
376 FvHob->Length = (*DxeFv)->FvLength;
377 return EFI_SUCCESS;
378 }
379
380 /**
381 Entry point to the C language phase of UEFI payload.
382
383 @param[in] BootloaderParameter The starting address of bootloader parameter block.
384
385 @retval It will not return if SUCCESS, and return error when passing bootloader parameter.
386 **/
387 EFI_STATUS
388 EFIAPI
389 _ModuleEntryPoint (
390 IN UINTN BootloaderParameter
391 )
392 {
393 EFI_STATUS Status;
394 PHYSICAL_ADDRESS DxeCoreEntryPoint;
395 EFI_PEI_HOB_POINTERS Hob;
396 EFI_FIRMWARE_VOLUME_HEADER *DxeFv;
397
398 mHobList = (VOID *) BootloaderParameter;
399 DxeFv = NULL;
400 // Call constructor for all libraries
401 ProcessLibraryConstructorList ();
402
403 DEBUG ((DEBUG_INFO, "Entering Universal Payload...\n"));
404 DEBUG ((DEBUG_INFO, "sizeof(UINTN) = 0x%x\n", sizeof(UINTN)));
405
406 DEBUG_CODE (
407 //
408 // Dump the Hobs from boot loader
409 //
410 PrintHob (mHobList);
411 );
412
413 // Initialize floating point operating environment to be compliant with UEFI spec.
414 InitializeFloatingPointUnits ();
415
416 // Build HOB based on information from Bootloader
417 Status = BuildHobs (BootloaderParameter, &DxeFv);
418 ASSERT_EFI_ERROR (Status);
419
420 FixUpPcdDatabase (DxeFv);
421 Status = UniversalLoadDxeCore (DxeFv, &DxeCoreEntryPoint);
422 ASSERT_EFI_ERROR (Status);
423
424 //
425 // Mask off all legacy 8259 interrupt sources
426 //
427 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0xFF);
428 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0xFF);
429
430 Hob.HandoffInformationTable = (EFI_HOB_HANDOFF_INFO_TABLE *) GetFirstHob(EFI_HOB_TYPE_HANDOFF);
431 HandOffToDxeCore (DxeCoreEntryPoint, Hob);
432
433 // Should not get here
434 CpuDeadLoop ();
435 return EFI_SUCCESS;
436 }