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
)) {
71 CurrentIndex
= (UINT16
)StrHexToUintn(&CapsuleLastStr
[sizeof("Capsule") - 1]);
76 Get a new capsule status variable index.
78 @return A new capsule status variable index.
79 @retval 0 No new capsule status variable index. Rolling over.
82 GetNewCapsuleResultIndex (
88 CurrentIndex
= GetCurrentCapsuleLastIndex();
89 if (CurrentIndex
>= PcdGet16(PcdCapsuleMax
)) {
90 DEBUG((DEBUG_INFO
, " CapsuleResult variable Rolling Over!\n"));
94 return CurrentIndex
+ 1;
98 Lock Variable by variable policy.
100 @param[in] VariableGuid The Guid of the variable to be locked
101 @param[in] VariableName The name of the variable to be locked
102 @param[in] VariablePolicy The pointer of variable lock policy
106 IN CONST EFI_GUID VariableGuid
,
107 IN CHAR16
*VariableName
,
108 IN EDKII_VARIABLE_POLICY_PROTOCOL
*VariablePolicy
113 // Set the policies to protect the target variables
114 Status
= RegisterBasicVariablePolicy (VariablePolicy
,
117 VARIABLE_POLICY_NO_MIN_SIZE
,
118 VARIABLE_POLICY_NO_MAX_SIZE
,
119 VARIABLE_POLICY_NO_MUST_ATTR
,
120 VARIABLE_POLICY_NO_CANT_ATTR
,
121 VARIABLE_POLICY_TYPE_LOCK_NOW
);
122 if (EFI_ERROR (Status
)) {
123 DEBUG ((DEBUG_ERROR
, "DxeCapsuleLibFmp: Failed to lock variable %g %s. Status = %r\n",
127 ASSERT_EFI_ERROR (Status
);
132 Write a new capsule status variable.
134 @param[in] CapsuleResult The capsule status variable
135 @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes
137 @retval EFI_SUCCESS The capsule status variable is recorded.
138 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
141 WriteNewCapsuleResultVariable (
142 IN VOID
*CapsuleResult
,
143 IN UINTN CapsuleResultSize
146 INTN CapsuleResultIndex
;
147 CHAR16 CapsuleResultStr
[sizeof("Capsule####")];
151 CapsuleResultIndex
= GetNewCapsuleResultIndex();
152 DEBUG((DEBUG_INFO
, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex
));
156 sizeof(CapsuleResultStr
),
161 Status
= gRT
->SetVariable(
163 &gEfiCapsuleReportGuid
,
164 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
168 if (!EFI_ERROR(Status
)) {
169 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
170 DEBUG((DEBUG_INFO
, "Set CapsuleLast - %s\n", CapsuleResultStr
));
171 Status
= gRT
->SetVariable(
173 &gEfiCapsuleReportGuid
,
174 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
184 Record capsule status variable and to local cache.
186 @param[in] CapsuleHeader The capsule image header
187 @param[in] CapsuleStatus The capsule process stauts
189 @retval EFI_SUCCESS The capsule status variable is recorded.
190 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
193 RecordCapsuleStatusVariable (
194 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
195 IN EFI_STATUS CapsuleStatus
198 EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable
;
201 CapsuleResultVariable
.VariableTotalSize
= sizeof(CapsuleResultVariable
);
202 CapsuleResultVariable
.Reserved
= 0;
203 CopyGuid (&CapsuleResultVariable
.CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
204 ZeroMem(&CapsuleResultVariable
.CapsuleProcessed
, sizeof(CapsuleResultVariable
.CapsuleProcessed
));
205 gRT
->GetTime(&CapsuleResultVariable
.CapsuleProcessed
, NULL
);
206 CapsuleResultVariable
.CapsuleStatus
= CapsuleStatus
;
208 Status
= EFI_SUCCESS
;
209 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
210 Status
= WriteNewCapsuleResultVariable(&CapsuleResultVariable
, sizeof(CapsuleResultVariable
));
216 Record FMP capsule status variable and to local cache.
218 @param[in] CapsuleHeader The capsule image header
219 @param[in] CapsuleStatus The capsule process stauts
220 @param[in] PayloadIndex FMP payload index
221 @param[in] ImageHeader FMP image header
222 @param[in] FmpDevicePath DevicePath associated with the FMP producer
223 @param[in] CapFileName Capsule file name
225 @retval EFI_SUCCESS The capsule status variable is recorded.
226 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
229 RecordFmpCapsuleStatusVariable (
230 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
231 IN EFI_STATUS CapsuleStatus
,
232 IN UINTN PayloadIndex
,
233 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
,
234 IN EFI_DEVICE_PATH_PROTOCOL
*FmpDevicePath OPTIONAL
,
235 IN CHAR16
*CapFileName OPTIONAL
238 EFI_CAPSULE_RESULT_VARIABLE_HEADER
*CapsuleResultVariableHeader
;
239 EFI_CAPSULE_RESULT_VARIABLE_FMP
*CapsuleResultVariableFmp
;
241 UINT8
*CapsuleResultVariable
;
242 UINTN CapsuleResultVariableSize
;
243 CHAR16
*DevicePathStr
;
244 UINTN DevicePathStrSize
;
245 UINTN CapFileNameSize
;
247 DevicePathStr
= NULL
;
248 CapFileNameSize
= sizeof(CHAR16
);
250 if (FmpDevicePath
!= NULL
) {
251 DevicePathStr
= ConvertDevicePathToText (FmpDevicePath
, FALSE
, FALSE
);
253 if (DevicePathStr
!= NULL
) {
254 DevicePathStrSize
= StrSize(DevicePathStr
);
256 DevicePathStrSize
= sizeof(CHAR16
);
259 if (CapFileName
!= NULL
) {
260 CapFileNameSize
= StrSize(CapFileName
);
264 // Allocate room for CapsuleFileName.
266 CapsuleResultVariableSize
= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
) + CapFileNameSize
+ DevicePathStrSize
;
268 CapsuleResultVariable
= AllocateZeroPool (CapsuleResultVariableSize
);
269 if (CapsuleResultVariable
== NULL
) {
270 return EFI_OUT_OF_RESOURCES
;
272 CapsuleResultVariableHeader
= (VOID
*)CapsuleResultVariable
;
273 CapsuleResultVariableHeader
->VariableTotalSize
= (UINT32
)CapsuleResultVariableSize
;
274 CapsuleResultVariableHeader
->Reserved
= 0;
275 CopyGuid(&CapsuleResultVariableHeader
->CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
276 ZeroMem(&CapsuleResultVariableHeader
->CapsuleProcessed
, sizeof(CapsuleResultVariableHeader
->CapsuleProcessed
));
277 gRT
->GetTime(&CapsuleResultVariableHeader
->CapsuleProcessed
, NULL
);
278 CapsuleResultVariableHeader
->CapsuleStatus
= CapsuleStatus
;
280 CapsuleResultVariableFmp
= (VOID
*)(CapsuleResultVariable
+ sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
));
281 CapsuleResultVariableFmp
->Version
= 0x1;
282 CapsuleResultVariableFmp
->PayloadIndex
= (UINT8
)PayloadIndex
;
283 CapsuleResultVariableFmp
->UpdateImageIndex
= ImageHeader
->UpdateImageIndex
;
284 CopyGuid (&CapsuleResultVariableFmp
->UpdateImageTypeId
, &ImageHeader
->UpdateImageTypeId
);
286 if (CapFileName
!= NULL
) {
287 CopyMem((UINT8
*)CapsuleResultVariableFmp
+ sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
), CapFileName
, CapFileNameSize
);
290 if (DevicePathStr
!= NULL
) {
291 CopyMem ((UINT8
*)CapsuleResultVariableFmp
+ sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
) + CapFileNameSize
, DevicePathStr
, DevicePathStrSize
);
292 FreePool (DevicePathStr
);
293 DevicePathStr
= NULL
;
296 Status
= EFI_SUCCESS
;
297 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
298 Status
= WriteNewCapsuleResultVariable(CapsuleResultVariable
, CapsuleResultVariableSize
);
300 FreePool (CapsuleResultVariable
);
305 Initialize CapsuleMax variables.
307 @param[in] VariablePolicy The pointer of variable lock policy
310 InitCapsuleMaxVariable (
311 EDKII_VARIABLE_POLICY_PROTOCOL
*VariablePolicy
316 CHAR16 CapsuleMaxStr
[sizeof("Capsule####")];
320 sizeof(CapsuleMaxStr
),
322 PcdGet16(PcdCapsuleMax
)
325 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
326 Status
= gRT
->SetVariable(
328 &gEfiCapsuleReportGuid
,
329 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
333 if (!EFI_ERROR(Status
)) {
334 // Lock it per UEFI spec.
335 LockVariable (gEfiCapsuleReportGuid
, L
"CapsuleMax", VariablePolicy
);
340 Initialize CapsuleLast variables.
342 @param[in] VariablePolicy The pointer of variable lock policy
345 InitCapsuleLastVariable (
346 EDKII_VARIABLE_POLICY_PROTOCOL
*VariablePolicy
350 EFI_BOOT_MODE BootMode
;
353 CHAR16 CapsuleLastStr
[sizeof("Capsule####")];
355 BootMode
= GetBootModeHob();
356 if (BootMode
== BOOT_ON_FLASH_UPDATE
) {
357 Status
= gRT
->SetVariable(
359 &gEfiCapsuleReportGuid
,
360 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
364 // Do not lock it because it will be updated later.
367 // Check if OS/APP cleared L"Capsule####"
369 ZeroMem(CapsuleLastStr
, sizeof(CapsuleLastStr
));
370 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
371 Status
= gRT
->GetVariable(
373 &gEfiCapsuleReportGuid
,
378 if (!EFI_ERROR(Status
)) {
380 // L"CapsuleLast" is got, check if data is there.
382 Status
= GetVariable2 (
384 &gEfiCapsuleReportGuid
,
385 (VOID
**) &CapsuleResult
,
388 if (EFI_ERROR(Status
)) {
390 // If no data, delete L"CapsuleLast"
392 Status
= gRT
->SetVariable(
394 &gEfiCapsuleReportGuid
,
395 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
400 if (CapsuleResult
!= NULL
) {
401 FreePool (CapsuleResult
);
406 // Lock it in normal boot path per UEFI spec.
407 LockVariable (gEfiCapsuleReportGuid
, L
"CapsuleLast", VariablePolicy
);
412 Initialize capsule update variables.
415 InitCapsuleUpdateVariable (
421 CHAR16 CapsuleVarName
[30];
425 // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
426 // as early as possible which will avoid the next time boot after the capsule update
427 // will still into the capsule loop
429 StrCpyS (CapsuleVarName
, sizeof(CapsuleVarName
)/sizeof(CapsuleVarName
[0]), EFI_CAPSULE_VARIABLE_NAME
);
430 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
434 UnicodeValueToStringS (
436 sizeof (CapsuleVarName
) - ((UINTN
)TempVarName
- (UINTN
)CapsuleVarName
),
442 Status
= gRT
->SetVariable (
444 &gEfiCapsuleVendorGuid
,
445 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
449 if (EFI_ERROR (Status
)) {
451 // There is no capsule variables, quit
460 Initialize capsule relocation info variable.
462 @param[in] VariablePolicy The pointer of variable lock policy
465 InitCapsuleRelocationInfo (
466 EDKII_VARIABLE_POLICY_PROTOCOL
*VariablePolicy
469 CoDClearCapsuleRelocationInfo();
472 // Unlock Capsule On Disk relocation Info variable only when Capsule On Disk flag is enabled
474 if (!CoDCheckCapsuleOnDiskFlag()) {
475 LockVariable (gEfiCapsuleVendorGuid
, COD_RELOCATION_INFO_VAR_NAME
, VariablePolicy
);
480 Initialize capsule related variables.
483 InitCapsuleVariable (
488 EDKII_VARIABLE_POLICY_PROTOCOL
*VariablePolicy
;
490 // Locate the VariablePolicy protocol
491 Status
= gBS
->LocateProtocol (&gEdkiiVariablePolicyProtocolGuid
, NULL
, (VOID
**)&VariablePolicy
);
492 if (EFI_ERROR (Status
)) {
493 DEBUG ((DEBUG_ERROR
, "DxeCapsuleReportLib %a - Could not locate VariablePolicy protocol! %r\n", __FUNCTION__
, Status
));
494 ASSERT_EFI_ERROR (Status
);
496 InitCapsuleUpdateVariable();
497 InitCapsuleMaxVariable (VariablePolicy
);
498 InitCapsuleLastVariable (VariablePolicy
);
499 InitCapsuleRelocationInfo (VariablePolicy
);
502 // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"
503 // to check status and delete them.