2 DXE capsule report related function.
4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include <Protocol/FirmwareManagement.h>
17 #include <Protocol/VariableLock.h>
18 #include <Guid/CapsuleReport.h>
19 #include <Guid/FmpCapsule.h>
20 #include <Guid/CapsuleVendor.h>
22 #include <Library/BaseLib.h>
23 #include <Library/DebugLib.h>
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/UefiBootServicesTableLib.h>
26 #include <Library/UefiRuntimeServicesTableLib.h>
27 #include <Library/MemoryAllocationLib.h>
28 #include <Library/UefiLib.h>
29 #include <Library/PcdLib.h>
30 #include <Library/HobLib.h>
31 #include <Library/PrintLib.h>
32 #include <Library/ReportStatusCodeLib.h>
33 #include <Library/DevicePathLib.h>
34 #include <Library/CapsuleLib.h>
36 #include <IndustryStandard/WindowsUxCapsule.h>
39 EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultHeader
;
40 EFI_CAPSULE_RESULT_VARIABLE_FMP CapsuleResultFmp
;
41 } CAPSULE_RESULT_VARIABLE_CACHE
;
43 #define CAPSULE_RESULT_VARIABLE_CACHE_COUNT 0x10
45 CAPSULE_RESULT_VARIABLE_CACHE
*mCapsuleResultVariableCache
;
46 UINTN mCapsuleResultVariableCacheMaxCount
;
47 UINTN mCapsuleResultVariableCacheCount
;
50 Get current capsule last variable index.
52 @return Current capsule last variable index.
53 @retval -1 No current capsule last variable.
56 GetCurrentCapsuleLastIndex (
61 CHAR16 CapsuleLastStr
[sizeof("Capsule####")];
65 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
66 Status
= gRT
->GetVariable(
68 &gEfiCapsuleReportGuid
,
73 if (EFI_ERROR(Status
)) {
76 CurrentIndex
= (UINT16
)StrHexToUintn(&CapsuleLastStr
[sizeof("Capsule") - 1]);
81 Check if this FMP capsule is processed.
83 @param[in] CapsuleHeader The capsule image header
84 @param[in] PayloadIndex FMP payload index
85 @param[in] ImageHeader FMP image header
87 @retval TRUE This FMP capsule is processed.
88 @retval FALSE This FMP capsule is not processed.
91 IsFmpCapsuleProcessed (
92 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
93 IN UINTN PayloadIndex
,
94 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
98 EFI_CAPSULE_RESULT_VARIABLE_HEADER
*CapsuleResult
;
99 EFI_CAPSULE_RESULT_VARIABLE_FMP
*CapsuleResultFmp
;
101 for (Index
= 0; Index
< mCapsuleResultVariableCacheCount
; Index
++) {
105 CapsuleResult
= &mCapsuleResultVariableCache
[Index
].CapsuleResultHeader
;
106 if (CapsuleResult
->VariableTotalSize
>= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
)) {
107 if (CompareGuid(&CapsuleResult
->CapsuleGuid
, &gEfiFmpCapsuleGuid
)) {
108 if (CapsuleResult
->VariableTotalSize
>= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
) + sizeof(CHAR16
) * 2) {
109 CapsuleResultFmp
= (EFI_CAPSULE_RESULT_VARIABLE_FMP
*)(CapsuleResult
+ 1);
110 if (CompareGuid(&CapsuleResultFmp
->UpdateImageTypeId
, &ImageHeader
->UpdateImageTypeId
) &&
111 (CapsuleResultFmp
->UpdateImageIndex
== ImageHeader
->UpdateImageIndex
) &&
112 (CapsuleResultFmp
->PayloadIndex
== PayloadIndex
) ) {
124 Write a new capsule status variable cache.
126 @param[in] CapsuleResult The capsule status variable
127 @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes
129 @retval EFI_SUCCESS The capsule status variable is cached.
130 @retval EFI_OUT_OF_RESOURCES No resource to cache the capsule status variable.
133 WriteNewCapsuleResultVariableCache (
134 IN VOID
*CapsuleResult
,
135 IN UINTN CapsuleResultSize
138 if (CapsuleResultSize
> sizeof(CAPSULE_RESULT_VARIABLE_CACHE
)) {
139 CapsuleResultSize
= sizeof(CAPSULE_RESULT_VARIABLE_CACHE
);
142 if (mCapsuleResultVariableCacheCount
== mCapsuleResultVariableCacheMaxCount
) {
143 mCapsuleResultVariableCache
= ReallocatePool(
144 mCapsuleResultVariableCacheMaxCount
* sizeof(CAPSULE_RESULT_VARIABLE_CACHE
),
145 (mCapsuleResultVariableCacheMaxCount
+ CAPSULE_RESULT_VARIABLE_CACHE_COUNT
) * sizeof(CAPSULE_RESULT_VARIABLE_CACHE
),
146 mCapsuleResultVariableCache
148 if (mCapsuleResultVariableCache
== NULL
) {
149 return EFI_OUT_OF_RESOURCES
;
151 mCapsuleResultVariableCacheMaxCount
+= CAPSULE_RESULT_VARIABLE_CACHE_COUNT
;
154 ASSERT(mCapsuleResultVariableCacheCount
< mCapsuleResultVariableCacheMaxCount
);
155 ASSERT(mCapsuleResultVariableCache
!= NULL
);
157 &mCapsuleResultVariableCache
[mCapsuleResultVariableCacheCount
],
161 mCapsuleResultVariableCacheCount
++;
167 Get a new capsule status variable index.
169 @return A new capsule status variable index.
170 @retval 0 No new capsule status variable index. Rolling over.
173 GetNewCapsuleResultIndex (
179 CurrentIndex
= GetCurrentCapsuleLastIndex();
180 if (CurrentIndex
>= PcdGet16(PcdCapsuleMax
)) {
181 DEBUG((DEBUG_INFO
, " CapsuleResult variable Rolling Over!\n"));
185 return CurrentIndex
+ 1;
189 Write a new capsule status variable.
191 @param[in] CapsuleResult The capsule status variable
192 @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes
194 @retval EFI_SUCCESS The capsule status variable is recorded.
195 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
198 WriteNewCapsuleResultVariable (
199 IN VOID
*CapsuleResult
,
200 IN UINTN CapsuleResultSize
203 INTN CapsuleResultIndex
;
204 CHAR16 CapsuleResultStr
[sizeof("Capsule####")];
208 CapsuleResultIndex
= GetNewCapsuleResultIndex();
209 DEBUG((DEBUG_INFO
, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex
));
213 sizeof(CapsuleResultStr
),
218 Status
= gRT
->SetVariable(
220 &gEfiCapsuleReportGuid
,
221 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
225 if (!EFI_ERROR(Status
)) {
226 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
227 DEBUG((DEBUG_INFO
, "Set CapsuleLast - %s\n", CapsuleResultStr
));
228 Status
= gRT
->SetVariable(
230 &gEfiCapsuleReportGuid
,
231 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
241 Record capsule status variable and to local cache.
243 @param[in] CapsuleHeader The capsule image header
244 @param[in] CapsuleStatus The capsule process stauts
246 @retval EFI_SUCCESS The capsule status variable is recorded.
247 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
250 RecordCapsuleStatusVariable (
251 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
252 IN EFI_STATUS CapsuleStatus
255 EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable
;
258 CapsuleResultVariable
.VariableTotalSize
= sizeof(CapsuleResultVariable
);
259 CapsuleResultVariable
.Reserved
= 0;
260 CopyGuid (&CapsuleResultVariable
.CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
261 ZeroMem(&CapsuleResultVariable
.CapsuleProcessed
, sizeof(CapsuleResultVariable
.CapsuleProcessed
));
262 gRT
->GetTime(&CapsuleResultVariable
.CapsuleProcessed
, NULL
);
263 CapsuleResultVariable
.CapsuleStatus
= CapsuleStatus
;
268 Status
= WriteNewCapsuleResultVariableCache(&CapsuleResultVariable
, sizeof(CapsuleResultVariable
));
270 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
271 Status
= WriteNewCapsuleResultVariable(&CapsuleResultVariable
, sizeof(CapsuleResultVariable
));
277 Record FMP capsule status variable and to local cache.
279 @param[in] CapsuleHeader The capsule image header
280 @param[in] CapsuleStatus The capsule process stauts
281 @param[in] PayloadIndex FMP payload index
282 @param[in] ImageHeader FMP image header
283 @param[in] FmpDevicePath DevicePath associated with the FMP producer
285 @retval EFI_SUCCESS The capsule status variable is recorded.
286 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
289 RecordFmpCapsuleStatusVariable (
290 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
291 IN EFI_STATUS CapsuleStatus
,
292 IN UINTN PayloadIndex
,
293 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
,
294 IN EFI_DEVICE_PATH_PROTOCOL
*FmpDevicePath OPTIONAL
297 EFI_CAPSULE_RESULT_VARIABLE_HEADER
*CapsuleResultVariableHeader
;
298 EFI_CAPSULE_RESULT_VARIABLE_FMP
*CapsuleResultVariableFmp
;
300 UINT8
*CapsuleResultVariable
;
301 UINTN CapsuleResultVariableSize
;
302 CHAR16
*DevicePathStr
;
303 UINTN DevicePathStrSize
;
305 DevicePathStr
= NULL
;
306 if (FmpDevicePath
!= NULL
) {
307 DevicePathStr
= ConvertDevicePathToText (FmpDevicePath
, FALSE
, FALSE
);
309 if (DevicePathStr
!= NULL
) {
310 DevicePathStrSize
= StrSize(DevicePathStr
);
312 DevicePathStrSize
= sizeof(CHAR16
);
315 // Allocate zero CHAR16 for CapsuleFileName.
317 CapsuleResultVariableSize
= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
) + sizeof(CHAR16
) + DevicePathStrSize
;
318 CapsuleResultVariable
= AllocateZeroPool (CapsuleResultVariableSize
);
319 if (CapsuleResultVariable
== NULL
) {
320 return EFI_OUT_OF_RESOURCES
;
322 CapsuleResultVariableHeader
= (VOID
*)CapsuleResultVariable
;
323 CapsuleResultVariableHeader
->VariableTotalSize
= (UINT32
)CapsuleResultVariableSize
;
324 CapsuleResultVariableHeader
->Reserved
= 0;
325 CopyGuid(&CapsuleResultVariableHeader
->CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
326 ZeroMem(&CapsuleResultVariableHeader
->CapsuleProcessed
, sizeof(CapsuleResultVariableHeader
->CapsuleProcessed
));
327 gRT
->GetTime(&CapsuleResultVariableHeader
->CapsuleProcessed
, NULL
);
328 CapsuleResultVariableHeader
->CapsuleStatus
= CapsuleStatus
;
330 CapsuleResultVariableFmp
= (VOID
*)(CapsuleResultVariable
+ sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
));
331 CapsuleResultVariableFmp
->Version
= 0x1;
332 CapsuleResultVariableFmp
->PayloadIndex
= (UINT8
)PayloadIndex
;
333 CapsuleResultVariableFmp
->UpdateImageIndex
= ImageHeader
->UpdateImageIndex
;
334 CopyGuid (&CapsuleResultVariableFmp
->UpdateImageTypeId
, &ImageHeader
->UpdateImageTypeId
);
335 if (DevicePathStr
!= NULL
) {
336 CopyMem ((UINT8
*)CapsuleResultVariableFmp
+ sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
) + sizeof(CHAR16
), DevicePathStr
, DevicePathStrSize
);
337 FreePool (DevicePathStr
);
338 DevicePathStr
= NULL
;
344 Status
= WriteNewCapsuleResultVariableCache(CapsuleResultVariable
, CapsuleResultVariableSize
);
346 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
347 Status
= WriteNewCapsuleResultVariable(CapsuleResultVariable
, CapsuleResultVariableSize
);
349 FreePool (CapsuleResultVariable
);
354 Initialize CapsuleMax variables.
357 InitCapsuleMaxVariable (
363 CHAR16 CapsuleMaxStr
[sizeof("Capsule####")];
364 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
368 sizeof(CapsuleMaxStr
),
370 PcdGet16(PcdCapsuleMax
)
373 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
374 Status
= gRT
->SetVariable(
376 &gEfiCapsuleReportGuid
,
377 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
381 if (!EFI_ERROR(Status
)) {
382 // Lock it per UEFI spec.
383 Status
= gBS
->LocateProtocol(&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLock
);
384 if (!EFI_ERROR(Status
)) {
385 Status
= VariableLock
->RequestToLock(VariableLock
, L
"CapsuleMax", &gEfiCapsuleReportGuid
);
386 ASSERT_EFI_ERROR(Status
);
392 Initialize CapsuleLast variables.
395 InitCapsuleLastVariable (
400 EFI_BOOT_MODE BootMode
;
401 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
404 CHAR16 CapsuleLastStr
[sizeof("Capsule####")];
406 BootMode
= GetBootModeHob();
407 if (BootMode
== BOOT_ON_FLASH_UPDATE
) {
408 Status
= gRT
->SetVariable(
410 &gEfiCapsuleReportGuid
,
411 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
415 // Do not lock it because it will be updated later.
418 // Check if OS/APP cleared L"Capsule####"
420 ZeroMem(CapsuleLastStr
, sizeof(CapsuleLastStr
));
421 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
422 Status
= gRT
->GetVariable(
424 &gEfiCapsuleReportGuid
,
429 if (!EFI_ERROR(Status
)) {
431 // L"CapsuleLast" is got, check if data is there.
433 Status
= GetVariable2 (
435 &gEfiCapsuleReportGuid
,
436 (VOID
**) &CapsuleResult
,
439 if (EFI_ERROR(Status
)) {
441 // If no data, delete L"CapsuleLast"
443 Status
= gRT
->SetVariable(
445 &gEfiCapsuleReportGuid
,
446 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
453 // Lock it in normal boot path per UEFI spec.
454 Status
= gBS
->LocateProtocol(&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLock
);
455 if (!EFI_ERROR(Status
)) {
456 Status
= VariableLock
->RequestToLock(VariableLock
, L
"CapsuleLast", &gEfiCapsuleReportGuid
);
457 ASSERT_EFI_ERROR(Status
);
463 Initialize capsule update variables.
466 InitCapsuleUpdateVariable (
472 CHAR16 CapsuleVarName
[30];
476 // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
477 // as early as possible which will avoid the next time boot after the capsule update
478 // will still into the capsule loop
480 StrCpyS (CapsuleVarName
, sizeof(CapsuleVarName
)/sizeof(CapsuleVarName
[0]), EFI_CAPSULE_VARIABLE_NAME
);
481 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
485 UnicodeValueToString (TempVarName
, 0, Index
, 0);
487 Status
= gRT
->SetVariable (
489 &gEfiCapsuleVendorGuid
,
490 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
494 if (EFI_ERROR (Status
)) {
496 // There is no capsule variables, quit
505 Initialize capsule related variables.
508 InitCapsuleVariable (
512 InitCapsuleUpdateVariable();
513 InitCapsuleMaxVariable();
514 InitCapsuleLastVariable();
516 // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"
517 // to check status and delete them.