SmmControl2Dxe.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. /** @file
  2. A DXE_RUNTIME_DRIVER providing synchronous SMI activations via the
  3. EFI_SMM_CONTROL2_PROTOCOL.
  4. We expect the PEI phase to have covered the following:
  5. - ensure that the underlying QEMU machine type be Q35
  6. (responsible: OvmfPkg/SmmAccess/SmmAccessPei.inf)
  7. - ensure that the ACPI PM IO space be configured
  8. (responsible: OvmfPkg/PlatformPei/PlatformPei.inf)
  9. Our own entry point is responsible for confirming the SMI feature and for
  10. configuring it.
  11. Copyright (C) 2013, 2015, Red Hat, Inc.<BR>
  12. Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
  13. SPDX-License-Identifier: BSD-2-Clause-Patent
  14. **/
  15. #include <IndustryStandard/Q35MchIch9.h>
  16. #include <Library/BaseLib.h>
  17. #include <Library/DebugLib.h>
  18. #include <Library/IoLib.h>
  19. #include <Library/PcdLib.h>
  20. #include <Library/PciLib.h>
  21. #include <Library/UefiBootServicesTableLib.h>
  22. #include <Protocol/S3SaveState.h>
  23. #include <Protocol/SmmControl2.h>
  24. #include "SmiFeatures.h"
  25. //
  26. // Forward declaration.
  27. //
  28. STATIC
  29. VOID
  30. EFIAPI
  31. OnS3SaveStateInstalled (
  32. IN EFI_EVENT Event,
  33. IN VOID *Context
  34. );
  35. //
  36. // The absolute IO port address of the SMI Control and Enable Register. It is
  37. // only used to carry information from the entry point function to the
  38. // S3SaveState protocol installation callback, strictly before the runtime
  39. // phase.
  40. //
  41. STATIC UINTN mSmiEnable;
  42. //
  43. // Captures whether SMI feature negotiation is supported. The variable is only
  44. // used to carry this information from the entry point function to the
  45. // S3SaveState protocol installation callback.
  46. //
  47. STATIC BOOLEAN mSmiFeatureNegotiation;
  48. //
  49. // Event signaled when an S3SaveState protocol interface is installed.
  50. //
  51. STATIC EFI_EVENT mS3SaveStateInstalled;
  52. /**
  53. Invokes SMI activation from either the preboot or runtime environment.
  54. This function generates an SMI.
  55. @param[in] This The EFI_SMM_CONTROL2_PROTOCOL instance.
  56. @param[in,out] CommandPort The value written to the command port.
  57. @param[in,out] DataPort The value written to the data port.
  58. @param[in] Periodic Optional mechanism to engender a periodic
  59. stream.
  60. @param[in] ActivationInterval Optional parameter to repeat at this
  61. period one time or, if the Periodic
  62. Boolean is set, periodically.
  63. @retval EFI_SUCCESS The SMI/PMI has been engendered.
  64. @retval EFI_DEVICE_ERROR The timing is unsupported.
  65. @retval EFI_INVALID_PARAMETER The activation period is unsupported.
  66. @retval EFI_INVALID_PARAMETER The last periodic activation has not been
  67. cleared.
  68. @retval EFI_NOT_STARTED The SMM base service has not been initialized.
  69. **/
  70. STATIC
  71. EFI_STATUS
  72. EFIAPI
  73. SmmControl2DxeTrigger (
  74. IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
  75. IN OUT UINT8 *CommandPort OPTIONAL,
  76. IN OUT UINT8 *DataPort OPTIONAL,
  77. IN BOOLEAN Periodic OPTIONAL,
  78. IN UINTN ActivationInterval OPTIONAL
  79. )
  80. {
  81. //
  82. // No support for queued or periodic activation.
  83. //
  84. if (Periodic || (ActivationInterval > 0)) {
  85. return EFI_DEVICE_ERROR;
  86. }
  87. //
  88. // The so-called "Advanced Power Management Status Port Register" is in fact
  89. // a generic data passing register, between the caller and the SMI
  90. // dispatcher. The ICH9 spec calls it "scratchpad register" -- calling it
  91. // "status" elsewhere seems quite the misnomer. Status registers usually
  92. // report about hardware status, while this register is fully governed by
  93. // software.
  94. //
  95. // Write to the status register first, as this won't trigger the SMI just
  96. // yet. Then write to the control register.
  97. //
  98. IoWrite8 (ICH9_APM_STS, DataPort == NULL ? 0 : *DataPort);
  99. IoWrite8 (ICH9_APM_CNT, CommandPort == NULL ? 0 : *CommandPort);
  100. return EFI_SUCCESS;
  101. }
  102. /**
  103. Clears any system state that was created in response to the Trigger() call.
  104. This function acknowledges and causes the deassertion of the SMI activation
  105. source.
  106. @param[in] This The EFI_SMM_CONTROL2_PROTOCOL instance.
  107. @param[in] Periodic Optional parameter to repeat at this period
  108. one time
  109. @retval EFI_SUCCESS The SMI/PMI has been engendered.
  110. @retval EFI_DEVICE_ERROR The source could not be cleared.
  111. @retval EFI_INVALID_PARAMETER The service did not support the Periodic input
  112. argument.
  113. **/
  114. STATIC
  115. EFI_STATUS
  116. EFIAPI
  117. SmmControl2DxeClear (
  118. IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
  119. IN BOOLEAN Periodic OPTIONAL
  120. )
  121. {
  122. if (Periodic) {
  123. return EFI_INVALID_PARAMETER;
  124. }
  125. //
  126. // The PI spec v1.4 explains that Clear() is only supposed to clear software
  127. // status; it is not in fact responsible for deasserting the SMI. It gives
  128. // two reasons for this: (a) many boards clear the SMI automatically when
  129. // entering SMM, (b) if Clear() actually deasserted the SMI, then it could
  130. // incorrectly suppress an SMI that was asynchronously asserted between the
  131. // last return of the SMI handler and the call made to Clear().
  132. //
  133. // In fact QEMU automatically deasserts CPU_INTERRUPT_SMI in:
  134. // - x86_cpu_exec_interrupt() [target-i386/seg_helper.c], and
  135. // - kvm_arch_pre_run() [target-i386/kvm.c].
  136. //
  137. // So, nothing to do here.
  138. //
  139. return EFI_SUCCESS;
  140. }
  141. STATIC EFI_SMM_CONTROL2_PROTOCOL mControl2 = {
  142. &SmmControl2DxeTrigger,
  143. &SmmControl2DxeClear,
  144. MAX_UINTN // MinimumTriggerPeriod -- we don't support periodic SMIs
  145. };
  146. //
  147. // Entry point of this driver.
  148. //
  149. EFI_STATUS
  150. EFIAPI
  151. SmmControl2DxeEntryPoint (
  152. IN EFI_HANDLE ImageHandle,
  153. IN EFI_SYSTEM_TABLE *SystemTable
  154. )
  155. {
  156. UINT32 PmBase;
  157. UINT32 SmiEnableVal;
  158. EFI_STATUS Status;
  159. //
  160. // This module should only be included if SMRAM support is required.
  161. //
  162. ASSERT (FeaturePcdGet (PcdSmmSmramRequire));
  163. //
  164. // Calculate the absolute IO port address of the SMI Control and Enable
  165. // Register. (As noted at the top, the PEI phase has left us with a working
  166. // ACPI PM IO space.)
  167. //
  168. PmBase = PciRead32 (POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE)) &
  169. ICH9_PMBASE_MASK;
  170. mSmiEnable = PmBase + ICH9_PMBASE_OFS_SMI_EN;
  171. //
  172. // If APMC_EN is pre-set in SMI_EN, that's QEMU's way to tell us that SMI
  173. // support is not available. (For example due to KVM lacking it.) Otherwise,
  174. // this bit is clear after each reset.
  175. //
  176. SmiEnableVal = IoRead32 (mSmiEnable);
  177. if ((SmiEnableVal & ICH9_SMI_EN_APMC_EN) != 0) {
  178. DEBUG ((
  179. DEBUG_ERROR,
  180. "%a: this Q35 implementation lacks SMI\n",
  181. __FUNCTION__
  182. ));
  183. goto FatalError;
  184. }
  185. //
  186. // Otherwise, configure the board to inject an SMI when ICH9_APM_CNT is
  187. // written to. (See the Trigger() method above.)
  188. //
  189. SmiEnableVal |= ICH9_SMI_EN_APMC_EN | ICH9_SMI_EN_GBL_SMI_EN;
  190. IoWrite32 (mSmiEnable, SmiEnableVal);
  191. //
  192. // Prevent software from undoing the above (until platform reset).
  193. //
  194. PciOr16 (
  195. POWER_MGMT_REGISTER_Q35 (ICH9_GEN_PMCON_1),
  196. ICH9_GEN_PMCON_1_SMI_LOCK
  197. );
  198. //
  199. // If we can clear GBL_SMI_EN now, that means QEMU's SMI support is not
  200. // appropriate.
  201. //
  202. IoWrite32 (mSmiEnable, SmiEnableVal & ~(UINT32)ICH9_SMI_EN_GBL_SMI_EN);
  203. if (IoRead32 (mSmiEnable) != SmiEnableVal) {
  204. DEBUG ((
  205. DEBUG_ERROR,
  206. "%a: failed to lock down GBL_SMI_EN\n",
  207. __FUNCTION__
  208. ));
  209. goto FatalError;
  210. }
  211. //
  212. // QEMU can inject SMIs in different ways, negotiate our preferences.
  213. //
  214. mSmiFeatureNegotiation = NegotiateSmiFeatures ();
  215. if (PcdGetBool (PcdAcpiS3Enable)) {
  216. VOID *Registration;
  217. //
  218. // On S3 resume the above register settings have to be repeated. Register a
  219. // protocol notify callback that, when boot script saving becomes
  220. // available, saves operations equivalent to the above to the boot script.
  221. //
  222. Status = gBS->CreateEvent (
  223. EVT_NOTIFY_SIGNAL,
  224. TPL_CALLBACK,
  225. OnS3SaveStateInstalled,
  226. NULL /* Context */,
  227. &mS3SaveStateInstalled
  228. );
  229. if (EFI_ERROR (Status)) {
  230. DEBUG ((DEBUG_ERROR, "%a: CreateEvent: %r\n", __FUNCTION__, Status));
  231. goto FatalError;
  232. }
  233. Status = gBS->RegisterProtocolNotify (
  234. &gEfiS3SaveStateProtocolGuid,
  235. mS3SaveStateInstalled,
  236. &Registration
  237. );
  238. if (EFI_ERROR (Status)) {
  239. DEBUG ((
  240. DEBUG_ERROR,
  241. "%a: RegisterProtocolNotify: %r\n",
  242. __FUNCTION__,
  243. Status
  244. ));
  245. goto ReleaseEvent;
  246. }
  247. //
  248. // Kick the event right now -- maybe the boot script is already saveable.
  249. //
  250. Status = gBS->SignalEvent (mS3SaveStateInstalled);
  251. if (EFI_ERROR (Status)) {
  252. DEBUG ((DEBUG_ERROR, "%a: SignalEvent: %r\n", __FUNCTION__, Status));
  253. goto ReleaseEvent;
  254. }
  255. }
  256. //
  257. // We have no pointers to convert to virtual addresses. The handle itself
  258. // doesn't matter, as protocol services are not accessible at runtime.
  259. //
  260. Status = gBS->InstallMultipleProtocolInterfaces (
  261. &ImageHandle,
  262. &gEfiSmmControl2ProtocolGuid,
  263. &mControl2,
  264. NULL
  265. );
  266. if (EFI_ERROR (Status)) {
  267. DEBUG ((
  268. DEBUG_ERROR,
  269. "%a: InstallMultipleProtocolInterfaces: %r\n",
  270. __FUNCTION__,
  271. Status
  272. ));
  273. goto ReleaseEvent;
  274. }
  275. return EFI_SUCCESS;
  276. ReleaseEvent:
  277. if (mS3SaveStateInstalled != NULL) {
  278. gBS->CloseEvent (mS3SaveStateInstalled);
  279. }
  280. FatalError:
  281. //
  282. // We really don't want to continue in this case.
  283. //
  284. ASSERT (FALSE);
  285. CpuDeadLoop ();
  286. return EFI_UNSUPPORTED;
  287. }
  288. /**
  289. Notification callback for S3SaveState installation.
  290. @param[in] Event Event whose notification function is being invoked.
  291. @param[in] Context The pointer to the notification function's context, which
  292. is implementation-dependent.
  293. **/
  294. STATIC
  295. VOID
  296. EFIAPI
  297. OnS3SaveStateInstalled (
  298. IN EFI_EVENT Event,
  299. IN VOID *Context
  300. )
  301. {
  302. EFI_STATUS Status;
  303. EFI_S3_SAVE_STATE_PROTOCOL *S3SaveState;
  304. UINT32 SmiEnOrMask, SmiEnAndMask;
  305. UINT64 GenPmCon1Address;
  306. UINT16 GenPmCon1OrMask, GenPmCon1AndMask;
  307. ASSERT (Event == mS3SaveStateInstalled);
  308. Status = gBS->LocateProtocol (
  309. &gEfiS3SaveStateProtocolGuid,
  310. NULL /* Registration */,
  311. (VOID **)&S3SaveState
  312. );
  313. if (EFI_ERROR (Status)) {
  314. return;
  315. }
  316. //
  317. // These operations were originally done, verified and explained in the entry
  318. // point function of the driver.
  319. //
  320. SmiEnOrMask = ICH9_SMI_EN_APMC_EN | ICH9_SMI_EN_GBL_SMI_EN;
  321. SmiEnAndMask = MAX_UINT32;
  322. Status = S3SaveState->Write (
  323. S3SaveState,
  324. EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE,
  325. EfiBootScriptWidthUint32,
  326. (UINT64)mSmiEnable,
  327. &SmiEnOrMask,
  328. &SmiEnAndMask
  329. );
  330. if (EFI_ERROR (Status)) {
  331. DEBUG ((
  332. DEBUG_ERROR,
  333. "%a: EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE: %r\n",
  334. __FUNCTION__,
  335. Status
  336. ));
  337. ASSERT (FALSE);
  338. CpuDeadLoop ();
  339. }
  340. GenPmCon1Address = POWER_MGMT_REGISTER_Q35_EFI_PCI_ADDRESS (
  341. ICH9_GEN_PMCON_1
  342. );
  343. GenPmCon1OrMask = ICH9_GEN_PMCON_1_SMI_LOCK;
  344. GenPmCon1AndMask = MAX_UINT16;
  345. Status = S3SaveState->Write (
  346. S3SaveState,
  347. EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE,
  348. EfiBootScriptWidthUint16,
  349. GenPmCon1Address,
  350. &GenPmCon1OrMask,
  351. &GenPmCon1AndMask
  352. );
  353. if (EFI_ERROR (Status)) {
  354. DEBUG ((
  355. DEBUG_ERROR,
  356. "%a: EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE: %r\n",
  357. __FUNCTION__,
  358. Status
  359. ));
  360. ASSERT (FALSE);
  361. CpuDeadLoop ();
  362. }
  363. DEBUG ((DEBUG_VERBOSE, "%a: chipset boot script saved\n", __FUNCTION__));
  364. //
  365. // Append a boot script fragment that re-selects the negotiated SMI features.
  366. //
  367. if (mSmiFeatureNegotiation) {
  368. SaveSmiFeatures ();
  369. }
  370. gBS->CloseEvent (Event);
  371. mS3SaveStateInstalled = NULL;
  372. }