]> git.proxmox.com Git - mirror_edk2.git/blob - UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.c
DynamicTablesPkg: Add support to specify FADT minor revision
[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
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 **/
102 VOID
103 AddNewHob (
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
115 if (NewHob.Header != NULL) {
116 CopyMem (NewHob.Header + 1, Hob->Header + 1, Hob->Header->HobLength - sizeof (EFI_HOB_GENERIC_HEADER));
117 }
118 }
119
120 /**
121 Found the Resource Descriptor HOB that contains a range (Base, Top)
122
123 @param[in] HobList Hob start address
124 @param[in] Base Memory start address
125 @param[in] Top Memory end address.
126
127 @retval The pointer to the Resource Descriptor HOB.
128 **/
129 EFI_HOB_RESOURCE_DESCRIPTOR *
130 FindResourceDescriptorByRange (
131 IN VOID *HobList,
132 IN EFI_PHYSICAL_ADDRESS Base,
133 IN EFI_PHYSICAL_ADDRESS Top
134 )
135 {
136 EFI_PEI_HOB_POINTERS Hob;
137 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
138
139 for (Hob.Raw = (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
140 //
141 // Skip all HOBs except Resource Descriptor HOBs
142 //
143 if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
144 continue;
145 }
146
147 //
148 // Skip Resource Descriptor HOBs that do not describe tested system memory
149 //
150 ResourceHob = Hob.ResourceDescriptor;
151 if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
152 continue;
153 }
154
155 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
156 continue;
157 }
158
159 //
160 // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
161 //
162 if (Base < ResourceHob->PhysicalStart) {
163 continue;
164 }
165
166 if (Top > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) {
167 continue;
168 }
169
170 return ResourceHob;
171 }
172
173 return NULL;
174 }
175
176 /**
177 Find the highest below 4G memory resource descriptor, except the input Resource Descriptor.
178
179 @param[in] HobList Hob start address
180 @param[in] MinimalNeededSize Minimal needed size.
181 @param[in] ExceptResourceHob Ignore this Resource Descriptor.
182
183 @retval The pointer to the Resource Descriptor HOB.
184 **/
185 EFI_HOB_RESOURCE_DESCRIPTOR *
186 FindAnotherHighestBelow4GResourceDescriptor (
187 IN VOID *HobList,
188 IN UINTN MinimalNeededSize,
189 IN EFI_HOB_RESOURCE_DESCRIPTOR *ExceptResourceHob
190 )
191 {
192 EFI_PEI_HOB_POINTERS Hob;
193 EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
194 EFI_HOB_RESOURCE_DESCRIPTOR *ReturnResourceHob;
195
196 ReturnResourceHob = NULL;
197
198 for (Hob.Raw = (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
199 //
200 // Skip all HOBs except Resource Descriptor HOBs
201 //
202 if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
203 continue;
204 }
205
206 //
207 // Skip Resource Descriptor HOBs that do not describe tested system memory
208 //
209 ResourceHob = Hob.ResourceDescriptor;
210 if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
211 continue;
212 }
213
214 if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
215 continue;
216 }
217
218 //
219 // Skip if the Resource Descriptor HOB equals to ExceptResourceHob
220 //
221 if (ResourceHob == ExceptResourceHob) {
222 continue;
223 }
224
225 //
226 // Skip Resource Descriptor HOBs that are beyond 4G
227 //
228 if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > BASE_4GB) {
229 continue;
230 }
231
232 //
233 // Skip Resource Descriptor HOBs that are too small
234 //
235 if (ResourceHob->ResourceLength < MinimalNeededSize) {
236 continue;
237 }
238
239 //
240 // Return the topest Resource Descriptor
241 //
242 if (ReturnResourceHob == NULL) {
243 ReturnResourceHob = ResourceHob;
244 } else {
245 if (ReturnResourceHob->PhysicalStart < ResourceHob->PhysicalStart) {
246 ReturnResourceHob = ResourceHob;
247 }
248 }
249 }
250
251 return ReturnResourceHob;
252 }
253
254 /**
255 Check the HOB and decide if it is need inside Payload
256
257 Payload maintainer may make decision which HOB is need or needn't
258 Then add the check logic in the function.
259
260 @param[in] Hob The HOB to check
261
262 @retval TRUE If HOB is need inside Payload
263 @retval FALSE If HOB is needn't inside Payload
264 **/
265 BOOLEAN
266 IsHobNeed (
267 EFI_PEI_HOB_POINTERS Hob
268 )
269 {
270 if (Hob.Header->HobType == EFI_HOB_TYPE_HANDOFF) {
271 return FALSE;
272 }
273
274 if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
275 if (CompareGuid (&Hob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
276 return FALSE;
277 }
278 }
279
280 // Arrive here mean the HOB is need
281 return TRUE;
282 }
283
284 /**
285 It will build HOBs based on information from bootloaders.
286
287 @param[in] BootloaderParameter The starting memory address of bootloader parameter block.
288 @param[out] DxeFv The pointer to the DXE FV in memory.
289
290 @retval EFI_SUCCESS If it completed successfully.
291 @retval Others If it failed to build required HOBs.
292 **/
293 EFI_STATUS
294 BuildHobs (
295 IN UINTN BootloaderParameter,
296 OUT EFI_FIRMWARE_VOLUME_HEADER **DxeFv
297 )
298 {
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;
308 UINT8 *GuidHob;
309 EFI_HOB_FIRMWARE_VOLUME *FvHob;
310 UNIVERSAL_PAYLOAD_ACPI_TABLE *AcpiTable;
311 ACPI_BOARD_INFO *AcpiBoardInfo;
312
313 Hob.Raw = (UINT8 *)BootloaderParameter;
314 MinimalNeededSize = FixedPcdGet32 (PcdSystemMemoryUefiRegionSize);
315
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);
321
322 //
323 // Try to find Resource Descriptor HOB that contains Hob range EfiMemoryBottom..EfiMemoryTop
324 //
325 PhitResourceHob = FindResourceDescriptorByRange (Hob.Raw, Hob.HandoffInformationTable->EfiMemoryBottom, Hob.HandoffInformationTable->EfiMemoryTop);
326 if (PhitResourceHob == NULL) {
327 //
328 // Boot loader's Phit Hob is not in an available Resource Descriptor, find another Resource Descriptor for new Phit Hob
329 //
330 ResourceHob = FindAnotherHighestBelow4GResourceDescriptor (Hob.Raw, MinimalNeededSize, NULL);
331 if (ResourceHob == NULL) {
332 return EFI_NOT_FOUND;
333 }
334
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) {
340 //
341 // New availiable Memory range in new hob is right above memory top in old hob.
342 //
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) {
348 //
349 // New availiable Memory range in new hob is right below memory bottom in old hob.
350 //
351 MemoryBottom = Hob.HandoffInformationTable->EfiMemoryBottom - MinimalNeededSize;
352 FreeMemoryBottom = MemoryBottom;
353 FreeMemoryTop = Hob.HandoffInformationTable->EfiMemoryBottom;
354 MemoryTop = Hob.HandoffInformationTable->EfiMemoryTop;
355 } else {
356 //
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
359 //
360 ResourceHob = FindAnotherHighestBelow4GResourceDescriptor (Hob.Raw, MinimalNeededSize, PhitResourceHob);
361 if (ResourceHob == NULL) {
362 return EFI_NOT_FOUND;
363 }
364
365 MemoryBottom = ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MinimalNeededSize;
366 FreeMemoryBottom = MemoryBottom;
367 FreeMemoryTop = ResourceHob->PhysicalStart + ResourceHob->ResourceLength;
368 MemoryTop = FreeMemoryTop;
369 }
370
371 HobConstructor ((VOID *)(UINTN)MemoryBottom, (VOID *)(UINTN)MemoryTop, (VOID *)(UINTN)FreeMemoryBottom, (VOID *)(UINTN)FreeMemoryTop);
372 //
373 // From now on, mHobList will point to the new Hob range.
374 //
375
376 //
377 // Create an empty FvHob for the DXE FV that contains DXE core.
378 //
379 BuildFvHob ((EFI_PHYSICAL_ADDRESS)0, 0);
380 //
381 // Since payload created new Hob, move all hobs except PHIT from boot loader hob list.
382 //
383 while (!END_OF_HOB_LIST (Hob)) {
384 if (IsHobNeed (Hob)) {
385 // Add this hob to payload HOB
386 AddNewHob (&Hob);
387 }
388
389 Hob.Raw = GET_NEXT_HOB (Hob);
390 }
391
392 //
393 // Get DXE FV location
394 //
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);
400
401 *DxeFv = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)ExtraData->Entry[0].Base;
402 ASSERT ((*DxeFv)->FvLength == ExtraData->Entry[0].Size);
403
404 //
405 // Create guid hob for acpi board information
406 //
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);
412 }
413
414 //
415 // Update DXE FV information to first fv hob in the hob list, which
416 // is the empty FvHob created before.
417 //
418 FvHob = GetFirstHob (EFI_HOB_TYPE_FV);
419 FvHob->BaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)*DxeFv;
420 FvHob->Length = (*DxeFv)->FvLength;
421 return EFI_SUCCESS;
422 }
423
424 /**
425 Entry point to the C language phase of UEFI payload.
426
427 @param[in] BootloaderParameter The starting address of bootloader parameter block.
428
429 @retval It will not return if SUCCESS, and return error when passing bootloader parameter.
430 **/
431 EFI_STATUS
432 EFIAPI
433 _ModuleEntryPoint (
434 IN UINTN BootloaderParameter
435 )
436 {
437 EFI_STATUS Status;
438 PHYSICAL_ADDRESS DxeCoreEntryPoint;
439 EFI_PEI_HOB_POINTERS Hob;
440 EFI_FIRMWARE_VOLUME_HEADER *DxeFv;
441
442 mHobList = (VOID *)BootloaderParameter;
443 DxeFv = NULL;
444 // Call constructor for all libraries
445 ProcessLibraryConstructorList ();
446
447 DEBUG ((DEBUG_INFO, "Entering Universal Payload...\n"));
448 DEBUG ((DEBUG_INFO, "sizeof(UINTN) = 0x%x\n", sizeof (UINTN)));
449
450 DEBUG_CODE (
451 //
452 // Dump the Hobs from boot loader
453 //
454 PrintHob (mHobList);
455 );
456
457 // Initialize floating point operating environment to be compliant with UEFI spec.
458 InitializeFloatingPointUnits ();
459
460 // Build HOB based on information from Bootloader
461 Status = BuildHobs (BootloaderParameter, &DxeFv);
462 ASSERT_EFI_ERROR (Status);
463
464 FixUpPcdDatabase (DxeFv);
465 Status = UniversalLoadDxeCore (DxeFv, &DxeCoreEntryPoint);
466 ASSERT_EFI_ERROR (Status);
467
468 //
469 // Mask off all legacy 8259 interrupt sources
470 //
471 IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0xFF);
472 IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0xFF);
473
474 Hob.HandoffInformationTable = (EFI_HOB_HANDOFF_INFO_TABLE *)GetFirstHob (EFI_HOB_TYPE_HANDOFF);
475 HandOffToDxeCore (DxeCoreEntryPoint, Hob);
476
477 // Should not get here
478 CpuDeadLoop ();
479 return EFI_SUCCESS;
480 }