]>
Commit | Line | Data |
---|---|---|
a6d73269 | 1 | /** @file\r |
b0bacc00 KM |
2 | UEFI variable support functions for Firmware Management Protocol based\r |
3 | firmware updates.\r | |
4 | \r | |
5 | Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>\r | |
2f6f3329 | 6 | Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved.<BR>\r |
b0bacc00 | 7 | \r |
bcef758c | 8 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
b0bacc00 KM |
9 | \r |
10 | **/\r | |
11 | \r | |
67c1e5ee | 12 | #include "FmpDxe.h"\r |
b0bacc00 KM |
13 | #include "VariableSupport.h"\r |
14 | \r | |
67c1e5ee EJ |
15 | /**\r |
16 | Retrieve the value of a 32-bit UEFI Variable specified by VariableName and\r | |
17 | a GUID of gEfiCallerIdGuid.\r | |
18 | \r | |
19 | @param[in] VariableName Pointer to the UEFI Variable name to retrieve.\r | |
20 | @param[out] Valid Set to TRUE if UEFI Variable is present and the size\r | |
21 | of the UEFI Variable value is 32-bits. Otherwise\r | |
22 | FALSE.\r | |
23 | @param[out] Value If Valid is set to TRUE, then the 32-bit value of\r | |
24 | the UEFI Variable. Otherwise 0.\r | |
25 | **/\r | |
26 | static\r | |
27 | VOID\r | |
28 | GetFmpVariable (\r | |
29 | IN CHAR16 *VariableName,\r | |
30 | OUT BOOLEAN *Valid,\r | |
31 | OUT UINT32 *Value\r | |
32 | )\r | |
33 | {\r | |
34 | EFI_STATUS Status;\r | |
35 | UINTN Size;\r | |
36 | UINT32 *Buffer;\r | |
37 | \r | |
38 | *Valid = FALSE;\r | |
39 | *Value = 0;\r | |
40 | Size = 0;\r | |
41 | Buffer = NULL;\r | |
42 | Status = GetVariable2 (\r | |
43 | VariableName,\r | |
44 | &gEfiCallerIdGuid,\r | |
45 | (VOID **)&Buffer,\r | |
46 | &Size\r | |
47 | );\r | |
45ce0a67 | 48 | if (!EFI_ERROR (Status) && (Size == sizeof (*Value)) && (Buffer != NULL)) {\r |
67c1e5ee EJ |
49 | *Valid = TRUE;\r |
50 | *Value = *Buffer;\r | |
51 | }\r | |
45ce0a67 | 52 | \r |
67c1e5ee EJ |
53 | if (Buffer != NULL) {\r |
54 | FreePool (Buffer);\r | |
55 | }\r | |
56 | }\r | |
b0bacc00 KM |
57 | \r |
58 | /**\r | |
67c1e5ee EJ |
59 | Delete the UEFI Variable with name specified by VariableName and GUID of\r |
60 | gEfiCallerIdGuid. If the variable can not be deleted, then print a\r | |
61 | DEBUG_ERROR message.\r | |
b0bacc00 | 62 | \r |
67c1e5ee EJ |
63 | @param[in] VariableName Pointer to the UEFI Variable name to delete.\r |
64 | **/\r | |
65 | static\r | |
66 | VOID\r | |
67 | DeleteFmpVariable (\r | |
68 | IN CHAR16 *VariableName\r | |
69 | )\r | |
70 | {\r | |
71 | EFI_STATUS Status;\r | |
72 | BOOLEAN Valid;\r | |
73 | UINT32 Value;\r | |
b0bacc00 | 74 | \r |
67c1e5ee EJ |
75 | GetFmpVariable (VariableName, &Valid, &Value);\r |
76 | if (Valid) {\r | |
77 | Status = gRT->SetVariable (VariableName, &gEfiCallerIdGuid, 0, 0, NULL);\r | |
78 | if (EFI_ERROR (Status)) {\r | |
e0961677 | 79 | DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to delete variable %s. Status = %r\n", mImageIdName, VariableName, Status));\r |
67c1e5ee | 80 | } else {\r |
e0961677 | 81 | DEBUG ((DEBUG_INFO, "FmpDxe(%s): Deleted variable %s\n", mImageIdName, VariableName));\r |
67c1e5ee EJ |
82 | }\r |
83 | }\r | |
84 | }\r | |
85 | \r | |
86 | /**\r | |
87 | Retrieve the FMP Controller State UEFI Variable value. Return NULL if\r | |
88 | the variable does not exist or if the size of the UEFI Variable is not the\r | |
89 | size of FMP_CONTROLLER_STATE. The buffer for the UEFI Variable value\r | |
90 | if allocated using the UEFI Boot Service AllocatePool().\r | |
b0bacc00 | 91 | \r |
67c1e5ee EJ |
92 | @param[in] Private Private context structure for the managed controller.\r |
93 | \r | |
94 | @return Pointer to the allocated FMP Controller State. Returns NULL\r | |
95 | if the variable does not exist or is a different size than expected.\r | |
b0bacc00 | 96 | **/\r |
67c1e5ee EJ |
97 | static\r |
98 | FMP_CONTROLLER_STATE *\r | |
99 | GetFmpControllerState (\r | |
100 | IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private\r | |
b0bacc00 KM |
101 | )\r |
102 | {\r | |
67c1e5ee EJ |
103 | EFI_STATUS Status;\r |
104 | FMP_CONTROLLER_STATE *FmpControllerState;\r | |
105 | UINTN Size;\r | |
106 | \r | |
107 | FmpControllerState = NULL;\r | |
108 | Size = 0;\r | |
45ce0a67 MK |
109 | Status = GetVariable2 (\r |
110 | Private->FmpStateVariableName,\r | |
111 | &gEfiCallerIdGuid,\r | |
112 | (VOID **)&FmpControllerState,\r | |
113 | &Size\r | |
114 | );\r | |
115 | if (EFI_ERROR (Status) || (FmpControllerState == NULL)) {\r | |
e0961677 | 116 | DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to get the controller state. Status = %r\n", mImageIdName, Status));\r |
67c1e5ee EJ |
117 | } else {\r |
118 | if (Size == sizeof (*FmpControllerState)) {\r | |
119 | return FmpControllerState;\r | |
120 | }\r | |
45ce0a67 | 121 | \r |
e0961677 | 122 | DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Getting controller state returned a size different than expected. Size = 0x%x\n", mImageIdName, Size));\r |
67c1e5ee | 123 | }\r |
45ce0a67 | 124 | \r |
67c1e5ee EJ |
125 | if (FmpControllerState != NULL) {\r |
126 | FreePool (FmpControllerState);\r | |
127 | }\r | |
45ce0a67 | 128 | \r |
67c1e5ee EJ |
129 | return NULL;\r |
130 | }\r | |
b0bacc00 | 131 | \r |
67c1e5ee EJ |
132 | /**\r |
133 | Generates a Null-terminated Unicode string UEFI Variable name from a base name\r | |
134 | and a hardware instance. If the hardware instance value is 0, then the base\r | |
135 | name is returned. If the hardware instance value is non-zero, then the 64-bit\r | |
136 | hardware instance value is converted to a 16 character hex string and appended\r | |
137 | to base name. The UEFI Variable name returned is allocated using the UEFI\r | |
138 | Boot Service AllocatePool().\r | |
139 | \r | |
140 | @param[in] HardwareInstance 64-bit hardware instance value.\r | |
141 | @param[in] BaseVariableName Null-terminated Unicode string that is the base\r | |
142 | name of the UEFI Variable.\r | |
143 | \r | |
144 | @return Pointer to the allocated UEFI Variable name. Returns NULL if the\r | |
145 | UEFI Variable can not be allocated.\r | |
146 | **/\r | |
147 | static\r | |
148 | CHAR16 *\r | |
149 | GenerateFmpVariableName (\r | |
150 | IN UINT64 HardwareInstance,\r | |
151 | IN CHAR16 *BaseVariableName\r | |
152 | )\r | |
153 | {\r | |
a5944b6a | 154 | UINTN Size;\r |
67c1e5ee EJ |
155 | CHAR16 *VariableName;\r |
156 | \r | |
a5944b6a EJ |
157 | //\r |
158 | // Allocate Unicode string with room for BaseVariableName and a 16 digit\r | |
159 | // hexadecimal value for the HardwareInstance value.\r | |
160 | //\r | |
45ce0a67 | 161 | Size = StrSize (BaseVariableName) + 16 * sizeof (CHAR16);\r |
a5944b6a | 162 | VariableName = AllocateCopyPool (Size, BaseVariableName);\r |
67c1e5ee | 163 | if (VariableName == NULL) {\r |
e0961677 | 164 | DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to generate variable name %s.\n", mImageIdName, BaseVariableName));\r |
67c1e5ee EJ |
165 | return VariableName;\r |
166 | }\r | |
45ce0a67 | 167 | \r |
67c1e5ee EJ |
168 | if (HardwareInstance == 0) {\r |
169 | return VariableName;\r | |
170 | }\r | |
45ce0a67 | 171 | \r |
a5944b6a | 172 | UnicodeValueToStringS (\r |
45ce0a67 | 173 | &VariableName[StrLen (BaseVariableName)],\r |
a5944b6a EJ |
174 | Size,\r |
175 | PREFIX_ZERO | RADIX_HEX,\r | |
176 | HardwareInstance,\r | |
177 | 16\r | |
178 | );\r | |
67c1e5ee EJ |
179 | return VariableName;\r |
180 | }\r | |
181 | \r | |
182 | /**\r | |
183 | Generate the names of the UEFI Variables used to store state information for\r | |
184 | a managed controller. The UEFI Variables names are a combination of a base\r | |
185 | name and an optional hardware instance value as a 16 character hex value. If\r | |
186 | the hardware instance value is 0, then the 16 character hex value is not\r | |
187 | included. These storage for the UEFI Variable names are allocated using the\r | |
188 | UEFI Boot Service AllocatePool() and the pointers are stored in the Private.\r | |
189 | The following are examples of variable names produces for hardware instance\r | |
190 | value 0 and value 0x1234567812345678.\r | |
191 | \r | |
192 | FmpVersion\r | |
193 | FmpLsv\r | |
194 | LastAttemptStatus\r | |
195 | LastAttemptVersion\r | |
196 | FmpState\r | |
197 | \r | |
198 | FmpVersion1234567812345678\r | |
199 | FmpLsv1234567812345678\r | |
200 | LastAttemptStatus1234567812345678\r | |
201 | LastAttemptVersion1234567812345678\r | |
202 | FmpState1234567812345678\r | |
203 | \r | |
204 | @param[in,out] Private Private context structure for the managed controller.\r | |
205 | **/\r | |
206 | VOID\r | |
207 | GenerateFmpVariableNames (\r | |
208 | IN OUT FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private\r | |
209 | )\r | |
210 | {\r | |
45ce0a67 MK |
211 | EFI_STATUS Status;\r |
212 | VOID *Buffer;\r | |
67c1e5ee EJ |
213 | FMP_CONTROLLER_STATE FmpControllerState;\r |
214 | \r | |
215 | if (Private->VersionVariableName != NULL) {\r | |
216 | FreePool (Private->VersionVariableName);\r | |
217 | }\r | |
45ce0a67 | 218 | \r |
67c1e5ee EJ |
219 | if (Private->LsvVariableName != NULL) {\r |
220 | FreePool (Private->LsvVariableName);\r | |
221 | }\r | |
45ce0a67 | 222 | \r |
67c1e5ee EJ |
223 | if (Private->LastAttemptStatusVariableName != NULL) {\r |
224 | FreePool (Private->LastAttemptStatusVariableName);\r | |
225 | }\r | |
45ce0a67 | 226 | \r |
67c1e5ee EJ |
227 | if (Private->LastAttemptVersionVariableName != NULL) {\r |
228 | FreePool (Private->LastAttemptVersionVariableName);\r | |
229 | }\r | |
45ce0a67 | 230 | \r |
67c1e5ee EJ |
231 | if (Private->FmpStateVariableName != NULL) {\r |
232 | FreePool (Private->FmpStateVariableName);\r | |
233 | }\r | |
b0bacc00 | 234 | \r |
67c1e5ee EJ |
235 | Private->VersionVariableName = GenerateFmpVariableName (\r |
236 | Private->Descriptor.HardwareInstance,\r | |
237 | VARNAME_VERSION\r | |
238 | );\r | |
239 | Private->LsvVariableName = GenerateFmpVariableName (\r | |
240 | Private->Descriptor.HardwareInstance,\r | |
241 | VARNAME_LSV\r | |
242 | );\r | |
243 | Private->LastAttemptStatusVariableName = GenerateFmpVariableName (\r | |
244 | Private->Descriptor.HardwareInstance,\r | |
245 | VARNAME_LASTATTEMPTSTATUS\r | |
246 | );\r | |
247 | Private->LastAttemptVersionVariableName = GenerateFmpVariableName (\r | |
248 | Private->Descriptor.HardwareInstance,\r | |
249 | VARNAME_LASTATTEMPTVERSION\r | |
250 | );\r | |
251 | Private->FmpStateVariableName = GenerateFmpVariableName (\r | |
252 | Private->Descriptor.HardwareInstance,\r | |
253 | VARNAME_FMPSTATE\r | |
254 | );\r | |
255 | \r | |
e0961677 EJ |
256 | DEBUG ((DEBUG_INFO, "FmpDxe(%s): Variable %g %s\n", mImageIdName, &gEfiCallerIdGuid, Private->VersionVariableName));\r |
257 | DEBUG ((DEBUG_INFO, "FmpDxe(%s): Variable %g %s\n", mImageIdName, &gEfiCallerIdGuid, Private->LsvVariableName));\r | |
258 | DEBUG ((DEBUG_INFO, "FmpDxe(%s): Variable %g %s\n", mImageIdName, &gEfiCallerIdGuid, Private->LastAttemptStatusVariableName));\r | |
259 | DEBUG ((DEBUG_INFO, "FmpDxe(%s): Variable %g %s\n", mImageIdName, &gEfiCallerIdGuid, Private->LastAttemptVersionVariableName));\r | |
260 | DEBUG ((DEBUG_INFO, "FmpDxe(%s): Variable %g %s\n", mImageIdName, &gEfiCallerIdGuid, Private->FmpStateVariableName));\r | |
67c1e5ee EJ |
261 | \r |
262 | Buffer = GetFmpControllerState (Private);\r | |
263 | if (Buffer != NULL) {\r | |
264 | //\r | |
265 | // FMP Controller State was found with correct size.\r | |
266 | // Delete old variables if they exist.\r | |
267 | //\r | |
268 | FreePool (Buffer);\r | |
269 | DeleteFmpVariable (Private->VersionVariableName);\r | |
270 | DeleteFmpVariable (Private->LsvVariableName);\r | |
271 | DeleteFmpVariable (Private->LastAttemptStatusVariableName);\r | |
272 | DeleteFmpVariable (Private->LastAttemptVersionVariableName);\r | |
273 | return;\r | |
b0bacc00 KM |
274 | }\r |
275 | \r | |
276 | //\r | |
67c1e5ee EJ |
277 | // FMP Controller State was either not found or is wrong size.\r |
278 | // Create a new FMP Controller State variable with the correct size.\r | |
b0bacc00 | 279 | //\r |
e0961677 | 280 | DEBUG ((DEBUG_INFO, "FmpDxe(%s): Create controller state\n", mImageIdName));\r |
67c1e5ee EJ |
281 | GetFmpVariable (\r |
282 | Private->VersionVariableName,\r | |
283 | &FmpControllerState.VersionValid,\r | |
284 | &FmpControllerState.Version\r | |
285 | );\r | |
286 | GetFmpVariable (\r | |
287 | Private->LsvVariableName,\r | |
288 | &FmpControllerState.LsvValid,\r | |
289 | &FmpControllerState.Lsv\r | |
290 | );\r | |
291 | GetFmpVariable (\r | |
292 | Private->LastAttemptStatusVariableName,\r | |
293 | &FmpControllerState.LastAttemptStatusValid,\r | |
294 | &FmpControllerState.LastAttemptStatus\r | |
295 | );\r | |
296 | GetFmpVariable (\r | |
297 | Private->LastAttemptVersionVariableName,\r | |
298 | &FmpControllerState.LastAttemptVersionValid,\r | |
299 | &FmpControllerState.LastAttemptVersion\r | |
300 | );\r | |
301 | Status = gRT->SetVariable (\r | |
302 | Private->FmpStateVariableName,\r | |
303 | &gEfiCallerIdGuid,\r | |
304 | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r | |
305 | sizeof (FmpControllerState),\r | |
306 | &FmpControllerState\r | |
307 | );\r | |
308 | if (EFI_ERROR (Status)) {\r | |
b0bacc00 | 309 | //\r |
67c1e5ee EJ |
310 | // Failed to create FMP Controller State. In this case, do not\r |
311 | // delete the individual variables. They can be used again on next boot\r | |
312 | // to create the FMP Controller State.\r | |
b0bacc00 | 313 | //\r |
e0961677 | 314 | DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to create controller state. Status = %r\n", mImageIdName, Status));\r |
b0bacc00 | 315 | } else {\r |
67c1e5ee EJ |
316 | DeleteFmpVariable (Private->VersionVariableName);\r |
317 | DeleteFmpVariable (Private->LsvVariableName);\r | |
318 | DeleteFmpVariable (Private->LastAttemptStatusVariableName);\r | |
319 | DeleteFmpVariable (Private->LastAttemptVersionVariableName);\r | |
b0bacc00 | 320 | }\r |
67c1e5ee | 321 | }\r |
b0bacc00 | 322 | \r |
67c1e5ee EJ |
323 | /**\r |
324 | Returns the value used to fill in the Version field of the\r | |
325 | EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()\r | |
326 | service of the Firmware Management Protocol. The value is read from a UEFI\r | |
327 | variable. If the UEFI variables does not exist, then a default version value\r | |
328 | is returned.\r | |
329 | \r | |
330 | UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"\r | |
b0bacc00 | 331 | \r |
67c1e5ee EJ |
332 | @param[in] Private Private context structure for the managed controller.\r |
333 | \r | |
334 | @return The version of the firmware image in the firmware device.\r | |
335 | **/\r | |
336 | UINT32\r | |
337 | GetVersionFromVariable (\r | |
338 | IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private\r | |
339 | )\r | |
340 | {\r | |
341 | FMP_CONTROLLER_STATE *FmpControllerState;\r | |
342 | UINT32 Value;\r | |
343 | \r | |
45ce0a67 | 344 | Value = DEFAULT_VERSION;\r |
67c1e5ee EJ |
345 | FmpControllerState = GetFmpControllerState (Private);\r |
346 | if (FmpControllerState != NULL) {\r | |
347 | if (FmpControllerState->VersionValid) {\r | |
348 | Value = FmpControllerState->Version;\r | |
45ce0a67 MK |
349 | DEBUG ((\r |
350 | DEBUG_INFO,\r | |
351 | "FmpDxe(%s): Get variable %g %s Version %08x\n",\r | |
e0961677 | 352 | mImageIdName,\r |
67c1e5ee EJ |
353 | &gEfiCallerIdGuid,\r |
354 | Private->FmpStateVariableName,\r | |
355 | Value\r | |
356 | ));\r | |
357 | }\r | |
45ce0a67 | 358 | \r |
67c1e5ee EJ |
359 | FreePool (FmpControllerState);\r |
360 | }\r | |
45ce0a67 | 361 | \r |
67c1e5ee | 362 | return Value;\r |
b0bacc00 KM |
363 | }\r |
364 | \r | |
365 | /**\r | |
366 | Returns the value used to fill in the LowestSupportedVersion field of the\r | |
367 | EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()\r | |
368 | service of the Firmware Management Protocol. The value is read from a UEFI\r | |
369 | variable. If the UEFI variables does not exist, then a default lowest\r | |
370 | supported version value is returned.\r | |
371 | \r | |
67c1e5ee EJ |
372 | UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"\r |
373 | \r | |
374 | @param[in] Private Private context structure for the managed controller.\r | |
b0bacc00 KM |
375 | \r |
376 | @return The lowest supported version of the firmware image in the firmware\r | |
377 | device.\r | |
b0bacc00 KM |
378 | **/\r |
379 | UINT32\r | |
380 | GetLowestSupportedVersionFromVariable (\r | |
67c1e5ee | 381 | IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private\r |
b0bacc00 KM |
382 | )\r |
383 | {\r | |
67c1e5ee EJ |
384 | FMP_CONTROLLER_STATE *FmpControllerState;\r |
385 | UINT32 Value;\r | |
386 | \r | |
45ce0a67 | 387 | Value = DEFAULT_LOWESTSUPPORTEDVERSION;\r |
67c1e5ee EJ |
388 | FmpControllerState = GetFmpControllerState (Private);\r |
389 | if (FmpControllerState != NULL) {\r | |
390 | if (FmpControllerState->LsvValid) {\r | |
391 | Value = FmpControllerState->Lsv;\r | |
45ce0a67 MK |
392 | DEBUG ((\r |
393 | DEBUG_INFO,\r | |
394 | "FmpDxe(%s): Get variable %g %s LowestSupportedVersion %08x\n",\r | |
e0961677 | 395 | mImageIdName,\r |
67c1e5ee EJ |
396 | &gEfiCallerIdGuid,\r |
397 | Private->FmpStateVariableName,\r | |
398 | Value\r | |
399 | ));\r | |
400 | }\r | |
45ce0a67 | 401 | \r |
67c1e5ee | 402 | FreePool (FmpControllerState);\r |
b0bacc00 | 403 | }\r |
45ce0a67 | 404 | \r |
67c1e5ee | 405 | return Value;\r |
b0bacc00 KM |
406 | }\r |
407 | \r | |
408 | /**\r | |
409 | Returns the value used to fill in the LastAttemptStatus field of the\r | |
410 | EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()\r | |
411 | service of the Firmware Management Protocol. The value is read from a UEFI\r | |
412 | variable. If the UEFI variables does not exist, then a default last attempt\r | |
413 | status value is returned.\r | |
414 | \r | |
67c1e5ee | 415 | UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"\r |
b0bacc00 | 416 | \r |
67c1e5ee | 417 | @param[in] Private Private context structure for the managed controller.\r |
b0bacc00 | 418 | \r |
67c1e5ee | 419 | @return The last attempt status value for the most recent capsule update.\r |
b0bacc00 KM |
420 | **/\r |
421 | UINT32\r | |
422 | GetLastAttemptStatusFromVariable (\r | |
67c1e5ee | 423 | IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private\r |
b0bacc00 KM |
424 | )\r |
425 | {\r | |
67c1e5ee EJ |
426 | FMP_CONTROLLER_STATE *FmpControllerState;\r |
427 | UINT32 Value;\r | |
428 | \r | |
45ce0a67 | 429 | Value = DEFAULT_LASTATTEMPTSTATUS;\r |
67c1e5ee EJ |
430 | FmpControllerState = GetFmpControllerState (Private);\r |
431 | if (FmpControllerState != NULL) {\r | |
432 | if (FmpControllerState->LastAttemptStatusValid) {\r | |
433 | Value = FmpControllerState->LastAttemptStatus;\r | |
45ce0a67 MK |
434 | DEBUG ((\r |
435 | DEBUG_INFO,\r | |
436 | "FmpDxe(%s): Get variable %g %s LastAttemptStatus %08x\n",\r | |
e0961677 | 437 | mImageIdName,\r |
67c1e5ee EJ |
438 | &gEfiCallerIdGuid,\r |
439 | Private->FmpStateVariableName,\r | |
440 | Value\r | |
441 | ));\r | |
442 | }\r | |
45ce0a67 | 443 | \r |
67c1e5ee | 444 | FreePool (FmpControllerState);\r |
b0bacc00 | 445 | }\r |
45ce0a67 | 446 | \r |
67c1e5ee | 447 | return Value;\r |
b0bacc00 KM |
448 | }\r |
449 | \r | |
450 | /**\r | |
451 | Returns the value used to fill in the LastAttemptVersion field of the\r | |
452 | EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()\r | |
453 | service of the Firmware Management Protocol. The value is read from a UEFI\r | |
454 | variable. If the UEFI variables does not exist, then a default last attempt\r | |
455 | version value is returned.\r | |
456 | \r | |
67c1e5ee | 457 | UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"\r |
b0bacc00 | 458 | \r |
67c1e5ee | 459 | @param[in] Private Private context structure for the managed controller.\r |
b0bacc00 | 460 | \r |
67c1e5ee | 461 | @return The last attempt version value for the most recent capsule update.\r |
b0bacc00 KM |
462 | **/\r |
463 | UINT32\r | |
464 | GetLastAttemptVersionFromVariable (\r | |
67c1e5ee | 465 | IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private\r |
b0bacc00 KM |
466 | )\r |
467 | {\r | |
67c1e5ee EJ |
468 | FMP_CONTROLLER_STATE *FmpControllerState;\r |
469 | UINT32 Value;\r | |
470 | \r | |
45ce0a67 | 471 | Value = DEFAULT_LASTATTEMPTVERSION;\r |
67c1e5ee EJ |
472 | FmpControllerState = GetFmpControllerState (Private);\r |
473 | if (FmpControllerState != NULL) {\r | |
474 | if (FmpControllerState->LastAttemptVersionValid) {\r | |
475 | Value = FmpControllerState->LastAttemptVersion;\r | |
45ce0a67 MK |
476 | DEBUG ((\r |
477 | DEBUG_INFO,\r | |
478 | "FmpDxe(%s): Get variable %g %s LastAttemptVersion %08x\n",\r | |
e0961677 | 479 | mImageIdName,\r |
67c1e5ee EJ |
480 | &gEfiCallerIdGuid,\r |
481 | Private->FmpStateVariableName,\r | |
482 | Value\r | |
483 | ));\r | |
484 | }\r | |
45ce0a67 | 485 | \r |
67c1e5ee | 486 | FreePool (FmpControllerState);\r |
b0bacc00 | 487 | }\r |
45ce0a67 | 488 | \r |
67c1e5ee | 489 | return Value;\r |
b0bacc00 KM |
490 | }\r |
491 | \r | |
b0bacc00 KM |
492 | /**\r |
493 | Saves the version current of the firmware image in the firmware device to a\r | |
494 | UEFI variable.\r | |
495 | \r | |
67c1e5ee | 496 | UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"\r |
b0bacc00 | 497 | \r |
67c1e5ee | 498 | @param[in] Private Private context structure for the managed controller.\r |
b0bacc00 | 499 | @param[in] Version The version of the firmware image in the firmware device.\r |
b0bacc00 KM |
500 | **/\r |
501 | VOID\r | |
502 | SetVersionInVariable (\r | |
67c1e5ee EJ |
503 | IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private,\r |
504 | IN UINT32 Version\r | |
b0bacc00 KM |
505 | )\r |
506 | {\r | |
67c1e5ee EJ |
507 | EFI_STATUS Status;\r |
508 | FMP_CONTROLLER_STATE *FmpControllerState;\r | |
509 | BOOLEAN Update;\r | |
b0bacc00 | 510 | \r |
67c1e5ee EJ |
511 | FmpControllerState = GetFmpControllerState (Private);\r |
512 | if (FmpControllerState == NULL) {\r | |
513 | //\r | |
514 | // Can not update value if FMP Controller State does not exist.\r | |
515 | // This variable is guaranteed to be created by GenerateFmpVariableNames().\r | |
516 | //\r | |
517 | return;\r | |
518 | }\r | |
b0bacc00 | 519 | \r |
67c1e5ee EJ |
520 | Update = FALSE;\r |
521 | if (!FmpControllerState->VersionValid) {\r | |
522 | Update = TRUE;\r | |
523 | }\r | |
45ce0a67 | 524 | \r |
67c1e5ee EJ |
525 | if (FmpControllerState->Version != Version) {\r |
526 | Update = TRUE;\r | |
527 | }\r | |
45ce0a67 | 528 | \r |
67c1e5ee | 529 | if (!Update) {\r |
e0961677 | 530 | DEBUG ((DEBUG_INFO, "FmpDxe(%s): No need to update controller state. Same value as before.\n", mImageIdName));\r |
67c1e5ee EJ |
531 | } else {\r |
532 | FmpControllerState->VersionValid = TRUE;\r | |
533 | FmpControllerState->Version = Version;\r | |
45ce0a67 MK |
534 | Status = gRT->SetVariable (\r |
535 | Private->FmpStateVariableName,\r | |
536 | &gEfiCallerIdGuid,\r | |
537 | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r | |
538 | sizeof (*FmpControllerState),\r | |
539 | FmpControllerState\r | |
540 | );\r | |
b0bacc00 | 541 | if (EFI_ERROR (Status)) {\r |
e0961677 | 542 | DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to update controller state. Status = %r\n", mImageIdName, Status));\r |
67c1e5ee | 543 | } else {\r |
45ce0a67 MK |
544 | DEBUG ((\r |
545 | DEBUG_INFO,\r | |
546 | "FmpDxe(%s): Set variable %g %s Version %08x\n",\r | |
e0961677 | 547 | mImageIdName,\r |
67c1e5ee EJ |
548 | &gEfiCallerIdGuid,\r |
549 | Private->FmpStateVariableName,\r | |
550 | Version\r | |
551 | ));\r | |
b0bacc00 | 552 | }\r |
b0bacc00 | 553 | }\r |
45ce0a67 | 554 | \r |
67c1e5ee | 555 | FreePool (FmpControllerState);\r |
b0bacc00 KM |
556 | }\r |
557 | \r | |
558 | /**\r | |
559 | Saves the lowest supported version current of the firmware image in the\r | |
560 | firmware device to a UEFI variable.\r | |
561 | \r | |
67c1e5ee | 562 | UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"\r |
b0bacc00 | 563 | \r |
67c1e5ee EJ |
564 | @param[in] Private Private context structure for the managed\r |
565 | controller.\r | |
566 | @param[in] LowestSupportedVersion The lowest supported version of the\r | |
567 | firmware image in the firmware device.\r | |
b0bacc00 KM |
568 | **/\r |
569 | VOID\r | |
570 | SetLowestSupportedVersionInVariable (\r | |
67c1e5ee EJ |
571 | IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private,\r |
572 | IN UINT32 LowestSupportedVersion\r | |
b0bacc00 KM |
573 | )\r |
574 | {\r | |
67c1e5ee EJ |
575 | EFI_STATUS Status;\r |
576 | FMP_CONTROLLER_STATE *FmpControllerState;\r | |
577 | BOOLEAN Update;\r | |
b0bacc00 | 578 | \r |
67c1e5ee EJ |
579 | FmpControllerState = GetFmpControllerState (Private);\r |
580 | if (FmpControllerState == NULL) {\r | |
581 | //\r | |
582 | // Can not update value if FMP Controller State does not exist.\r | |
583 | // This variable is guaranteed to be created by GenerateFmpVariableNames().\r | |
584 | //\r | |
585 | return;\r | |
586 | }\r | |
b0bacc00 | 587 | \r |
67c1e5ee EJ |
588 | Update = FALSE;\r |
589 | if (!FmpControllerState->LsvValid) {\r | |
590 | Update = TRUE;\r | |
591 | }\r | |
45ce0a67 | 592 | \r |
67c1e5ee EJ |
593 | if (FmpControllerState->Lsv < LowestSupportedVersion) {\r |
594 | Update = TRUE;\r | |
595 | }\r | |
45ce0a67 | 596 | \r |
67c1e5ee | 597 | if (!Update) {\r |
e0961677 | 598 | DEBUG ((DEBUG_INFO, "FmpDxe(%s): No need to update controller state. Same value as before.\n", mImageIdName));\r |
67c1e5ee EJ |
599 | } else {\r |
600 | FmpControllerState->LsvValid = TRUE;\r | |
601 | FmpControllerState->Lsv = LowestSupportedVersion;\r | |
45ce0a67 MK |
602 | Status = gRT->SetVariable (\r |
603 | Private->FmpStateVariableName,\r | |
604 | &gEfiCallerIdGuid,\r | |
605 | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r | |
606 | sizeof (*FmpControllerState),\r | |
607 | FmpControllerState\r | |
608 | );\r | |
b0bacc00 | 609 | if (EFI_ERROR (Status)) {\r |
e0961677 | 610 | DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to update controller state. Status = %r\n", mImageIdName, Status));\r |
67c1e5ee | 611 | } else {\r |
45ce0a67 MK |
612 | DEBUG ((\r |
613 | DEBUG_INFO,\r | |
614 | "FmpDxe(%s): Set variable %g %s LowestSupportedVersion %08x\n",\r | |
e0961677 | 615 | mImageIdName,\r |
67c1e5ee EJ |
616 | &gEfiCallerIdGuid,\r |
617 | Private->FmpStateVariableName,\r | |
618 | LowestSupportedVersion\r | |
619 | ));\r | |
b0bacc00 | 620 | }\r |
b0bacc00 | 621 | }\r |
45ce0a67 | 622 | \r |
67c1e5ee | 623 | FreePool (FmpControllerState);\r |
b0bacc00 KM |
624 | }\r |
625 | \r | |
626 | /**\r | |
627 | Saves the last attempt status value of the most recent FMP capsule update to a\r | |
628 | UEFI variable.\r | |
629 | \r | |
67c1e5ee | 630 | UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"\r |
b0bacc00 | 631 | \r |
67c1e5ee EJ |
632 | @param[in] Private Private context structure for the managed\r |
633 | controller.\r | |
b0bacc00 KM |
634 | @param[in] LastAttemptStatus The last attempt status of the most recent FMP\r |
635 | capsule update.\r | |
b0bacc00 KM |
636 | **/\r |
637 | VOID\r | |
638 | SetLastAttemptStatusInVariable (\r | |
67c1e5ee EJ |
639 | IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private,\r |
640 | IN UINT32 LastAttemptStatus\r | |
b0bacc00 KM |
641 | )\r |
642 | {\r | |
67c1e5ee EJ |
643 | EFI_STATUS Status;\r |
644 | FMP_CONTROLLER_STATE *FmpControllerState;\r | |
645 | BOOLEAN Update;\r | |
b0bacc00 | 646 | \r |
67c1e5ee EJ |
647 | FmpControllerState = GetFmpControllerState (Private);\r |
648 | if (FmpControllerState == NULL) {\r | |
649 | //\r | |
650 | // Can not update value if FMP Controller State does not exist.\r | |
651 | // This variable is guaranteed to be created by GenerateFmpVariableNames().\r | |
652 | //\r | |
653 | return;\r | |
654 | }\r | |
b0bacc00 | 655 | \r |
67c1e5ee EJ |
656 | Update = FALSE;\r |
657 | if (!FmpControllerState->LastAttemptStatusValid) {\r | |
658 | Update = TRUE;\r | |
659 | }\r | |
45ce0a67 | 660 | \r |
67c1e5ee EJ |
661 | if (FmpControllerState->LastAttemptStatus != LastAttemptStatus) {\r |
662 | Update = TRUE;\r | |
663 | }\r | |
45ce0a67 | 664 | \r |
67c1e5ee | 665 | if (!Update) {\r |
e0961677 | 666 | DEBUG ((DEBUG_INFO, "FmpDxe(%s): No need to update controller state. Same value as before.\n", mImageIdName));\r |
67c1e5ee EJ |
667 | } else {\r |
668 | FmpControllerState->LastAttemptStatusValid = TRUE;\r | |
669 | FmpControllerState->LastAttemptStatus = LastAttemptStatus;\r | |
45ce0a67 MK |
670 | Status = gRT->SetVariable (\r |
671 | Private->FmpStateVariableName,\r | |
672 | &gEfiCallerIdGuid,\r | |
673 | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r | |
674 | sizeof (*FmpControllerState),\r | |
675 | FmpControllerState\r | |
676 | );\r | |
b0bacc00 | 677 | if (EFI_ERROR (Status)) {\r |
e0961677 | 678 | DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to update controller state. Status = %r\n", mImageIdName, Status));\r |
67c1e5ee | 679 | } else {\r |
45ce0a67 MK |
680 | DEBUG ((\r |
681 | DEBUG_INFO,\r | |
682 | "FmpDxe(%s): Set variable %g %s LastAttemptStatus %08x\n",\r | |
e0961677 | 683 | mImageIdName,\r |
67c1e5ee EJ |
684 | &gEfiCallerIdGuid,\r |
685 | Private->FmpStateVariableName,\r | |
686 | LastAttemptStatus\r | |
687 | ));\r | |
b0bacc00 | 688 | }\r |
b0bacc00 | 689 | }\r |
45ce0a67 | 690 | \r |
67c1e5ee | 691 | FreePool (FmpControllerState);\r |
b0bacc00 KM |
692 | }\r |
693 | \r | |
694 | /**\r | |
695 | Saves the last attempt version value of the most recent FMP capsule update to\r | |
696 | a UEFI variable.\r | |
697 | \r | |
67c1e5ee | 698 | UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"\r |
b0bacc00 | 699 | \r |
67c1e5ee EJ |
700 | @param[in] Private Private context structure for the managed\r |
701 | controller.\r | |
b0bacc00 KM |
702 | @param[in] LastAttemptVersion The last attempt version value of the most\r |
703 | recent FMP capsule update.\r | |
b0bacc00 KM |
704 | **/\r |
705 | VOID\r | |
706 | SetLastAttemptVersionInVariable (\r | |
67c1e5ee EJ |
707 | IN FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private,\r |
708 | IN UINT32 LastAttemptVersion\r | |
b0bacc00 KM |
709 | )\r |
710 | {\r | |
67c1e5ee EJ |
711 | EFI_STATUS Status;\r |
712 | FMP_CONTROLLER_STATE *FmpControllerState;\r | |
713 | BOOLEAN Update;\r | |
b0bacc00 | 714 | \r |
67c1e5ee EJ |
715 | FmpControllerState = GetFmpControllerState (Private);\r |
716 | if (FmpControllerState == NULL) {\r | |
717 | //\r | |
718 | // Can not update value if FMP Controller State does not exist.\r | |
719 | // This variable is guaranteed to be created by GenerateFmpVariableNames().\r | |
720 | //\r | |
721 | return;\r | |
722 | }\r | |
b0bacc00 | 723 | \r |
67c1e5ee EJ |
724 | Update = FALSE;\r |
725 | if (!FmpControllerState->LastAttemptVersionValid) {\r | |
726 | Update = TRUE;\r | |
727 | }\r | |
45ce0a67 | 728 | \r |
67c1e5ee EJ |
729 | if (FmpControllerState->LastAttemptVersion != LastAttemptVersion) {\r |
730 | Update = TRUE;\r | |
731 | }\r | |
45ce0a67 | 732 | \r |
67c1e5ee | 733 | if (!Update) {\r |
e0961677 | 734 | DEBUG ((DEBUG_INFO, "FmpDxe(%s): No need to update controller state. Same value as before.\n", mImageIdName));\r |
67c1e5ee EJ |
735 | } else {\r |
736 | FmpControllerState->LastAttemptVersionValid = TRUE;\r | |
737 | FmpControllerState->LastAttemptVersion = LastAttemptVersion;\r | |
45ce0a67 MK |
738 | Status = gRT->SetVariable (\r |
739 | Private->FmpStateVariableName,\r | |
740 | &gEfiCallerIdGuid,\r | |
741 | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r | |
742 | sizeof (*FmpControllerState),\r | |
743 | FmpControllerState\r | |
744 | );\r | |
b0bacc00 | 745 | if (EFI_ERROR (Status)) {\r |
e0961677 | 746 | DEBUG ((DEBUG_ERROR, "FmpDxe(%s): Failed to update controller state. Status = %r\n", mImageIdName, Status));\r |
67c1e5ee | 747 | } else {\r |
45ce0a67 MK |
748 | DEBUG ((\r |
749 | DEBUG_INFO,\r | |
750 | "FmpDxe(%s): Set variable %g %s LastAttemptVersion %08x\n",\r | |
e0961677 | 751 | mImageIdName,\r |
67c1e5ee EJ |
752 | &gEfiCallerIdGuid,\r |
753 | Private->FmpStateVariableName,\r | |
754 | LastAttemptVersion\r | |
755 | ));\r | |
b0bacc00 | 756 | }\r |
b0bacc00 | 757 | }\r |
45ce0a67 | 758 | \r |
67c1e5ee | 759 | FreePool (FmpControllerState);\r |
b0bacc00 KM |
760 | }\r |
761 | \r | |
762 | /**\r | |
67c1e5ee EJ |
763 | Attempts to lock a single UEFI Variable propagating the error state of the\r |
764 | first lock attempt that fails. Uses gEfiCallerIdGuid as the variable GUID.\r | |
765 | \r | |
766 | @param[in] PreviousStatus The previous UEFI Variable lock attempt status.\r | |
767 | @param[in] VariableLock The EDK II Variable Lock Protocol instance.\r | |
768 | @param[in] VariableName The name of the UEFI Variable to lock.\r | |
769 | \r | |
770 | @retval EFI_SUCCESS The UEFI Variable was locked and the previous variable\r | |
771 | lock attempt also succeeded.\r | |
772 | @retval Other The UEFI Variable could not be locked or the previous\r | |
773 | variable lock attempt failed.\r | |
774 | **/\r | |
775 | static\r | |
776 | EFI_STATUS\r | |
777 | LockFmpVariable (\r | |
2f6f3329 YJ |
778 | IN EFI_STATUS PreviousStatus,\r |
779 | IN EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy,\r | |
780 | IN CHAR16 *VariableName\r | |
67c1e5ee EJ |
781 | )\r |
782 | {\r | |
783 | EFI_STATUS Status;\r | |
784 | \r | |
2f6f3329 | 785 | // If success, go ahead and set the policies to protect the target variables.\r |
45ce0a67 MK |
786 | Status = RegisterBasicVariablePolicy (\r |
787 | VariablePolicy,\r | |
788 | &gEfiCallerIdGuid,\r | |
789 | VariableName,\r | |
790 | VARIABLE_POLICY_NO_MIN_SIZE,\r | |
791 | VARIABLE_POLICY_NO_MAX_SIZE,\r | |
792 | VARIABLE_POLICY_NO_MUST_ATTR,\r | |
793 | VARIABLE_POLICY_NO_CANT_ATTR,\r | |
794 | VARIABLE_POLICY_TYPE_LOCK_NOW\r | |
795 | );\r | |
2f6f3329 | 796 | if (EFI_ERROR (Status)) {\r |
45ce0a67 MK |
797 | DEBUG ((\r |
798 | DEBUG_ERROR,\r | |
799 | "FmpDxe(%s): Failed to lock variable %g %s. Status = %r\n",\r | |
800 | mImageIdName,\r | |
801 | &gEfiCallerIdGuid,\r | |
802 | VariableName,\r | |
803 | Status\r | |
804 | ));\r | |
67c1e5ee | 805 | }\r |
45ce0a67 | 806 | \r |
67c1e5ee EJ |
807 | if (EFI_ERROR (PreviousStatus)) {\r |
808 | return PreviousStatus;\r | |
809 | }\r | |
45ce0a67 | 810 | \r |
67c1e5ee EJ |
811 | return Status;\r |
812 | }\r | |
813 | \r | |
814 | /**\r | |
815 | Locks all the UEFI Variables that use gEfiCallerIdGuid of the currently\r | |
816 | executing module.\r | |
817 | \r | |
818 | @param[in] Private Private context structure for the managed controller.\r | |
b0bacc00 KM |
819 | \r |
820 | @retval EFI_SUCCESS All UEFI variables are locked.\r | |
821 | @retval EFI_UNSUPPORTED Variable Lock Protocol not found.\r | |
822 | @retval Other One of the UEFI variables could not be locked.\r | |
b0bacc00 KM |
823 | **/\r |
824 | EFI_STATUS\r | |
825 | LockAllFmpVariables (\r | |
67c1e5ee | 826 | FIRMWARE_MANAGEMENT_PRIVATE_DATA *Private\r |
b0bacc00 KM |
827 | )\r |
828 | {\r | |
45ce0a67 MK |
829 | EFI_STATUS Status;\r |
830 | EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy;\r | |
2f6f3329 YJ |
831 | \r |
832 | // Locate the VariablePolicy protocol.\r | |
45ce0a67 | 833 | Status = gBS->LocateProtocol (&gEdkiiVariablePolicyProtocolGuid, NULL, (VOID **)&VariablePolicy);\r |
2f6f3329 YJ |
834 | if (EFI_ERROR (Status)) {\r |
835 | DEBUG ((DEBUG_ERROR, "FmpDxe %a - Could not locate VariablePolicy protocol! %r\n", __FUNCTION__, Status));\r | |
836 | return Status;\r | |
b0bacc00 KM |
837 | }\r |
838 | \r | |
67c1e5ee | 839 | Status = EFI_SUCCESS;\r |
2f6f3329 YJ |
840 | Status = LockFmpVariable (Status, VariablePolicy, Private->VersionVariableName);\r |
841 | Status = LockFmpVariable (Status, VariablePolicy, Private->LsvVariableName);\r | |
842 | Status = LockFmpVariable (Status, VariablePolicy, Private->LastAttemptStatusVariableName);\r | |
843 | Status = LockFmpVariable (Status, VariablePolicy, Private->LastAttemptVersionVariableName);\r | |
844 | Status = LockFmpVariable (Status, VariablePolicy, Private->FmpStateVariableName);\r | |
b0bacc00 | 845 | \r |
67c1e5ee | 846 | return Status;\r |
b0bacc00 | 847 | }\r |