2 DXE capsule report related function.
4 Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <Protocol/FirmwareManagement.h>
11 #include <Protocol/VariableLock.h>
12 #include <Guid/CapsuleReport.h>
13 #include <Guid/FmpCapsule.h>
14 #include <Guid/CapsuleVendor.h>
16 #include <Library/BaseLib.h>
17 #include <Library/DebugLib.h>
18 #include <Library/BaseMemoryLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
20 #include <Library/UefiRuntimeServicesTableLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/UefiLib.h>
23 #include <Library/PcdLib.h>
24 #include <Library/HobLib.h>
25 #include <Library/PrintLib.h>
26 #include <Library/ReportStatusCodeLib.h>
27 #include <Library/DevicePathLib.h>
28 #include <Library/CapsuleLib.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 Write a new capsule status variable.
100 @param[in] CapsuleResult The capsule status variable
101 @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes
103 @retval EFI_SUCCESS The capsule status variable is recorded.
104 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
107 WriteNewCapsuleResultVariable (
108 IN VOID
*CapsuleResult
,
109 IN UINTN CapsuleResultSize
112 INTN CapsuleResultIndex
;
113 CHAR16 CapsuleResultStr
[sizeof("Capsule####")];
117 CapsuleResultIndex
= GetNewCapsuleResultIndex();
118 DEBUG((DEBUG_INFO
, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex
));
122 sizeof(CapsuleResultStr
),
127 Status
= gRT
->SetVariable(
129 &gEfiCapsuleReportGuid
,
130 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
134 if (!EFI_ERROR(Status
)) {
135 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
136 DEBUG((DEBUG_INFO
, "Set CapsuleLast - %s\n", CapsuleResultStr
));
137 Status
= gRT
->SetVariable(
139 &gEfiCapsuleReportGuid
,
140 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
150 Record capsule status variable and to local cache.
152 @param[in] CapsuleHeader The capsule image header
153 @param[in] CapsuleStatus The capsule process stauts
155 @retval EFI_SUCCESS The capsule status variable is recorded.
156 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
159 RecordCapsuleStatusVariable (
160 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
161 IN EFI_STATUS CapsuleStatus
164 EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable
;
167 CapsuleResultVariable
.VariableTotalSize
= sizeof(CapsuleResultVariable
);
168 CapsuleResultVariable
.Reserved
= 0;
169 CopyGuid (&CapsuleResultVariable
.CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
170 ZeroMem(&CapsuleResultVariable
.CapsuleProcessed
, sizeof(CapsuleResultVariable
.CapsuleProcessed
));
171 gRT
->GetTime(&CapsuleResultVariable
.CapsuleProcessed
, NULL
);
172 CapsuleResultVariable
.CapsuleStatus
= CapsuleStatus
;
174 Status
= EFI_SUCCESS
;
175 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
176 Status
= WriteNewCapsuleResultVariable(&CapsuleResultVariable
, sizeof(CapsuleResultVariable
));
182 Record FMP capsule status variable and to local cache.
184 @param[in] CapsuleHeader The capsule image header
185 @param[in] CapsuleStatus The capsule process stauts
186 @param[in] PayloadIndex FMP payload index
187 @param[in] ImageHeader FMP image header
188 @param[in] FmpDevicePath DevicePath associated with the FMP producer
189 @param[in] CapFileName Capsule file name
191 @retval EFI_SUCCESS The capsule status variable is recorded.
192 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
195 RecordFmpCapsuleStatusVariable (
196 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
197 IN EFI_STATUS CapsuleStatus
,
198 IN UINTN PayloadIndex
,
199 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
,
200 IN EFI_DEVICE_PATH_PROTOCOL
*FmpDevicePath
, OPTIONAL
201 IN CHAR16
*CapFileName OPTIONAL
204 EFI_CAPSULE_RESULT_VARIABLE_HEADER
*CapsuleResultVariableHeader
;
205 EFI_CAPSULE_RESULT_VARIABLE_FMP
*CapsuleResultVariableFmp
;
207 UINT8
*CapsuleResultVariable
;
208 UINTN CapsuleResultVariableSize
;
209 CHAR16
*DevicePathStr
;
210 UINTN DevicePathStrSize
;
211 UINTN CapFileNameSize
;
213 DevicePathStr
= NULL
;
214 CapFileNameSize
= sizeof(CHAR16
);
216 if (FmpDevicePath
!= NULL
) {
217 DevicePathStr
= ConvertDevicePathToText (FmpDevicePath
, FALSE
, FALSE
);
219 if (DevicePathStr
!= NULL
) {
220 DevicePathStrSize
= StrSize(DevicePathStr
);
222 DevicePathStrSize
= sizeof(CHAR16
);
225 if (CapFileName
!= NULL
) {
226 CapFileNameSize
= StrSize(CapFileName
);
230 // Allocate room for CapsuleFileName.
232 CapsuleResultVariableSize
= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
) + CapFileNameSize
+ DevicePathStrSize
;
234 CapsuleResultVariable
= AllocateZeroPool (CapsuleResultVariableSize
);
235 if (CapsuleResultVariable
== NULL
) {
236 return EFI_OUT_OF_RESOURCES
;
238 CapsuleResultVariableHeader
= (VOID
*)CapsuleResultVariable
;
239 CapsuleResultVariableHeader
->VariableTotalSize
= (UINT32
)CapsuleResultVariableSize
;
240 CapsuleResultVariableHeader
->Reserved
= 0;
241 CopyGuid(&CapsuleResultVariableHeader
->CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
242 ZeroMem(&CapsuleResultVariableHeader
->CapsuleProcessed
, sizeof(CapsuleResultVariableHeader
->CapsuleProcessed
));
243 gRT
->GetTime(&CapsuleResultVariableHeader
->CapsuleProcessed
, NULL
);
244 CapsuleResultVariableHeader
->CapsuleStatus
= CapsuleStatus
;
246 CapsuleResultVariableFmp
= (VOID
*)(CapsuleResultVariable
+ sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
));
247 CapsuleResultVariableFmp
->Version
= 0x1;
248 CapsuleResultVariableFmp
->PayloadIndex
= (UINT8
)PayloadIndex
;
249 CapsuleResultVariableFmp
->UpdateImageIndex
= ImageHeader
->UpdateImageIndex
;
250 CopyGuid (&CapsuleResultVariableFmp
->UpdateImageTypeId
, &ImageHeader
->UpdateImageTypeId
);
252 if (CapFileName
!= NULL
) {
253 CopyMem((UINT8
*)CapsuleResultVariableFmp
+ sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
), CapFileName
, CapFileNameSize
);
256 if (DevicePathStr
!= NULL
) {
257 CopyMem ((UINT8
*)CapsuleResultVariableFmp
+ sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
) + CapFileNameSize
, DevicePathStr
, DevicePathStrSize
);
258 FreePool (DevicePathStr
);
259 DevicePathStr
= NULL
;
262 Status
= EFI_SUCCESS
;
263 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
264 Status
= WriteNewCapsuleResultVariable(CapsuleResultVariable
, CapsuleResultVariableSize
);
266 FreePool (CapsuleResultVariable
);
271 Initialize CapsuleMax variables.
274 InitCapsuleMaxVariable (
280 CHAR16 CapsuleMaxStr
[sizeof("Capsule####")];
281 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
285 sizeof(CapsuleMaxStr
),
287 PcdGet16(PcdCapsuleMax
)
290 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
291 Status
= gRT
->SetVariable(
293 &gEfiCapsuleReportGuid
,
294 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
298 if (!EFI_ERROR(Status
)) {
299 // Lock it per UEFI spec.
300 Status
= gBS
->LocateProtocol(&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLock
);
301 if (!EFI_ERROR(Status
)) {
302 Status
= VariableLock
->RequestToLock(VariableLock
, L
"CapsuleMax", &gEfiCapsuleReportGuid
);
303 ASSERT_EFI_ERROR(Status
);
309 Initialize CapsuleLast variables.
312 InitCapsuleLastVariable (
317 EFI_BOOT_MODE BootMode
;
318 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
321 CHAR16 CapsuleLastStr
[sizeof("Capsule####")];
323 BootMode
= GetBootModeHob();
324 if (BootMode
== BOOT_ON_FLASH_UPDATE
) {
325 Status
= gRT
->SetVariable(
327 &gEfiCapsuleReportGuid
,
328 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
332 // Do not lock it because it will be updated later.
335 // Check if OS/APP cleared L"Capsule####"
337 ZeroMem(CapsuleLastStr
, sizeof(CapsuleLastStr
));
338 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
339 Status
= gRT
->GetVariable(
341 &gEfiCapsuleReportGuid
,
346 if (!EFI_ERROR(Status
)) {
348 // L"CapsuleLast" is got, check if data is there.
350 Status
= GetVariable2 (
352 &gEfiCapsuleReportGuid
,
353 (VOID
**) &CapsuleResult
,
356 if (EFI_ERROR(Status
)) {
358 // If no data, delete L"CapsuleLast"
360 Status
= gRT
->SetVariable(
362 &gEfiCapsuleReportGuid
,
363 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
368 if (CapsuleResult
!= NULL
) {
369 FreePool (CapsuleResult
);
374 // Lock it in normal boot path per UEFI spec.
375 Status
= gBS
->LocateProtocol(&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLock
);
376 if (!EFI_ERROR(Status
)) {
377 Status
= VariableLock
->RequestToLock(VariableLock
, L
"CapsuleLast", &gEfiCapsuleReportGuid
);
378 ASSERT_EFI_ERROR(Status
);
384 Initialize capsule update variables.
387 InitCapsuleUpdateVariable (
393 CHAR16 CapsuleVarName
[30];
397 // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
398 // as early as possible which will avoid the next time boot after the capsule update
399 // will still into the capsule loop
401 StrCpyS (CapsuleVarName
, sizeof(CapsuleVarName
)/sizeof(CapsuleVarName
[0]), EFI_CAPSULE_VARIABLE_NAME
);
402 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
406 UnicodeValueToStringS (
408 sizeof (CapsuleVarName
) - ((UINTN
)TempVarName
- (UINTN
)CapsuleVarName
),
414 Status
= gRT
->SetVariable (
416 &gEfiCapsuleVendorGuid
,
417 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
421 if (EFI_ERROR (Status
)) {
423 // There is no capsule variables, quit
432 Initialize capsule relocation info variable.
435 InitCapsuleRelocationInfo (
440 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
442 CoDClearCapsuleRelocationInfo();
445 // Unlock Capsule On Disk relocation Info variable only when Capsule On Disk flag is enabled
447 if (!CoDCheckCapsuleOnDiskFlag()) {
448 Status
= gBS
->LocateProtocol (&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**) &VariableLock
);
449 if (!EFI_ERROR (Status
)) {
450 Status
= VariableLock
->RequestToLock (VariableLock
, COD_RELOCATION_INFO_VAR_NAME
, &gEfiCapsuleVendorGuid
);
451 ASSERT_EFI_ERROR (Status
);
457 Initialize capsule related variables.
460 InitCapsuleVariable (
464 InitCapsuleUpdateVariable();
465 InitCapsuleMaxVariable();
466 InitCapsuleLastVariable();
467 InitCapsuleRelocationInfo();
470 // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"
471 // to check status and delete them.