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