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/QemuFwCfgLib.h>
29 #include <Library/QemuFwCfgS3Lib.h>
30 #include <Library/UefiBootServicesTableLib.h>
31 #include <Protocol/S3SaveState.h>
32 #include <Protocol/SmmControl2.h>
34 #include "SmiFeatures.h"
37 // Forward declaration.
42 OnS3SaveStateInstalled (
48 // The absolute IO port address of the SMI Control and Enable Register. It is
49 // only used to carry information from the entry point function to the
50 // S3SaveState protocol installation callback, strictly before the runtime
53 STATIC UINTN mSmiEnable
;
56 // Captures whether SMI feature negotiation is supported. The variable is only
57 // used to carry this information from the entry point function to the
58 // S3SaveState protocol installation callback.
60 STATIC BOOLEAN mSmiFeatureNegotiation
;
63 // Event signaled when an S3SaveState protocol interface is installed.
65 STATIC EFI_EVENT mS3SaveStateInstalled
;
68 Invokes SMI activation from either the preboot or runtime environment.
70 This function generates an SMI.
72 @param[in] This The EFI_SMM_CONTROL2_PROTOCOL instance.
73 @param[in,out] CommandPort The value written to the command port.
74 @param[in,out] DataPort The value written to the data port.
75 @param[in] Periodic Optional mechanism to engender a periodic
77 @param[in] ActivationInterval Optional parameter to repeat at this
78 period one time or, if the Periodic
79 Boolean is set, periodically.
81 @retval EFI_SUCCESS The SMI/PMI has been engendered.
82 @retval EFI_DEVICE_ERROR The timing is unsupported.
83 @retval EFI_INVALID_PARAMETER The activation period is unsupported.
84 @retval EFI_INVALID_PARAMETER The last periodic activation has not been
86 @retval EFI_NOT_STARTED The SMM base service has not been initialized.
91 SmmControl2DxeTrigger (
92 IN CONST EFI_SMM_CONTROL2_PROTOCOL
*This
,
93 IN OUT UINT8
*CommandPort OPTIONAL
,
94 IN OUT UINT8
*DataPort OPTIONAL
,
95 IN BOOLEAN Periodic OPTIONAL
,
96 IN UINTN ActivationInterval OPTIONAL
100 // No support for queued or periodic activation.
102 if (Periodic
|| ActivationInterval
> 0) {
103 return EFI_DEVICE_ERROR
;
107 // The so-called "Advanced Power Management Status Port Register" is in fact
108 // a generic data passing register, between the caller and the SMI
109 // dispatcher. The ICH9 spec calls it "scratchpad register" -- calling it
110 // "status" elsewhere seems quite the misnomer. Status registers usually
111 // report about hardware status, while this register is fully governed by
114 // Write to the status register first, as this won't trigger the SMI just
115 // yet. Then write to the control register.
117 IoWrite8 (ICH9_APM_STS
, DataPort
== NULL
? 0 : *DataPort
);
118 IoWrite8 (ICH9_APM_CNT
, CommandPort
== NULL
? 0 : *CommandPort
);
123 Clears any system state that was created in response to the Trigger() call.
125 This function acknowledges and causes the deassertion of the SMI activation
128 @param[in] This The EFI_SMM_CONTROL2_PROTOCOL instance.
129 @param[in] Periodic Optional parameter to repeat at this period
132 @retval EFI_SUCCESS The SMI/PMI has been engendered.
133 @retval EFI_DEVICE_ERROR The source could not be cleared.
134 @retval EFI_INVALID_PARAMETER The service did not support the Periodic input
140 SmmControl2DxeClear (
141 IN CONST EFI_SMM_CONTROL2_PROTOCOL
*This
,
142 IN BOOLEAN Periodic OPTIONAL
146 return EFI_INVALID_PARAMETER
;
150 // The PI spec v1.4 explains that Clear() is only supposed to clear software
151 // status; it is not in fact responsible for deasserting the SMI. It gives
152 // two reasons for this: (a) many boards clear the SMI automatically when
153 // entering SMM, (b) if Clear() actually deasserted the SMI, then it could
154 // incorrectly suppress an SMI that was asynchronously asserted between the
155 // last return of the SMI handler and the call made to Clear().
157 // In fact QEMU automatically deasserts CPU_INTERRUPT_SMI in:
158 // - x86_cpu_exec_interrupt() [target-i386/seg_helper.c], and
159 // - kvm_arch_pre_run() [target-i386/kvm.c].
161 // So, nothing to do here.
166 STATIC EFI_SMM_CONTROL2_PROTOCOL mControl2
= {
167 &SmmControl2DxeTrigger
,
168 &SmmControl2DxeClear
,
169 MAX_UINTN
// MinimumTriggerPeriod -- we don't support periodic SMIs
173 // Entry point of this driver.
177 SmmControl2DxeEntryPoint (
178 IN EFI_HANDLE ImageHandle
,
179 IN EFI_SYSTEM_TABLE
*SystemTable
187 // This module should only be included if SMRAM support is required.
189 ASSERT (FeaturePcdGet (PcdSmmSmramRequire
));
192 // Calculate the absolute IO port address of the SMI Control and Enable
193 // Register. (As noted at the top, the PEI phase has left us with a working
194 // ACPI PM IO space.)
196 PmBase
= PciRead32 (POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE
)) &
198 mSmiEnable
= PmBase
+ ICH9_PMBASE_OFS_SMI_EN
;
201 // If APMC_EN is pre-set in SMI_EN, that's QEMU's way to tell us that SMI
202 // support is not available. (For example due to KVM lacking it.) Otherwise,
203 // this bit is clear after each reset.
205 SmiEnableVal
= IoRead32 (mSmiEnable
);
206 if ((SmiEnableVal
& ICH9_SMI_EN_APMC_EN
) != 0) {
207 DEBUG ((EFI_D_ERROR
, "%a: this Q35 implementation lacks SMI\n",
213 // Otherwise, configure the board to inject an SMI when ICH9_APM_CNT is
214 // written to. (See the Trigger() method above.)
216 SmiEnableVal
|= ICH9_SMI_EN_APMC_EN
| ICH9_SMI_EN_GBL_SMI_EN
;
217 IoWrite32 (mSmiEnable
, SmiEnableVal
);
220 // Prevent software from undoing the above (until platform reset).
222 PciOr16 (POWER_MGMT_REGISTER_Q35 (ICH9_GEN_PMCON_1
),
223 ICH9_GEN_PMCON_1_SMI_LOCK
);
226 // If we can clear GBL_SMI_EN now, that means QEMU's SMI support is not
229 IoWrite32 (mSmiEnable
, SmiEnableVal
& ~(UINT32
)ICH9_SMI_EN_GBL_SMI_EN
);
230 if (IoRead32 (mSmiEnable
) != SmiEnableVal
) {
231 DEBUG ((EFI_D_ERROR
, "%a: failed to lock down GBL_SMI_EN\n",
237 // QEMU can inject SMIs in different ways, negotiate our preferences.
239 mSmiFeatureNegotiation
= NegotiateSmiFeatures ();
241 if (QemuFwCfgS3Enabled ()) {
245 // On S3 resume the above register settings have to be repeated. Register a
246 // protocol notify callback that, when boot script saving becomes
247 // available, saves operations equivalent to the above to the boot script.
249 Status
= gBS
->CreateEvent (EVT_NOTIFY_SIGNAL
, TPL_CALLBACK
,
250 OnS3SaveStateInstalled
, NULL
/* Context */,
251 &mS3SaveStateInstalled
);
252 if (EFI_ERROR (Status
)) {
253 DEBUG ((EFI_D_ERROR
, "%a: CreateEvent: %r\n", __FUNCTION__
, Status
));
257 Status
= gBS
->RegisterProtocolNotify (&gEfiS3SaveStateProtocolGuid
,
258 mS3SaveStateInstalled
, &Registration
);
259 if (EFI_ERROR (Status
)) {
260 DEBUG ((EFI_D_ERROR
, "%a: RegisterProtocolNotify: %r\n", __FUNCTION__
,
266 // Kick the event right now -- maybe the boot script is already saveable.
268 Status
= gBS
->SignalEvent (mS3SaveStateInstalled
);
269 if (EFI_ERROR (Status
)) {
270 DEBUG ((EFI_D_ERROR
, "%a: SignalEvent: %r\n", __FUNCTION__
, Status
));
276 // We have no pointers to convert to virtual addresses. The handle itself
277 // doesn't matter, as protocol services are not accessible at runtime.
279 Status
= gBS
->InstallMultipleProtocolInterfaces (&ImageHandle
,
280 &gEfiSmmControl2ProtocolGuid
, &mControl2
,
282 if (EFI_ERROR (Status
)) {
283 DEBUG ((EFI_D_ERROR
, "%a: InstallMultipleProtocolInterfaces: %r\n",
284 __FUNCTION__
, Status
));
291 if (mS3SaveStateInstalled
!= NULL
) {
292 gBS
->CloseEvent (mS3SaveStateInstalled
);
297 // We really don't want to continue in this case.
301 return EFI_UNSUPPORTED
;
305 Notification callback for S3SaveState installation.
307 @param[in] Event Event whose notification function is being invoked.
309 @param[in] Context The pointer to the notification function's context, which
310 is implementation-dependent.
315 OnS3SaveStateInstalled (
321 EFI_S3_SAVE_STATE_PROTOCOL
*S3SaveState
;
322 UINT32 SmiEnOrMask
, SmiEnAndMask
;
323 UINT64 GenPmCon1Address
;
324 UINT16 GenPmCon1OrMask
, GenPmCon1AndMask
;
326 ASSERT (Event
== mS3SaveStateInstalled
);
328 Status
= gBS
->LocateProtocol (&gEfiS3SaveStateProtocolGuid
,
329 NULL
/* Registration */, (VOID
**)&S3SaveState
);
330 if (EFI_ERROR (Status
)) {
335 // These operations were originally done, verified and explained in the entry
336 // point function of the driver.
338 SmiEnOrMask
= ICH9_SMI_EN_APMC_EN
| ICH9_SMI_EN_GBL_SMI_EN
;
339 SmiEnAndMask
= MAX_UINT32
;
340 Status
= S3SaveState
->Write (
342 EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE
,
343 EfiBootScriptWidthUint32
,
348 if (EFI_ERROR (Status
)) {
349 DEBUG ((EFI_D_ERROR
, "%a: EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE: %r\n",
350 __FUNCTION__
, Status
));
355 GenPmCon1Address
= POWER_MGMT_REGISTER_Q35_EFI_PCI_ADDRESS (
357 GenPmCon1OrMask
= ICH9_GEN_PMCON_1_SMI_LOCK
;
358 GenPmCon1AndMask
= MAX_UINT16
;
359 Status
= S3SaveState
->Write (
361 EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE
,
362 EfiBootScriptWidthUint16
,
367 if (EFI_ERROR (Status
)) {
369 "%a: EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE: %r\n", __FUNCTION__
,
375 DEBUG ((DEBUG_VERBOSE
, "%a: chipset boot script saved\n", __FUNCTION__
));
378 // Append a boot script fragment that re-selects the negotiated SMI features.
380 if (mSmiFeatureNegotiation
) {
384 gBS
->CloseEvent (Event
);
385 mS3SaveStateInstalled
= NULL
;