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