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