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