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 UINT8 CapsuleResultVariable
[sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
)];
295 EFI_CAPSULE_RESULT_VARIABLE_HEADER
*CapsuleResultVariableHeader
;
296 EFI_CAPSULE_RESULT_VARIABLE_FMP
*CapsuleResultVariableFmp
;
299 CapsuleResultVariableHeader
= (VOID
*)&CapsuleResultVariable
[0];
300 CapsuleResultVariableHeader
->VariableTotalSize
= sizeof(CapsuleResultVariable
);
301 CopyGuid(&CapsuleResultVariableHeader
->CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
302 ZeroMem(&CapsuleResultVariableHeader
->CapsuleProcessed
, sizeof(CapsuleResultVariableHeader
->CapsuleProcessed
));
303 gRT
->GetTime(&CapsuleResultVariableHeader
->CapsuleProcessed
, NULL
);
304 CapsuleResultVariableHeader
->CapsuleStatus
= CapsuleStatus
;
306 CapsuleResultVariableFmp
= (VOID
*)&CapsuleResultVariable
[sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
)];
307 CapsuleResultVariableFmp
->Version
= 0x1;
308 CapsuleResultVariableFmp
->PayloadIndex
= (UINT8
)PayloadIndex
;
309 CapsuleResultVariableFmp
->UpdateImageIndex
= ImageHeader
->UpdateImageIndex
;
310 CopyGuid (&CapsuleResultVariableFmp
->UpdateImageTypeId
, &ImageHeader
->UpdateImageTypeId
);
315 Status
= WriteNewCapsuleResultVariableCache(&CapsuleResultVariable
, sizeof(CapsuleResultVariable
));
317 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
318 Status
= WriteNewCapsuleResultVariable(&CapsuleResultVariable
, sizeof(CapsuleResultVariable
));
324 Initialize CapsuleMax variables.
327 InitCapsuleMaxVariable (
333 CHAR16 CapsuleMaxStr
[sizeof("Capsule####")];
334 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
338 sizeof(CapsuleMaxStr
),
340 PcdGet16(PcdCapsuleMax
)
343 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
344 Status
= gRT
->SetVariable(
346 &gEfiCapsuleReportGuid
,
347 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
351 if (!EFI_ERROR(Status
)) {
352 // Lock it per UEFI spec.
353 Status
= gBS
->LocateProtocol(&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLock
);
354 if (!EFI_ERROR(Status
)) {
355 Status
= VariableLock
->RequestToLock(VariableLock
, L
"CapsuleMax", &gEfiCapsuleReportGuid
);
356 ASSERT_EFI_ERROR(Status
);
362 Initialize CapsuleLast variables.
365 InitCapsuleLastVariable (
370 EFI_BOOT_MODE BootMode
;
371 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
374 CHAR16 CapsuleLastStr
[sizeof("Capsule####")];
376 BootMode
= GetBootModeHob();
377 if (BootMode
== BOOT_ON_FLASH_UPDATE
) {
378 Status
= gRT
->SetVariable(
380 &gEfiCapsuleReportGuid
,
381 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
385 // Do not lock it because it will be updated later.
388 // Check if OS/APP cleared L"Capsule####"
390 ZeroMem(CapsuleLastStr
, sizeof(CapsuleLastStr
));
391 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
392 Status
= gRT
->GetVariable(
394 &gEfiCapsuleReportGuid
,
399 if (!EFI_ERROR(Status
)) {
401 // L"CapsuleLast" is got, check if data is there.
403 Status
= GetVariable2 (
405 &gEfiCapsuleReportGuid
,
406 (VOID
**) &CapsuleResult
,
409 if (EFI_ERROR(Status
)) {
411 // If no data, delete L"CapsuleLast"
413 Status
= gRT
->SetVariable(
415 &gEfiCapsuleReportGuid
,
416 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
423 // Lock it in normal boot path per UEFI spec.
424 Status
= gBS
->LocateProtocol(&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLock
);
425 if (!EFI_ERROR(Status
)) {
426 Status
= VariableLock
->RequestToLock(VariableLock
, L
"CapsuleLast", &gEfiCapsuleReportGuid
);
427 ASSERT_EFI_ERROR(Status
);
433 Initialize capsule update variables.
436 InitCapsuleUpdateVariable (
442 CHAR16 CapsuleVarName
[30];
446 // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
447 // as early as possible which will avoid the next time boot after the capsule update
448 // will still into the capsule loop
450 StrCpyS (CapsuleVarName
, sizeof(CapsuleVarName
)/sizeof(CapsuleVarName
[0]), EFI_CAPSULE_VARIABLE_NAME
);
451 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
455 UnicodeValueToString (TempVarName
, 0, Index
, 0);
457 Status
= gRT
->SetVariable (
459 &gEfiCapsuleVendorGuid
,
460 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
464 if (EFI_ERROR (Status
)) {
466 // There is no capsule variables, quit
475 Initialize capsule related variables.
478 InitCapsuleVariable (
482 InitCapsuleUpdateVariable();
483 InitCapsuleMaxVariable();
484 InitCapsuleLastVariable();
486 // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"
487 // to check status and delete them.