]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/SmmControl2Dxe/SmiFeatures.c
OvmfPkg/TpmMmioSevDecryptPei: Mark TPM MMIO range as unencrypted for SEV-ES
[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
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
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
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
LE
43typedef union {\r
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
LE
53//\r
54STATIC FIRMWARE_CONFIG_ITEM mRequestedFeaturesItem;\r
55STATIC FIRMWARE_CONFIG_ITEM mFeaturesOkItem;\r
56\r
57//\r
58// Carries the negotiated SMI features from NegotiateSmiFeatures() to\r
36a6aa6c 59// AppendFwCfgBootScript().\r
a316d7ac
LE
60//\r
61STATIC UINT64 mSmiFeatures;\r
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
79 FIRMWARE_CONFIG_ITEM SupportedFeaturesItem;\r
80 UINTN SupportedFeaturesSize;\r
81 UINTN RequestedFeaturesSize;\r
82 UINTN FeaturesOkSize;\r
5ba203b5 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
91 if (RETURN_ERROR (QemuFwCfgFindFile ("etc/smi/supported-features",\r
92 &SupportedFeaturesItem, &SupportedFeaturesSize)) ||\r
93 RETURN_ERROR (QemuFwCfgFindFile ("etc/smi/requested-features",\r
94 &mRequestedFeaturesItem, &RequestedFeaturesSize)) ||\r
95 RETURN_ERROR (QemuFwCfgFindFile ("etc/smi/features-ok",\r
96 &mFeaturesOkItem, &FeaturesOkSize))) {\r
97 DEBUG ((DEBUG_INFO, "%a: SMI feature negotiation unavailable\n",\r
98 __FUNCTION__));\r
99 return FALSE;\r
100 }\r
101\r
102 //\r
103 // If the files are present but their sizes disagree with us, that's a fatal\r
104 // error (we can't trust the behavior of SMIs either way).\r
105 //\r
106 if (SupportedFeaturesSize != sizeof mSmiFeatures ||\r
107 RequestedFeaturesSize != sizeof mSmiFeatures ||\r
108 FeaturesOkSize != sizeof (UINT8)) {\r
109 DEBUG ((DEBUG_ERROR, "%a: size mismatch in feature negotiation\n",\r
110 __FUNCTION__));\r
111 goto FatalError;\r
112 }\r
113\r
114 //\r
115 // Get the features supported by the host.\r
116 //\r
117 QemuFwCfgSelectItem (SupportedFeaturesItem);\r
118 QemuFwCfgReadBytes (sizeof mSmiFeatures, &mSmiFeatures);\r
119\r
120 //\r
f3bdfc41
AA
121 // We want broadcast SMI, SMI on CPU hotplug, SMI on CPU hot-unplug\r
122 // and nothing else.\r
a316d7ac 123 //\r
5ba203b5
LE
124 RequestedFeaturesMask = ICH9_LPC_SMI_F_BROADCAST;\r
125 if (!MemEncryptSevIsEnabled ()) {\r
126 //\r
127 // For now, we only support hotplug with SEV disabled.\r
128 //\r
129 RequestedFeaturesMask |= ICH9_LPC_SMI_F_CPU_HOTPLUG;\r
f3bdfc41 130 RequestedFeaturesMask |= ICH9_LPC_SMI_F_CPU_HOT_UNPLUG;\r
5ba203b5
LE
131 }\r
132 mSmiFeatures &= RequestedFeaturesMask;\r
a316d7ac
LE
133 QemuFwCfgSelectItem (mRequestedFeaturesItem);\r
134 QemuFwCfgWriteBytes (sizeof mSmiFeatures, &mSmiFeatures);\r
135\r
136 //\r
137 // Invoke feature validation in QEMU. If the selection is accepted, the\r
138 // features will be locked down. If the selection is rejected, feature\r
139 // negotiation remains open; however we don't know what to do in that case,\r
140 // so that's a fatal error.\r
141 //\r
142 QemuFwCfgSelectItem (mFeaturesOkItem);\r
143 if (QemuFwCfgRead8 () != 1) {\r
144 DEBUG ((DEBUG_ERROR, "%a: negotiation failed for feature bitmap 0x%Lx\n",\r
145 __FUNCTION__, mSmiFeatures));\r
146 goto FatalError;\r
147 }\r
148\r
149 if ((mSmiFeatures & ICH9_LPC_SMI_F_BROADCAST) == 0) {\r
150 //\r
151 // If we can't get broadcast SMIs from QEMU, that's acceptable too,\r
152 // although not optimal.\r
153 //\r
154 DEBUG ((DEBUG_INFO, "%a: SMI broadcast unavailable\n", __FUNCTION__));\r
155 } else {\r
156 //\r
157 // Configure the traditional AP sync / SMI delivery mode for\r
158 // PiSmmCpuDxeSmm. Effectively, restore the UefiCpuPkg defaults, from which\r
159 // the original QEMU behavior (i.e., unicast SMI) used to differ.\r
160 //\r
161 if (RETURN_ERROR (PcdSet64S (PcdCpuSmmApSyncTimeout, 1000000)) ||\r
162 RETURN_ERROR (PcdSet8S (PcdCpuSmmSyncMode, 0x00))) {\r
163 DEBUG ((DEBUG_ERROR, "%a: PiSmmCpuDxeSmm PCD configuration failed\n",\r
164 __FUNCTION__));\r
165 goto FatalError;\r
166 }\r
167 DEBUG ((DEBUG_INFO, "%a: using SMI broadcast\n", __FUNCTION__));\r
168 }\r
169\r
5ba203b5
LE
170 if ((mSmiFeatures & ICH9_LPC_SMI_F_CPU_HOTPLUG) == 0) {\r
171 DEBUG ((DEBUG_INFO, "%a: CPU hotplug not negotiated\n", __FUNCTION__));\r
172 } else {\r
173 DEBUG ((DEBUG_INFO, "%a: CPU hotplug with SMI negotiated\n",\r
174 __FUNCTION__));\r
175 }\r
176\r
f3bdfc41
AA
177 if ((mSmiFeatures & ICH9_LPC_SMI_F_CPU_HOT_UNPLUG) == 0) {\r
178 DEBUG ((DEBUG_INFO, "%a: CPU hot-unplug not negotiated\n", __FUNCTION__));\r
179 } else {\r
180 DEBUG ((DEBUG_INFO, "%a: CPU hot-unplug with SMI negotiated\n",\r
181 __FUNCTION__));\r
182 }\r
183\r
a316d7ac
LE
184 //\r
185 // Negotiation successful (although we may not have gotten the optimal\r
186 // feature set).\r
187 //\r
188 return TRUE;\r
189\r
190FatalError:\r
191 ASSERT (FALSE);\r
192 CpuDeadLoop ();\r
193 //\r
194 // Keep the compiler happy.\r
195 //\r
196 return FALSE;\r
197}\r
198\r
199/**\r
36a6aa6c 200 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION provided to QemuFwCfgS3Lib.\r
a316d7ac 201**/\r
36a6aa6c 202STATIC\r
a316d7ac 203VOID\r
36a6aa6c
LE
204EFIAPI\r
205AppendFwCfgBootScript (\r
206 IN OUT VOID *Context, OPTIONAL\r
207 IN OUT VOID *ExternalScratchBuffer\r
a316d7ac
LE
208 )\r
209{\r
210 SCRATCH_BUFFER *ScratchBuffer;\r
36a6aa6c 211 RETURN_STATUS Status;\r
a316d7ac 212\r
36a6aa6c 213 ScratchBuffer = ExternalScratchBuffer;\r
a316d7ac
LE
214\r
215 //\r
36a6aa6c 216 // Write the negotiated feature bitmap into "etc/smi/requested-features".\r
a316d7ac 217 //\r
36a6aa6c
LE
218 ScratchBuffer->Features = mSmiFeatures;\r
219 Status = QemuFwCfgS3ScriptWriteBytes (mRequestedFeaturesItem,\r
220 sizeof ScratchBuffer->Features);\r
221 if (RETURN_ERROR (Status)) {\r
a316d7ac
LE
222 goto FatalError;\r
223 }\r
224\r
225 //\r
36a6aa6c
LE
226 // Read back "etc/smi/features-ok". This invokes the feature validation &\r
227 // lockdown. (The validation succeeded at first boot.)\r
a316d7ac 228 //\r
36a6aa6c
LE
229 Status = QemuFwCfgS3ScriptReadBytes (mFeaturesOkItem,\r
230 sizeof ScratchBuffer->FeaturesOk);\r
231 if (RETURN_ERROR (Status)) {\r
a316d7ac
LE
232 goto FatalError;\r
233 }\r
234\r
235 //\r
36a6aa6c
LE
236 // If "etc/smi/features-ok" read as 1, we're good. Otherwise, hang the S3\r
237 // resume process.\r
a316d7ac 238 //\r
36a6aa6c
LE
239 Status = QemuFwCfgS3ScriptCheckValue (&ScratchBuffer->FeaturesOk,\r
240 sizeof ScratchBuffer->FeaturesOk, MAX_UINT8, 1);\r
241 if (RETURN_ERROR (Status)) {\r
a316d7ac
LE
242 goto FatalError;\r
243 }\r
244\r
36a6aa6c
LE
245 DEBUG ((DEBUG_VERBOSE, "%a: SMI feature negotiation boot script saved\n",\r
246 __FUNCTION__));\r
a316d7ac
LE
247 return;\r
248\r
249FatalError:\r
250 ASSERT (FALSE);\r
251 CpuDeadLoop ();\r
252}\r
36a6aa6c
LE
253\r
254\r
255/**\r
256 Append a boot script fragment that will re-select the previously negotiated\r
257 SMI features during S3 resume.\r
258**/\r
259VOID\r
260SaveSmiFeatures (\r
261 VOID\r
262 )\r
263{\r
264 RETURN_STATUS Status;\r
265\r
266 //\r
267 // We are already running at TPL_CALLBACK, on the stack of\r
268 // OnS3SaveStateInstalled(). But that's okay, we can easily queue more\r
269 // notification functions while executing a notification function.\r
270 //\r
271 Status = QemuFwCfgS3CallWhenBootScriptReady (AppendFwCfgBootScript, NULL,\r
272 sizeof (SCRATCH_BUFFER));\r
273 if (RETURN_ERROR (Status)) {\r
274 ASSERT (FALSE);\r
275 CpuDeadLoop ();\r
276 }\r
277}\r