3 A DXE_RUNTIME_DRIVER providing synchronous SMI activations via the
4 EFI_SMM_CONTROL2_PROTOCOL.
6 We expect the PEI phase to have covered the following:
7 - ensure that the underlying QEMU machine type be Q35
8 (responsible: OvmfPkg/SmmAccess/SmmAccessPei.inf)
9 - ensure that the ACPI PM IO space be configured
10 (responsible: OvmfPkg/PlatformPei/PlatformPei.inf)
12 Our own entry point is responsible for confirming the SMI feature and for
15 Copyright (C) 2013, 2015, Red Hat, Inc.<BR>
16 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
18 SPDX-License-Identifier: BSD-2-Clause-Patent
22 #include <IndustryStandard/Q35MchIch9.h>
23 #include <Library/BaseLib.h>
24 #include <Library/DebugLib.h>
25 #include <Library/IoLib.h>
26 #include <Library/PcdLib.h>
27 #include <Library/PciLib.h>
28 #include <Library/UefiBootServicesTableLib.h>
29 #include <Protocol/S3SaveState.h>
30 #include <Protocol/SmmControl2.h>
32 #include "SmiFeatures.h"
35 // Forward declaration.
40 OnS3SaveStateInstalled (
46 // The absolute IO port address of the SMI Control and Enable Register. It is
47 // only used to carry information from the entry point function to the
48 // S3SaveState protocol installation callback, strictly before the runtime
51 STATIC UINTN mSmiEnable
;
54 // Captures whether SMI feature negotiation is supported. The variable is only
55 // used to carry this information from the entry point function to the
56 // S3SaveState protocol installation callback.
58 STATIC BOOLEAN mSmiFeatureNegotiation
;
61 // Event signaled when an S3SaveState protocol interface is installed.
63 STATIC EFI_EVENT mS3SaveStateInstalled
;
66 Invokes SMI activation from either the preboot or runtime environment.
68 This function generates an SMI.
70 @param[in] This The EFI_SMM_CONTROL2_PROTOCOL instance.
71 @param[in,out] CommandPort The value written to the command port.
72 @param[in,out] DataPort The value written to the data port.
73 @param[in] Periodic Optional mechanism to engender a periodic
75 @param[in] ActivationInterval Optional parameter to repeat at this
76 period one time or, if the Periodic
77 Boolean is set, periodically.
79 @retval EFI_SUCCESS The SMI/PMI has been engendered.
80 @retval EFI_DEVICE_ERROR The timing is unsupported.
81 @retval EFI_INVALID_PARAMETER The activation period is unsupported.
82 @retval EFI_INVALID_PARAMETER The last periodic activation has not been
84 @retval EFI_NOT_STARTED The SMM base service has not been initialized.
89 SmmControl2DxeTrigger (
90 IN CONST EFI_SMM_CONTROL2_PROTOCOL
*This
,
91 IN OUT UINT8
*CommandPort OPTIONAL
,
92 IN OUT UINT8
*DataPort OPTIONAL
,
93 IN BOOLEAN Periodic OPTIONAL
,
94 IN UINTN ActivationInterval OPTIONAL
98 // No support for queued or periodic activation.
100 if (Periodic
|| (ActivationInterval
> 0)) {
101 return EFI_DEVICE_ERROR
;
105 // The so-called "Advanced Power Management Status Port Register" is in fact
106 // a generic data passing register, between the caller and the SMI
107 // dispatcher. The ICH9 spec calls it "scratchpad register" -- calling it
108 // "status" elsewhere seems quite the misnomer. Status registers usually
109 // report about hardware status, while this register is fully governed by
112 // Write to the status register first, as this won't trigger the SMI just
113 // yet. Then write to the control register.
115 IoWrite8 (ICH9_APM_STS
, DataPort
== NULL
? 0 : *DataPort
);
116 IoWrite8 (ICH9_APM_CNT
, CommandPort
== NULL
? 0 : *CommandPort
);
121 Clears any system state that was created in response to the Trigger() call.
123 This function acknowledges and causes the deassertion of the SMI activation
126 @param[in] This The EFI_SMM_CONTROL2_PROTOCOL instance.
127 @param[in] Periodic Optional parameter to repeat at this period
130 @retval EFI_SUCCESS The SMI/PMI has been engendered.
131 @retval EFI_DEVICE_ERROR The source could not be cleared.
132 @retval EFI_INVALID_PARAMETER The service did not support the Periodic input
138 SmmControl2DxeClear (
139 IN CONST EFI_SMM_CONTROL2_PROTOCOL
*This
,
140 IN BOOLEAN Periodic OPTIONAL
144 return EFI_INVALID_PARAMETER
;
148 // The PI spec v1.4 explains that Clear() is only supposed to clear software
149 // status; it is not in fact responsible for deasserting the SMI. It gives
150 // two reasons for this: (a) many boards clear the SMI automatically when
151 // entering SMM, (b) if Clear() actually deasserted the SMI, then it could
152 // incorrectly suppress an SMI that was asynchronously asserted between the
153 // last return of the SMI handler and the call made to Clear().
155 // In fact QEMU automatically deasserts CPU_INTERRUPT_SMI in:
156 // - x86_cpu_exec_interrupt() [target-i386/seg_helper.c], and
157 // - kvm_arch_pre_run() [target-i386/kvm.c].
159 // So, nothing to do here.
164 STATIC EFI_SMM_CONTROL2_PROTOCOL mControl2
= {
165 &SmmControl2DxeTrigger
,
166 &SmmControl2DxeClear
,
167 MAX_UINTN
// MinimumTriggerPeriod -- we don't support periodic SMIs
171 // Entry point of this driver.
175 SmmControl2DxeEntryPoint (
176 IN EFI_HANDLE ImageHandle
,
177 IN EFI_SYSTEM_TABLE
*SystemTable
185 // This module should only be included if SMRAM support is required.
187 ASSERT (FeaturePcdGet (PcdSmmSmramRequire
));
190 // Calculate the absolute IO port address of the SMI Control and Enable
191 // Register. (As noted at the top, the PEI phase has left us with a working
192 // ACPI PM IO space.)
194 PmBase
= PciRead32 (POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
)) &
196 mSmiEnable
= PmBase
+ ICH9_PMBASE_OFS_SMI_EN
;
199 // If APMC_EN is pre-set in SMI_EN, that's QEMU's way to tell us that SMI
200 // support is not available. (For example due to KVM lacking it.) Otherwise,
201 // this bit is clear after each reset.
203 SmiEnableVal
= IoRead32 (mSmiEnable
);
204 if ((SmiEnableVal
& ICH9_SMI_EN_APMC_EN
) != 0) {
207 "%a: this Q35 implementation lacks SMI\n",
214 // Otherwise, configure the board to inject an SMI when ICH9_APM_CNT is
215 // written to. (See the Trigger() method above.)
217 SmiEnableVal
|= ICH9_SMI_EN_APMC_EN
| ICH9_SMI_EN_GBL_SMI_EN
;
218 IoWrite32 (mSmiEnable
, SmiEnableVal
);
221 // Prevent software from undoing the above (until platform reset).
224 POWER_MGMT_REGISTER_Q35 (ICH9_GEN_PMCON_1
),
225 ICH9_GEN_PMCON_1_SMI_LOCK
229 // If we can clear GBL_SMI_EN now, that means QEMU's SMI support is not
232 IoWrite32 (mSmiEnable
, SmiEnableVal
& ~(UINT32
)ICH9_SMI_EN_GBL_SMI_EN
);
233 if (IoRead32 (mSmiEnable
) != SmiEnableVal
) {
236 "%a: failed to lock down GBL_SMI_EN\n",
243 // QEMU can inject SMIs in different ways, negotiate our preferences.
245 mSmiFeatureNegotiation
= NegotiateSmiFeatures ();
247 if (PcdGetBool (PcdAcpiS3Enable
)) {
251 // On S3 resume the above register settings have to be repeated. Register a
252 // protocol notify callback that, when boot script saving becomes
253 // available, saves operations equivalent to the above to the boot script.
255 Status
= gBS
->CreateEvent (
258 OnS3SaveStateInstalled
,
260 &mS3SaveStateInstalled
262 if (EFI_ERROR (Status
)) {
263 DEBUG ((DEBUG_ERROR
, "%a: CreateEvent: %r\n", __FUNCTION__
, Status
));
267 Status
= gBS
->RegisterProtocolNotify (
268 &gEfiS3SaveStateProtocolGuid
,
269 mS3SaveStateInstalled
,
272 if (EFI_ERROR (Status
)) {
275 "%a: RegisterProtocolNotify: %r\n",
283 // Kick the event right now -- maybe the boot script is already saveable.
285 Status
= gBS
->SignalEvent (mS3SaveStateInstalled
);
286 if (EFI_ERROR (Status
)) {
287 DEBUG ((DEBUG_ERROR
, "%a: SignalEvent: %r\n", __FUNCTION__
, Status
));
293 // We have no pointers to convert to virtual addresses. The handle itself
294 // doesn't matter, as protocol services are not accessible at runtime.
296 Status
= gBS
->InstallMultipleProtocolInterfaces (
298 &gEfiSmmControl2ProtocolGuid
,
302 if (EFI_ERROR (Status
)) {
305 "%a: InstallMultipleProtocolInterfaces: %r\n",
315 if (mS3SaveStateInstalled
!= NULL
) {
316 gBS
->CloseEvent (mS3SaveStateInstalled
);
321 // We really don't want to continue in this case.
325 return EFI_UNSUPPORTED
;
329 Notification callback for S3SaveState installation.
331 @param[in] Event Event whose notification function is being invoked.
333 @param[in] Context The pointer to the notification function's context, which
334 is implementation-dependent.
339 OnS3SaveStateInstalled (
345 EFI_S3_SAVE_STATE_PROTOCOL
*S3SaveState
;
346 UINT32 SmiEnOrMask
, SmiEnAndMask
;
347 UINT64 GenPmCon1Address
;
348 UINT16 GenPmCon1OrMask
, GenPmCon1AndMask
;
350 ASSERT (Event
== mS3SaveStateInstalled
);
352 Status
= gBS
->LocateProtocol (
353 &gEfiS3SaveStateProtocolGuid
,
354 NULL
/* Registration */,
355 (VOID
**)&S3SaveState
357 if (EFI_ERROR (Status
)) {
362 // These operations were originally done, verified and explained in the entry
363 // point function of the driver.
365 SmiEnOrMask
= ICH9_SMI_EN_APMC_EN
| ICH9_SMI_EN_GBL_SMI_EN
;
366 SmiEnAndMask
= MAX_UINT32
;
367 Status
= S3SaveState
->Write (
369 EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE
,
370 EfiBootScriptWidthUint32
,
375 if (EFI_ERROR (Status
)) {
378 "%a: EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE: %r\n",
386 GenPmCon1Address
= POWER_MGMT_REGISTER_Q35_EFI_PCI_ADDRESS (
389 GenPmCon1OrMask
= ICH9_GEN_PMCON_1_SMI_LOCK
;
390 GenPmCon1AndMask
= MAX_UINT16
;
391 Status
= S3SaveState
->Write (
393 EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE
,
394 EfiBootScriptWidthUint16
,
399 if (EFI_ERROR (Status
)) {
402 "%a: EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE: %r\n",
410 DEBUG ((DEBUG_VERBOSE
, "%a: chipset boot script saved\n", __FUNCTION__
));
413 // Append a boot script fragment that re-selects the negotiated SMI features.
415 if (mSmiFeatureNegotiation
) {
419 gBS
->CloseEvent (Event
);
420 mS3SaveStateInstalled
= NULL
;