]> git.proxmox.com Git - mirror_edk2.git/blame - FmpDevicePkg/FmpDxe/VariableSupport.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / FmpDevicePkg / FmpDxe / VariableSupport.c
CommitLineData
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
26static\r
27VOID\r
28GetFmpVariable (\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
65static\r
66VOID\r
67DeleteFmpVariable (\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
97static\r
98FMP_CONTROLLER_STATE *\r
99GetFmpControllerState (\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
147static\r
148CHAR16 *\r
149GenerateFmpVariableName (\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
206VOID\r
207GenerateFmpVariableNames (\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
336UINT32\r
337GetVersionFromVariable (\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
379UINT32\r
380GetLowestSupportedVersionFromVariable (\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
421UINT32\r
422GetLastAttemptStatusFromVariable (\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
463UINT32\r
464GetLastAttemptVersionFromVariable (\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
501VOID\r
502SetVersionInVariable (\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
569VOID\r
570SetLowestSupportedVersionInVariable (\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
637VOID\r
638SetLastAttemptStatusInVariable (\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
705VOID\r
706SetLastAttemptVersionInVariable (\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
775static\r
776EFI_STATUS\r
777LockFmpVariable (\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
824EFI_STATUS\r
825LockAllFmpVariables (\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