2 DXE capsule report related function.
4 Copyright (c) 2016 - 2017, 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 Get current capsule last variable index.
35 @return Current capsule last variable index.
36 @retval -1 No current capsule last variable.
39 GetCurrentCapsuleLastIndex (
44 CHAR16 CapsuleLastStr
[sizeof("Capsule####")];
48 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
49 Status
= gRT
->GetVariable(
51 &gEfiCapsuleReportGuid
,
56 if (EFI_ERROR(Status
)) {
59 CurrentIndex
= (UINT16
)StrHexToUintn(&CapsuleLastStr
[sizeof("Capsule") - 1]);
64 Get a new capsule status variable index.
66 @return A new capsule status variable index.
67 @retval 0 No new capsule status variable index. Rolling over.
70 GetNewCapsuleResultIndex (
76 CurrentIndex
= GetCurrentCapsuleLastIndex();
77 if (CurrentIndex
>= PcdGet16(PcdCapsuleMax
)) {
78 DEBUG((DEBUG_INFO
, " CapsuleResult variable Rolling Over!\n"));
82 return CurrentIndex
+ 1;
86 Write a new capsule status variable.
88 @param[in] CapsuleResult The capsule status variable
89 @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes
91 @retval EFI_SUCCESS The capsule status variable is recorded.
92 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
95 WriteNewCapsuleResultVariable (
96 IN VOID
*CapsuleResult
,
97 IN UINTN CapsuleResultSize
100 INTN CapsuleResultIndex
;
101 CHAR16 CapsuleResultStr
[sizeof("Capsule####")];
105 CapsuleResultIndex
= GetNewCapsuleResultIndex();
106 DEBUG((DEBUG_INFO
, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex
));
110 sizeof(CapsuleResultStr
),
115 Status
= gRT
->SetVariable(
117 &gEfiCapsuleReportGuid
,
118 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
122 if (!EFI_ERROR(Status
)) {
123 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
124 DEBUG((DEBUG_INFO
, "Set CapsuleLast - %s\n", CapsuleResultStr
));
125 Status
= gRT
->SetVariable(
127 &gEfiCapsuleReportGuid
,
128 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
138 Record capsule status variable and to local cache.
140 @param[in] CapsuleHeader The capsule image header
141 @param[in] CapsuleStatus The capsule process stauts
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 RecordCapsuleStatusVariable (
148 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
149 IN EFI_STATUS CapsuleStatus
152 EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable
;
155 CapsuleResultVariable
.VariableTotalSize
= sizeof(CapsuleResultVariable
);
156 CapsuleResultVariable
.Reserved
= 0;
157 CopyGuid (&CapsuleResultVariable
.CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
158 ZeroMem(&CapsuleResultVariable
.CapsuleProcessed
, sizeof(CapsuleResultVariable
.CapsuleProcessed
));
159 gRT
->GetTime(&CapsuleResultVariable
.CapsuleProcessed
, NULL
);
160 CapsuleResultVariable
.CapsuleStatus
= CapsuleStatus
;
162 Status
= EFI_SUCCESS
;
163 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
164 Status
= WriteNewCapsuleResultVariable(&CapsuleResultVariable
, sizeof(CapsuleResultVariable
));
170 Record FMP capsule status variable and to local cache.
172 @param[in] CapsuleHeader The capsule image header
173 @param[in] CapsuleStatus The capsule process stauts
174 @param[in] PayloadIndex FMP payload index
175 @param[in] ImageHeader FMP image header
176 @param[in] FmpDevicePath DevicePath associated with the FMP producer
178 @retval EFI_SUCCESS The capsule status variable is recorded.
179 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
182 RecordFmpCapsuleStatusVariable (
183 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
184 IN EFI_STATUS CapsuleStatus
,
185 IN UINTN PayloadIndex
,
186 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
,
187 IN EFI_DEVICE_PATH_PROTOCOL
*FmpDevicePath OPTIONAL
190 EFI_CAPSULE_RESULT_VARIABLE_HEADER
*CapsuleResultVariableHeader
;
191 EFI_CAPSULE_RESULT_VARIABLE_FMP
*CapsuleResultVariableFmp
;
193 UINT8
*CapsuleResultVariable
;
194 UINTN CapsuleResultVariableSize
;
195 CHAR16
*DevicePathStr
;
196 UINTN DevicePathStrSize
;
198 DevicePathStr
= NULL
;
199 if (FmpDevicePath
!= NULL
) {
200 DevicePathStr
= ConvertDevicePathToText (FmpDevicePath
, FALSE
, FALSE
);
202 if (DevicePathStr
!= NULL
) {
203 DevicePathStrSize
= StrSize(DevicePathStr
);
205 DevicePathStrSize
= sizeof(CHAR16
);
208 // Allocate zero CHAR16 for CapsuleFileName.
210 CapsuleResultVariableSize
= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
) + sizeof(CHAR16
) + DevicePathStrSize
;
211 CapsuleResultVariable
= AllocateZeroPool (CapsuleResultVariableSize
);
212 if (CapsuleResultVariable
== NULL
) {
213 return EFI_OUT_OF_RESOURCES
;
215 CapsuleResultVariableHeader
= (VOID
*)CapsuleResultVariable
;
216 CapsuleResultVariableHeader
->VariableTotalSize
= (UINT32
)CapsuleResultVariableSize
;
217 CapsuleResultVariableHeader
->Reserved
= 0;
218 CopyGuid(&CapsuleResultVariableHeader
->CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
219 ZeroMem(&CapsuleResultVariableHeader
->CapsuleProcessed
, sizeof(CapsuleResultVariableHeader
->CapsuleProcessed
));
220 gRT
->GetTime(&CapsuleResultVariableHeader
->CapsuleProcessed
, NULL
);
221 CapsuleResultVariableHeader
->CapsuleStatus
= CapsuleStatus
;
223 CapsuleResultVariableFmp
= (VOID
*)(CapsuleResultVariable
+ sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
));
224 CapsuleResultVariableFmp
->Version
= 0x1;
225 CapsuleResultVariableFmp
->PayloadIndex
= (UINT8
)PayloadIndex
;
226 CapsuleResultVariableFmp
->UpdateImageIndex
= ImageHeader
->UpdateImageIndex
;
227 CopyGuid (&CapsuleResultVariableFmp
->UpdateImageTypeId
, &ImageHeader
->UpdateImageTypeId
);
228 if (DevicePathStr
!= NULL
) {
229 CopyMem ((UINT8
*)CapsuleResultVariableFmp
+ sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
) + sizeof(CHAR16
), DevicePathStr
, DevicePathStrSize
);
230 FreePool (DevicePathStr
);
231 DevicePathStr
= NULL
;
234 Status
= EFI_SUCCESS
;
235 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
236 Status
= WriteNewCapsuleResultVariable(CapsuleResultVariable
, CapsuleResultVariableSize
);
238 FreePool (CapsuleResultVariable
);
243 Initialize CapsuleMax variables.
246 InitCapsuleMaxVariable (
252 CHAR16 CapsuleMaxStr
[sizeof("Capsule####")];
253 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
257 sizeof(CapsuleMaxStr
),
259 PcdGet16(PcdCapsuleMax
)
262 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
263 Status
= gRT
->SetVariable(
265 &gEfiCapsuleReportGuid
,
266 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
270 if (!EFI_ERROR(Status
)) {
271 // Lock it per UEFI spec.
272 Status
= gBS
->LocateProtocol(&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLock
);
273 if (!EFI_ERROR(Status
)) {
274 Status
= VariableLock
->RequestToLock(VariableLock
, L
"CapsuleMax", &gEfiCapsuleReportGuid
);
275 ASSERT_EFI_ERROR(Status
);
281 Initialize CapsuleLast variables.
284 InitCapsuleLastVariable (
289 EFI_BOOT_MODE BootMode
;
290 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
293 CHAR16 CapsuleLastStr
[sizeof("Capsule####")];
295 BootMode
= GetBootModeHob();
296 if (BootMode
== BOOT_ON_FLASH_UPDATE
) {
297 Status
= gRT
->SetVariable(
299 &gEfiCapsuleReportGuid
,
300 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
304 // Do not lock it because it will be updated later.
307 // Check if OS/APP cleared L"Capsule####"
309 ZeroMem(CapsuleLastStr
, sizeof(CapsuleLastStr
));
310 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
311 Status
= gRT
->GetVariable(
313 &gEfiCapsuleReportGuid
,
318 if (!EFI_ERROR(Status
)) {
320 // L"CapsuleLast" is got, check if data is there.
322 Status
= GetVariable2 (
324 &gEfiCapsuleReportGuid
,
325 (VOID
**) &CapsuleResult
,
328 if (EFI_ERROR(Status
)) {
330 // If no data, delete L"CapsuleLast"
332 Status
= gRT
->SetVariable(
334 &gEfiCapsuleReportGuid
,
335 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
340 if (CapsuleResult
!= NULL
) {
341 FreePool (CapsuleResult
);
346 // Lock it in normal boot path per UEFI spec.
347 Status
= gBS
->LocateProtocol(&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLock
);
348 if (!EFI_ERROR(Status
)) {
349 Status
= VariableLock
->RequestToLock(VariableLock
, L
"CapsuleLast", &gEfiCapsuleReportGuid
);
350 ASSERT_EFI_ERROR(Status
);
356 Initialize capsule update variables.
359 InitCapsuleUpdateVariable (
365 CHAR16 CapsuleVarName
[30];
369 // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
370 // as early as possible which will avoid the next time boot after the capsule update
371 // will still into the capsule loop
373 StrCpyS (CapsuleVarName
, sizeof(CapsuleVarName
)/sizeof(CapsuleVarName
[0]), EFI_CAPSULE_VARIABLE_NAME
);
374 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
378 UnicodeValueToStringS (
380 sizeof (CapsuleVarName
) - ((UINTN
)TempVarName
- (UINTN
)CapsuleVarName
),
386 Status
= gRT
->SetVariable (
388 &gEfiCapsuleVendorGuid
,
389 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
393 if (EFI_ERROR (Status
)) {
395 // There is no capsule variables, quit
404 Initialize capsule related variables.
407 InitCapsuleVariable (
411 InitCapsuleUpdateVariable();
412 InitCapsuleMaxVariable();
413 InitCapsuleLastVariable();
415 // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"
416 // to check status and delete them.