]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - FmpDevicePkg/FmpDxe/VariableSupport.c
FmpDevicePkg: Add DSC file to build all package components
[mirror_edk2.git] / FmpDevicePkg / FmpDxe / VariableSupport.c
... / ...
CommitLineData
1/** @file\r
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
6 Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>\r
7\r
8 Redistribution and use in source and binary forms, with or without\r
9 modification, are permitted provided that the following conditions are met:\r
10 1. Redistributions of source code must retain the above copyright notice,\r
11 this list of conditions and the following disclaimer.\r
12 2. Redistributions in binary form must reproduce the above copyright notice,\r
13 this list of conditions and the following disclaimer in the documentation\r
14 and/or other materials provided with the distribution.\r
15\r
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND\r
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
19 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\r
20 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\r
21 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
23 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\r
24 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\r
25 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
26\r
27**/\r
28\r
29#include <PiDxe.h>\r
30#include <Library/DebugLib.h>\r
31#include <Library/UefiBootServicesTableLib.h>\r
32#include <Library/UefiRuntimeServicesTableLib.h>\r
33#include <Library/UefiLib.h>\r
34#include <Library/MemoryAllocationLib.h>\r
35#include <Protocol/VariableLock.h>\r
36#include "VariableSupport.h"\r
37\r
38///\r
39/// Array of UEFI variable names that are locked in LockAllFmpVariables().\r
40///\r
41const CHAR16 *mFmpVariableLockList[] = {\r
42 VARNAME_VERSION,\r
43 VARNAME_LSV,\r
44 VARNAME_LASTATTEMPTSTATUS,\r
45 VARNAME_LASTATTEMPTVERSION\r
46};\r
47\r
48/**\r
49 Returns the value used to fill in the Version field of the\r
50 EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()\r
51 service of the Firmware Management Protocol. The value is read from a UEFI\r
52 variable. If the UEFI variables does not exist, then a default version value\r
53 is returned.\r
54\r
55 UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpVersion"\r
56\r
57 @return The version of the firmware image in the firmware device.\r
58\r
59**/\r
60UINT32\r
61GetVersionFromVariable (\r
62 VOID\r
63 )\r
64{\r
65 EFI_STATUS Status;\r
66 UINT32 *Value;\r
67 UINTN Size;\r
68 UINT32 Version;\r
69\r
70 Value = NULL;\r
71 Size = 0;\r
72 Version = DEFAULT_VERSION;\r
73\r
74 Status = GetVariable2 (VARNAME_VERSION, &gEfiCallerIdGuid, (VOID **)&Value, &Size);\r
75 if (EFI_ERROR (Status)) {\r
76 DEBUG ((DEBUG_ERROR, "Failed to get the Version from variable. Status = %r\n", Status));\r
77 return Version;\r
78 }\r
79\r
80 //\r
81 // No error from call\r
82 //\r
83 if (Size == sizeof (*Value)) {\r
84 //\r
85 // Successful read\r
86 //\r
87 Version = *Value;\r
88 } else {\r
89 //\r
90 // Return default since size was unknown\r
91 //\r
92 DEBUG ((DEBUG_ERROR, "Getting version Variable returned a size different than expected. Size = 0x%x\n", Size));\r
93 }\r
94\r
95 FreePool (Value);\r
96\r
97 return Version;\r
98}\r
99\r
100/**\r
101 Returns the value used to fill in the LowestSupportedVersion field of the\r
102 EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()\r
103 service of the Firmware Management Protocol. The value is read from a UEFI\r
104 variable. If the UEFI variables does not exist, then a default lowest\r
105 supported version value is returned.\r
106\r
107 UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpLsv"\r
108\r
109 @return The lowest supported version of the firmware image in the firmware\r
110 device.\r
111\r
112**/\r
113UINT32\r
114GetLowestSupportedVersionFromVariable (\r
115 VOID\r
116 )\r
117{\r
118 EFI_STATUS Status;\r
119 UINT32 *Value;\r
120 UINTN Size;\r
121 UINT32 Version;\r
122\r
123 Value = NULL;\r
124 Size = 0;\r
125 Version = DEFAULT_LOWESTSUPPORTEDVERSION;\r
126\r
127 Status = GetVariable2 (VARNAME_LSV, &gEfiCallerIdGuid, (VOID **)&Value, &Size);\r
128 if (EFI_ERROR (Status)) {\r
129 DEBUG ((DEBUG_WARN, "Warning: Failed to get the Lowest Supported Version from variable. Status = %r\n", Status));\r
130 return Version;\r
131 }\r
132\r
133 //\r
134 // No error from call\r
135 //\r
136 if (Size == sizeof (*Value)) {\r
137 //\r
138 // Successful read\r
139 //\r
140 Version = *Value;\r
141 } else {\r
142 //\r
143 // Return default since size was unknown\r
144 //\r
145 DEBUG ((DEBUG_ERROR, "Getting LSV Variable returned a size different than expected. Size = 0x%x\n", Size));\r
146 }\r
147\r
148 FreePool (Value);\r
149\r
150 return Version;\r
151}\r
152\r
153/**\r
154 Returns the value used to fill in the LastAttemptStatus field of the\r
155 EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()\r
156 service of the Firmware Management Protocol. The value is read from a UEFI\r
157 variable. If the UEFI variables does not exist, then a default last attempt\r
158 status value is returned.\r
159\r
160 UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"LastAttemptStatus"\r
161\r
162 @return The last attempt status value for the most recent capsule update.\r
163\r
164**/\r
165UINT32\r
166GetLastAttemptStatusFromVariable (\r
167 VOID\r
168 )\r
169{\r
170 EFI_STATUS Status;\r
171 UINT32 *Value;\r
172 UINTN Size;\r
173 UINT32 LastAttemptStatus;\r
174\r
175 Value = NULL;\r
176 Size = 0;\r
177 LastAttemptStatus = DEFAULT_LASTATTEMPT;\r
178\r
179 Status = GetVariable2 (VARNAME_LASTATTEMPTSTATUS, &gEfiCallerIdGuid, (VOID **)&Value, &Size);\r
180 if (EFI_ERROR (Status)) {\r
181 DEBUG ((DEBUG_WARN, "Warning: Failed to get the Last Attempt Status from variable. Status = %r\n", Status));\r
182 return LastAttemptStatus;\r
183 }\r
184\r
185 //\r
186 // No error from call\r
187 //\r
188 if (Size == sizeof (*Value)) {\r
189 //\r
190 // Successful read\r
191 //\r
192 LastAttemptStatus = *Value;\r
193 } else {\r
194 //\r
195 // Return default since size was unknown\r
196 //\r
197 DEBUG (\r
198 (DEBUG_ERROR,\r
199 "Getting Last Attempt Status Variable returned a size different than expected. Size = 0x%x\n",\r
200 Size)\r
201 );\r
202 }\r
203\r
204 FreePool (Value);\r
205\r
206 return LastAttemptStatus;\r
207}\r
208\r
209/**\r
210 Returns the value used to fill in the LastAttemptVersion field of the\r
211 EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()\r
212 service of the Firmware Management Protocol. The value is read from a UEFI\r
213 variable. If the UEFI variables does not exist, then a default last attempt\r
214 version value is returned.\r
215\r
216 UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"LastAttemptVersion"\r
217\r
218 @return The last attempt version value for the most recent capsule update.\r
219\r
220**/\r
221UINT32\r
222GetLastAttemptVersionFromVariable (\r
223 VOID\r
224 )\r
225{\r
226 EFI_STATUS Status;\r
227 UINT32 *Value;\r
228 UINTN Size;\r
229 UINT32 Version;\r
230\r
231 Value = NULL;\r
232 Size = 0;\r
233 Version = DEFAULT_LASTATTEMPT;\r
234\r
235 Status = GetVariable2 (VARNAME_LASTATTEMPTVERSION, &gEfiCallerIdGuid, (VOID **)&Value, &Size);\r
236 if (EFI_ERROR (Status)) {\r
237 DEBUG ((DEBUG_WARN, "Warning: Failed to get the Last Attempt Version from variable. Status = %r\n", Status));\r
238 return Version;\r
239 }\r
240\r
241 //\r
242 // No error from call\r
243 //\r
244 if (Size == sizeof (*Value)) {\r
245 //\r
246 // Successful read\r
247 //\r
248 Version = *Value;\r
249 } else {\r
250 //\r
251 // Return default since size was unknown\r
252 //\r
253 DEBUG (\r
254 (DEBUG_ERROR,\r
255 "Getting Last Attempt Version variable returned a size different than expected. Size = 0x%x\n",\r
256 Size)\r
257 );\r
258 }\r
259\r
260 FreePool (Value);\r
261\r
262 return Version;\r
263}\r
264\r
265\r
266/**\r
267 Saves the version current of the firmware image in the firmware device to a\r
268 UEFI variable.\r
269\r
270 UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpVersion"\r
271\r
272 @param[in] Version The version of the firmware image in the firmware device.\r
273\r
274**/\r
275VOID\r
276SetVersionInVariable (\r
277 UINT32 Version\r
278 )\r
279{\r
280 EFI_STATUS Status;\r
281 UINT32 Current;\r
282\r
283 Status = EFI_SUCCESS;\r
284\r
285 Current = GetVersionFromVariable();\r
286 if (Current != Version) {\r
287 Status = gRT->SetVariable (\r
288 VARNAME_VERSION,\r
289 &gEfiCallerIdGuid,\r
290 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
291 sizeof (Version),\r
292 &Version\r
293 );\r
294 if (EFI_ERROR (Status)) {\r
295 DEBUG ((DEBUG_ERROR, "Failed to set the Version into a variable. Status = %r\n", Status));\r
296 }\r
297 } else {\r
298 DEBUG ((DEBUG_INFO, "Version variable doesn't need to update. Same value as before.\n"));\r
299 }\r
300}\r
301\r
302/**\r
303 Saves the lowest supported version current of the firmware image in the\r
304 firmware device to a UEFI variable.\r
305\r
306 UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpLsv"\r
307\r
308 @param[in] LowestSupported The lowest supported version of the firmware image\r
309 in the firmware device.\r
310\r
311**/\r
312VOID\r
313SetLowestSupportedVersionInVariable (\r
314 UINT32 LowestSupportedVersion\r
315 )\r
316{\r
317 EFI_STATUS Status;\r
318 UINT32 Current;\r
319\r
320 Status = EFI_SUCCESS;\r
321\r
322 Current = GetLowestSupportedVersionFromVariable();\r
323 if (LowestSupportedVersion > Current) {\r
324 Status = gRT->SetVariable (\r
325 VARNAME_LSV,\r
326 &gEfiCallerIdGuid,\r
327 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
328 sizeof (LowestSupportedVersion), &LowestSupportedVersion\r
329 );\r
330 if (EFI_ERROR (Status)) {\r
331 DEBUG ((DEBUG_ERROR, "Failed to set the LSV into a variable. Status = %r\n", Status));\r
332 }\r
333 } else {\r
334 DEBUG ((DEBUG_INFO, "LSV variable doesn't need to update. Same value as before.\n"));\r
335 }\r
336}\r
337\r
338/**\r
339 Saves the last attempt status value of the most recent FMP capsule update to a\r
340 UEFI variable.\r
341\r
342 UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"LastAttemptStatus"\r
343\r
344 @param[in] LastAttemptStatus The last attempt status of the most recent FMP\r
345 capsule update.\r
346\r
347**/\r
348VOID\r
349SetLastAttemptStatusInVariable (\r
350 UINT32 LastAttemptStatus\r
351 )\r
352{\r
353 EFI_STATUS Status;\r
354 UINT32 Current;\r
355\r
356 Status = EFI_SUCCESS;\r
357\r
358 Current = GetLastAttemptStatusFromVariable();\r
359 if (Current != LastAttemptStatus) {\r
360 Status = gRT->SetVariable (\r
361 VARNAME_LASTATTEMPTSTATUS,\r
362 &gEfiCallerIdGuid,\r
363 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
364 sizeof (LastAttemptStatus),\r
365 &LastAttemptStatus\r
366 );\r
367 if (EFI_ERROR (Status)) {\r
368 DEBUG ((DEBUG_ERROR, "Failed to set the LastAttemptStatus into a variable. Status = %r\n", Status));\r
369 }\r
370 } else {\r
371 DEBUG ((DEBUG_INFO, "LastAttemptStatus variable doesn't need to update. Same value as before.\n"));\r
372 }\r
373}\r
374\r
375/**\r
376 Saves the last attempt version value of the most recent FMP capsule update to\r
377 a UEFI variable.\r
378\r
379 UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"LastAttemptVersion"\r
380\r
381 @param[in] LastAttemptVersion The last attempt version value of the most\r
382 recent FMP capsule update.\r
383\r
384**/\r
385VOID\r
386SetLastAttemptVersionInVariable (\r
387 UINT32 LastAttemptVersion\r
388 )\r
389{\r
390 EFI_STATUS Status;\r
391 UINT32 Current;\r
392\r
393 Status = EFI_SUCCESS;\r
394\r
395 Current = GetLastAttemptVersionFromVariable();\r
396 if (Current != LastAttemptVersion) {\r
397 Status = gRT->SetVariable (\r
398 VARNAME_LASTATTEMPTVERSION,\r
399 &gEfiCallerIdGuid,\r
400 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
401 sizeof (LastAttemptVersion),\r
402 &LastAttemptVersion\r
403 );\r
404 if (EFI_ERROR (Status)) {\r
405 DEBUG ((DEBUG_ERROR, "Failed to set the LastAttemptVersion into a variable. Status = %r\n", Status));\r
406 }\r
407 } else {\r
408 DEBUG ((DEBUG_INFO, "LastAttemptVersion variable doesn't need to update. Same value as before.\n"));\r
409 }\r
410}\r
411\r
412/**\r
413 Locks all the UEFI Variables used by this module.\r
414\r
415 @retval EFI_SUCCESS All UEFI variables are locked.\r
416 @retval EFI_UNSUPPORTED Variable Lock Protocol not found.\r
417 @retval Other One of the UEFI variables could not be locked.\r
418\r
419**/\r
420EFI_STATUS\r
421LockAllFmpVariables (\r
422 VOID\r
423 )\r
424{\r
425 EFI_STATUS Status;\r
426 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
427 EFI_STATUS ReturnStatus;\r
428 UINTN Index;\r
429\r
430 VariableLock = NULL;\r
431 Status = gBS->LocateProtocol (\r
432 &gEdkiiVariableLockProtocolGuid,\r
433 NULL,\r
434 (VOID **)&VariableLock\r
435 );\r
436 if (EFI_ERROR (Status)) {\r
437 DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to locate Variable Lock Protocol (%r).\n", Status));\r
438 return EFI_UNSUPPORTED;\r
439 }\r
440\r
441 ReturnStatus = EFI_SUCCESS;\r
442 for (Index = 0; Index < ARRAY_SIZE (mFmpVariableLockList); Index++) {\r
443 Status = VariableLock->RequestToLock (\r
444 VariableLock,\r
445 (CHAR16 *)mFmpVariableLockList[Index],\r
446 &gEfiCallerIdGuid\r
447 );\r
448 if (EFI_ERROR (Status)) {\r
449 DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to lock variable %g %s. Status = %r\n",\r
450 &gEfiCallerIdGuid,\r
451 mFmpVariableLockList[Index],\r
452 Status\r
453 ));\r
454 if (!EFI_ERROR (ReturnStatus)) {\r
455 ReturnStatus = Status;\r
456 }\r
457 }\r
458 }\r
459\r
460 return ReturnStatus;\r
461}\r