TianoCore EDK2 master
Loading...
Searching...
No Matches
SmiFeatures.c
Go to the documentation of this file.
1
11#include <Library/BaseLib.h>
12#include <Library/DebugLib.h>
15#include <Library/PcdLib.h>
18
19#include "SmiFeatures.h"
20
21//
22// The following bit value stands for "broadcast SMI" in the
23// "etc/smi/supported-features" and "etc/smi/requested-features" fw_cfg files.
24//
25#define ICH9_LPC_SMI_F_BROADCAST BIT0
26//
27// The following bit value stands for "enable CPU hotplug, and inject an SMI
28// with control value ICH9_APM_CNT_CPU_HOTPLUG upon hotplug", in the
29// "etc/smi/supported-features" and "etc/smi/requested-features" fw_cfg files.
30//
31#define ICH9_LPC_SMI_F_CPU_HOTPLUG BIT1
32//
33// The following bit value stands for "enable CPU hot-unplug, and inject an SMI
34// with control value ICH9_APM_CNT_CPU_HOTPLUG upon hot-unplug", in the
35// "etc/smi/supported-features" and "etc/smi/requested-features" fw_cfg files.
36//
37#define ICH9_LPC_SMI_F_CPU_HOT_UNPLUG BIT2
38
39//
40// Provides a scratch buffer (allocated in EfiReservedMemoryType type memory)
41// for the S3 boot script fragment to write to and read from.
42//
43#pragma pack (1)
44typedef union {
45 UINT64 Features;
46 UINT8 FeaturesOk;
48#pragma pack ()
49
50//
51// These carry the selector keys of the "etc/smi/requested-features" and
52// "etc/smi/features-ok" fw_cfg files from NegotiateSmiFeatures() to
53// AppendFwCfgBootScript().
54//
55STATIC FIRMWARE_CONFIG_ITEM mRequestedFeaturesItem;
56STATIC FIRMWARE_CONFIG_ITEM mFeaturesOkItem;
57
58//
59// Carries the negotiated SMI features from NegotiateSmiFeatures() to
60// AppendFwCfgBootScript().
61//
62STATIC UINT64 mSmiFeatures;
63
75BOOLEAN
77 VOID
78 )
79{
80 FIRMWARE_CONFIG_ITEM SupportedFeaturesItem;
81 UINTN SupportedFeaturesSize;
82 UINTN RequestedFeaturesSize;
83 UINTN FeaturesOkSize;
84 UINT64 RequestedFeaturesMask;
85
86 //
87 // Look up the fw_cfg files used for feature negotiation. The selector keys
88 // of "etc/smi/requested-features" and "etc/smi/features-ok" are saved
89 // statically. If the files are missing, then QEMU doesn't support SMI
90 // feature negotiation.
91 //
92 if (RETURN_ERROR (
94 "etc/smi/supported-features",
95 &SupportedFeaturesItem,
96 &SupportedFeaturesSize
97 )
98 ) ||
101 "etc/smi/requested-features",
102 &mRequestedFeaturesItem,
103 &RequestedFeaturesSize
104 )
105 ) ||
108 "etc/smi/features-ok",
109 &mFeaturesOkItem,
110 &FeaturesOkSize
111 )
112 ))
113 {
114 DEBUG ((
115 DEBUG_INFO,
116 "%a: SMI feature negotiation unavailable\n",
117 __func__
118 ));
119 return FALSE;
120 }
121
122 //
123 // If the files are present but their sizes disagree with us, that's a fatal
124 // error (we can't trust the behavior of SMIs either way).
125 //
126 if ((SupportedFeaturesSize != sizeof mSmiFeatures) ||
127 (RequestedFeaturesSize != sizeof mSmiFeatures) ||
128 (FeaturesOkSize != sizeof (UINT8)))
129 {
130 DEBUG ((
131 DEBUG_ERROR,
132 "%a: size mismatch in feature negotiation\n",
133 __func__
134 ));
135 goto FatalError;
136 }
137
138 //
139 // Get the features supported by the host.
140 //
141 QemuFwCfgSelectItem (SupportedFeaturesItem);
142 QemuFwCfgReadBytes (sizeof mSmiFeatures, &mSmiFeatures);
143
144 //
145 // We want broadcast SMI, SMI on CPU hotplug, SMI on CPU hot-unplug
146 // and nothing else.
147 //
148 RequestedFeaturesMask = ICH9_LPC_SMI_F_BROADCAST;
149 if (!MemEncryptSevIsEnabled ()) {
150 //
151 // For now, we only support hotplug with SEV disabled.
152 //
153 RequestedFeaturesMask |= ICH9_LPC_SMI_F_CPU_HOTPLUG;
154 RequestedFeaturesMask |= ICH9_LPC_SMI_F_CPU_HOT_UNPLUG;
155 }
156
157 mSmiFeatures &= RequestedFeaturesMask;
158 QemuFwCfgSelectItem (mRequestedFeaturesItem);
159 QemuFwCfgWriteBytes (sizeof mSmiFeatures, &mSmiFeatures);
160
161 //
162 // Invoke feature validation in QEMU. If the selection is accepted, the
163 // features will be locked down. If the selection is rejected, feature
164 // negotiation remains open; however we don't know what to do in that case,
165 // so that's a fatal error.
166 //
167 QemuFwCfgSelectItem (mFeaturesOkItem);
168 if (QemuFwCfgRead8 () != 1) {
169 DEBUG ((
170 DEBUG_ERROR,
171 "%a: negotiation failed for feature bitmap 0x%Lx\n",
172 __func__,
173 mSmiFeatures
174 ));
175 goto FatalError;
176 }
177
178 if ((mSmiFeatures & ICH9_LPC_SMI_F_BROADCAST) == 0) {
179 //
180 // If we can't get broadcast SMIs from QEMU, that's acceptable too,
181 // although not optimal.
182 //
183 DEBUG ((DEBUG_INFO, "%a: SMI broadcast unavailable\n", __func__));
184 } else {
185 //
186 // Configure the traditional AP sync / SMI delivery mode for
187 // PiSmmCpuDxeSmm. Effectively, restore the UefiCpuPkg defaults, from which
188 // the original QEMU behavior (i.e., unicast SMI) used to differ.
189 //
190 if (RETURN_ERROR (PcdSet64S (PcdCpuSmmApSyncTimeout, 1000000)) ||
191 RETURN_ERROR (PcdSet64S (PcdCpuSmmApSyncTimeout2, 1000000)) ||
192 RETURN_ERROR (PcdSet8S (PcdCpuSmmSyncMode, 0x00)))
193 {
194 DEBUG ((
195 DEBUG_ERROR,
196 "%a: PiSmmCpuDxeSmm PCD configuration failed\n",
197 __func__
198 ));
199 goto FatalError;
200 }
201
202 DEBUG ((DEBUG_INFO, "%a: using SMI broadcast\n", __func__));
203 }
204
205 if ((mSmiFeatures & ICH9_LPC_SMI_F_CPU_HOTPLUG) == 0) {
206 DEBUG ((DEBUG_INFO, "%a: CPU hotplug not negotiated\n", __func__));
207 } else {
208 DEBUG ((
209 DEBUG_INFO,
210 "%a: CPU hotplug with SMI negotiated\n",
211 __func__
212 ));
213 }
214
215 if ((mSmiFeatures & ICH9_LPC_SMI_F_CPU_HOT_UNPLUG) == 0) {
216 DEBUG ((DEBUG_INFO, "%a: CPU hot-unplug not negotiated\n", __func__));
217 } else {
218 DEBUG ((
219 DEBUG_INFO,
220 "%a: CPU hot-unplug with SMI negotiated\n",
221 __func__
222 ));
223 }
224
225 //
226 // Negotiation successful (although we may not have gotten the optimal
227 // feature set).
228 //
229 return TRUE;
230
231FatalError:
232 ASSERT (FALSE);
233 CpuDeadLoop ();
234 //
235 // Keep the compiler happy.
236 //
237 return FALSE;
238}
239
243STATIC
244VOID
245EFIAPI
247 IN OUT VOID *Context OPTIONAL,
248 IN OUT VOID *ExternalScratchBuffer
249 )
250{
251 SCRATCH_BUFFER *ScratchBuffer;
252 RETURN_STATUS Status;
253
254 ScratchBuffer = ExternalScratchBuffer;
255
256 //
257 // Write the negotiated feature bitmap into "etc/smi/requested-features".
258 //
259 ScratchBuffer->Features = mSmiFeatures;
261 mRequestedFeaturesItem,
262 sizeof ScratchBuffer->Features
263 );
264 if (RETURN_ERROR (Status)) {
265 goto FatalError;
266 }
267
268 //
269 // Read back "etc/smi/features-ok". This invokes the feature validation &
270 // lockdown. (The validation succeeded at first boot.)
271 //
273 mFeaturesOkItem,
274 sizeof ScratchBuffer->FeaturesOk
275 );
276 if (RETURN_ERROR (Status)) {
277 goto FatalError;
278 }
279
280 //
281 // If "etc/smi/features-ok" read as 1, we're good. Otherwise, hang the S3
282 // resume process.
283 //
285 &ScratchBuffer->FeaturesOk,
286 sizeof ScratchBuffer->FeaturesOk,
287 MAX_UINT8,
288 1
289 );
290 if (RETURN_ERROR (Status)) {
291 goto FatalError;
292 }
293
294 DEBUG ((
295 DEBUG_VERBOSE,
296 "%a: SMI feature negotiation boot script saved\n",
297 __func__
298 ));
299 return;
300
301FatalError:
302 ASSERT (FALSE);
303 CpuDeadLoop ();
304}
305
310VOID
312 VOID
313 )
314{
315 RETURN_STATUS Status;
316
317 //
318 // We are already running at TPL_CALLBACK, on the stack of
319 // OnS3SaveStateInstalled(). But that's okay, we can easily queue more
320 // notification functions while executing a notification function.
321 //
324 NULL,
325 sizeof (SCRATCH_BUFFER)
326 );
327 if (RETURN_ERROR (Status)) {
328 ASSERT (FALSE);
329 CpuDeadLoop ();
330 }
331}
UINT64 UINTN
VOID EFIAPI CpuDeadLoop(VOID)
Definition: CpuDeadLoop.c:25
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define RETURN_ERROR(StatusCode)
Definition: Base.h:1061
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
BOOLEAN EFIAPI MemEncryptSevIsEnabled(VOID)
#define PcdSet64S(TokenName, Value)
Definition: PcdLib.h:511
#define PcdSet8S(TokenName, Value)
Definition: PcdLib.h:469
VOID EFIAPI QemuFwCfgWriteBytes(IN UINTN Size, IN VOID *Buffer)
Definition: QemuFwCfgLib.c:101
UINT8 EFIAPI QemuFwCfgRead8(VOID)
Definition: QemuFwCfgLib.c:167
RETURN_STATUS EFIAPI QemuFwCfgFindFile(IN CONST CHAR8 *Name, OUT FIRMWARE_CONFIG_ITEM *Item, OUT UINTN *Size)
Definition: QemuFwCfgLib.c:250
VOID EFIAPI QemuFwCfgReadBytes(IN UINTN Size, IN VOID *Buffer OPTIONAL)
Definition: QemuFwCfgNull.c:66
VOID EFIAPI QemuFwCfgSelectItem(IN FIRMWARE_CONFIG_ITEM QemuFwCfgItem)
Definition: QemuFwCfgLib.c:33
RETURN_STATUS EFIAPI QemuFwCfgS3ScriptReadBytes(IN INT32 FirmwareConfigItem, IN UINTN NumberOfBytes)
RETURN_STATUS EFIAPI QemuFwCfgS3ScriptWriteBytes(IN INT32 FirmwareConfigItem, IN UINTN NumberOfBytes)
RETURN_STATUS EFIAPI QemuFwCfgS3CallWhenBootScriptReady(IN FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION *Callback, IN OUT VOID *Context OPTIONAL, IN UINTN ScratchBufferSize)
RETURN_STATUS EFIAPI QemuFwCfgS3ScriptCheckValue(IN VOID *ScratchData, IN UINT8 ValueSize, IN UINT64 ValueMask, IN UINT64 Value)
BOOLEAN NegotiateSmiFeatures(VOID)
Definition: SmiFeatures.c:76
STATIC VOID EFIAPI AppendFwCfgBootScript(IN OUT VOID *Context OPTIONAL, IN OUT VOID *ExternalScratchBuffer)
Definition: SmiFeatures.c:246
VOID SaveSmiFeatures(VOID)
Definition: SmiFeatures.c:311