]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.c
OvmfPkg/Csm/LegacyBiosDxe: Fix Legacy16GetTableAddress call for E820 data
[mirror_edk2.git] / OvmfPkg / SmmControl2Dxe / SmmControl2Dxe.c
1 /** @file
2
3 A DXE_RUNTIME_DRIVER providing synchronous SMI activations via the
4 EFI_SMM_CONTROL2_PROTOCOL.
5
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)
11
12 Our own entry point is responsible for confirming the SMI feature and for
13 configuring it.
14
15 Copyright (C) 2013, 2015, Red Hat, Inc.<BR>
16 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
17
18 SPDX-License-Identifier: BSD-2-Clause-Patent
19
20 **/
21
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>
33
34 #include "SmiFeatures.h"
35
36 //
37 // Forward declaration.
38 //
39 STATIC
40 VOID
41 EFIAPI
42 OnS3SaveStateInstalled (
43 IN EFI_EVENT Event,
44 IN VOID *Context
45 );
46
47 //
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
51 // phase.
52 //
53 STATIC UINTN mSmiEnable;
54
55 //
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.
59 //
60 STATIC BOOLEAN mSmiFeatureNegotiation;
61
62 //
63 // Event signaled when an S3SaveState protocol interface is installed.
64 //
65 STATIC EFI_EVENT mS3SaveStateInstalled;
66
67 /**
68 Invokes SMI activation from either the preboot or runtime environment.
69
70 This function generates an SMI.
71
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
76 stream.
77 @param[in] ActivationInterval Optional parameter to repeat at this
78 period one time or, if the Periodic
79 Boolean is set, periodically.
80
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
85 cleared.
86 @retval EFI_NOT_STARTED The SMM base service has not been initialized.
87 **/
88 STATIC
89 EFI_STATUS
90 EFIAPI
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
97 )
98 {
99 //
100 // No support for queued or periodic activation.
101 //
102 if (Periodic || ActivationInterval > 0) {
103 return EFI_DEVICE_ERROR;
104 }
105
106 //
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
112 // software.
113 //
114 // Write to the status register first, as this won't trigger the SMI just
115 // yet. Then write to the control register.
116 //
117 IoWrite8 (ICH9_APM_STS, DataPort == NULL ? 0 : *DataPort);
118 IoWrite8 (ICH9_APM_CNT, CommandPort == NULL ? 0 : *CommandPort);
119 return EFI_SUCCESS;
120 }
121
122 /**
123 Clears any system state that was created in response to the Trigger() call.
124
125 This function acknowledges and causes the deassertion of the SMI activation
126 source.
127
128 @param[in] This The EFI_SMM_CONTROL2_PROTOCOL instance.
129 @param[in] Periodic Optional parameter to repeat at this period
130 one time
131
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
135 argument.
136 **/
137 STATIC
138 EFI_STATUS
139 EFIAPI
140 SmmControl2DxeClear (
141 IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
142 IN BOOLEAN Periodic OPTIONAL
143 )
144 {
145 if (Periodic) {
146 return EFI_INVALID_PARAMETER;
147 }
148
149 //
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().
156 //
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].
160 //
161 // So, nothing to do here.
162 //
163 return EFI_SUCCESS;
164 }
165
166 STATIC EFI_SMM_CONTROL2_PROTOCOL mControl2 = {
167 &SmmControl2DxeTrigger,
168 &SmmControl2DxeClear,
169 MAX_UINTN // MinimumTriggerPeriod -- we don't support periodic SMIs
170 };
171
172 //
173 // Entry point of this driver.
174 //
175 EFI_STATUS
176 EFIAPI
177 SmmControl2DxeEntryPoint (
178 IN EFI_HANDLE ImageHandle,
179 IN EFI_SYSTEM_TABLE *SystemTable
180 )
181 {
182 UINT32 PmBase;
183 UINT32 SmiEnableVal;
184 EFI_STATUS Status;
185
186 //
187 // This module should only be included if SMRAM support is required.
188 //
189 ASSERT (FeaturePcdGet (PcdSmmSmramRequire));
190
191 //
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.)
195 //
196 PmBase = PciRead32 (POWER_MGMT_REGISTER_Q35 (ICH9_PMBASE)) &
197 ICH9_PMBASE_MASK;
198 mSmiEnable = PmBase + ICH9_PMBASE_OFS_SMI_EN;
199
200 //
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.
204 //
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",
208 __FUNCTION__));
209 goto FatalError;
210 }
211
212 //
213 // Otherwise, configure the board to inject an SMI when ICH9_APM_CNT is
214 // written to. (See the Trigger() method above.)
215 //
216 SmiEnableVal |= ICH9_SMI_EN_APMC_EN | ICH9_SMI_EN_GBL_SMI_EN;
217 IoWrite32 (mSmiEnable, SmiEnableVal);
218
219 //
220 // Prevent software from undoing the above (until platform reset).
221 //
222 PciOr16 (POWER_MGMT_REGISTER_Q35 (ICH9_GEN_PMCON_1),
223 ICH9_GEN_PMCON_1_SMI_LOCK);
224
225 //
226 // If we can clear GBL_SMI_EN now, that means QEMU's SMI support is not
227 // appropriate.
228 //
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",
232 __FUNCTION__));
233 goto FatalError;
234 }
235
236 //
237 // QEMU can inject SMIs in different ways, negotiate our preferences.
238 //
239 mSmiFeatureNegotiation = NegotiateSmiFeatures ();
240
241 if (QemuFwCfgS3Enabled ()) {
242 VOID *Registration;
243
244 //
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.
248 //
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));
254 goto FatalError;
255 }
256
257 Status = gBS->RegisterProtocolNotify (&gEfiS3SaveStateProtocolGuid,
258 mS3SaveStateInstalled, &Registration);
259 if (EFI_ERROR (Status)) {
260 DEBUG ((EFI_D_ERROR, "%a: RegisterProtocolNotify: %r\n", __FUNCTION__,
261 Status));
262 goto ReleaseEvent;
263 }
264
265 //
266 // Kick the event right now -- maybe the boot script is already saveable.
267 //
268 Status = gBS->SignalEvent (mS3SaveStateInstalled);
269 if (EFI_ERROR (Status)) {
270 DEBUG ((EFI_D_ERROR, "%a: SignalEvent: %r\n", __FUNCTION__, Status));
271 goto ReleaseEvent;
272 }
273 }
274
275 //
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.
278 //
279 Status = gBS->InstallMultipleProtocolInterfaces (&ImageHandle,
280 &gEfiSmmControl2ProtocolGuid, &mControl2,
281 NULL);
282 if (EFI_ERROR (Status)) {
283 DEBUG ((EFI_D_ERROR, "%a: InstallMultipleProtocolInterfaces: %r\n",
284 __FUNCTION__, Status));
285 goto ReleaseEvent;
286 }
287
288 return EFI_SUCCESS;
289
290 ReleaseEvent:
291 if (mS3SaveStateInstalled != NULL) {
292 gBS->CloseEvent (mS3SaveStateInstalled);
293 }
294
295 FatalError:
296 //
297 // We really don't want to continue in this case.
298 //
299 ASSERT (FALSE);
300 CpuDeadLoop ();
301 return EFI_UNSUPPORTED;
302 }
303
304 /**
305 Notification callback for S3SaveState installation.
306
307 @param[in] Event Event whose notification function is being invoked.
308
309 @param[in] Context The pointer to the notification function's context, which
310 is implementation-dependent.
311 **/
312 STATIC
313 VOID
314 EFIAPI
315 OnS3SaveStateInstalled (
316 IN EFI_EVENT Event,
317 IN VOID *Context
318 )
319 {
320 EFI_STATUS Status;
321 EFI_S3_SAVE_STATE_PROTOCOL *S3SaveState;
322 UINT32 SmiEnOrMask, SmiEnAndMask;
323 UINT64 GenPmCon1Address;
324 UINT16 GenPmCon1OrMask, GenPmCon1AndMask;
325
326 ASSERT (Event == mS3SaveStateInstalled);
327
328 Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid,
329 NULL /* Registration */, (VOID **)&S3SaveState);
330 if (EFI_ERROR (Status)) {
331 return;
332 }
333
334 //
335 // These operations were originally done, verified and explained in the entry
336 // point function of the driver.
337 //
338 SmiEnOrMask = ICH9_SMI_EN_APMC_EN | ICH9_SMI_EN_GBL_SMI_EN;
339 SmiEnAndMask = MAX_UINT32;
340 Status = S3SaveState->Write (
341 S3SaveState,
342 EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE,
343 EfiBootScriptWidthUint32,
344 (UINT64)mSmiEnable,
345 &SmiEnOrMask,
346 &SmiEnAndMask
347 );
348 if (EFI_ERROR (Status)) {
349 DEBUG ((EFI_D_ERROR, "%a: EFI_BOOT_SCRIPT_IO_READ_WRITE_OPCODE: %r\n",
350 __FUNCTION__, Status));
351 ASSERT (FALSE);
352 CpuDeadLoop ();
353 }
354
355 GenPmCon1Address = POWER_MGMT_REGISTER_Q35_EFI_PCI_ADDRESS (
356 ICH9_GEN_PMCON_1);
357 GenPmCon1OrMask = ICH9_GEN_PMCON_1_SMI_LOCK;
358 GenPmCon1AndMask = MAX_UINT16;
359 Status = S3SaveState->Write (
360 S3SaveState,
361 EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE,
362 EfiBootScriptWidthUint16,
363 GenPmCon1Address,
364 &GenPmCon1OrMask,
365 &GenPmCon1AndMask
366 );
367 if (EFI_ERROR (Status)) {
368 DEBUG ((EFI_D_ERROR,
369 "%a: EFI_BOOT_SCRIPT_PCI_CONFIG_READ_WRITE_OPCODE: %r\n", __FUNCTION__,
370 Status));
371 ASSERT (FALSE);
372 CpuDeadLoop ();
373 }
374
375 DEBUG ((DEBUG_VERBOSE, "%a: chipset boot script saved\n", __FUNCTION__));
376
377 //
378 // Append a boot script fragment that re-selects the negotiated SMI features.
379 //
380 if (mSmiFeatureNegotiation) {
381 SaveSmiFeatures ();
382 }
383
384 gBS->CloseEvent (Event);
385 mS3SaveStateInstalled = NULL;
386 }