2 DXE capsule report related function.
4 Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Protocol/FirmwareManagement.h>
11 #include <Guid/CapsuleReport.h>
12 #include <Guid/FmpCapsule.h>
13 #include <Guid/CapsuleVendor.h>
15 #include <Library/BaseLib.h>
16 #include <Library/DebugLib.h>
17 #include <Library/BaseMemoryLib.h>
18 #include <Library/UefiBootServicesTableLib.h>
19 #include <Library/UefiRuntimeServicesTableLib.h>
20 #include <Library/MemoryAllocationLib.h>
21 #include <Library/UefiLib.h>
22 #include <Library/PcdLib.h>
23 #include <Library/HobLib.h>
24 #include <Library/PrintLib.h>
25 #include <Library/ReportStatusCodeLib.h>
26 #include <Library/DevicePathLib.h>
27 #include <Library/CapsuleLib.h>
28 #include <Library/VariablePolicyHelperLib.h>
30 #include <IndustryStandard/WindowsUxCapsule.h>
33 This routine is called to clear CapsuleOnDisk Relocation Info variable.
34 Total Capsule On Disk length is recorded in this variable
36 @retval EFI_SUCCESS Capsule On Disk flags are cleared
40 CoDClearCapsuleRelocationInfo (
45 Get current capsule last variable index.
47 @return Current capsule last variable index.
48 @retval -1 No current capsule last variable.
51 GetCurrentCapsuleLastIndex (
56 CHAR16 CapsuleLastStr
[sizeof ("Capsule####")];
60 Size
= sizeof (L
"Capsule####") - sizeof (CHAR16
); // no zero terminator
61 Status
= gRT
->GetVariable (
63 &gEfiCapsuleReportGuid
,
68 if (EFI_ERROR (Status
)) {
72 CurrentIndex
= (UINT16
)StrHexToUintn (&CapsuleLastStr
[sizeof ("Capsule") - 1]);
77 Get a new capsule status variable index.
79 @return A new capsule status variable index.
80 @retval 0 No new capsule status variable index. Rolling over.
83 GetNewCapsuleResultIndex (
89 CurrentIndex
= GetCurrentCapsuleLastIndex ();
90 if (CurrentIndex
>= PcdGet16 (PcdCapsuleMax
)) {
91 DEBUG ((DEBUG_INFO
, " CapsuleResult variable Rolling Over!\n"));
95 return CurrentIndex
+ 1;
99 Lock Variable by variable policy.
101 @param[in] VariableGuid The Guid of the variable to be locked
102 @param[in] VariableName The name of the variable to be locked
103 @param[in] VariablePolicy The pointer of variable lock policy
107 IN CONST EFI_GUID VariableGuid
,
108 IN CHAR16
*VariableName
,
109 IN EDKII_VARIABLE_POLICY_PROTOCOL
*VariablePolicy
114 // Set the policies to protect the target variables
115 Status
= RegisterBasicVariablePolicy (
119 VARIABLE_POLICY_NO_MIN_SIZE
,
120 VARIABLE_POLICY_NO_MAX_SIZE
,
121 VARIABLE_POLICY_NO_MUST_ATTR
,
122 VARIABLE_POLICY_NO_CANT_ATTR
,
123 VARIABLE_POLICY_TYPE_LOCK_NOW
125 if (EFI_ERROR (Status
)) {
128 "DxeCapsuleLibFmp: Failed to lock variable %g %s. Status = %r\n",
133 ASSERT_EFI_ERROR (Status
);
138 Write a new capsule status variable.
140 @param[in] CapsuleResult The capsule status variable
141 @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes
143 @retval EFI_SUCCESS The capsule status variable is recorded.
144 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
147 WriteNewCapsuleResultVariable (
148 IN VOID
*CapsuleResult
,
149 IN UINTN CapsuleResultSize
152 INTN CapsuleResultIndex
;
153 CHAR16 CapsuleResultStr
[sizeof ("Capsule####")];
157 CapsuleResultIndex
= GetNewCapsuleResultIndex ();
158 DEBUG ((DEBUG_INFO
, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex
));
162 sizeof (CapsuleResultStr
),
167 Status
= gRT
->SetVariable (
169 &gEfiCapsuleReportGuid
,
170 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
174 if (!EFI_ERROR (Status
)) {
175 Size
= sizeof (L
"Capsule####") - sizeof (CHAR16
); // no zero terminator
176 DEBUG ((DEBUG_INFO
, "Set CapsuleLast - %s\n", CapsuleResultStr
));
177 Status
= gRT
->SetVariable (
179 &gEfiCapsuleReportGuid
,
180 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
190 Record capsule status variable and to local cache.
192 @param[in] CapsuleHeader The capsule image header
193 @param[in] CapsuleStatus The capsule process stauts
195 @retval EFI_SUCCESS The capsule status variable is recorded.
196 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
199 RecordCapsuleStatusVariable (
200 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
201 IN EFI_STATUS CapsuleStatus
204 EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable
;
207 CapsuleResultVariable
.VariableTotalSize
= sizeof (CapsuleResultVariable
);
208 CapsuleResultVariable
.Reserved
= 0;
209 CopyGuid (&CapsuleResultVariable
.CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
210 ZeroMem (&CapsuleResultVariable
.CapsuleProcessed
, sizeof (CapsuleResultVariable
.CapsuleProcessed
));
211 gRT
->GetTime (&CapsuleResultVariable
.CapsuleProcessed
, NULL
);
212 CapsuleResultVariable
.CapsuleStatus
= CapsuleStatus
;
214 Status
= EFI_SUCCESS
;
215 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
216 Status
= WriteNewCapsuleResultVariable (&CapsuleResultVariable
, sizeof (CapsuleResultVariable
));
223 Record FMP capsule status variable and to local cache.
225 @param[in] CapsuleHeader The capsule image header
226 @param[in] CapsuleStatus The capsule process stauts
227 @param[in] PayloadIndex FMP payload index
228 @param[in] ImageHeader FMP image header
229 @param[in] FmpDevicePath DevicePath associated with the FMP producer
230 @param[in] CapFileName Capsule file name
232 @retval EFI_SUCCESS The capsule status variable is recorded.
233 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
236 RecordFmpCapsuleStatusVariable (
237 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
238 IN EFI_STATUS CapsuleStatus
,
239 IN UINTN PayloadIndex
,
240 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
,
241 IN EFI_DEVICE_PATH_PROTOCOL
*FmpDevicePath OPTIONAL
,
242 IN CHAR16
*CapFileName OPTIONAL
245 EFI_CAPSULE_RESULT_VARIABLE_HEADER
*CapsuleResultVariableHeader
;
246 EFI_CAPSULE_RESULT_VARIABLE_FMP
*CapsuleResultVariableFmp
;
248 UINT8
*CapsuleResultVariable
;
249 UINTN CapsuleResultVariableSize
;
250 CHAR16
*DevicePathStr
;
251 UINTN DevicePathStrSize
;
252 UINTN CapFileNameSize
;
254 DevicePathStr
= NULL
;
255 CapFileNameSize
= sizeof (CHAR16
);
257 if (FmpDevicePath
!= NULL
) {
258 DevicePathStr
= ConvertDevicePathToText (FmpDevicePath
, FALSE
, FALSE
);
261 if (DevicePathStr
!= NULL
) {
262 DevicePathStrSize
= StrSize (DevicePathStr
);
264 DevicePathStrSize
= sizeof (CHAR16
);
267 if (CapFileName
!= NULL
) {
268 CapFileNameSize
= StrSize (CapFileName
);
272 // Allocate room for CapsuleFileName.
274 CapsuleResultVariableSize
= sizeof (EFI_CAPSULE_RESULT_VARIABLE_HEADER
) + sizeof (EFI_CAPSULE_RESULT_VARIABLE_FMP
) + CapFileNameSize
+ DevicePathStrSize
;
276 CapsuleResultVariable
= AllocateZeroPool (CapsuleResultVariableSize
);
277 if (CapsuleResultVariable
== NULL
) {
278 return EFI_OUT_OF_RESOURCES
;
281 CapsuleResultVariableHeader
= (VOID
*)CapsuleResultVariable
;
282 CapsuleResultVariableHeader
->VariableTotalSize
= (UINT32
)CapsuleResultVariableSize
;
283 CapsuleResultVariableHeader
->Reserved
= 0;
284 CopyGuid (&CapsuleResultVariableHeader
->CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
285 ZeroMem (&CapsuleResultVariableHeader
->CapsuleProcessed
, sizeof (CapsuleResultVariableHeader
->CapsuleProcessed
));
286 gRT
->GetTime (&CapsuleResultVariableHeader
->CapsuleProcessed
, NULL
);
287 CapsuleResultVariableHeader
->CapsuleStatus
= CapsuleStatus
;
289 CapsuleResultVariableFmp
= (VOID
*)(CapsuleResultVariable
+ sizeof (EFI_CAPSULE_RESULT_VARIABLE_HEADER
));
290 CapsuleResultVariableFmp
->Version
= 0x1;
291 CapsuleResultVariableFmp
->PayloadIndex
= (UINT8
)PayloadIndex
;
292 CapsuleResultVariableFmp
->UpdateImageIndex
= ImageHeader
->UpdateImageIndex
;
293 CopyGuid (&CapsuleResultVariableFmp
->UpdateImageTypeId
, &ImageHeader
->UpdateImageTypeId
);
295 if (CapFileName
!= NULL
) {
296 CopyMem ((UINT8
*)CapsuleResultVariableFmp
+ sizeof (EFI_CAPSULE_RESULT_VARIABLE_FMP
), CapFileName
, CapFileNameSize
);
299 if (DevicePathStr
!= NULL
) {
300 CopyMem ((UINT8
*)CapsuleResultVariableFmp
+ sizeof (EFI_CAPSULE_RESULT_VARIABLE_FMP
) + CapFileNameSize
, DevicePathStr
, DevicePathStrSize
);
301 FreePool (DevicePathStr
);
302 DevicePathStr
= NULL
;
305 Status
= EFI_SUCCESS
;
306 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
307 Status
= WriteNewCapsuleResultVariable (CapsuleResultVariable
, CapsuleResultVariableSize
);
310 FreePool (CapsuleResultVariable
);
315 Initialize CapsuleMax variables.
317 @param[in] VariablePolicy The pointer of variable lock policy
320 InitCapsuleMaxVariable (
321 EDKII_VARIABLE_POLICY_PROTOCOL
*VariablePolicy
326 CHAR16 CapsuleMaxStr
[sizeof ("Capsule####")];
330 sizeof (CapsuleMaxStr
),
332 PcdGet16 (PcdCapsuleMax
)
335 Size
= sizeof (L
"Capsule####") - sizeof (CHAR16
); // no zero terminator
336 Status
= gRT
->SetVariable (
338 &gEfiCapsuleReportGuid
,
339 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
343 if (!EFI_ERROR (Status
)) {
344 // Lock it per UEFI spec.
345 LockVariable (gEfiCapsuleReportGuid
, L
"CapsuleMax", VariablePolicy
);
350 Initialize CapsuleLast variables.
352 @param[in] VariablePolicy The pointer of variable lock policy
355 InitCapsuleLastVariable (
356 EDKII_VARIABLE_POLICY_PROTOCOL
*VariablePolicy
360 EFI_BOOT_MODE BootMode
;
363 CHAR16 CapsuleLastStr
[sizeof ("Capsule####")];
365 BootMode
= GetBootModeHob ();
366 if (BootMode
== BOOT_ON_FLASH_UPDATE
) {
367 Status
= gRT
->SetVariable (
369 &gEfiCapsuleReportGuid
,
370 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
374 // Do not lock it because it will be updated later.
377 // Check if OS/APP cleared L"Capsule####"
379 ZeroMem (CapsuleLastStr
, sizeof (CapsuleLastStr
));
380 Size
= sizeof (L
"Capsule####") - sizeof (CHAR16
); // no zero terminator
381 Status
= gRT
->GetVariable (
383 &gEfiCapsuleReportGuid
,
388 if (!EFI_ERROR (Status
)) {
390 // L"CapsuleLast" is got, check if data is there.
392 Status
= GetVariable2 (
394 &gEfiCapsuleReportGuid
,
395 (VOID
**)&CapsuleResult
,
398 if (EFI_ERROR (Status
)) {
400 // If no data, delete L"CapsuleLast"
402 Status
= gRT
->SetVariable (
404 &gEfiCapsuleReportGuid
,
405 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
410 if (CapsuleResult
!= NULL
) {
411 FreePool (CapsuleResult
);
416 // Lock it in normal boot path per UEFI spec.
417 LockVariable (gEfiCapsuleReportGuid
, L
"CapsuleLast", VariablePolicy
);
422 Initialize capsule update variables.
425 InitCapsuleUpdateVariable (
431 CHAR16 CapsuleVarName
[30];
435 // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
436 // as early as possible which will avoid the next time boot after the capsule update
437 // will still into the capsule loop
439 StrCpyS (CapsuleVarName
, sizeof (CapsuleVarName
)/sizeof (CapsuleVarName
[0]), EFI_CAPSULE_VARIABLE_NAME
);
440 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
444 UnicodeValueToStringS (
446 sizeof (CapsuleVarName
) - ((UINTN
)TempVarName
- (UINTN
)CapsuleVarName
),
453 Status
= gRT
->SetVariable (
455 &gEfiCapsuleVendorGuid
,
456 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
460 if (EFI_ERROR (Status
)) {
462 // There is no capsule variables, quit
472 Initialize capsule relocation info variable.
474 @param[in] VariablePolicy The pointer of variable lock policy
477 InitCapsuleRelocationInfo (
478 EDKII_VARIABLE_POLICY_PROTOCOL
*VariablePolicy
481 CoDClearCapsuleRelocationInfo ();
484 // Unlock Capsule On Disk relocation Info variable only when Capsule On Disk flag is enabled
486 if (!CoDCheckCapsuleOnDiskFlag ()) {
487 LockVariable (gEfiCapsuleVendorGuid
, COD_RELOCATION_INFO_VAR_NAME
, VariablePolicy
);
492 Initialize capsule related variables.
495 InitCapsuleVariable (
500 EDKII_VARIABLE_POLICY_PROTOCOL
*VariablePolicy
;
502 // Locate the VariablePolicy protocol
503 Status
= gBS
->LocateProtocol (&gEdkiiVariablePolicyProtocolGuid
, NULL
, (VOID
**)&VariablePolicy
);
504 if (EFI_ERROR (Status
)) {
505 DEBUG ((DEBUG_ERROR
, "DxeCapsuleReportLib %a - Could not locate VariablePolicy protocol! %r\n", __FUNCTION__
, Status
));
506 ASSERT_EFI_ERROR (Status
);
509 InitCapsuleUpdateVariable ();
510 InitCapsuleMaxVariable (VariablePolicy
);
511 InitCapsuleLastVariable (VariablePolicy
);
512 InitCapsuleRelocationInfo (VariablePolicy
);
515 // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"
516 // to check status and delete them.