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