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