2 Negotiate SMI features with QEMU, and configure UefiCpuPkg/PiSmmCpuDxeSmm
5 Copyright (C) 2016-2017, Red Hat, Inc.
7 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Library/BaseLib.h>
11 #include <Library/DebugLib.h>
12 #include <Library/MemEncryptSevLib.h>
13 #include <Library/MemoryAllocationLib.h>
14 #include <Library/PcdLib.h>
15 #include <Library/QemuFwCfgLib.h>
16 #include <Library/QemuFwCfgS3Lib.h>
18 #include "SmiFeatures.h"
21 // The following bit value stands for "broadcast SMI" in the
22 // "etc/smi/supported-features" and "etc/smi/requested-features" fw_cfg files.
24 #define ICH9_LPC_SMI_F_BROADCAST BIT0
26 // The following bit value stands for "enable CPU hotplug, and inject an SMI
27 // with control value ICH9_APM_CNT_CPU_HOTPLUG upon hotplug", in the
28 // "etc/smi/supported-features" and "etc/smi/requested-features" fw_cfg files.
30 #define ICH9_LPC_SMI_F_CPU_HOTPLUG BIT1
32 // The following bit value stands for "enable CPU hot-unplug, and inject an SMI
33 // with control value ICH9_APM_CNT_CPU_HOTPLUG upon hot-unplug", in the
34 // "etc/smi/supported-features" and "etc/smi/requested-features" fw_cfg files.
36 #define ICH9_LPC_SMI_F_CPU_HOT_UNPLUG BIT2
39 // Provides a scratch buffer (allocated in EfiReservedMemoryType type memory)
40 // for the S3 boot script fragment to write to and read from.
50 // These carry the selector keys of the "etc/smi/requested-features" and
51 // "etc/smi/features-ok" fw_cfg files from NegotiateSmiFeatures() to
52 // AppendFwCfgBootScript().
54 STATIC FIRMWARE_CONFIG_ITEM mRequestedFeaturesItem
;
55 STATIC FIRMWARE_CONFIG_ITEM mFeaturesOkItem
;
58 // Carries the negotiated SMI features from NegotiateSmiFeatures() to
59 // AppendFwCfgBootScript().
61 STATIC UINT64 mSmiFeatures
;
64 Negotiate SMI features with QEMU.
66 @retval FALSE If SMI feature negotiation is not supported by QEMU. This is
67 not an error, it just means that SaveSmiFeatures() should not
70 @retval TRUE SMI feature negotiation is supported, and it has completed
71 successfully as well. (Failure to negotiate is a fatal error
72 and the function never returns in that case.)
75 NegotiateSmiFeatures (
79 FIRMWARE_CONFIG_ITEM SupportedFeaturesItem
;
80 UINTN SupportedFeaturesSize
;
81 UINTN RequestedFeaturesSize
;
83 UINT64 RequestedFeaturesMask
;
86 // Look up the fw_cfg files used for feature negotiation. The selector keys
87 // of "etc/smi/requested-features" and "etc/smi/features-ok" are saved
88 // statically. If the files are missing, then QEMU doesn't support SMI
89 // feature negotiation.
93 "etc/smi/supported-features",
94 &SupportedFeaturesItem
,
95 &SupportedFeaturesSize
100 "etc/smi/requested-features",
101 &mRequestedFeaturesItem
,
102 &RequestedFeaturesSize
107 "etc/smi/features-ok",
115 "%a: SMI feature negotiation unavailable\n",
122 // If the files are present but their sizes disagree with us, that's a fatal
123 // error (we can't trust the behavior of SMIs either way).
125 if ((SupportedFeaturesSize
!= sizeof mSmiFeatures
) ||
126 (RequestedFeaturesSize
!= sizeof mSmiFeatures
) ||
127 (FeaturesOkSize
!= sizeof (UINT8
)))
131 "%a: size mismatch in feature negotiation\n",
138 // Get the features supported by the host.
140 QemuFwCfgSelectItem (SupportedFeaturesItem
);
141 QemuFwCfgReadBytes (sizeof mSmiFeatures
, &mSmiFeatures
);
144 // We want broadcast SMI, SMI on CPU hotplug, SMI on CPU hot-unplug
147 RequestedFeaturesMask
= ICH9_LPC_SMI_F_BROADCAST
;
148 if (!MemEncryptSevIsEnabled ()) {
150 // For now, we only support hotplug with SEV disabled.
152 RequestedFeaturesMask
|= ICH9_LPC_SMI_F_CPU_HOTPLUG
;
153 RequestedFeaturesMask
|= ICH9_LPC_SMI_F_CPU_HOT_UNPLUG
;
156 mSmiFeatures
&= RequestedFeaturesMask
;
157 QemuFwCfgSelectItem (mRequestedFeaturesItem
);
158 QemuFwCfgWriteBytes (sizeof mSmiFeatures
, &mSmiFeatures
);
161 // Invoke feature validation in QEMU. If the selection is accepted, the
162 // features will be locked down. If the selection is rejected, feature
163 // negotiation remains open; however we don't know what to do in that case,
164 // so that's a fatal error.
166 QemuFwCfgSelectItem (mFeaturesOkItem
);
167 if (QemuFwCfgRead8 () != 1) {
170 "%a: negotiation failed for feature bitmap 0x%Lx\n",
177 if ((mSmiFeatures
& ICH9_LPC_SMI_F_BROADCAST
) == 0) {
179 // If we can't get broadcast SMIs from QEMU, that's acceptable too,
180 // although not optimal.
182 DEBUG ((DEBUG_INFO
, "%a: SMI broadcast unavailable\n", __FUNCTION__
));
185 // Configure the traditional AP sync / SMI delivery mode for
186 // PiSmmCpuDxeSmm. Effectively, restore the UefiCpuPkg defaults, from which
187 // the original QEMU behavior (i.e., unicast SMI) used to differ.
189 if (RETURN_ERROR (PcdSet64S (PcdCpuSmmApSyncTimeout
, 1000000)) ||
190 RETURN_ERROR (PcdSet8S (PcdCpuSmmSyncMode
, 0x00)))
194 "%a: PiSmmCpuDxeSmm PCD configuration failed\n",
200 DEBUG ((DEBUG_INFO
, "%a: using SMI broadcast\n", __FUNCTION__
));
203 if ((mSmiFeatures
& ICH9_LPC_SMI_F_CPU_HOTPLUG
) == 0) {
204 DEBUG ((DEBUG_INFO
, "%a: CPU hotplug not negotiated\n", __FUNCTION__
));
208 "%a: CPU hotplug with SMI negotiated\n",
213 if ((mSmiFeatures
& ICH9_LPC_SMI_F_CPU_HOT_UNPLUG
) == 0) {
214 DEBUG ((DEBUG_INFO
, "%a: CPU hot-unplug not negotiated\n", __FUNCTION__
));
218 "%a: CPU hot-unplug with SMI negotiated\n",
224 // Negotiation successful (although we may not have gotten the optimal
233 // Keep the compiler happy.
239 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION provided to QemuFwCfgS3Lib.
244 AppendFwCfgBootScript (
245 IN OUT VOID
*Context OPTIONAL
,
246 IN OUT VOID
*ExternalScratchBuffer
249 SCRATCH_BUFFER
*ScratchBuffer
;
250 RETURN_STATUS Status
;
252 ScratchBuffer
= ExternalScratchBuffer
;
255 // Write the negotiated feature bitmap into "etc/smi/requested-features".
257 ScratchBuffer
->Features
= mSmiFeatures
;
258 Status
= QemuFwCfgS3ScriptWriteBytes (
259 mRequestedFeaturesItem
,
260 sizeof ScratchBuffer
->Features
262 if (RETURN_ERROR (Status
)) {
267 // Read back "etc/smi/features-ok". This invokes the feature validation &
268 // lockdown. (The validation succeeded at first boot.)
270 Status
= QemuFwCfgS3ScriptReadBytes (
272 sizeof ScratchBuffer
->FeaturesOk
274 if (RETURN_ERROR (Status
)) {
279 // If "etc/smi/features-ok" read as 1, we're good. Otherwise, hang the S3
282 Status
= QemuFwCfgS3ScriptCheckValue (
283 &ScratchBuffer
->FeaturesOk
,
284 sizeof ScratchBuffer
->FeaturesOk
,
288 if (RETURN_ERROR (Status
)) {
294 "%a: SMI feature negotiation boot script saved\n",
305 Append a boot script fragment that will re-select the previously negotiated
306 SMI features during S3 resume.
313 RETURN_STATUS Status
;
316 // We are already running at TPL_CALLBACK, on the stack of
317 // OnS3SaveStateInstalled(). But that's okay, we can easily queue more
318 // notification functions while executing a notification function.
320 Status
= QemuFwCfgS3CallWhenBootScriptReady (
321 AppendFwCfgBootScript
,
323 sizeof (SCRATCH_BUFFER
)
325 if (RETURN_ERROR (Status
)) {