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/MemoryAllocationLib.h>
13 #include <Library/PcdLib.h>
14 #include <Library/QemuFwCfgLib.h>
15 #include <Library/QemuFwCfgS3Lib.h>
17 #include "SmiFeatures.h"
20 // The following bit value stands for "broadcast SMI" in the
21 // "etc/smi/supported-features" and "etc/smi/requested-features" fw_cfg files.
23 #define ICH9_LPC_SMI_F_BROADCAST BIT0
26 // Provides a scratch buffer (allocated in EfiReservedMemoryType type memory)
27 // for the S3 boot script fragment to write to and read from.
37 // These carry the selector keys of the "etc/smi/requested-features" and
38 // "etc/smi/features-ok" fw_cfg files from NegotiateSmiFeatures() to
39 // AppendFwCfgBootScript().
41 STATIC FIRMWARE_CONFIG_ITEM mRequestedFeaturesItem
;
42 STATIC FIRMWARE_CONFIG_ITEM mFeaturesOkItem
;
45 // Carries the negotiated SMI features from NegotiateSmiFeatures() to
46 // AppendFwCfgBootScript().
48 STATIC UINT64 mSmiFeatures
;
51 Negotiate SMI features with QEMU.
53 @retval FALSE If SMI feature negotiation is not supported by QEMU. This is
54 not an error, it just means that SaveSmiFeatures() should not
57 @retval TRUE SMI feature negotiation is supported, and it has completed
58 successfully as well. (Failure to negotiate is a fatal error
59 and the function never returns in that case.)
62 NegotiateSmiFeatures (
66 FIRMWARE_CONFIG_ITEM SupportedFeaturesItem
;
67 UINTN SupportedFeaturesSize
;
68 UINTN RequestedFeaturesSize
;
72 // Look up the fw_cfg files used for feature negotiation. The selector keys
73 // of "etc/smi/requested-features" and "etc/smi/features-ok" are saved
74 // statically. If the files are missing, then QEMU doesn't support SMI
75 // feature negotiation.
77 if (RETURN_ERROR (QemuFwCfgFindFile ("etc/smi/supported-features",
78 &SupportedFeaturesItem
, &SupportedFeaturesSize
)) ||
79 RETURN_ERROR (QemuFwCfgFindFile ("etc/smi/requested-features",
80 &mRequestedFeaturesItem
, &RequestedFeaturesSize
)) ||
81 RETURN_ERROR (QemuFwCfgFindFile ("etc/smi/features-ok",
82 &mFeaturesOkItem
, &FeaturesOkSize
))) {
83 DEBUG ((DEBUG_INFO
, "%a: SMI feature negotiation unavailable\n",
89 // If the files are present but their sizes disagree with us, that's a fatal
90 // error (we can't trust the behavior of SMIs either way).
92 if (SupportedFeaturesSize
!= sizeof mSmiFeatures
||
93 RequestedFeaturesSize
!= sizeof mSmiFeatures
||
94 FeaturesOkSize
!= sizeof (UINT8
)) {
95 DEBUG ((DEBUG_ERROR
, "%a: size mismatch in feature negotiation\n",
101 // Get the features supported by the host.
103 QemuFwCfgSelectItem (SupportedFeaturesItem
);
104 QemuFwCfgReadBytes (sizeof mSmiFeatures
, &mSmiFeatures
);
107 // We want broadcast SMI and nothing else.
109 mSmiFeatures
&= ICH9_LPC_SMI_F_BROADCAST
;
110 QemuFwCfgSelectItem (mRequestedFeaturesItem
);
111 QemuFwCfgWriteBytes (sizeof mSmiFeatures
, &mSmiFeatures
);
114 // Invoke feature validation in QEMU. If the selection is accepted, the
115 // features will be locked down. If the selection is rejected, feature
116 // negotiation remains open; however we don't know what to do in that case,
117 // so that's a fatal error.
119 QemuFwCfgSelectItem (mFeaturesOkItem
);
120 if (QemuFwCfgRead8 () != 1) {
121 DEBUG ((DEBUG_ERROR
, "%a: negotiation failed for feature bitmap 0x%Lx\n",
122 __FUNCTION__
, mSmiFeatures
));
126 if ((mSmiFeatures
& ICH9_LPC_SMI_F_BROADCAST
) == 0) {
128 // If we can't get broadcast SMIs from QEMU, that's acceptable too,
129 // although not optimal.
131 DEBUG ((DEBUG_INFO
, "%a: SMI broadcast unavailable\n", __FUNCTION__
));
134 // Configure the traditional AP sync / SMI delivery mode for
135 // PiSmmCpuDxeSmm. Effectively, restore the UefiCpuPkg defaults, from which
136 // the original QEMU behavior (i.e., unicast SMI) used to differ.
138 if (RETURN_ERROR (PcdSet64S (PcdCpuSmmApSyncTimeout
, 1000000)) ||
139 RETURN_ERROR (PcdSet8S (PcdCpuSmmSyncMode
, 0x00))) {
140 DEBUG ((DEBUG_ERROR
, "%a: PiSmmCpuDxeSmm PCD configuration failed\n",
144 DEBUG ((DEBUG_INFO
, "%a: using SMI broadcast\n", __FUNCTION__
));
148 // Negotiation successful (although we may not have gotten the optimal
157 // Keep the compiler happy.
163 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION provided to QemuFwCfgS3Lib.
168 AppendFwCfgBootScript (
169 IN OUT VOID
*Context
, OPTIONAL
170 IN OUT VOID
*ExternalScratchBuffer
173 SCRATCH_BUFFER
*ScratchBuffer
;
174 RETURN_STATUS Status
;
176 ScratchBuffer
= ExternalScratchBuffer
;
179 // Write the negotiated feature bitmap into "etc/smi/requested-features".
181 ScratchBuffer
->Features
= mSmiFeatures
;
182 Status
= QemuFwCfgS3ScriptWriteBytes (mRequestedFeaturesItem
,
183 sizeof ScratchBuffer
->Features
);
184 if (RETURN_ERROR (Status
)) {
189 // Read back "etc/smi/features-ok". This invokes the feature validation &
190 // lockdown. (The validation succeeded at first boot.)
192 Status
= QemuFwCfgS3ScriptReadBytes (mFeaturesOkItem
,
193 sizeof ScratchBuffer
->FeaturesOk
);
194 if (RETURN_ERROR (Status
)) {
199 // If "etc/smi/features-ok" read as 1, we're good. Otherwise, hang the S3
202 Status
= QemuFwCfgS3ScriptCheckValue (&ScratchBuffer
->FeaturesOk
,
203 sizeof ScratchBuffer
->FeaturesOk
, MAX_UINT8
, 1);
204 if (RETURN_ERROR (Status
)) {
208 DEBUG ((DEBUG_VERBOSE
, "%a: SMI feature negotiation boot script saved\n",
219 Append a boot script fragment that will re-select the previously negotiated
220 SMI features during S3 resume.
227 RETURN_STATUS Status
;
230 // We are already running at TPL_CALLBACK, on the stack of
231 // OnS3SaveStateInstalled(). But that's okay, we can easily queue more
232 // notification functions while executing a notification function.
234 Status
= QemuFwCfgS3CallWhenBootScriptReady (AppendFwCfgBootScript
, NULL
,
235 sizeof (SCRATCH_BUFFER
));
236 if (RETURN_ERROR (Status
)) {