UefiPayloadEntry.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. /** @file
  2. Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>
  3. SPDX-License-Identifier: BSD-2-Clause-Patent
  4. **/
  5. #include <Guid/MemoryTypeInformation.h>
  6. #include "UefiPayloadEntry.h"
  7. STATIC UINT32 mTopOfLowerUsableDram = 0;
  8. EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = {
  9. { EfiACPIReclaimMemory, FixedPcdGet32 (PcdMemoryTypeEfiACPIReclaimMemory) },
  10. { EfiACPIMemoryNVS, FixedPcdGet32 (PcdMemoryTypeEfiACPIMemoryNVS) },
  11. { EfiReservedMemoryType, FixedPcdGet32 (PcdMemoryTypeEfiReservedMemoryType) },
  12. { EfiRuntimeServicesData, FixedPcdGet32 (PcdMemoryTypeEfiRuntimeServicesData) },
  13. { EfiRuntimeServicesCode, FixedPcdGet32 (PcdMemoryTypeEfiRuntimeServicesCode) },
  14. { EfiMaxMemoryType, 0 }
  15. };
  16. /**
  17. Function to reserve memory below 4GB for EDKII Modules.
  18. This causes the DXE to dispatch everything under 4GB and allows Operating
  19. System's that require EFI_LOADED_IMAGE to be under 4GB to start.
  20. e.g. Xen hypervisor used in Qubes.
  21. **/
  22. VOID
  23. ForceModulesBelow4G (
  24. VOID
  25. )
  26. {
  27. DEBUG ((DEBUG_INFO, "Building hob to restrict memory resorces to below 4G.\n"));
  28. //
  29. // Create Memory Type Information HOB
  30. //
  31. BuildGuidDataHob (
  32. &gEfiMemoryTypeInformationGuid,
  33. mDefaultMemoryTypeInformation,
  34. sizeof (mDefaultMemoryTypeInformation)
  35. );
  36. }
  37. /**
  38. Callback function to build resource descriptor HOB
  39. This function build a HOB based on the memory map entry info.
  40. It creates only EFI_RESOURCE_MEMORY_MAPPED_IO and EFI_RESOURCE_MEMORY_RESERVED
  41. resources.
  42. @param MemoryMapEntry Memory map entry info got from bootloader.
  43. @param Params A pointer to ACPI_BOARD_INFO.
  44. @retval EFI_SUCCESS Successfully build a HOB.
  45. @retval EFI_INVALID_PARAMETER Invalid parameter provided.
  46. **/
  47. EFI_STATUS
  48. MemInfoCallbackMmio (
  49. IN MEMORY_MAP_ENTRY *MemoryMapEntry,
  50. IN VOID *Params
  51. )
  52. {
  53. EFI_PHYSICAL_ADDRESS Base;
  54. EFI_RESOURCE_TYPE Type;
  55. UINT64 Size;
  56. EFI_RESOURCE_ATTRIBUTE_TYPE Attribue;
  57. ACPI_BOARD_INFO *AcpiBoardInfo;
  58. AcpiBoardInfo = (ACPI_BOARD_INFO *)Params;
  59. if (AcpiBoardInfo == NULL) {
  60. return EFI_INVALID_PARAMETER;
  61. }
  62. //
  63. // Skip types already handled in MemInfoCallback
  64. //
  65. if ((MemoryMapEntry->Type == E820_RAM) || (MemoryMapEntry->Type == E820_ACPI)) {
  66. return EFI_SUCCESS;
  67. }
  68. if (MemoryMapEntry->Base == AcpiBoardInfo->PcieBaseAddress) {
  69. //
  70. // MMCONF is always MMIO
  71. //
  72. Type = EFI_RESOURCE_MEMORY_MAPPED_IO;
  73. } else if (MemoryMapEntry->Base < mTopOfLowerUsableDram) {
  74. //
  75. // It's in DRAM and thus must be reserved
  76. //
  77. Type = EFI_RESOURCE_MEMORY_RESERVED;
  78. } else if ((MemoryMapEntry->Base < 0x100000000ULL) && (MemoryMapEntry->Base >= mTopOfLowerUsableDram)) {
  79. //
  80. // It's not in DRAM, must be MMIO
  81. //
  82. Type = EFI_RESOURCE_MEMORY_MAPPED_IO;
  83. } else {
  84. Type = EFI_RESOURCE_MEMORY_RESERVED;
  85. }
  86. Base = MemoryMapEntry->Base;
  87. Size = MemoryMapEntry->Size;
  88. Attribue = EFI_RESOURCE_ATTRIBUTE_PRESENT |
  89. EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
  90. EFI_RESOURCE_ATTRIBUTE_TESTED |
  91. EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
  92. EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
  93. EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
  94. EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE;
  95. BuildResourceDescriptorHob (Type, Attribue, (EFI_PHYSICAL_ADDRESS)Base, Size);
  96. DEBUG ((DEBUG_INFO, "buildhob: base = 0x%lx, size = 0x%lx, type = 0x%x\n", Base, Size, Type));
  97. if ((MemoryMapEntry->Type == E820_UNUSABLE) ||
  98. (MemoryMapEntry->Type == E820_DISABLED))
  99. {
  100. BuildMemoryAllocationHob (Base, Size, EfiUnusableMemory);
  101. } else if (MemoryMapEntry->Type == E820_PMEM) {
  102. BuildMemoryAllocationHob (Base, Size, EfiPersistentMemory);
  103. }
  104. return EFI_SUCCESS;
  105. }
  106. /**
  107. Callback function to find TOLUD (Top of Lower Usable DRAM)
  108. Estimate where TOLUD (Top of Lower Usable DRAM) resides. The exact position
  109. would require platform specific code.
  110. @param MemoryMapEntry Memory map entry info got from bootloader.
  111. @param Params Not used for now.
  112. @retval EFI_SUCCESS Successfully updated mTopOfLowerUsableDram.
  113. **/
  114. EFI_STATUS
  115. FindToludCallback (
  116. IN MEMORY_MAP_ENTRY *MemoryMapEntry,
  117. IN VOID *Params
  118. )
  119. {
  120. //
  121. // This code assumes that the memory map on this x86 machine below 4GiB is continous
  122. // until TOLUD. In addition it assumes that the bootloader provided memory tables have
  123. // no "holes" and thus the first memory range not covered by e820 marks the end of
  124. // usable DRAM. In addition it's assumed that every reserved memory region touching
  125. // usable RAM is also covering DRAM, everything else that is marked reserved thus must be
  126. // MMIO not detectable by bootloader/OS
  127. //
  128. //
  129. // Skip memory types not RAM or reserved
  130. //
  131. if ((MemoryMapEntry->Type == E820_UNUSABLE) || (MemoryMapEntry->Type == E820_DISABLED) ||
  132. (MemoryMapEntry->Type == E820_PMEM))
  133. {
  134. return EFI_SUCCESS;
  135. }
  136. //
  137. // Skip resources above 4GiB
  138. //
  139. if ((MemoryMapEntry->Base + MemoryMapEntry->Size) > 0x100000000ULL) {
  140. return EFI_SUCCESS;
  141. }
  142. if ((MemoryMapEntry->Type == E820_RAM) || (MemoryMapEntry->Type == E820_ACPI) ||
  143. (MemoryMapEntry->Type == E820_NVS))
  144. {
  145. //
  146. // It's usable DRAM. Update TOLUD.
  147. //
  148. if (mTopOfLowerUsableDram < (MemoryMapEntry->Base + MemoryMapEntry->Size)) {
  149. mTopOfLowerUsableDram = (UINT32)(MemoryMapEntry->Base + MemoryMapEntry->Size);
  150. }
  151. } else {
  152. //
  153. // It might be 'reserved DRAM' or 'MMIO'.
  154. //
  155. // If it touches usable DRAM at Base assume it's DRAM as well,
  156. // as it could be bootloader installed tables, TSEG, GTT, ...
  157. //
  158. if (mTopOfLowerUsableDram == MemoryMapEntry->Base) {
  159. mTopOfLowerUsableDram = (UINT32)(MemoryMapEntry->Base + MemoryMapEntry->Size);
  160. }
  161. }
  162. return EFI_SUCCESS;
  163. }
  164. /**
  165. Callback function to build resource descriptor HOB
  166. This function build a HOB based on the memory map entry info.
  167. Only add EFI_RESOURCE_SYSTEM_MEMORY.
  168. @param MemoryMapEntry Memory map entry info got from bootloader.
  169. @param Params Not used for now.
  170. @retval RETURN_SUCCESS Successfully build a HOB.
  171. **/
  172. EFI_STATUS
  173. MemInfoCallback (
  174. IN MEMORY_MAP_ENTRY *MemoryMapEntry,
  175. IN VOID *Params
  176. )
  177. {
  178. EFI_PHYSICAL_ADDRESS Base;
  179. EFI_RESOURCE_TYPE Type;
  180. UINT64 Size;
  181. EFI_RESOURCE_ATTRIBUTE_TYPE Attribue;
  182. //
  183. // Skip everything not known to be usable DRAM.
  184. // It will be added later.
  185. //
  186. if ((MemoryMapEntry->Type != E820_RAM) && (MemoryMapEntry->Type != E820_ACPI) &&
  187. (MemoryMapEntry->Type != E820_NVS))
  188. {
  189. return RETURN_SUCCESS;
  190. }
  191. Type = EFI_RESOURCE_SYSTEM_MEMORY;
  192. Base = MemoryMapEntry->Base;
  193. Size = MemoryMapEntry->Size;
  194. Attribue = EFI_RESOURCE_ATTRIBUTE_PRESENT |
  195. EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
  196. EFI_RESOURCE_ATTRIBUTE_TESTED |
  197. EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
  198. EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
  199. EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
  200. EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE;
  201. BuildResourceDescriptorHob (Type, Attribue, (EFI_PHYSICAL_ADDRESS)Base, Size);
  202. DEBUG ((DEBUG_INFO, "buildhob: base = 0x%lx, size = 0x%lx, type = 0x%x\n", Base, Size, Type));
  203. if (MemoryMapEntry->Type == E820_ACPI) {
  204. BuildMemoryAllocationHob (Base, Size, EfiACPIReclaimMemory);
  205. } else if (MemoryMapEntry->Type == E820_NVS) {
  206. BuildMemoryAllocationHob (Base, Size, EfiACPIMemoryNVS);
  207. }
  208. return RETURN_SUCCESS;
  209. }
  210. /**
  211. It will build HOBs based on information from bootloaders.
  212. @retval EFI_SUCCESS If it completed successfully.
  213. @retval Others If it failed to build required HOBs.
  214. **/
  215. EFI_STATUS
  216. BuildHobFromBl (
  217. VOID
  218. )
  219. {
  220. EFI_STATUS Status;
  221. ACPI_BOARD_INFO *AcpiBoardInfo;
  222. EFI_PEI_GRAPHICS_INFO_HOB GfxInfo;
  223. EFI_PEI_GRAPHICS_INFO_HOB *NewGfxInfo;
  224. EFI_PEI_GRAPHICS_DEVICE_INFO_HOB GfxDeviceInfo;
  225. EFI_PEI_GRAPHICS_DEVICE_INFO_HOB *NewGfxDeviceInfo;
  226. UNIVERSAL_PAYLOAD_SMBIOS_TABLE *SmBiosTableHob;
  227. UNIVERSAL_PAYLOAD_ACPI_TABLE *AcpiTableHob;
  228. //
  229. // First find TOLUD
  230. //
  231. DEBUG ((DEBUG_INFO, "Guessing Top of Lower Usable DRAM:\n"));
  232. Status = ParseMemoryInfo (FindToludCallback, NULL);
  233. if (EFI_ERROR (Status)) {
  234. return Status;
  235. }
  236. DEBUG ((DEBUG_INFO, "Assuming TOLUD = 0x%x\n", mTopOfLowerUsableDram));
  237. //
  238. // Parse memory info and build memory HOBs for Usable RAM
  239. //
  240. DEBUG ((DEBUG_INFO, "Building ResourceDescriptorHobs for usable memory:\n"));
  241. Status = ParseMemoryInfo (MemInfoCallback, NULL);
  242. if (EFI_ERROR (Status)) {
  243. return Status;
  244. }
  245. //
  246. // Create guid hob for frame buffer information
  247. //
  248. Status = ParseGfxInfo (&GfxInfo);
  249. if (!EFI_ERROR (Status)) {
  250. NewGfxInfo = BuildGuidHob (&gEfiGraphicsInfoHobGuid, sizeof (GfxInfo));
  251. ASSERT (NewGfxInfo != NULL);
  252. CopyMem (NewGfxInfo, &GfxInfo, sizeof (GfxInfo));
  253. DEBUG ((DEBUG_INFO, "Created graphics info hob\n"));
  254. }
  255. Status = ParseGfxDeviceInfo (&GfxDeviceInfo);
  256. if (!EFI_ERROR (Status)) {
  257. NewGfxDeviceInfo = BuildGuidHob (&gEfiGraphicsDeviceInfoHobGuid, sizeof (GfxDeviceInfo));
  258. ASSERT (NewGfxDeviceInfo != NULL);
  259. CopyMem (NewGfxDeviceInfo, &GfxDeviceInfo, sizeof (GfxDeviceInfo));
  260. DEBUG ((DEBUG_INFO, "Created graphics device info hob\n"));
  261. }
  262. //
  263. // Creat SmBios table Hob
  264. //
  265. SmBiosTableHob = BuildGuidHob (&gUniversalPayloadSmbiosTableGuid, sizeof (UNIVERSAL_PAYLOAD_SMBIOS_TABLE));
  266. ASSERT (SmBiosTableHob != NULL);
  267. SmBiosTableHob->Header.Revision = UNIVERSAL_PAYLOAD_SMBIOS_TABLE_REVISION;
  268. SmBiosTableHob->Header.Length = sizeof (UNIVERSAL_PAYLOAD_SMBIOS_TABLE);
  269. DEBUG ((DEBUG_INFO, "Create smbios table gUniversalPayloadSmbiosTableGuid guid hob\n"));
  270. Status = ParseSmbiosTable (SmBiosTableHob);
  271. if (!EFI_ERROR (Status)) {
  272. DEBUG ((DEBUG_INFO, "Detected Smbios Table at 0x%lx\n", SmBiosTableHob->SmBiosEntryPoint));
  273. }
  274. //
  275. // Creat ACPI table Hob
  276. //
  277. AcpiTableHob = BuildGuidHob (&gUniversalPayloadAcpiTableGuid, sizeof (UNIVERSAL_PAYLOAD_ACPI_TABLE));
  278. ASSERT (AcpiTableHob != NULL);
  279. AcpiTableHob->Header.Revision = UNIVERSAL_PAYLOAD_ACPI_TABLE_REVISION;
  280. AcpiTableHob->Header.Length = sizeof (UNIVERSAL_PAYLOAD_ACPI_TABLE);
  281. DEBUG ((DEBUG_INFO, "Create ACPI table gUniversalPayloadAcpiTableGuid guid hob\n"));
  282. Status = ParseAcpiTableInfo (AcpiTableHob);
  283. if (!EFI_ERROR (Status)) {
  284. DEBUG ((DEBUG_INFO, "Detected ACPI Table at 0x%lx\n", AcpiTableHob->Rsdp));
  285. }
  286. //
  287. // Create guid hob for acpi board information
  288. //
  289. AcpiBoardInfo = BuildHobFromAcpi (AcpiTableHob->Rsdp);
  290. ASSERT (AcpiBoardInfo != NULL);
  291. //
  292. // Parse memory info and build memory HOBs for reserved DRAM and MMIO
  293. //
  294. DEBUG ((DEBUG_INFO, "Building ResourceDescriptorHobs for reserved memory:\n"));
  295. Status = ParseMemoryInfo (MemInfoCallbackMmio, AcpiBoardInfo);
  296. if (EFI_ERROR (Status)) {
  297. return Status;
  298. }
  299. //
  300. // Parse the misc info provided by bootloader
  301. //
  302. Status = ParseMiscInfo ();
  303. if (EFI_ERROR (Status)) {
  304. DEBUG ((DEBUG_WARN, "Error when parsing misc info, Status = %r\n", Status));
  305. }
  306. //
  307. // Parse platform specific information.
  308. //
  309. Status = ParsePlatformInfo ();
  310. if (EFI_ERROR (Status)) {
  311. DEBUG ((DEBUG_ERROR, "Error when parsing platform info, Status = %r\n", Status));
  312. return Status;
  313. }
  314. return EFI_SUCCESS;
  315. }
  316. /**
  317. This function will build some generic HOBs that doesn't depend on information from bootloaders.
  318. **/
  319. VOID
  320. BuildGenericHob (
  321. VOID
  322. )
  323. {
  324. UINT32 RegEax;
  325. UINT8 PhysicalAddressBits;
  326. EFI_RESOURCE_ATTRIBUTE_TYPE ResourceAttribute;
  327. // The UEFI payload FV
  328. BuildMemoryAllocationHob (PcdGet32 (PcdPayloadFdMemBase), PcdGet32 (PcdPayloadFdMemSize), EfiBootServicesData);
  329. //
  330. // Build CPU memory space and IO space hob
  331. //
  332. AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
  333. if (RegEax >= 0x80000008) {
  334. AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
  335. PhysicalAddressBits = (UINT8)RegEax;
  336. } else {
  337. PhysicalAddressBits = 36;
  338. }
  339. BuildCpuHob (PhysicalAddressBits, 16);
  340. //
  341. // Report Local APIC range, cause sbl HOB to be NULL, comment now
  342. //
  343. ResourceAttribute = (
  344. EFI_RESOURCE_ATTRIBUTE_PRESENT |
  345. EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
  346. EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
  347. EFI_RESOURCE_ATTRIBUTE_TESTED
  348. );
  349. BuildResourceDescriptorHob (EFI_RESOURCE_MEMORY_MAPPED_IO, ResourceAttribute, 0xFEC80000, SIZE_512KB);
  350. BuildMemoryAllocationHob (0xFEC80000, SIZE_512KB, EfiMemoryMappedIO);
  351. }
  352. /**
  353. Entry point to the C language phase of UEFI payload.
  354. @param[in] BootloaderParameter The starting address of bootloader parameter block.
  355. @retval It will not return if SUCCESS, and return error when passing bootloader parameter.
  356. **/
  357. EFI_STATUS
  358. EFIAPI
  359. _ModuleEntryPoint (
  360. IN UINTN BootloaderParameter
  361. )
  362. {
  363. EFI_STATUS Status;
  364. PHYSICAL_ADDRESS DxeCoreEntryPoint;
  365. UINTN MemBase;
  366. UINTN HobMemBase;
  367. UINTN HobMemTop;
  368. EFI_PEI_HOB_POINTERS Hob;
  369. SERIAL_PORT_INFO SerialPortInfo;
  370. UNIVERSAL_PAYLOAD_SERIAL_PORT_INFO *UniversalSerialPort;
  371. Status = PcdSet64S (PcdBootloaderParameter, BootloaderParameter);
  372. ASSERT_EFI_ERROR (Status);
  373. // Initialize floating point operating environment to be compliant with UEFI spec.
  374. InitializeFloatingPointUnits ();
  375. // HOB region is used for HOB and memory allocation for this module
  376. MemBase = PcdGet32 (PcdPayloadFdMemBase);
  377. HobMemBase = ALIGN_VALUE (MemBase + PcdGet32 (PcdPayloadFdMemSize), SIZE_1MB);
  378. HobMemTop = HobMemBase + FixedPcdGet32 (PcdSystemMemoryUefiRegionSize);
  379. HobConstructor ((VOID *)MemBase, (VOID *)HobMemTop, (VOID *)HobMemBase, (VOID *)HobMemTop);
  380. //
  381. // Build serial port info
  382. //
  383. Status = ParseSerialInfo (&SerialPortInfo);
  384. if (!EFI_ERROR (Status)) {
  385. UniversalSerialPort = BuildGuidHob (&gUniversalPayloadSerialPortInfoGuid, sizeof (UNIVERSAL_PAYLOAD_SERIAL_PORT_INFO));
  386. ASSERT (UniversalSerialPort != NULL);
  387. UniversalSerialPort->Header.Revision = UNIVERSAL_PAYLOAD_SERIAL_PORT_INFO_REVISION;
  388. UniversalSerialPort->Header.Length = sizeof (UNIVERSAL_PAYLOAD_SERIAL_PORT_INFO);
  389. UniversalSerialPort->UseMmio = (SerialPortInfo.Type == 1) ? FALSE : TRUE;
  390. UniversalSerialPort->RegisterBase = SerialPortInfo.BaseAddr;
  391. UniversalSerialPort->BaudRate = SerialPortInfo.Baud;
  392. UniversalSerialPort->RegisterStride = (UINT8)SerialPortInfo.RegWidth;
  393. }
  394. // The library constructors might depend on serial port, so call it after serial port hob
  395. ProcessLibraryConstructorList ();
  396. DEBUG ((DEBUG_INFO, "sizeof(UINTN) = 0x%x\n", sizeof (UINTN)));
  397. // Build HOB based on information from Bootloader
  398. Status = BuildHobFromBl ();
  399. if (EFI_ERROR (Status)) {
  400. DEBUG ((DEBUG_ERROR, "BuildHobFromBl Status = %r\n", Status));
  401. return Status;
  402. }
  403. // Build other HOBs required by DXE
  404. BuildGenericHob ();
  405. // Create a HOB to make resources for EDKII modules below 4G
  406. if (!FixedPcdGetBool (PcdDispatchModuleAbove4GMemory)) {
  407. ForceModulesBelow4G ();
  408. }
  409. // Load the DXE Core
  410. Status = LoadDxeCore (&DxeCoreEntryPoint);
  411. ASSERT_EFI_ERROR (Status);
  412. DEBUG ((DEBUG_INFO, "DxeCoreEntryPoint = 0x%lx\n", DxeCoreEntryPoint));
  413. //
  414. // Mask off all legacy 8259 interrupt sources
  415. //
  416. IoWrite8 (LEGACY_8259_MASK_REGISTER_MASTER, 0xFF);
  417. IoWrite8 (LEGACY_8259_MASK_REGISTER_SLAVE, 0xFF);
  418. Hob.HandoffInformationTable = (EFI_HOB_HANDOFF_INFO_TABLE *)GetFirstHob (EFI_HOB_TYPE_HANDOFF);
  419. HandOffToDxeCore (DxeCoreEntryPoint, Hob);
  420. // Should not get here
  421. CpuDeadLoop ();
  422. return EFI_SUCCESS;
  423. }