2 DXE capsule report related function.
4 Copyright (c) 2016 - 2017, 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 Get current capsule last variable index.
41 @return Current capsule last variable index.
42 @retval -1 No current capsule last variable.
45 GetCurrentCapsuleLastIndex (
50 CHAR16 CapsuleLastStr
[sizeof("Capsule####")];
54 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
55 Status
= gRT
->GetVariable(
57 &gEfiCapsuleReportGuid
,
62 if (EFI_ERROR(Status
)) {
65 CurrentIndex
= (UINT16
)StrHexToUintn(&CapsuleLastStr
[sizeof("Capsule") - 1]);
70 Get a new capsule status variable index.
72 @return A new capsule status variable index.
73 @retval 0 No new capsule status variable index. Rolling over.
76 GetNewCapsuleResultIndex (
82 CurrentIndex
= GetCurrentCapsuleLastIndex();
83 if (CurrentIndex
>= PcdGet16(PcdCapsuleMax
)) {
84 DEBUG((DEBUG_INFO
, " CapsuleResult variable Rolling Over!\n"));
88 return CurrentIndex
+ 1;
92 Write a new capsule status variable.
94 @param[in] CapsuleResult The capsule status variable
95 @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes
97 @retval EFI_SUCCESS The capsule status variable is recorded.
98 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
101 WriteNewCapsuleResultVariable (
102 IN VOID
*CapsuleResult
,
103 IN UINTN CapsuleResultSize
106 INTN CapsuleResultIndex
;
107 CHAR16 CapsuleResultStr
[sizeof("Capsule####")];
111 CapsuleResultIndex
= GetNewCapsuleResultIndex();
112 DEBUG((DEBUG_INFO
, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex
));
116 sizeof(CapsuleResultStr
),
121 Status
= gRT
->SetVariable(
123 &gEfiCapsuleReportGuid
,
124 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
128 if (!EFI_ERROR(Status
)) {
129 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
130 DEBUG((DEBUG_INFO
, "Set CapsuleLast - %s\n", CapsuleResultStr
));
131 Status
= gRT
->SetVariable(
133 &gEfiCapsuleReportGuid
,
134 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
144 Record capsule status variable and to local cache.
146 @param[in] CapsuleHeader The capsule image header
147 @param[in] CapsuleStatus The capsule process stauts
149 @retval EFI_SUCCESS The capsule status variable is recorded.
150 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
153 RecordCapsuleStatusVariable (
154 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
155 IN EFI_STATUS CapsuleStatus
158 EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable
;
161 CapsuleResultVariable
.VariableTotalSize
= sizeof(CapsuleResultVariable
);
162 CapsuleResultVariable
.Reserved
= 0;
163 CopyGuid (&CapsuleResultVariable
.CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
164 ZeroMem(&CapsuleResultVariable
.CapsuleProcessed
, sizeof(CapsuleResultVariable
.CapsuleProcessed
));
165 gRT
->GetTime(&CapsuleResultVariable
.CapsuleProcessed
, NULL
);
166 CapsuleResultVariable
.CapsuleStatus
= CapsuleStatus
;
168 Status
= EFI_SUCCESS
;
169 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
170 Status
= WriteNewCapsuleResultVariable(&CapsuleResultVariable
, sizeof(CapsuleResultVariable
));
176 Record FMP capsule status variable and to local cache.
178 @param[in] CapsuleHeader The capsule image header
179 @param[in] CapsuleStatus The capsule process stauts
180 @param[in] PayloadIndex FMP payload index
181 @param[in] ImageHeader FMP image header
182 @param[in] FmpDevicePath DevicePath associated with the FMP producer
184 @retval EFI_SUCCESS The capsule status variable is recorded.
185 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
188 RecordFmpCapsuleStatusVariable (
189 IN EFI_CAPSULE_HEADER
*CapsuleHeader
,
190 IN EFI_STATUS CapsuleStatus
,
191 IN UINTN PayloadIndex
,
192 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
*ImageHeader
,
193 IN EFI_DEVICE_PATH_PROTOCOL
*FmpDevicePath OPTIONAL
196 EFI_CAPSULE_RESULT_VARIABLE_HEADER
*CapsuleResultVariableHeader
;
197 EFI_CAPSULE_RESULT_VARIABLE_FMP
*CapsuleResultVariableFmp
;
199 UINT8
*CapsuleResultVariable
;
200 UINTN CapsuleResultVariableSize
;
201 CHAR16
*DevicePathStr
;
202 UINTN DevicePathStrSize
;
204 DevicePathStr
= NULL
;
205 if (FmpDevicePath
!= NULL
) {
206 DevicePathStr
= ConvertDevicePathToText (FmpDevicePath
, FALSE
, FALSE
);
208 if (DevicePathStr
!= NULL
) {
209 DevicePathStrSize
= StrSize(DevicePathStr
);
211 DevicePathStrSize
= sizeof(CHAR16
);
214 // Allocate zero CHAR16 for CapsuleFileName.
216 CapsuleResultVariableSize
= sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
) + sizeof(CHAR16
) + DevicePathStrSize
;
217 CapsuleResultVariable
= AllocateZeroPool (CapsuleResultVariableSize
);
218 if (CapsuleResultVariable
== NULL
) {
219 return EFI_OUT_OF_RESOURCES
;
221 CapsuleResultVariableHeader
= (VOID
*)CapsuleResultVariable
;
222 CapsuleResultVariableHeader
->VariableTotalSize
= (UINT32
)CapsuleResultVariableSize
;
223 CapsuleResultVariableHeader
->Reserved
= 0;
224 CopyGuid(&CapsuleResultVariableHeader
->CapsuleGuid
, &CapsuleHeader
->CapsuleGuid
);
225 ZeroMem(&CapsuleResultVariableHeader
->CapsuleProcessed
, sizeof(CapsuleResultVariableHeader
->CapsuleProcessed
));
226 gRT
->GetTime(&CapsuleResultVariableHeader
->CapsuleProcessed
, NULL
);
227 CapsuleResultVariableHeader
->CapsuleStatus
= CapsuleStatus
;
229 CapsuleResultVariableFmp
= (VOID
*)(CapsuleResultVariable
+ sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER
));
230 CapsuleResultVariableFmp
->Version
= 0x1;
231 CapsuleResultVariableFmp
->PayloadIndex
= (UINT8
)PayloadIndex
;
232 CapsuleResultVariableFmp
->UpdateImageIndex
= ImageHeader
->UpdateImageIndex
;
233 CopyGuid (&CapsuleResultVariableFmp
->UpdateImageTypeId
, &ImageHeader
->UpdateImageTypeId
);
234 if (DevicePathStr
!= NULL
) {
235 CopyMem ((UINT8
*)CapsuleResultVariableFmp
+ sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP
) + sizeof(CHAR16
), DevicePathStr
, DevicePathStrSize
);
236 FreePool (DevicePathStr
);
237 DevicePathStr
= NULL
;
240 Status
= EFI_SUCCESS
;
241 if ((CapsuleHeader
->Flags
& CAPSULE_FLAGS_PERSIST_ACROSS_RESET
) != 0) {
242 Status
= WriteNewCapsuleResultVariable(CapsuleResultVariable
, CapsuleResultVariableSize
);
244 FreePool (CapsuleResultVariable
);
249 Initialize CapsuleMax variables.
252 InitCapsuleMaxVariable (
258 CHAR16 CapsuleMaxStr
[sizeof("Capsule####")];
259 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
263 sizeof(CapsuleMaxStr
),
265 PcdGet16(PcdCapsuleMax
)
268 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
269 Status
= gRT
->SetVariable(
271 &gEfiCapsuleReportGuid
,
272 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
276 if (!EFI_ERROR(Status
)) {
277 // Lock it per UEFI spec.
278 Status
= gBS
->LocateProtocol(&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLock
);
279 if (!EFI_ERROR(Status
)) {
280 Status
= VariableLock
->RequestToLock(VariableLock
, L
"CapsuleMax", &gEfiCapsuleReportGuid
);
281 ASSERT_EFI_ERROR(Status
);
287 Initialize CapsuleLast variables.
290 InitCapsuleLastVariable (
295 EFI_BOOT_MODE BootMode
;
296 EDKII_VARIABLE_LOCK_PROTOCOL
*VariableLock
;
299 CHAR16 CapsuleLastStr
[sizeof("Capsule####")];
301 BootMode
= GetBootModeHob();
302 if (BootMode
== BOOT_ON_FLASH_UPDATE
) {
303 Status
= gRT
->SetVariable(
305 &gEfiCapsuleReportGuid
,
306 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
310 // Do not lock it because it will be updated later.
313 // Check if OS/APP cleared L"Capsule####"
315 ZeroMem(CapsuleLastStr
, sizeof(CapsuleLastStr
));
316 Size
= sizeof(L
"Capsule####") - sizeof(CHAR16
); // no zero terminator
317 Status
= gRT
->GetVariable(
319 &gEfiCapsuleReportGuid
,
324 if (!EFI_ERROR(Status
)) {
326 // L"CapsuleLast" is got, check if data is there.
328 Status
= GetVariable2 (
330 &gEfiCapsuleReportGuid
,
331 (VOID
**) &CapsuleResult
,
334 if (EFI_ERROR(Status
)) {
336 // If no data, delete L"CapsuleLast"
338 Status
= gRT
->SetVariable(
340 &gEfiCapsuleReportGuid
,
341 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
348 // Lock it in normal boot path per UEFI spec.
349 Status
= gBS
->LocateProtocol(&gEdkiiVariableLockProtocolGuid
, NULL
, (VOID
**)&VariableLock
);
350 if (!EFI_ERROR(Status
)) {
351 Status
= VariableLock
->RequestToLock(VariableLock
, L
"CapsuleLast", &gEfiCapsuleReportGuid
);
352 ASSERT_EFI_ERROR(Status
);
358 Initialize capsule update variables.
361 InitCapsuleUpdateVariable (
367 CHAR16 CapsuleVarName
[30];
371 // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...
372 // as early as possible which will avoid the next time boot after the capsule update
373 // will still into the capsule loop
375 StrCpyS (CapsuleVarName
, sizeof(CapsuleVarName
)/sizeof(CapsuleVarName
[0]), EFI_CAPSULE_VARIABLE_NAME
);
376 TempVarName
= CapsuleVarName
+ StrLen (CapsuleVarName
);
380 UnicodeValueToStringS (
382 sizeof (CapsuleVarName
) - ((UINTN
)TempVarName
- (UINTN
)CapsuleVarName
),
388 Status
= gRT
->SetVariable (
390 &gEfiCapsuleVendorGuid
,
391 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
395 if (EFI_ERROR (Status
)) {
397 // There is no capsule variables, quit
406 Initialize capsule related variables.
409 InitCapsuleVariable (
413 InitCapsuleUpdateVariable();
414 InitCapsuleMaxVariable();
415 InitCapsuleLastVariable();
417 // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"
418 // to check status and delete them.