UniversalPayloadEntry.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  1. /** @file
  2. Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
  3. SPDX-License-Identifier: BSD-2-Clause-Patent
  4. **/
  5. #include "UefiPayloadEntry.h"
  6. #define MEMORY_ATTRIBUTE_MASK (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
  7. EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
  8. EFI_RESOURCE_ATTRIBUTE_TESTED | \
  9. EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED | \
  10. EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED | \
  11. EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED | \
  12. EFI_RESOURCE_ATTRIBUTE_READ_ONLY_PROTECTED | \
  13. EFI_RESOURCE_ATTRIBUTE_16_BIT_IO | \
  14. EFI_RESOURCE_ATTRIBUTE_32_BIT_IO | \
  15. EFI_RESOURCE_ATTRIBUTE_64_BIT_IO | \
  16. EFI_RESOURCE_ATTRIBUTE_PERSISTENT )
  17. #define TESTED_MEMORY_ATTRIBUTES (EFI_RESOURCE_ATTRIBUTE_PRESENT | \
  18. EFI_RESOURCE_ATTRIBUTE_INITIALIZED | \
  19. EFI_RESOURCE_ATTRIBUTE_TESTED )
  20. extern VOID *mHobList;
  21. /**
  22. Print all HOBs info from the HOB list.
  23. @return The pointer to the HOB list.
  24. **/
  25. VOID
  26. PrintHob (
  27. IN CONST VOID *HobStart
  28. );
  29. /**
  30. Some bootloader may pass a pcd database, and UPL also contain a PCD database.
  31. Dxe PCD driver has the assumption that the two PCD database can be catenated and
  32. the local token number should be successive.
  33. 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.
  35. @retval EFI_SUCCESS If it completed successfully.
  36. @retval other Failed to fix up.
  37. **/
  38. EFI_STATUS
  39. FixUpPcdDatabase (
  40. IN EFI_FIRMWARE_VOLUME_HEADER *DxeFv
  41. )
  42. {
  43. EFI_STATUS Status;
  44. EFI_FFS_FILE_HEADER *FileHeader;
  45. VOID *PcdRawData;
  46. PEI_PCD_DATABASE *PeiDatabase;
  47. PEI_PCD_DATABASE *UplDatabase;
  48. EFI_HOB_GUID_TYPE *GuidHob;
  49. DYNAMICEX_MAPPING *ExMapTable;
  50. UINTN Index;
  51. GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid);
  52. if (GuidHob == NULL) {
  53. //
  54. // No fix-up is needed.
  55. //
  56. return EFI_SUCCESS;
  57. }
  58. PeiDatabase = (PEI_PCD_DATABASE *)GET_GUID_HOB_DATA (GuidHob);
  59. DEBUG ((DEBUG_INFO, "Find the Pei PCD data base, the total local token number is %d\n", PeiDatabase->LocalTokenCount));
  60. Status = FvFindFileByTypeGuid (DxeFv, EFI_FV_FILETYPE_DRIVER, PcdGetPtr (PcdPcdDriverFile), &FileHeader);
  61. ASSERT_EFI_ERROR (Status);
  62. if (EFI_ERROR (Status)) {
  63. return Status;
  64. }
  65. Status = FileFindSection (FileHeader, EFI_SECTION_RAW, &PcdRawData);
  66. ASSERT_EFI_ERROR (Status);
  67. if (EFI_ERROR (Status)) {
  68. return Status;
  69. }
  70. UplDatabase = (PEI_PCD_DATABASE *)PcdRawData;
  71. ExMapTable = (DYNAMICEX_MAPPING *)(UINTN)((UINTN)PcdRawData + UplDatabase->ExMapTableOffset);
  72. for (Index = 0; Index < UplDatabase->ExTokenCount; Index++) {
  73. ExMapTable[Index].TokenNumber += PeiDatabase->LocalTokenCount;
  74. }
  75. DEBUG ((DEBUG_INFO, "Fix up UPL PCD database successfully\n"));
  76. return EFI_SUCCESS;
  77. }
  78. /**
  79. Add HOB into HOB list
  80. @param[in] Hob The HOB to be added into the HOB list.
  81. **/
  82. VOID
  83. AddNewHob (
  84. IN EFI_PEI_HOB_POINTERS *Hob
  85. )
  86. {
  87. EFI_PEI_HOB_POINTERS NewHob;
  88. if (Hob->Raw == NULL) {
  89. return;
  90. }
  91. NewHob.Header = CreateHob (Hob->Header->HobType, Hob->Header->HobLength);
  92. if (NewHob.Header != NULL) {
  93. CopyMem (NewHob.Header + 1, Hob->Header + 1, Hob->Header->HobLength - sizeof (EFI_HOB_GENERIC_HEADER));
  94. }
  95. }
  96. /**
  97. Found the Resource Descriptor HOB that contains a range (Base, Top)
  98. @param[in] HobList Hob start address
  99. @param[in] Base Memory start address
  100. @param[in] Top Memory end address.
  101. @retval The pointer to the Resource Descriptor HOB.
  102. **/
  103. EFI_HOB_RESOURCE_DESCRIPTOR *
  104. FindResourceDescriptorByRange (
  105. IN VOID *HobList,
  106. IN EFI_PHYSICAL_ADDRESS Base,
  107. IN EFI_PHYSICAL_ADDRESS Top
  108. )
  109. {
  110. EFI_PEI_HOB_POINTERS Hob;
  111. EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
  112. for (Hob.Raw = (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
  113. //
  114. // Skip all HOBs except Resource Descriptor HOBs
  115. //
  116. if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
  117. continue;
  118. }
  119. //
  120. // Skip Resource Descriptor HOBs that do not describe tested system memory
  121. //
  122. ResourceHob = Hob.ResourceDescriptor;
  123. if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
  124. continue;
  125. }
  126. if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
  127. continue;
  128. }
  129. //
  130. // Skip Resource Descriptor HOBs that do not contain the PHIT range EfiFreeMemoryBottom..EfiFreeMemoryTop
  131. //
  132. if (Base < ResourceHob->PhysicalStart) {
  133. continue;
  134. }
  135. if (Top > (ResourceHob->PhysicalStart + ResourceHob->ResourceLength)) {
  136. continue;
  137. }
  138. return ResourceHob;
  139. }
  140. return NULL;
  141. }
  142. /**
  143. Find the highest below 4G memory resource descriptor, except the input Resource Descriptor.
  144. @param[in] HobList Hob start address
  145. @param[in] MinimalNeededSize Minimal needed size.
  146. @param[in] ExceptResourceHob Ignore this Resource Descriptor.
  147. @retval The pointer to the Resource Descriptor HOB.
  148. **/
  149. EFI_HOB_RESOURCE_DESCRIPTOR *
  150. FindAnotherHighestBelow4GResourceDescriptor (
  151. IN VOID *HobList,
  152. IN UINTN MinimalNeededSize,
  153. IN EFI_HOB_RESOURCE_DESCRIPTOR *ExceptResourceHob
  154. )
  155. {
  156. EFI_PEI_HOB_POINTERS Hob;
  157. EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
  158. EFI_HOB_RESOURCE_DESCRIPTOR *ReturnResourceHob;
  159. ReturnResourceHob = NULL;
  160. for (Hob.Raw = (UINT8 *)HobList; !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
  161. //
  162. // Skip all HOBs except Resource Descriptor HOBs
  163. //
  164. if (GET_HOB_TYPE (Hob) != EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
  165. continue;
  166. }
  167. //
  168. // Skip Resource Descriptor HOBs that do not describe tested system memory
  169. //
  170. ResourceHob = Hob.ResourceDescriptor;
  171. if (ResourceHob->ResourceType != EFI_RESOURCE_SYSTEM_MEMORY) {
  172. continue;
  173. }
  174. if ((ResourceHob->ResourceAttribute & MEMORY_ATTRIBUTE_MASK) != TESTED_MEMORY_ATTRIBUTES) {
  175. continue;
  176. }
  177. //
  178. // Skip if the Resource Descriptor HOB equals to ExceptResourceHob
  179. //
  180. if (ResourceHob == ExceptResourceHob) {
  181. continue;
  182. }
  183. //
  184. // Skip Resource Descriptor HOBs that are beyond 4G
  185. //
  186. if ((ResourceHob->PhysicalStart + ResourceHob->ResourceLength) > BASE_4GB) {
  187. continue;
  188. }
  189. //
  190. // Skip Resource Descriptor HOBs that are too small
  191. //
  192. if (ResourceHob->ResourceLength < MinimalNeededSize) {
  193. continue;
  194. }
  195. //
  196. // Return the topest Resource Descriptor
  197. //
  198. if (ReturnResourceHob == NULL) {
  199. ReturnResourceHob = ResourceHob;
  200. } else {
  201. if (ReturnResourceHob->PhysicalStart < ResourceHob->PhysicalStart) {
  202. ReturnResourceHob = ResourceHob;
  203. }
  204. }
  205. }
  206. return ReturnResourceHob;
  207. }
  208. /**
  209. Check the HOB and decide if it is need inside Payload
  210. Payload maintainer may make decision which HOB is need or needn't
  211. Then add the check logic in the function.
  212. @param[in] Hob The HOB to check
  213. @retval TRUE If HOB is need inside Payload
  214. @retval FALSE If HOB is needn't inside Payload
  215. **/
  216. BOOLEAN
  217. IsHobNeed (
  218. EFI_PEI_HOB_POINTERS Hob
  219. )
  220. {
  221. if (Hob.Header->HobType == EFI_HOB_TYPE_HANDOFF) {
  222. return FALSE;
  223. }
  224. if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
  225. if (CompareGuid (&Hob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
  226. return FALSE;
  227. }
  228. }
  229. // Arrive here mean the HOB is need
  230. return TRUE;
  231. }
  232. /**
  233. It will build HOBs based on information from bootloaders.
  234. @param[in] BootloaderParameter The starting memory address of bootloader parameter block.
  235. @param[out] DxeFv The pointer to the DXE FV in memory.
  236. @retval EFI_SUCCESS If it completed successfully.
  237. @retval Others If it failed to build required HOBs.
  238. **/
  239. EFI_STATUS
  240. BuildHobs (
  241. IN UINTN BootloaderParameter,
  242. OUT EFI_FIRMWARE_VOLUME_HEADER **DxeFv
  243. )
  244. {
  245. EFI_PEI_HOB_POINTERS Hob;
  246. UINTN MinimalNeededSize;
  247. EFI_PHYSICAL_ADDRESS FreeMemoryBottom;
  248. EFI_PHYSICAL_ADDRESS FreeMemoryTop;
  249. EFI_PHYSICAL_ADDRESS MemoryBottom;
  250. EFI_PHYSICAL_ADDRESS MemoryTop;
  251. EFI_HOB_RESOURCE_DESCRIPTOR *PhitResourceHob;
  252. EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
  253. UNIVERSAL_PAYLOAD_EXTRA_DATA *ExtraData;
  254. UINT8 *GuidHob;
  255. EFI_HOB_FIRMWARE_VOLUME *FvHob;
  256. UNIVERSAL_PAYLOAD_ACPI_TABLE *AcpiTable;
  257. ACPI_BOARD_INFO *AcpiBoardInfo;
  258. EFI_HOB_HANDOFF_INFO_TABLE *HobInfo;
  259. UINT8 Idx;
  260. Hob.Raw = (UINT8 *)BootloaderParameter;
  261. MinimalNeededSize = FixedPcdGet32 (PcdSystemMemoryUefiRegionSize);
  262. ASSERT (Hob.Raw != NULL);
  263. ASSERT ((UINTN)Hob.HandoffInformationTable->EfiFreeMemoryTop == Hob.HandoffInformationTable->EfiFreeMemoryTop);
  264. ASSERT ((UINTN)Hob.HandoffInformationTable->EfiMemoryTop == Hob.HandoffInformationTable->EfiMemoryTop);
  265. ASSERT ((UINTN)Hob.HandoffInformationTable->EfiFreeMemoryBottom == Hob.HandoffInformationTable->EfiFreeMemoryBottom);
  266. ASSERT ((UINTN)Hob.HandoffInformationTable->EfiMemoryBottom == Hob.HandoffInformationTable->EfiMemoryBottom);
  267. //
  268. // Try to find Resource Descriptor HOB that contains Hob range EfiMemoryBottom..EfiMemoryTop
  269. //
  270. PhitResourceHob = FindResourceDescriptorByRange (Hob.Raw, Hob.HandoffInformationTable->EfiMemoryBottom, Hob.HandoffInformationTable->EfiMemoryTop);
  271. if (PhitResourceHob == NULL) {
  272. //
  273. // Boot loader's Phit Hob is not in an available Resource Descriptor, find another Resource Descriptor for new Phit Hob
  274. //
  275. ResourceHob = FindAnotherHighestBelow4GResourceDescriptor (Hob.Raw, MinimalNeededSize, NULL);
  276. if (ResourceHob == NULL) {
  277. return EFI_NOT_FOUND;
  278. }
  279. MemoryBottom = ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MinimalNeededSize;
  280. FreeMemoryBottom = MemoryBottom;
  281. FreeMemoryTop = ResourceHob->PhysicalStart + ResourceHob->ResourceLength;
  282. MemoryTop = FreeMemoryTop;
  283. } else if (PhitResourceHob->PhysicalStart + PhitResourceHob->ResourceLength - Hob.HandoffInformationTable->EfiMemoryTop >= MinimalNeededSize) {
  284. //
  285. // New availiable Memory range in new hob is right above memory top in old hob.
  286. //
  287. MemoryBottom = Hob.HandoffInformationTable->EfiFreeMemoryTop;
  288. FreeMemoryBottom = Hob.HandoffInformationTable->EfiMemoryTop;
  289. FreeMemoryTop = FreeMemoryBottom + MinimalNeededSize;
  290. MemoryTop = FreeMemoryTop;
  291. } else if (Hob.HandoffInformationTable->EfiMemoryBottom - PhitResourceHob->PhysicalStart >= MinimalNeededSize) {
  292. //
  293. // New availiable Memory range in new hob is right below memory bottom in old hob.
  294. //
  295. MemoryBottom = Hob.HandoffInformationTable->EfiMemoryBottom - MinimalNeededSize;
  296. FreeMemoryBottom = MemoryBottom;
  297. FreeMemoryTop = Hob.HandoffInformationTable->EfiMemoryBottom;
  298. MemoryTop = Hob.HandoffInformationTable->EfiMemoryTop;
  299. } else {
  300. //
  301. // In the Resource Descriptor HOB contains boot loader Hob, there is no enough free memory size for payload hob
  302. // Find another Resource Descriptor Hob
  303. //
  304. ResourceHob = FindAnotherHighestBelow4GResourceDescriptor (Hob.Raw, MinimalNeededSize, PhitResourceHob);
  305. if (ResourceHob == NULL) {
  306. return EFI_NOT_FOUND;
  307. }
  308. MemoryBottom = ResourceHob->PhysicalStart + ResourceHob->ResourceLength - MinimalNeededSize;
  309. FreeMemoryBottom = MemoryBottom;
  310. FreeMemoryTop = ResourceHob->PhysicalStart + ResourceHob->ResourceLength;
  311. MemoryTop = FreeMemoryTop;
  312. }
  313. HobInfo = HobConstructor ((VOID *)(UINTN)MemoryBottom, (VOID *)(UINTN)MemoryTop, (VOID *)(UINTN)FreeMemoryBottom, (VOID *)(UINTN)FreeMemoryTop);
  314. HobInfo->BootMode = Hob.HandoffInformationTable->BootMode;
  315. //
  316. // From now on, mHobList will point to the new Hob range.
  317. //
  318. //
  319. // Create an empty FvHob for the DXE FV that contains DXE core.
  320. //
  321. BuildFvHob ((EFI_PHYSICAL_ADDRESS)0, 0);
  322. //
  323. // Since payload created new Hob, move all hobs except PHIT from boot loader hob list.
  324. //
  325. while (!END_OF_HOB_LIST (Hob)) {
  326. if (IsHobNeed (Hob)) {
  327. // Add this hob to payload HOB
  328. AddNewHob (&Hob);
  329. }
  330. Hob.Raw = GET_NEXT_HOB (Hob);
  331. }
  332. //
  333. // Get DXE FV location
  334. //
  335. GuidHob = GetFirstGuidHob (&gUniversalPayloadExtraDataGuid);
  336. ASSERT (GuidHob != NULL);
  337. ExtraData = (UNIVERSAL_PAYLOAD_EXTRA_DATA *)GET_GUID_HOB_DATA (GuidHob);
  338. DEBUG ((DEBUG_INFO, "Multiple Fv Count=%d\n", ExtraData->Count));
  339. ASSERT (AsciiStrCmp (ExtraData->Entry[0].Identifier, "uefi_fv") == 0);
  340. *DxeFv = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)ExtraData->Entry[0].Base;
  341. ASSERT ((*DxeFv)->FvLength == ExtraData->Entry[0].Size);
  342. //
  343. // support multiple FVs provided by UPL
  344. //
  345. for (Idx = 1; Idx < ExtraData->Count; Idx++) {
  346. BuildFvHob (ExtraData->Entry[Idx].Base, ExtraData->Entry[Idx].Size);
  347. DEBUG ((
  348. DEBUG_INFO,
  349. "UPL Multiple fv[%d], Base=0x%x, size=0x%x\n",
  350. Idx,
  351. ExtraData->Entry[Idx].Base,
  352. ExtraData->Entry[Idx].Size
  353. ));
  354. }
  355. //
  356. // Create guid hob for acpi board information
  357. //
  358. GuidHob = GetFirstGuidHob (&gUniversalPayloadAcpiTableGuid);
  359. if (GuidHob != NULL) {
  360. AcpiTable = (UNIVERSAL_PAYLOAD_ACPI_TABLE *)GET_GUID_HOB_DATA (GuidHob);
  361. AcpiBoardInfo = BuildHobFromAcpi ((UINT64)AcpiTable->Rsdp);
  362. ASSERT (AcpiBoardInfo != NULL);
  363. }
  364. //
  365. // Update DXE FV information to first fv hob in the hob list, which
  366. // is the empty FvHob created before.
  367. //
  368. FvHob = GetFirstHob (EFI_HOB_TYPE_FV);
  369. FvHob->BaseAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)*DxeFv;
  370. FvHob->Length = (*DxeFv)->FvLength;
  371. return EFI_SUCCESS;
  372. }
  373. /**
  374. Entry point to the C language phase of UEFI payload.
  375. @param[in] BootloaderParameter The starting address of bootloader parameter block.
  376. @retval It will not return if SUCCESS, and return error when passing bootloader parameter.
  377. **/
  378. EFI_STATUS
  379. EFIAPI
  380. _ModuleEntryPoint (
  381. IN UINTN BootloaderParameter
  382. )
  383. {
  384. EFI_STATUS Status;
  385. PHYSICAL_ADDRESS DxeCoreEntryPoint;
  386. EFI_PEI_HOB_POINTERS Hob;
  387. EFI_FIRMWARE_VOLUME_HEADER *DxeFv;
  388. mHobList = (VOID *)BootloaderParameter;
  389. DxeFv = NULL;
  390. // Call constructor for all libraries
  391. ProcessLibraryConstructorList ();
  392. DEBUG ((DEBUG_INFO, "Entering Universal Payload...\n"));
  393. DEBUG ((DEBUG_INFO, "sizeof(UINTN) = 0x%x\n", sizeof (UINTN)));
  394. DEBUG_CODE (
  395. //
  396. // Dump the Hobs from boot loader
  397. //
  398. PrintHob (mHobList);
  399. );
  400. // Initialize floating point operating environment to be compliant with UEFI spec.
  401. InitializeFloatingPointUnits ();
  402. // Build HOB based on information from Bootloader
  403. Status = BuildHobs (BootloaderParameter, &DxeFv);
  404. ASSERT_EFI_ERROR (Status);
  405. FixUpPcdDatabase (DxeFv);
  406. Status = UniversalLoadDxeCore (DxeFv, &DxeCoreEntryPoint);
  407. ASSERT_EFI_ERROR (Status);
  408. //
  409. // Mask off all legacy 8259 interrupt sources
  410. //
  411. IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0xFF);
  412. IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0xFF);
  413. Hob.HandoffInformationTable = (EFI_HOB_HANDOFF_INFO_TABLE *)GetFirstHob (EFI_HOB_TYPE_HANDOFF);
  414. HandOffToDxeCore (DxeCoreEntryPoint, Hob);
  415. // Should not get here
  416. CpuDeadLoop ();
  417. return EFI_SUCCESS;
  418. }