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