Platform.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. /**@file
  2. Platform PEI driver
  3. Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
  4. Copyright (c) 2011, Andrei Warkentin <andreiw@motorola.com>
  5. Copyright (c) 2019, Citrix Systems, Inc.
  6. SPDX-License-Identifier: BSD-2-Clause-Patent
  7. **/
  8. //
  9. // The package level header files this module uses
  10. //
  11. #include <PiPei.h>
  12. //
  13. // The Library classes this module consumes
  14. //
  15. #include <Library/BaseMemoryLib.h>
  16. #include <Library/BaseLib.h>
  17. #include <Library/DebugLib.h>
  18. #include <Library/HobLib.h>
  19. #include <Library/IoLib.h>
  20. #include <Library/MemoryAllocationLib.h>
  21. #include <Library/PcdLib.h>
  22. #include <Library/PciLib.h>
  23. #include <Library/PeimEntryPoint.h>
  24. #include <Library/PeiServicesLib.h>
  25. #include <Library/QemuFwCfgS3Lib.h>
  26. #include <Library/ResourcePublicationLib.h>
  27. #include <Guid/MemoryTypeInformation.h>
  28. #include <Ppi/MasterBootMode.h>
  29. #include <IndustryStandard/Pci22.h>
  30. #include <OvmfPlatforms.h>
  31. #include "Platform.h"
  32. #include "Cmos.h"
  33. EFI_MEMORY_TYPE_INFORMATION mDefaultMemoryTypeInformation[] = {
  34. { EfiACPIMemoryNVS, 0x004 },
  35. { EfiACPIReclaimMemory, 0x008 },
  36. { EfiReservedMemoryType, 0x004 },
  37. { EfiRuntimeServicesData, 0x024 },
  38. { EfiRuntimeServicesCode, 0x030 },
  39. { EfiBootServicesCode, 0x180 },
  40. { EfiBootServicesData, 0xF00 },
  41. { EfiMaxMemoryType, 0x000 }
  42. };
  43. EFI_PEI_PPI_DESCRIPTOR mPpiBootMode[] = {
  44. {
  45. EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
  46. &gEfiPeiMasterBootModePpiGuid,
  47. NULL
  48. }
  49. };
  50. UINT16 mHostBridgeDevId;
  51. EFI_BOOT_MODE mBootMode = BOOT_WITH_FULL_CONFIGURATION;
  52. VOID
  53. AddIoMemoryBaseSizeHob (
  54. EFI_PHYSICAL_ADDRESS MemoryBase,
  55. UINT64 MemorySize
  56. )
  57. {
  58. BuildResourceDescriptorHob (
  59. EFI_RESOURCE_MEMORY_MAPPED_IO,
  60. EFI_RESOURCE_ATTRIBUTE_PRESENT |
  61. EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
  62. EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
  63. EFI_RESOURCE_ATTRIBUTE_TESTED,
  64. MemoryBase,
  65. MemorySize
  66. );
  67. }
  68. VOID
  69. AddReservedMemoryBaseSizeHob (
  70. EFI_PHYSICAL_ADDRESS MemoryBase,
  71. UINT64 MemorySize,
  72. BOOLEAN Cacheable
  73. )
  74. {
  75. BuildResourceDescriptorHob (
  76. EFI_RESOURCE_MEMORY_RESERVED,
  77. EFI_RESOURCE_ATTRIBUTE_PRESENT |
  78. EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
  79. EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
  80. (Cacheable ?
  81. EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
  82. EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
  83. EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE :
  84. 0
  85. ) |
  86. EFI_RESOURCE_ATTRIBUTE_TESTED,
  87. MemoryBase,
  88. MemorySize
  89. );
  90. }
  91. VOID
  92. AddReservedMemoryRangeHob (
  93. EFI_PHYSICAL_ADDRESS MemoryBase,
  94. EFI_PHYSICAL_ADDRESS MemoryLimit,
  95. BOOLEAN Cacheable
  96. )
  97. {
  98. AddReservedMemoryBaseSizeHob (
  99. MemoryBase,
  100. (UINT64)(MemoryLimit - MemoryBase),
  101. Cacheable
  102. );
  103. }
  104. VOID
  105. AddIoMemoryRangeHob (
  106. EFI_PHYSICAL_ADDRESS MemoryBase,
  107. EFI_PHYSICAL_ADDRESS MemoryLimit
  108. )
  109. {
  110. AddIoMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
  111. }
  112. VOID
  113. AddMemoryBaseSizeHob (
  114. EFI_PHYSICAL_ADDRESS MemoryBase,
  115. UINT64 MemorySize
  116. )
  117. {
  118. BuildResourceDescriptorHob (
  119. EFI_RESOURCE_SYSTEM_MEMORY,
  120. EFI_RESOURCE_ATTRIBUTE_PRESENT |
  121. EFI_RESOURCE_ATTRIBUTE_INITIALIZED |
  122. EFI_RESOURCE_ATTRIBUTE_UNCACHEABLE |
  123. EFI_RESOURCE_ATTRIBUTE_WRITE_COMBINEABLE |
  124. EFI_RESOURCE_ATTRIBUTE_WRITE_THROUGH_CACHEABLE |
  125. EFI_RESOURCE_ATTRIBUTE_WRITE_BACK_CACHEABLE |
  126. EFI_RESOURCE_ATTRIBUTE_TESTED,
  127. MemoryBase,
  128. MemorySize
  129. );
  130. }
  131. VOID
  132. AddMemoryRangeHob (
  133. EFI_PHYSICAL_ADDRESS MemoryBase,
  134. EFI_PHYSICAL_ADDRESS MemoryLimit
  135. )
  136. {
  137. AddMemoryBaseSizeHob (MemoryBase, (UINT64)(MemoryLimit - MemoryBase));
  138. }
  139. VOID
  140. MemMapInitialization (
  141. VOID
  142. )
  143. {
  144. UINT64 PciIoBase;
  145. UINT64 PciIoSize;
  146. RETURN_STATUS PcdStatus;
  147. PciIoBase = 0xC000;
  148. PciIoSize = 0x4000;
  149. //
  150. // Create Memory Type Information HOB
  151. //
  152. BuildGuidDataHob (
  153. &gEfiMemoryTypeInformationGuid,
  154. mDefaultMemoryTypeInformation,
  155. sizeof (mDefaultMemoryTypeInformation)
  156. );
  157. //
  158. // Video memory + Legacy BIOS region
  159. //
  160. AddIoMemoryRangeHob (0x0A0000, BASE_1MB);
  161. //
  162. // Add PCI IO Port space available for PCI resource allocations.
  163. //
  164. BuildResourceDescriptorHob (
  165. EFI_RESOURCE_IO,
  166. EFI_RESOURCE_ATTRIBUTE_PRESENT |
  167. EFI_RESOURCE_ATTRIBUTE_INITIALIZED,
  168. PciIoBase,
  169. PciIoSize
  170. );
  171. PcdStatus = PcdSet64S (PcdPciIoBase, PciIoBase);
  172. ASSERT_RETURN_ERROR (PcdStatus);
  173. PcdStatus = PcdSet64S (PcdPciIoSize, PciIoSize);
  174. ASSERT_RETURN_ERROR (PcdStatus);
  175. }
  176. VOID
  177. PciExBarInitialization (
  178. VOID
  179. )
  180. {
  181. union {
  182. UINT64 Uint64;
  183. UINT32 Uint32[2];
  184. } PciExBarBase;
  185. //
  186. // We only support the 256MB size for the MMCONFIG area:
  187. // 256 buses * 32 devices * 8 functions * 4096 bytes config space.
  188. //
  189. // The masks used below enforce the Q35 requirements that the MMCONFIG area
  190. // be (a) correctly aligned -- here at 256 MB --, (b) located under 64 GB.
  191. //
  192. // Note that (b) also ensures that the minimum address width we have
  193. // determined in AddressWidthInitialization(), i.e., 36 bits, will suffice
  194. // for DXE's page tables to cover the MMCONFIG area.
  195. //
  196. PciExBarBase.Uint64 = FixedPcdGet64 (PcdPciExpressBaseAddress);
  197. ASSERT ((PciExBarBase.Uint32[1] & MCH_PCIEXBAR_HIGHMASK) == 0);
  198. ASSERT ((PciExBarBase.Uint32[0] & MCH_PCIEXBAR_LOWMASK) == 0);
  199. //
  200. // Clear the PCIEXBAREN bit first, before programming the high register.
  201. //
  202. PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW), 0);
  203. //
  204. // Program the high register. Then program the low register, setting the
  205. // MMCONFIG area size and enabling decoding at once.
  206. //
  207. PciWrite32 (DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_HIGH), PciExBarBase.Uint32[1]);
  208. PciWrite32 (
  209. DRAMC_REGISTER_Q35 (MCH_PCIEXBAR_LOW),
  210. PciExBarBase.Uint32[0] | MCH_PCIEXBAR_BUS_FF | MCH_PCIEXBAR_EN
  211. );
  212. }
  213. VOID
  214. MiscInitialization (
  215. VOID
  216. )
  217. {
  218. UINTN PmCmd;
  219. UINTN Pmba;
  220. UINT32 PmbaAndVal;
  221. UINT32 PmbaOrVal;
  222. UINTN AcpiCtlReg;
  223. UINT8 AcpiEnBit;
  224. RETURN_STATUS PcdStatus;
  225. //
  226. // Disable A20 Mask
  227. //
  228. IoOr8 (0x92, BIT1);
  229. //
  230. // Build the CPU HOB with guest RAM size dependent address width and 16-bits
  231. // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during
  232. // S3 resume as well, so we build it unconditionally.)
  233. //
  234. BuildCpuHob (mPhysMemAddressWidth, 16);
  235. //
  236. // Determine platform type and save Host Bridge DID to PCD
  237. //
  238. switch (mHostBridgeDevId) {
  239. case INTEL_82441_DEVICE_ID:
  240. PmCmd = POWER_MGMT_REGISTER_PIIX4 (PCI_COMMAND_OFFSET);
  241. Pmba = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMBA);
  242. PmbaAndVal = ~(UINT32)PIIX4_PMBA_MASK;
  243. PmbaOrVal = PIIX4_PMBA_VALUE;
  244. AcpiCtlReg = POWER_MGMT_REGISTER_PIIX4 (PIIX4_PMREGMISC);
  245. AcpiEnBit = PIIX4_PMREGMISC_PMIOSE;
  246. break;
  247. case INTEL_Q35_MCH_DEVICE_ID:
  248. PmCmd = POWER_MGMT_REGISTER_Q35 (PCI_COMMAND_OFFSET);
  249. Pmba = POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE);
  250. PmbaAndVal = ~(UINT32)ICH9_PMBASE_MASK;
  251. PmbaOrVal = ICH9_PMBASE_VALUE;
  252. AcpiCtlReg = POWER_MGMT_REGISTER_Q35 (ICH9_ACPI_CNTL);
  253. AcpiEnBit = ICH9_ACPI_CNTL_ACPI_EN;
  254. break;
  255. default:
  256. if (XenPvhDetected ()) {
  257. //
  258. // There is no PCI bus in this case
  259. //
  260. return;
  261. }
  262. DEBUG ((
  263. DEBUG_ERROR,
  264. "%a: Unknown Host Bridge Device ID: 0x%04x\n",
  265. __FUNCTION__,
  266. mHostBridgeDevId
  267. ));
  268. ASSERT (FALSE);
  269. return;
  270. }
  271. PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, mHostBridgeDevId);
  272. ASSERT_RETURN_ERROR (PcdStatus);
  273. //
  274. // If the appropriate IOspace enable bit is set, assume the ACPI PMBA
  275. // has been configured (e.g., by Xen) and skip the setup here.
  276. // This matches the logic in AcpiTimerLibConstructor ().
  277. //
  278. if ((PciRead8 (AcpiCtlReg) & AcpiEnBit) == 0) {
  279. //
  280. // The PEI phase should be exited with fully accessibe ACPI PM IO space:
  281. // 1. set PMBA
  282. //
  283. PciAndThenOr32 (Pmba, PmbaAndVal, PmbaOrVal);
  284. //
  285. // 2. set PCICMD/IOSE
  286. //
  287. PciOr8 (PmCmd, EFI_PCI_COMMAND_IO_SPACE);
  288. //
  289. // 3. set ACPI PM IO enable bit (PMREGMISC:PMIOSE or ACPI_CNTL:ACPI_EN)
  290. //
  291. PciOr8 (AcpiCtlReg, AcpiEnBit);
  292. }
  293. if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
  294. //
  295. // Set Root Complex Register Block BAR
  296. //
  297. PciWrite32 (
  298. POWER_MGMT_REGISTER_Q35 (ICH9_RCBA),
  299. ICH9_ROOT_COMPLEX_BASE | ICH9_RCBA_EN
  300. );
  301. //
  302. // Set PCI Express Register Range Base Address
  303. //
  304. PciExBarInitialization ();
  305. }
  306. }
  307. VOID
  308. BootModeInitialization (
  309. VOID
  310. )
  311. {
  312. EFI_STATUS Status;
  313. if (CmosRead8 (0xF) == 0xFE) {
  314. mBootMode = BOOT_ON_S3_RESUME;
  315. }
  316. CmosWrite8 (0xF, 0x00);
  317. Status = PeiServicesSetBootMode (mBootMode);
  318. ASSERT_EFI_ERROR (Status);
  319. Status = PeiServicesInstallPpi (mPpiBootMode);
  320. ASSERT_EFI_ERROR (Status);
  321. }
  322. VOID
  323. ReserveEmuVariableNvStore (
  324. )
  325. {
  326. EFI_PHYSICAL_ADDRESS VariableStore;
  327. RETURN_STATUS PcdStatus;
  328. //
  329. // Allocate storage for NV variables early on so it will be
  330. // at a consistent address. Since VM memory is preserved
  331. // across reboots, this allows the NV variable storage to survive
  332. // a VM reboot.
  333. //
  334. VariableStore =
  335. (EFI_PHYSICAL_ADDRESS)(UINTN)
  336. AllocateRuntimePages (
  337. EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize))
  338. );
  339. DEBUG ((
  340. DEBUG_INFO,
  341. "Reserved variable store memory: 0x%lX; size: %dkb\n",
  342. VariableStore,
  343. (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024
  344. ));
  345. PcdStatus = PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore);
  346. ASSERT_RETURN_ERROR (PcdStatus);
  347. }
  348. VOID
  349. DebugDumpCmos (
  350. VOID
  351. )
  352. {
  353. UINT32 Loop;
  354. DEBUG ((DEBUG_INFO, "CMOS:\n"));
  355. for (Loop = 0; Loop < 0x80; Loop++) {
  356. if ((Loop % 0x10) == 0) {
  357. DEBUG ((DEBUG_INFO, "%02x:", Loop));
  358. }
  359. DEBUG ((DEBUG_INFO, " %02x", CmosRead8 (Loop)));
  360. if ((Loop % 0x10) == 0xf) {
  361. DEBUG ((DEBUG_INFO, "\n"));
  362. }
  363. }
  364. }
  365. EFI_HOB_PLATFORM_INFO *
  366. BuildPlatformInfoHob (
  367. VOID
  368. )
  369. {
  370. EFI_HOB_PLATFORM_INFO PlatformInfoHob;
  371. EFI_HOB_GUID_TYPE *GuidHob;
  372. ZeroMem (&PlatformInfoHob, sizeof PlatformInfoHob);
  373. BuildGuidDataHob (&gUefiOvmfPkgPlatformInfoGuid, &PlatformInfoHob, sizeof (EFI_HOB_PLATFORM_INFO));
  374. GuidHob = GetFirstGuidHob (&gUefiOvmfPkgPlatformInfoGuid);
  375. return (EFI_HOB_PLATFORM_INFO *)GET_GUID_HOB_DATA (GuidHob);
  376. }
  377. /**
  378. Perform Platform PEI initialization.
  379. @param FileHandle Handle of the file being invoked.
  380. @param PeiServices Describes the list of possible PEI Services.
  381. @return EFI_SUCCESS The PEIM initialized successfully.
  382. **/
  383. EFI_STATUS
  384. EFIAPI
  385. InitializeXenPlatform (
  386. IN EFI_PEI_FILE_HANDLE FileHandle,
  387. IN CONST EFI_PEI_SERVICES **PeiServices
  388. )
  389. {
  390. EFI_STATUS Status;
  391. DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
  392. //
  393. // Platform Info HOB used by QemuFw libraries
  394. //
  395. BuildPlatformInfoHob ();
  396. DebugDumpCmos ();
  397. if (!XenDetect ()) {
  398. DEBUG ((DEBUG_ERROR, "ERROR: Xen isn't detected\n"));
  399. ASSERT (FALSE);
  400. CpuDeadLoop ();
  401. }
  402. //
  403. // This S3 conditional test is mainly for HVM Direct Kernel Boot since
  404. // QEMU fwcfg isn't really supported other than that.
  405. //
  406. if (QemuFwCfgS3Enabled ()) {
  407. DEBUG ((DEBUG_INFO, "S3 support was detected on QEMU\n"));
  408. Status = PcdSetBoolS (PcdAcpiS3Enable, TRUE);
  409. ASSERT_EFI_ERROR (Status);
  410. }
  411. XenConnect ();
  412. BootModeInitialization ();
  413. AddressWidthInitialization ();
  414. //
  415. // Query Host Bridge DID
  416. //
  417. mHostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
  418. PublishPeiMemory ();
  419. InitializeRamRegions ();
  420. CalibrateLapicTimer ();
  421. if (mBootMode != BOOT_ON_S3_RESUME) {
  422. ReserveEmuVariableNvStore ();
  423. PeiFvInitialization ();
  424. MemMapInitialization ();
  425. }
  426. InstallClearCacheCallback ();
  427. AmdSevInitialize ();
  428. MiscInitialization ();
  429. return EFI_SUCCESS;
  430. }