]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/SmmControl2Dxe/SmiFeatures.c
DynamicTablesPkg: AmlLib fix ECC errors
[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
a316d7ac
LE
31\r
32//\r
33// Provides a scratch buffer (allocated in EfiReservedMemoryType type memory)\r
36a6aa6c 34// for the S3 boot script fragment to write to and read from.\r
a316d7ac
LE
35//\r
36#pragma pack (1)\r
36a6aa6c
LE
37typedef union {\r
38 UINT64 Features;\r
39 UINT8 FeaturesOk;\r
a316d7ac
LE
40} SCRATCH_BUFFER;\r
41#pragma pack ()\r
42\r
43//\r
44// These carry the selector keys of the "etc/smi/requested-features" and\r
45// "etc/smi/features-ok" fw_cfg files from NegotiateSmiFeatures() to\r
36a6aa6c 46// AppendFwCfgBootScript().\r
a316d7ac
LE
47//\r
48STATIC FIRMWARE_CONFIG_ITEM mRequestedFeaturesItem;\r
49STATIC FIRMWARE_CONFIG_ITEM mFeaturesOkItem;\r
50\r
51//\r
52// Carries the negotiated SMI features from NegotiateSmiFeatures() to\r
36a6aa6c 53// AppendFwCfgBootScript().\r
a316d7ac
LE
54//\r
55STATIC UINT64 mSmiFeatures;\r
56\r
57/**\r
58 Negotiate SMI features with QEMU.\r
59\r
60 @retval FALSE If SMI feature negotiation is not supported by QEMU. This is\r
61 not an error, it just means that SaveSmiFeatures() should not\r
62 be called.\r
63\r
64 @retval TRUE SMI feature negotiation is supported, and it has completed\r
65 successfully as well. (Failure to negotiate is a fatal error\r
66 and the function never returns in that case.)\r
67**/\r
68BOOLEAN\r
69NegotiateSmiFeatures (\r
70 VOID\r
71 )\r
72{\r
73 FIRMWARE_CONFIG_ITEM SupportedFeaturesItem;\r
74 UINTN SupportedFeaturesSize;\r
75 UINTN RequestedFeaturesSize;\r
76 UINTN FeaturesOkSize;\r
5ba203b5 77 UINT64 RequestedFeaturesMask;\r
a316d7ac
LE
78\r
79 //\r
80 // Look up the fw_cfg files used for feature negotiation. The selector keys\r
81 // of "etc/smi/requested-features" and "etc/smi/features-ok" are saved\r
82 // statically. If the files are missing, then QEMU doesn't support SMI\r
83 // feature negotiation.\r
84 //\r
85 if (RETURN_ERROR (QemuFwCfgFindFile ("etc/smi/supported-features",\r
86 &SupportedFeaturesItem, &SupportedFeaturesSize)) ||\r
87 RETURN_ERROR (QemuFwCfgFindFile ("etc/smi/requested-features",\r
88 &mRequestedFeaturesItem, &RequestedFeaturesSize)) ||\r
89 RETURN_ERROR (QemuFwCfgFindFile ("etc/smi/features-ok",\r
90 &mFeaturesOkItem, &FeaturesOkSize))) {\r
91 DEBUG ((DEBUG_INFO, "%a: SMI feature negotiation unavailable\n",\r
92 __FUNCTION__));\r
93 return FALSE;\r
94 }\r
95\r
96 //\r
97 // If the files are present but their sizes disagree with us, that's a fatal\r
98 // error (we can't trust the behavior of SMIs either way).\r
99 //\r
100 if (SupportedFeaturesSize != sizeof mSmiFeatures ||\r
101 RequestedFeaturesSize != sizeof mSmiFeatures ||\r
102 FeaturesOkSize != sizeof (UINT8)) {\r
103 DEBUG ((DEBUG_ERROR, "%a: size mismatch in feature negotiation\n",\r
104 __FUNCTION__));\r
105 goto FatalError;\r
106 }\r
107\r
108 //\r
109 // Get the features supported by the host.\r
110 //\r
111 QemuFwCfgSelectItem (SupportedFeaturesItem);\r
112 QemuFwCfgReadBytes (sizeof mSmiFeatures, &mSmiFeatures);\r
113\r
114 //\r
5ba203b5 115 // We want broadcast SMI, SMI on CPU hotplug, and nothing else.\r
a316d7ac 116 //\r
5ba203b5
LE
117 RequestedFeaturesMask = ICH9_LPC_SMI_F_BROADCAST;\r
118 if (!MemEncryptSevIsEnabled ()) {\r
119 //\r
120 // For now, we only support hotplug with SEV disabled.\r
121 //\r
122 RequestedFeaturesMask |= ICH9_LPC_SMI_F_CPU_HOTPLUG;\r
123 }\r
124 mSmiFeatures &= RequestedFeaturesMask;\r
a316d7ac
LE
125 QemuFwCfgSelectItem (mRequestedFeaturesItem);\r
126 QemuFwCfgWriteBytes (sizeof mSmiFeatures, &mSmiFeatures);\r
127\r
128 //\r
129 // Invoke feature validation in QEMU. If the selection is accepted, the\r
130 // features will be locked down. If the selection is rejected, feature\r
131 // negotiation remains open; however we don't know what to do in that case,\r
132 // so that's a fatal error.\r
133 //\r
134 QemuFwCfgSelectItem (mFeaturesOkItem);\r
135 if (QemuFwCfgRead8 () != 1) {\r
136 DEBUG ((DEBUG_ERROR, "%a: negotiation failed for feature bitmap 0x%Lx\n",\r
137 __FUNCTION__, mSmiFeatures));\r
138 goto FatalError;\r
139 }\r
140\r
141 if ((mSmiFeatures & ICH9_LPC_SMI_F_BROADCAST) == 0) {\r
142 //\r
143 // If we can't get broadcast SMIs from QEMU, that's acceptable too,\r
144 // although not optimal.\r
145 //\r
146 DEBUG ((DEBUG_INFO, "%a: SMI broadcast unavailable\n", __FUNCTION__));\r
147 } else {\r
148 //\r
149 // Configure the traditional AP sync / SMI delivery mode for\r
150 // PiSmmCpuDxeSmm. Effectively, restore the UefiCpuPkg defaults, from which\r
151 // the original QEMU behavior (i.e., unicast SMI) used to differ.\r
152 //\r
153 if (RETURN_ERROR (PcdSet64S (PcdCpuSmmApSyncTimeout, 1000000)) ||\r
154 RETURN_ERROR (PcdSet8S (PcdCpuSmmSyncMode, 0x00))) {\r
155 DEBUG ((DEBUG_ERROR, "%a: PiSmmCpuDxeSmm PCD configuration failed\n",\r
156 __FUNCTION__));\r
157 goto FatalError;\r
158 }\r
159 DEBUG ((DEBUG_INFO, "%a: using SMI broadcast\n", __FUNCTION__));\r
160 }\r
161\r
5ba203b5
LE
162 if ((mSmiFeatures & ICH9_LPC_SMI_F_CPU_HOTPLUG) == 0) {\r
163 DEBUG ((DEBUG_INFO, "%a: CPU hotplug not negotiated\n", __FUNCTION__));\r
164 } else {\r
165 DEBUG ((DEBUG_INFO, "%a: CPU hotplug with SMI negotiated\n",\r
166 __FUNCTION__));\r
167 }\r
168\r
a316d7ac
LE
169 //\r
170 // Negotiation successful (although we may not have gotten the optimal\r
171 // feature set).\r
172 //\r
173 return TRUE;\r
174\r
175FatalError:\r
176 ASSERT (FALSE);\r
177 CpuDeadLoop ();\r
178 //\r
179 // Keep the compiler happy.\r
180 //\r
181 return FALSE;\r
182}\r
183\r
184/**\r
36a6aa6c 185 FW_CFG_BOOT_SCRIPT_CALLBACK_FUNCTION provided to QemuFwCfgS3Lib.\r
a316d7ac 186**/\r
36a6aa6c 187STATIC\r
a316d7ac 188VOID\r
36a6aa6c
LE
189EFIAPI\r
190AppendFwCfgBootScript (\r
191 IN OUT VOID *Context, OPTIONAL\r
192 IN OUT VOID *ExternalScratchBuffer\r
a316d7ac
LE
193 )\r
194{\r
195 SCRATCH_BUFFER *ScratchBuffer;\r
36a6aa6c 196 RETURN_STATUS Status;\r
a316d7ac 197\r
36a6aa6c 198 ScratchBuffer = ExternalScratchBuffer;\r
a316d7ac
LE
199\r
200 //\r
36a6aa6c 201 // Write the negotiated feature bitmap into "etc/smi/requested-features".\r
a316d7ac 202 //\r
36a6aa6c
LE
203 ScratchBuffer->Features = mSmiFeatures;\r
204 Status = QemuFwCfgS3ScriptWriteBytes (mRequestedFeaturesItem,\r
205 sizeof ScratchBuffer->Features);\r
206 if (RETURN_ERROR (Status)) {\r
a316d7ac
LE
207 goto FatalError;\r
208 }\r
209\r
210 //\r
36a6aa6c
LE
211 // Read back "etc/smi/features-ok". This invokes the feature validation &\r
212 // lockdown. (The validation succeeded at first boot.)\r
a316d7ac 213 //\r
36a6aa6c
LE
214 Status = QemuFwCfgS3ScriptReadBytes (mFeaturesOkItem,\r
215 sizeof ScratchBuffer->FeaturesOk);\r
216 if (RETURN_ERROR (Status)) {\r
a316d7ac
LE
217 goto FatalError;\r
218 }\r
219\r
220 //\r
36a6aa6c
LE
221 // If "etc/smi/features-ok" read as 1, we're good. Otherwise, hang the S3\r
222 // resume process.\r
a316d7ac 223 //\r
36a6aa6c
LE
224 Status = QemuFwCfgS3ScriptCheckValue (&ScratchBuffer->FeaturesOk,\r
225 sizeof ScratchBuffer->FeaturesOk, MAX_UINT8, 1);\r
226 if (RETURN_ERROR (Status)) {\r
a316d7ac
LE
227 goto FatalError;\r
228 }\r
229\r
36a6aa6c
LE
230 DEBUG ((DEBUG_VERBOSE, "%a: SMI feature negotiation boot script saved\n",\r
231 __FUNCTION__));\r
a316d7ac
LE
232 return;\r
233\r
234FatalError:\r
235 ASSERT (FALSE);\r
236 CpuDeadLoop ();\r
237}\r
36a6aa6c
LE
238\r
239\r
240/**\r
241 Append a boot script fragment that will re-select the previously negotiated\r
242 SMI features during S3 resume.\r
243**/\r
244VOID\r
245SaveSmiFeatures (\r
246 VOID\r
247 )\r
248{\r
249 RETURN_STATUS Status;\r
250\r
251 //\r
252 // We are already running at TPL_CALLBACK, on the stack of\r
253 // OnS3SaveStateInstalled(). But that's okay, we can easily queue more\r
254 // notification functions while executing a notification function.\r
255 //\r
256 Status = QemuFwCfgS3CallWhenBootScriptReady (AppendFwCfgBootScript, NULL,\r
257 sizeof (SCRATCH_BUFFER));\r
258 if (RETURN_ERROR (Status)) {\r
259 ASSERT (FALSE);\r
260 CpuDeadLoop ();\r
261 }\r
262}\r