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