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 -1 No new capsule status variable index.
173 GetNewCapsuleResultIndex (
179 CurrentIndex
= GetCurrentCapsuleLastIndex();
180 if (CurrentIndex
>= PcdGet16(PcdCapsuleMax
)) {
184 return CurrentIndex
+ 1;
188 Write a new capsule status variable.
190 @param[in] CapsuleResult The capsule status variable
191 @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes
193 @retval EFI_SUCCESS The capsule status variable is recorded.
194 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
197 WriteNewCapsuleResultVariable (
198 IN VOID
*CapsuleResult
,
199 IN UINTN CapsuleResultSize
202 INTN CapsuleResultIndex
;
203 CHAR16 CapsuleResultStr
[sizeof("Capsule####")];
207 CapsuleResultIndex
= GetNewCapsuleResultIndex();
208 DEBUG((DEBUG_INFO
, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex
));
209 if (CapsuleResultIndex
== -1) {
210 return EFI_OUT_OF_RESOURCES
;
214 sizeof(CapsuleResultStr
),
219 Status
= gRT
->SetVariable(
221 &gEfiCapsuleReportGuid
,
222 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
226 if (!EFI_ERROR(Status
)) {
227 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
228 DEBUG((DEBUG_INFO
, "Set CapsuleLast - %s\n", CapsuleResultStr
));
229 Status
= gRT
->SetVariable(
231 &gEfiCapsuleReportGuid
,
232 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
242 Record capsule status variable and to local cache.
244 @param[in] CapsuleHeader The capsule image header
245 @param[in] CapsuleStatus The capsule process stauts
247 @retval EFI_SUCCESS The capsule status variable is recorded.
248 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
251 RecordCapsuleStatusVariable (
252 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
253 IN EFI_STATUS CapsuleStatus
256 EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable
;
259 CapsuleResultVariable
.VariableTotalSize
= sizeof(CapsuleResultVariable
);
260 CapsuleResultVariable
.Reserved
= 0;
261 CopyGuid (&CapsuleResultVariable
.CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
262 ZeroMem(&CapsuleResultVariable
.CapsuleProcessed
, sizeof(CapsuleResultVariable
.CapsuleProcessed
));
263 gRT
->GetTime(&CapsuleResultVariable
.CapsuleProcessed
, NULL
);
264 CapsuleResultVariable
.CapsuleStatus
= CapsuleStatus
;
269 Status
= WriteNewCapsuleResultVariableCache(&CapsuleResultVariable
, sizeof(CapsuleResultVariable
));
271 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
272 Status
= WriteNewCapsuleResultVariable(&CapsuleResultVariable
, sizeof(CapsuleResultVariable
));
278 Record FMP capsule status variable and to local cache.
280 @param[in] CapsuleHeader The capsule image header
281 @param[in] CapsuleStatus The capsule process stauts
282 @param[in] PayloadIndex FMP payload index
283 @param[in] ImageHeader FMP image header
284 @param[in] FmpDevicePath DevicePath associated with the FMP producer
286 @retval EFI_SUCCESS The capsule status variable is recorded.
287 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
290 RecordFmpCapsuleStatusVariable (
291 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
292 IN EFI_STATUS CapsuleStatus
,
293 IN UINTN PayloadIndex
,
294 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
,
295 IN EFI_DEVICE_PATH_PROTOCOL
*FmpDevicePath OPTIONAL
298 EFI_CAPSULE_RESULT_VARIABLE_HEADER
*CapsuleResultVariableHeader
;
299 EFI_CAPSULE_RESULT_VARIABLE_FMP
*CapsuleResultVariableFmp
;
301 UINT8
*CapsuleResultVariable
;
302 UINTN CapsuleResultVariableSize
;
303 CHAR16
*DevicePathStr
;
304 UINTN DevicePathStrSize
;
306 DevicePathStr
= NULL
;
307 if (FmpDevicePath
!= NULL
) {
308 DevicePathStr
= ConvertDevicePathToText (FmpDevicePath
, FALSE
, FALSE
);
310 if (DevicePathStr
!= NULL
) {
311 DevicePathStrSize
= StrSize(DevicePathStr
);
313 DevicePathStrSize
= sizeof(CHAR16
);
316 // Allocate zero CHAR16 for CapsuleFileName.
318 CapsuleResultVariableSize
= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
) + sizeof(CHAR16
) + DevicePathStrSize
;
319 CapsuleResultVariable
= AllocateZeroPool (CapsuleResultVariableSize
);
320 if (CapsuleResultVariable
== NULL
) {
321 return EFI_OUT_OF_RESOURCES
;
323 CapsuleResultVariableHeader
= (VOID
*)CapsuleResultVariable
;
324 CapsuleResultVariableHeader
->VariableTotalSize
= (UINT32
)CapsuleResultVariableSize
;
325 CapsuleResultVariableHeader
->Reserved
= 0;
326 CopyGuid(&CapsuleResultVariableHeader
->CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
327 ZeroMem(&CapsuleResultVariableHeader
->CapsuleProcessed
, sizeof(CapsuleResultVariableHeader
->CapsuleProcessed
));
328 gRT
->GetTime(&CapsuleResultVariableHeader
->CapsuleProcessed
, NULL
);
329 CapsuleResultVariableHeader
->CapsuleStatus
= CapsuleStatus
;
331 CapsuleResultVariableFmp
= (VOID
*)(CapsuleResultVariable
+ sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
));
332 CapsuleResultVariableFmp
->Version
= 0x1;
333 CapsuleResultVariableFmp
->PayloadIndex
= (UINT8
)PayloadIndex
;
334 CapsuleResultVariableFmp
->UpdateImageIndex
= ImageHeader
->UpdateImageIndex
;
335 CopyGuid (&CapsuleResultVariableFmp
->UpdateImageTypeId
, &ImageHeader
->UpdateImageTypeId
);
336 if (DevicePathStr
!= NULL
) {
337 CopyMem ((UINT8
*)CapsuleResultVariableFmp
+ sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
) + sizeof(CHAR16
), DevicePathStr
, DevicePathStrSize
);
338 FreePool (DevicePathStr
);
339 DevicePathStr
= NULL
;
345 Status
= WriteNewCapsuleResultVariableCache(CapsuleResultVariable
, CapsuleResultVariableSize
);
347 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
348 Status
= WriteNewCapsuleResultVariable(CapsuleResultVariable
, CapsuleResultVariableSize
);
350 FreePool (CapsuleResultVariable
);
355 Initialize CapsuleMax variables.
358 InitCapsuleMaxVariable (
364 CHAR16 CapsuleMaxStr
[sizeof("Capsule####")];
365 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
369 sizeof(CapsuleMaxStr
),
371 PcdGet16(PcdCapsuleMax
)
374 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
375 Status
= gRT
->SetVariable(
377 &gEfiCapsuleReportGuid
,
378 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
382 if (!EFI_ERROR(Status
)) {
383 // Lock it per UEFI spec.
384 Status
= gBS
->LocateProtocol(&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLock
);
385 if (!EFI_ERROR(Status
)) {
386 Status
= VariableLock
->RequestToLock(VariableLock
, L
"CapsuleMax", &gEfiCapsuleReportGuid
);
387 ASSERT_EFI_ERROR(Status
);
393 Initialize CapsuleLast variables.
396 InitCapsuleLastVariable (
401 EFI_BOOT_MODE BootMode
;
402 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
405 CHAR16 CapsuleLastStr
[sizeof("Capsule####")];
407 BootMode
= GetBootModeHob();
408 if (BootMode
== BOOT_ON_FLASH_UPDATE
) {
409 Status
= gRT
->SetVariable(
411 &gEfiCapsuleReportGuid
,
412 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
416 // Do not lock it because it will be updated later.
419 // Check if OS/APP cleared L"Capsule####"
421 ZeroMem(CapsuleLastStr
, sizeof(CapsuleLastStr
));
422 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
423 Status
= gRT
->GetVariable(
425 &gEfiCapsuleReportGuid
,
430 if (!EFI_ERROR(Status
)) {
432 // L"CapsuleLast" is got, check if data is there.
434 Status
= GetVariable2 (
436 &gEfiCapsuleReportGuid
,
437 (VOID
**) &CapsuleResult
,
440 if (EFI_ERROR(Status
)) {
442 // If no data, delete L"CapsuleLast"
444 Status
= gRT
->SetVariable(
446 &gEfiCapsuleReportGuid
,
447 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
454 // Lock it in normal boot path per UEFI spec.
455 Status
= gBS
->LocateProtocol(&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLock
);
456 if (!EFI_ERROR(Status
)) {
457 Status
= VariableLock
->RequestToLock(VariableLock
, L
"CapsuleLast", &gEfiCapsuleReportGuid
);
458 ASSERT_EFI_ERROR(Status
);
464 Initialize capsule update variables.
467 InitCapsuleUpdateVariable (
473 CHAR16 CapsuleVarName
[30];
477 // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
478 // as early as possible which will avoid the next time boot after the capsule update
479 // will still into the capsule loop
481 StrCpyS (CapsuleVarName
, sizeof(CapsuleVarName
)/sizeof(CapsuleVarName
[0]), EFI_CAPSULE_VARIABLE_NAME
);
482 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
486 UnicodeValueToString (TempVarName
, 0, Index
, 0);
488 Status
= gRT
->SetVariable (
490 &gEfiCapsuleVendorGuid
,
491 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
495 if (EFI_ERROR (Status
)) {
497 // There is no capsule variables, quit
506 Initialize capsule related variables.
509 InitCapsuleVariable (
513 InitCapsuleUpdateVariable();
514 InitCapsuleMaxVariable();
515 InitCapsuleLastVariable();
517 // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"
518 // to check status and delete them.