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