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/CapsuleLib.h>
35 #include <IndustryStandard/WindowsUxCapsule.h>
38 EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultHeader
;
39 EFI_CAPSULE_RESULT_VARIABLE_FMP CapsuleResultFmp
;
40 } CAPSULE_RESULT_VARIABLE_CACHE
;
42 #define CAPSULE_RESULT_VARIABLE_CACHE_COUNT 0x10
44 CAPSULE_RESULT_VARIABLE_CACHE
*mCapsuleResultVariableCache
;
45 UINTN mCapsuleResultVariableCacheMaxCount
;
46 UINTN mCapsuleResultVariableCacheCount
;
49 Get current capsule last variable index.
51 @return Current capsule last variable index.
52 @retval -1 No current capsule last variable.
55 GetCurrentCapsuleLastIndex (
60 CHAR16 CapsuleLastStr
[sizeof("Capsule####")];
64 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
65 Status
= gRT
->GetVariable(
67 &gEfiCapsuleReportGuid
,
72 if (EFI_ERROR(Status
)) {
75 CurrentIndex
= (UINT16
)StrHexToUintn(&CapsuleLastStr
[sizeof("Capsule") - 1]);
80 Check if this FMP capsule is processed.
82 @param[in] CapsuleHeader The capsule image header
83 @param[in] PayloadIndex FMP payload index
84 @param[in] ImageHeader FMP image header
86 @retval TRUE This FMP capsule is processed.
87 @retval FALSE This FMP capsule is not processed.
90 IsFmpCapsuleProcessed (
91 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
92 IN UINTN PayloadIndex
,
93 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
97 EFI_CAPSULE_RESULT_VARIABLE_HEADER
*CapsuleResult
;
98 EFI_CAPSULE_RESULT_VARIABLE_FMP
*CapsuleResultFmp
;
100 for (Index
= 0; Index
< mCapsuleResultVariableCacheCount
; Index
++) {
104 CapsuleResult
= &mCapsuleResultVariableCache
[Index
].CapsuleResultHeader
;
105 if (CapsuleResult
->VariableTotalSize
>= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
)) {
106 if (CompareGuid(&CapsuleResult
->CapsuleGuid
, &gEfiFmpCapsuleGuid
)) {
107 if (CapsuleResult
->VariableTotalSize
>= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
) + sizeof(CHAR16
) * 2) {
108 CapsuleResultFmp
= (EFI_CAPSULE_RESULT_VARIABLE_FMP
*)(CapsuleResult
+ 1);
109 if (CompareGuid(&CapsuleResultFmp
->UpdateImageTypeId
, &ImageHeader
->UpdateImageTypeId
) &&
110 (CapsuleResultFmp
->UpdateImageIndex
== ImageHeader
->UpdateImageIndex
) &&
111 (CapsuleResultFmp
->PayloadIndex
== PayloadIndex
) ) {
123 Write a new capsule status variable cache.
125 @param[in] CapsuleResult The capsule status variable
126 @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes
128 @retval EFI_SUCCESS The capsule status variable is cached.
129 @retval EFI_OUT_OF_RESOURCES No resource to cache the capsule status variable.
132 WriteNewCapsuleResultVariableCache (
133 IN VOID
*CapsuleResult
,
134 IN UINTN CapsuleResultSize
137 if (CapsuleResultSize
> sizeof(CAPSULE_RESULT_VARIABLE_CACHE
)) {
138 CapsuleResultSize
= sizeof(CAPSULE_RESULT_VARIABLE_CACHE
);
141 if (mCapsuleResultVariableCacheCount
== mCapsuleResultVariableCacheMaxCount
) {
142 mCapsuleResultVariableCache
= ReallocatePool(
143 mCapsuleResultVariableCacheMaxCount
* sizeof(CAPSULE_RESULT_VARIABLE_CACHE
),
144 (mCapsuleResultVariableCacheMaxCount
+ CAPSULE_RESULT_VARIABLE_CACHE_COUNT
) * sizeof(CAPSULE_RESULT_VARIABLE_CACHE
),
145 mCapsuleResultVariableCache
147 if (mCapsuleResultVariableCache
== NULL
) {
148 return EFI_OUT_OF_RESOURCES
;
150 mCapsuleResultVariableCacheMaxCount
+= CAPSULE_RESULT_VARIABLE_CACHE_COUNT
;
153 ASSERT(mCapsuleResultVariableCacheCount
< mCapsuleResultVariableCacheMaxCount
);
154 ASSERT(mCapsuleResultVariableCache
!= NULL
);
156 &mCapsuleResultVariableCache
[mCapsuleResultVariableCacheCount
],
160 mCapsuleResultVariableCacheCount
++;
166 Get a new capsule status variable index.
168 @return A new capsule status variable index.
169 @retval -1 No new capsule status variable index.
172 GetNewCapsuleResultIndex (
178 CurrentIndex
= GetCurrentCapsuleLastIndex();
179 if (CurrentIndex
>= PcdGet16(PcdCapsuleMax
)) {
183 return CurrentIndex
+ 1;
187 Write a new capsule status variable.
189 @param[in] CapsuleResult The capsule status variable
190 @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes
192 @retval EFI_SUCCESS The capsule status variable is recorded.
193 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
196 WriteNewCapsuleResultVariable (
197 IN VOID
*CapsuleResult
,
198 IN UINTN CapsuleResultSize
201 INTN CapsuleResultIndex
;
202 CHAR16 CapsuleResultStr
[sizeof("Capsule####")];
206 CapsuleResultIndex
= GetNewCapsuleResultIndex();
207 DEBUG((DEBUG_INFO
, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex
));
208 if (CapsuleResultIndex
== -1) {
209 return EFI_OUT_OF_RESOURCES
;
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
284 @retval EFI_SUCCESS The capsule status variable is recorded.
285 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
288 RecordFmpCapsuleStatusVariable (
289 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
290 IN EFI_STATUS CapsuleStatus
,
291 IN UINTN PayloadIndex
,
292 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
295 EFI_CAPSULE_RESULT_VARIABLE_HEADER
*CapsuleResultVariableHeader
;
296 EFI_CAPSULE_RESULT_VARIABLE_FMP
*CapsuleResultVariableFmp
;
298 UINT8
*CapsuleResultVariable
;
299 UINT32 CapsuleResultVariableSize
;
301 CapsuleResultVariable
= NULL
;
303 // Allocate zero CHAR16 for CapsuleFileName and CapsuleTarget.
305 CapsuleResultVariableSize
= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
) + sizeof(CHAR16
) * 2;
306 CapsuleResultVariable
= AllocateZeroPool (CapsuleResultVariableSize
);
307 if (CapsuleResultVariable
== NULL
) {
308 return EFI_OUT_OF_RESOURCES
;
310 CapsuleResultVariableHeader
= (VOID
*)CapsuleResultVariable
;
311 CapsuleResultVariableHeader
->VariableTotalSize
= CapsuleResultVariableSize
;
312 CapsuleResultVariableHeader
->Reserved
= 0;
313 CopyGuid(&CapsuleResultVariableHeader
->CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
314 ZeroMem(&CapsuleResultVariableHeader
->CapsuleProcessed
, sizeof(CapsuleResultVariableHeader
->CapsuleProcessed
));
315 gRT
->GetTime(&CapsuleResultVariableHeader
->CapsuleProcessed
, NULL
);
316 CapsuleResultVariableHeader
->CapsuleStatus
= CapsuleStatus
;
318 CapsuleResultVariableFmp
= (VOID
*)(CapsuleResultVariable
+ sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
));
319 CapsuleResultVariableFmp
->Version
= 0x1;
320 CapsuleResultVariableFmp
->PayloadIndex
= (UINT8
)PayloadIndex
;
321 CapsuleResultVariableFmp
->UpdateImageIndex
= ImageHeader
->UpdateImageIndex
;
322 CopyGuid (&CapsuleResultVariableFmp
->UpdateImageTypeId
, &ImageHeader
->UpdateImageTypeId
);
327 Status
= WriteNewCapsuleResultVariableCache(CapsuleResultVariable
, CapsuleResultVariableSize
);
329 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
330 Status
= WriteNewCapsuleResultVariable(CapsuleResultVariable
, CapsuleResultVariableSize
);
332 FreePool (CapsuleResultVariable
);
337 Initialize CapsuleMax variables.
340 InitCapsuleMaxVariable (
346 CHAR16 CapsuleMaxStr
[sizeof("Capsule####")];
347 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
351 sizeof(CapsuleMaxStr
),
353 PcdGet16(PcdCapsuleMax
)
356 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
357 Status
= gRT
->SetVariable(
359 &gEfiCapsuleReportGuid
,
360 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
364 if (!EFI_ERROR(Status
)) {
365 // Lock it per UEFI spec.
366 Status
= gBS
->LocateProtocol(&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLock
);
367 if (!EFI_ERROR(Status
)) {
368 Status
= VariableLock
->RequestToLock(VariableLock
, L
"CapsuleMax", &gEfiCapsuleReportGuid
);
369 ASSERT_EFI_ERROR(Status
);
375 Initialize CapsuleLast variables.
378 InitCapsuleLastVariable (
383 EFI_BOOT_MODE BootMode
;
384 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
387 CHAR16 CapsuleLastStr
[sizeof("Capsule####")];
389 BootMode
= GetBootModeHob();
390 if (BootMode
== BOOT_ON_FLASH_UPDATE
) {
391 Status
= gRT
->SetVariable(
393 &gEfiCapsuleReportGuid
,
394 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
398 // Do not lock it because it will be updated later.
401 // Check if OS/APP cleared L"Capsule####"
403 ZeroMem(CapsuleLastStr
, sizeof(CapsuleLastStr
));
404 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
405 Status
= gRT
->GetVariable(
407 &gEfiCapsuleReportGuid
,
412 if (!EFI_ERROR(Status
)) {
414 // L"CapsuleLast" is got, check if data is there.
416 Status
= GetVariable2 (
418 &gEfiCapsuleReportGuid
,
419 (VOID
**) &CapsuleResult
,
422 if (EFI_ERROR(Status
)) {
424 // If no data, delete L"CapsuleLast"
426 Status
= gRT
->SetVariable(
428 &gEfiCapsuleReportGuid
,
429 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
436 // Lock it in normal boot path per UEFI spec.
437 Status
= gBS
->LocateProtocol(&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLock
);
438 if (!EFI_ERROR(Status
)) {
439 Status
= VariableLock
->RequestToLock(VariableLock
, L
"CapsuleLast", &gEfiCapsuleReportGuid
);
440 ASSERT_EFI_ERROR(Status
);
446 Initialize capsule update variables.
449 InitCapsuleUpdateVariable (
455 CHAR16 CapsuleVarName
[30];
459 // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
460 // as early as possible which will avoid the next time boot after the capsule update
461 // will still into the capsule loop
463 StrCpyS (CapsuleVarName
, sizeof(CapsuleVarName
)/sizeof(CapsuleVarName
[0]), EFI_CAPSULE_VARIABLE_NAME
);
464 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
468 UnicodeValueToString (TempVarName
, 0, Index
, 0);
470 Status
= gRT
->SetVariable (
472 &gEfiCapsuleVendorGuid
,
473 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
477 if (EFI_ERROR (Status
)) {
479 // There is no capsule variables, quit
488 Initialize capsule related variables.
491 InitCapsuleVariable (
495 InitCapsuleUpdateVariable();
496 InitCapsuleMaxVariable();
497 InitCapsuleLastVariable();
499 // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"
500 // to check status and delete them.