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
)) {
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 CopyGuid (&CapsuleResultVariable
.CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
260 ZeroMem(&CapsuleResultVariable
.CapsuleProcessed
, sizeof(CapsuleResultVariable
.CapsuleProcessed
));
261 gRT
->GetTime(&CapsuleResultVariable
.CapsuleProcessed
, NULL
);
262 CapsuleResultVariable
.CapsuleStatus
= CapsuleStatus
;
267 Status
= WriteNewCapsuleResultVariableCache(&CapsuleResultVariable
, sizeof(CapsuleResultVariable
));
269 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
270 Status
= WriteNewCapsuleResultVariable(&CapsuleResultVariable
, sizeof(CapsuleResultVariable
));
276 Record FMP capsule status variable and to local cache.
278 @param[in] CapsuleHeader The capsule image header
279 @param[in] CapsuleStatus The capsule process stauts
280 @param[in] PayloadIndex FMP payload index
281 @param[in] ImageHeader FMP image header
283 @retval EFI_SUCCESS The capsule status variable is recorded.
284 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
287 RecordFmpCapsuleStatusVariable (
288 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
289 IN EFI_STATUS CapsuleStatus
,
290 IN UINTN PayloadIndex
,
291 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
294 EFI_CAPSULE_RESULT_VARIABLE_HEADER
*CapsuleResultVariableHeader
;
295 EFI_CAPSULE_RESULT_VARIABLE_FMP
*CapsuleResultVariableFmp
;
297 UINT8
*CapsuleResultVariable
;
298 UINT32 CapsuleResultVariableSize
;
300 CapsuleResultVariable
= NULL
;
301 CapsuleResultVariableSize
= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
);
302 CapsuleResultVariable
= AllocatePool (CapsuleResultVariableSize
);
303 if (CapsuleResultVariable
== NULL
) {
304 return EFI_OUT_OF_RESOURCES
;
306 CapsuleResultVariableHeader
= (VOID
*)CapsuleResultVariable
;
307 CapsuleResultVariableHeader
->VariableTotalSize
= CapsuleResultVariableSize
;
308 CopyGuid(&CapsuleResultVariableHeader
->CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
309 ZeroMem(&CapsuleResultVariableHeader
->CapsuleProcessed
, sizeof(CapsuleResultVariableHeader
->CapsuleProcessed
));
310 gRT
->GetTime(&CapsuleResultVariableHeader
->CapsuleProcessed
, NULL
);
311 CapsuleResultVariableHeader
->CapsuleStatus
= CapsuleStatus
;
313 CapsuleResultVariableFmp
= (VOID
*)(CapsuleResultVariable
+ sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
));
314 CapsuleResultVariableFmp
->Version
= 0x1;
315 CapsuleResultVariableFmp
->PayloadIndex
= (UINT8
)PayloadIndex
;
316 CapsuleResultVariableFmp
->UpdateImageIndex
= ImageHeader
->UpdateImageIndex
;
317 CopyGuid (&CapsuleResultVariableFmp
->UpdateImageTypeId
, &ImageHeader
->UpdateImageTypeId
);
322 Status
= WriteNewCapsuleResultVariableCache(CapsuleResultVariable
, CapsuleResultVariableSize
);
324 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
325 Status
= WriteNewCapsuleResultVariable(CapsuleResultVariable
, CapsuleResultVariableSize
);
327 FreePool (CapsuleResultVariable
);
332 Initialize CapsuleMax variables.
335 InitCapsuleMaxVariable (
341 CHAR16 CapsuleMaxStr
[sizeof("Capsule####")];
342 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
346 sizeof(CapsuleMaxStr
),
348 PcdGet16(PcdCapsuleMax
)
351 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
352 Status
= gRT
->SetVariable(
354 &gEfiCapsuleReportGuid
,
355 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
359 if (!EFI_ERROR(Status
)) {
360 // Lock it per UEFI spec.
361 Status
= gBS
->LocateProtocol(&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLock
);
362 if (!EFI_ERROR(Status
)) {
363 Status
= VariableLock
->RequestToLock(VariableLock
, L
"CapsuleMax", &gEfiCapsuleReportGuid
);
364 ASSERT_EFI_ERROR(Status
);
370 Initialize CapsuleLast variables.
373 InitCapsuleLastVariable (
378 EFI_BOOT_MODE BootMode
;
379 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
382 CHAR16 CapsuleLastStr
[sizeof("Capsule####")];
384 BootMode
= GetBootModeHob();
385 if (BootMode
== BOOT_ON_FLASH_UPDATE
) {
386 Status
= gRT
->SetVariable(
388 &gEfiCapsuleReportGuid
,
389 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
393 // Do not lock it because it will be updated later.
396 // Check if OS/APP cleared L"Capsule####"
398 ZeroMem(CapsuleLastStr
, sizeof(CapsuleLastStr
));
399 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
400 Status
= gRT
->GetVariable(
402 &gEfiCapsuleReportGuid
,
407 if (!EFI_ERROR(Status
)) {
409 // L"CapsuleLast" is got, check if data is there.
411 Status
= GetVariable2 (
413 &gEfiCapsuleReportGuid
,
414 (VOID
**) &CapsuleResult
,
417 if (EFI_ERROR(Status
)) {
419 // If no data, delete L"CapsuleLast"
421 Status
= gRT
->SetVariable(
423 &gEfiCapsuleReportGuid
,
424 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
431 // Lock it in normal boot path per UEFI spec.
432 Status
= gBS
->LocateProtocol(&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLock
);
433 if (!EFI_ERROR(Status
)) {
434 Status
= VariableLock
->RequestToLock(VariableLock
, L
"CapsuleLast", &gEfiCapsuleReportGuid
);
435 ASSERT_EFI_ERROR(Status
);
441 Initialize capsule update variables.
444 InitCapsuleUpdateVariable (
450 CHAR16 CapsuleVarName
[30];
454 // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
455 // as early as possible which will avoid the next time boot after the capsule update
456 // will still into the capsule loop
458 StrCpyS (CapsuleVarName
, sizeof(CapsuleVarName
)/sizeof(CapsuleVarName
[0]), EFI_CAPSULE_VARIABLE_NAME
);
459 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
463 UnicodeValueToString (TempVarName
, 0, Index
, 0);
465 Status
= gRT
->SetVariable (
467 &gEfiCapsuleVendorGuid
,
468 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
472 if (EFI_ERROR (Status
)) {
474 // There is no capsule variables, quit
483 Initialize capsule related variables.
486 InitCapsuleVariable (
490 InitCapsuleUpdateVariable();
491 InitCapsuleMaxVariable();
492 InitCapsuleLastVariable();
494 // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"
495 // to check status and delete them.