Platform.c 12 KB

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