Platform.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  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. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. //
  8. // The package level header files this module uses
  9. //
  10. #include <PiPei.h>
  11. //
  12. // The Library classes this module consumes
  13. //
  14. #include <Library/BaseMemoryLib.h>
  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/QemuFwCfgLib.h>
  25. #include <Library/QemuFwCfgS3Lib.h>
  26. #include <Library/QemuFwCfgSimpleParserLib.h>
  27. #include <Library/ResourcePublicationLib.h>
  28. #include <Ppi/MasterBootMode.h>
  29. #include <IndustryStandard/I440FxPiix4.h>
  30. #include <IndustryStandard/Microvm.h>
  31. #include <IndustryStandard/Pci22.h>
  32. #include <IndustryStandard/Q35MchIch9.h>
  33. #include <IndustryStandard/QemuCpuHotplug.h>
  34. #include <Library/MemEncryptSevLib.h>
  35. #include <OvmfPlatforms.h>
  36. #include "Platform.h"
  37. EFI_PEI_PPI_DESCRIPTOR mPpiBootMode[] = {
  38. {
  39. EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
  40. &gEfiPeiMasterBootModePpiGuid,
  41. NULL
  42. }
  43. };
  44. VOID
  45. MemMapInitialization (
  46. IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob
  47. )
  48. {
  49. RETURN_STATUS PcdStatus;
  50. PlatformMemMapInitialization (PlatformInfoHob);
  51. if (PlatformInfoHob->HostBridgeDevId == 0xffff /* microvm */) {
  52. return;
  53. }
  54. PcdStatus = PcdSet64S (PcdPciMmio32Base, PlatformInfoHob->PcdPciMmio32Base);
  55. ASSERT_RETURN_ERROR (PcdStatus);
  56. PcdStatus = PcdSet64S (PcdPciMmio32Size, PlatformInfoHob->PcdPciMmio32Size);
  57. ASSERT_RETURN_ERROR (PcdStatus);
  58. PcdStatus = PcdSet64S (PcdPciIoBase, PlatformInfoHob->PcdPciIoBase);
  59. ASSERT_RETURN_ERROR (PcdStatus);
  60. PcdStatus = PcdSet64S (PcdPciIoSize, PlatformInfoHob->PcdPciIoSize);
  61. ASSERT_RETURN_ERROR (PcdStatus);
  62. }
  63. STATIC
  64. VOID
  65. NoexecDxeInitialization (
  66. IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob
  67. )
  68. {
  69. RETURN_STATUS Status;
  70. Status = PlatformNoexecDxeInitialization (PlatformInfoHob);
  71. if (!RETURN_ERROR (Status)) {
  72. Status = PcdSetBoolS (PcdSetNxForStack, PlatformInfoHob->PcdSetNxForStack);
  73. ASSERT_RETURN_ERROR (Status);
  74. }
  75. }
  76. static const UINT8 EmptyFdt[] = {
  77. 0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x00, 0x48,
  78. 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x48,
  79. 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11,
  80. 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
  81. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
  82. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  83. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  84. 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
  85. 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09,
  86. };
  87. VOID
  88. MicrovmInitialization (
  89. VOID
  90. )
  91. {
  92. FIRMWARE_CONFIG_ITEM FdtItem;
  93. UINTN FdtSize;
  94. UINTN FdtPages;
  95. EFI_STATUS Status;
  96. UINT64 *FdtHobData;
  97. VOID *NewBase;
  98. Status = QemuFwCfgFindFile ("etc/fdt", &FdtItem, &FdtSize);
  99. if (EFI_ERROR (Status)) {
  100. DEBUG ((DEBUG_INFO, "%a: no etc/fdt found in fw_cfg, using dummy\n", __FUNCTION__));
  101. FdtItem = 0;
  102. FdtSize = sizeof (EmptyFdt);
  103. }
  104. FdtPages = EFI_SIZE_TO_PAGES (FdtSize);
  105. NewBase = AllocatePages (FdtPages);
  106. if (NewBase == NULL) {
  107. DEBUG ((DEBUG_INFO, "%a: AllocatePages failed\n", __FUNCTION__));
  108. return;
  109. }
  110. if (FdtItem) {
  111. QemuFwCfgSelectItem (FdtItem);
  112. QemuFwCfgReadBytes (FdtSize, NewBase);
  113. } else {
  114. CopyMem (NewBase, EmptyFdt, FdtSize);
  115. }
  116. FdtHobData = BuildGuidHob (&gFdtHobGuid, sizeof (*FdtHobData));
  117. if (FdtHobData == NULL) {
  118. DEBUG ((DEBUG_INFO, "%a: BuildGuidHob failed\n", __FUNCTION__));
  119. return;
  120. }
  121. DEBUG ((
  122. DEBUG_INFO,
  123. "%a: fdt at 0x%x (size %d)\n",
  124. __FUNCTION__,
  125. NewBase,
  126. FdtSize
  127. ));
  128. *FdtHobData = (UINTN)NewBase;
  129. }
  130. VOID
  131. MiscInitializationForMicrovm (
  132. IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob
  133. )
  134. {
  135. RETURN_STATUS PcdStatus;
  136. ASSERT (PlatformInfoHob->HostBridgeDevId == 0xffff);
  137. DEBUG ((DEBUG_INFO, "%a: microvm\n", __FUNCTION__));
  138. //
  139. // Disable A20 Mask
  140. //
  141. IoOr8 (0x92, BIT1);
  142. //
  143. // Build the CPU HOB with guest RAM size dependent address width and 16-bits
  144. // of IO space. (Side note: unlike other HOBs, the CPU HOB is needed during
  145. // S3 resume as well, so we build it unconditionally.)
  146. //
  147. BuildCpuHob (PlatformInfoHob->PhysMemAddressWidth, 16);
  148. MicrovmInitialization ();
  149. PcdStatus = PcdSet16S (
  150. PcdOvmfHostBridgePciDevId,
  151. MICROVM_PSEUDO_DEVICE_ID
  152. );
  153. ASSERT_RETURN_ERROR (PcdStatus);
  154. }
  155. VOID
  156. MiscInitialization (
  157. IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob
  158. )
  159. {
  160. RETURN_STATUS PcdStatus;
  161. PlatformMiscInitialization (PlatformInfoHob);
  162. PcdStatus = PcdSet16S (PcdOvmfHostBridgePciDevId, PlatformInfoHob->HostBridgeDevId);
  163. ASSERT_RETURN_ERROR (PcdStatus);
  164. }
  165. VOID
  166. BootModeInitialization (
  167. IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob
  168. )
  169. {
  170. EFI_STATUS Status;
  171. if (PlatformCmosRead8 (0xF) == 0xFE) {
  172. PlatformInfoHob->BootMode = BOOT_ON_S3_RESUME;
  173. }
  174. PlatformCmosWrite8 (0xF, 0x00);
  175. Status = PeiServicesSetBootMode (PlatformInfoHob->BootMode);
  176. ASSERT_EFI_ERROR (Status);
  177. Status = PeiServicesInstallPpi (mPpiBootMode);
  178. ASSERT_EFI_ERROR (Status);
  179. }
  180. VOID
  181. ReserveEmuVariableNvStore (
  182. )
  183. {
  184. EFI_PHYSICAL_ADDRESS VariableStore;
  185. RETURN_STATUS PcdStatus;
  186. VariableStore = (EFI_PHYSICAL_ADDRESS)(UINTN)PlatformReserveEmuVariableNvStore ();
  187. PcdStatus = PcdSet64S (PcdEmuVariableNvStoreReserved, VariableStore);
  188. #ifdef SECURE_BOOT_FEATURE_ENABLED
  189. PlatformInitEmuVariableNvStore ((VOID *)(UINTN)VariableStore);
  190. #endif
  191. ASSERT_RETURN_ERROR (PcdStatus);
  192. }
  193. STATIC
  194. VOID
  195. S3Verification (
  196. IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob
  197. )
  198. {
  199. #if defined (MDE_CPU_X64)
  200. if (PlatformInfoHob->SmmSmramRequire && PlatformInfoHob->S3Supported) {
  201. DEBUG ((
  202. DEBUG_ERROR,
  203. "%a: S3Resume2Pei doesn't support X64 PEI + SMM yet.\n",
  204. __FUNCTION__
  205. ));
  206. DEBUG ((
  207. DEBUG_ERROR,
  208. "%a: Please disable S3 on the QEMU command line (see the README),\n",
  209. __FUNCTION__
  210. ));
  211. DEBUG ((
  212. DEBUG_ERROR,
  213. "%a: or build OVMF with \"OvmfPkgIa32X64.dsc\".\n",
  214. __FUNCTION__
  215. ));
  216. ASSERT (FALSE);
  217. CpuDeadLoop ();
  218. }
  219. #endif
  220. }
  221. STATIC
  222. VOID
  223. Q35BoardVerification (
  224. IN EFI_HOB_PLATFORM_INFO *PlatformInfoHob
  225. )
  226. {
  227. if (PlatformInfoHob->HostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) {
  228. return;
  229. }
  230. DEBUG ((
  231. DEBUG_ERROR,
  232. "%a: no TSEG (SMRAM) on host bridge DID=0x%04x; "
  233. "only DID=0x%04x (Q35) is supported\n",
  234. __FUNCTION__,
  235. PlatformInfoHob->HostBridgeDevId,
  236. INTEL_Q35_MCH_DEVICE_ID
  237. ));
  238. ASSERT (FALSE);
  239. CpuDeadLoop ();
  240. }
  241. /**
  242. Fetch the boot CPU count and the possible CPU count from QEMU, and expose
  243. them to UefiCpuPkg modules. Set the MaxCpuCount field in PlatformInfoHob.
  244. **/
  245. VOID
  246. MaxCpuCountInitialization (
  247. IN OUT EFI_HOB_PLATFORM_INFO *PlatformInfoHob
  248. )
  249. {
  250. RETURN_STATUS PcdStatus;
  251. PlatformMaxCpuCountInitialization (PlatformInfoHob);
  252. PcdStatus = PcdSet32S (PcdCpuBootLogicalProcessorNumber, PlatformInfoHob->PcdCpuBootLogicalProcessorNumber);
  253. ASSERT_RETURN_ERROR (PcdStatus);
  254. PcdStatus = PcdSet32S (PcdCpuMaxLogicalProcessorNumber, PlatformInfoHob->PcdCpuMaxLogicalProcessorNumber);
  255. ASSERT_RETURN_ERROR (PcdStatus);
  256. }
  257. /**
  258. * @brief Builds PlatformInfo Hob
  259. */
  260. EFI_HOB_PLATFORM_INFO *
  261. BuildPlatformInfoHob (
  262. VOID
  263. )
  264. {
  265. EFI_HOB_PLATFORM_INFO PlatformInfoHob;
  266. EFI_HOB_GUID_TYPE *GuidHob;
  267. ZeroMem (&PlatformInfoHob, sizeof PlatformInfoHob);
  268. BuildGuidDataHob (&gUefiOvmfPkgPlatformInfoGuid, &PlatformInfoHob, sizeof (EFI_HOB_PLATFORM_INFO));
  269. GuidHob = GetFirstGuidHob (&gUefiOvmfPkgPlatformInfoGuid);
  270. return (EFI_HOB_PLATFORM_INFO *)GET_GUID_HOB_DATA (GuidHob);
  271. }
  272. /**
  273. Perform Platform PEI initialization.
  274. @param FileHandle Handle of the file being invoked.
  275. @param PeiServices Describes the list of possible PEI Services.
  276. @return EFI_SUCCESS The PEIM initialized successfully.
  277. **/
  278. EFI_STATUS
  279. EFIAPI
  280. InitializePlatform (
  281. IN EFI_PEI_FILE_HANDLE FileHandle,
  282. IN CONST EFI_PEI_SERVICES **PeiServices
  283. )
  284. {
  285. EFI_HOB_PLATFORM_INFO *PlatformInfoHob;
  286. EFI_STATUS Status;
  287. DEBUG ((DEBUG_INFO, "Platform PEIM Loaded\n"));
  288. PlatformInfoHob = BuildPlatformInfoHob ();
  289. PlatformInfoHob->SmmSmramRequire = FeaturePcdGet (PcdSmmSmramRequire);
  290. PlatformInfoHob->SevEsIsEnabled = MemEncryptSevEsIsEnabled ();
  291. PlatformInfoHob->PcdPciMmio64Size = PcdGet64 (PcdPciMmio64Size);
  292. PlatformInfoHob->DefaultMaxCpuNumber = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
  293. PlatformDebugDumpCmos ();
  294. if (QemuFwCfgS3Enabled ()) {
  295. DEBUG ((DEBUG_INFO, "S3 support was detected on QEMU\n"));
  296. PlatformInfoHob->S3Supported = TRUE;
  297. Status = PcdSetBoolS (PcdAcpiS3Enable, TRUE);
  298. ASSERT_EFI_ERROR (Status);
  299. }
  300. S3Verification (PlatformInfoHob);
  301. BootModeInitialization (PlatformInfoHob);
  302. //
  303. // Query Host Bridge DID
  304. //
  305. PlatformInfoHob->HostBridgeDevId = PciRead16 (OVMF_HOSTBRIDGE_DID);
  306. AddressWidthInitialization (PlatformInfoHob);
  307. MaxCpuCountInitialization (PlatformInfoHob);
  308. if (PlatformInfoHob->SmmSmramRequire) {
  309. Q35BoardVerification (PlatformInfoHob);
  310. Q35TsegMbytesInitialization (PlatformInfoHob);
  311. Q35SmramAtDefaultSmbaseInitialization (PlatformInfoHob);
  312. }
  313. PublishPeiMemory (PlatformInfoHob);
  314. PlatformQemuUc32BaseInitialization (PlatformInfoHob);
  315. InitializeRamRegions (PlatformInfoHob);
  316. if (PlatformInfoHob->BootMode != BOOT_ON_S3_RESUME) {
  317. if (!PlatformInfoHob->SmmSmramRequire) {
  318. ReserveEmuVariableNvStore ();
  319. }
  320. PeiFvInitialization (PlatformInfoHob);
  321. MemTypeInfoInitialization (PlatformInfoHob);
  322. MemMapInitialization (PlatformInfoHob);
  323. NoexecDxeInitialization (PlatformInfoHob);
  324. }
  325. InstallClearCacheCallback ();
  326. AmdSevInitialize (PlatformInfoHob);
  327. if (PlatformInfoHob->HostBridgeDevId == 0xffff) {
  328. MiscInitializationForMicrovm (PlatformInfoHob);
  329. } else {
  330. MiscInitialization (PlatformInfoHob);
  331. }
  332. IntelTdxInitialize ();
  333. InstallFeatureControlCallback (PlatformInfoHob);
  334. return EFI_SUCCESS;
  335. }