]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
MdeModulePkg/DxeCapsuleLibFmp: Use new Variable Lock interface
[mirror_edk2.git] / MdeModulePkg / Library / DxeCapsuleLibFmp / DxeCapsuleReportLib.c
CommitLineData
d2a16030
JY
1/** @file\r
2 DXE capsule report related function.\r
3\r
8c8867c5 4 Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>\r
9d510e61 5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
d2a16030
JY
6\r
7**/\r
8\r
9#include <PiDxe.h>\r
10#include <Protocol/FirmwareManagement.h>\r
d2a16030
JY
11#include <Guid/CapsuleReport.h>\r
12#include <Guid/FmpCapsule.h>\r
13#include <Guid/CapsuleVendor.h>\r
14\r
15#include <Library/BaseLib.h>\r
16#include <Library/DebugLib.h>\r
17#include <Library/BaseMemoryLib.h>\r
18#include <Library/UefiBootServicesTableLib.h>\r
19#include <Library/UefiRuntimeServicesTableLib.h>\r
20#include <Library/MemoryAllocationLib.h>\r
21#include <Library/UefiLib.h>\r
22#include <Library/PcdLib.h>\r
23#include <Library/HobLib.h>\r
24#include <Library/PrintLib.h>\r
25#include <Library/ReportStatusCodeLib.h>\r
8f6db161 26#include <Library/DevicePathLib.h>\r
d2a16030 27#include <Library/CapsuleLib.h>\r
8c8867c5 28#include <Library/VariablePolicyHelperLib.h>\r
d2a16030
JY
29\r
30#include <IndustryStandard/WindowsUxCapsule.h>\r
31\r
28889a78
WX
32/**\r
33 This routine is called to clear CapsuleOnDisk Relocation Info variable.\r
34 Total Capsule On Disk length is recorded in this variable\r
35\r
36 @retval EFI_SUCCESS Capsule On Disk flags are cleared\r
37\r
38**/\r
39EFI_STATUS\r
40CoDClearCapsuleRelocationInfo(\r
41 VOID\r
42 );\r
43\r
d2a16030
JY
44/**\r
45 Get current capsule last variable index.\r
46\r
47 @return Current capsule last variable index.\r
48 @retval -1 No current capsule last variable.\r
49**/\r
50INTN\r
51GetCurrentCapsuleLastIndex (\r
52 VOID\r
53 )\r
54{\r
55 UINTN Size;\r
56 CHAR16 CapsuleLastStr[sizeof("Capsule####")];\r
57 EFI_STATUS Status;\r
58 UINT16 CurrentIndex;\r
59\r
60 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
61 Status = gRT->GetVariable(\r
62 L"CapsuleLast",\r
63 &gEfiCapsuleReportGuid,\r
64 NULL,\r
65 &Size,\r
66 CapsuleLastStr\r
67 );\r
68 if (EFI_ERROR(Status)) {\r
69 return -1;\r
70 }\r
71 CurrentIndex = (UINT16)StrHexToUintn(&CapsuleLastStr[sizeof("Capsule") - 1]);\r
72 return CurrentIndex;\r
73}\r
74\r
d2a16030
JY
75/**\r
76 Get a new capsule status variable index.\r
77\r
78 @return A new capsule status variable index.\r
777034ce 79 @retval 0 No new capsule status variable index. Rolling over.\r
d2a16030
JY
80**/\r
81INTN\r
82GetNewCapsuleResultIndex (\r
83 VOID\r
84 )\r
85{\r
86 INTN CurrentIndex;\r
87\r
88 CurrentIndex = GetCurrentCapsuleLastIndex();\r
89 if (CurrentIndex >= PcdGet16(PcdCapsuleMax)) {\r
777034ce
JY
90 DEBUG((DEBUG_INFO, " CapsuleResult variable Rolling Over!\n"));\r
91 return 0;\r
d2a16030
JY
92 }\r
93\r
94 return CurrentIndex + 1;\r
95}\r
96\r
8c8867c5
YJ
97/**\r
98 Lock Variable by variable policy.\r
99\r
100 @param[in] VariableGuid The Guid of the variable to be locked\r
101 @param[in] VariableName The name of the variable to be locked\r
102 @param[in] VariablePolicy The pointer of variable lock policy\r
103**/\r
104VOID\r
105LockVariable (\r
106 IN CONST EFI_GUID VariableGuid,\r
107 IN CHAR16 *VariableName,\r
108 IN EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy\r
109 )\r
110{\r
111 EFI_STATUS Status;\r
112\r
113 // Set the policies to protect the target variables\r
114 Status = RegisterBasicVariablePolicy (VariablePolicy,\r
115 &VariableGuid,\r
116 VariableName,\r
117 VARIABLE_POLICY_NO_MIN_SIZE,\r
118 VARIABLE_POLICY_NO_MAX_SIZE,\r
119 VARIABLE_POLICY_NO_MUST_ATTR,\r
120 VARIABLE_POLICY_NO_CANT_ATTR,\r
121 VARIABLE_POLICY_TYPE_LOCK_NOW);\r
122 if (EFI_ERROR (Status)) {\r
123 DEBUG ((DEBUG_ERROR, "DxeCapsuleLibFmp: Failed to lock variable %g %s. Status = %r\n",\r
124 &VariableGuid,\r
125 VariableName,\r
126 Status));\r
127 ASSERT_EFI_ERROR (Status);\r
128 }\r
129}\r
130\r
d2a16030
JY
131/**\r
132 Write a new capsule status variable.\r
133\r
134 @param[in] CapsuleResult The capsule status variable\r
135 @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes\r
136\r
137 @retval EFI_SUCCESS The capsule status variable is recorded.\r
138 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
139**/\r
140EFI_STATUS\r
141WriteNewCapsuleResultVariable (\r
142 IN VOID *CapsuleResult,\r
143 IN UINTN CapsuleResultSize\r
144 )\r
145{\r
146 INTN CapsuleResultIndex;\r
147 CHAR16 CapsuleResultStr[sizeof("Capsule####")];\r
148 UINTN Size;\r
149 EFI_STATUS Status;\r
150\r
151 CapsuleResultIndex = GetNewCapsuleResultIndex();\r
152 DEBUG((DEBUG_INFO, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex));\r
777034ce 153\r
d2a16030
JY
154 UnicodeSPrint(\r
155 CapsuleResultStr,\r
156 sizeof(CapsuleResultStr),\r
157 L"Capsule%04x",\r
158 CapsuleResultIndex\r
159 );\r
160\r
161 Status = gRT->SetVariable(\r
162 CapsuleResultStr,\r
163 &gEfiCapsuleReportGuid,\r
164 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
165 CapsuleResultSize,\r
166 CapsuleResult\r
167 );\r
168 if (!EFI_ERROR(Status)) {\r
169 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
170 DEBUG((DEBUG_INFO, "Set CapsuleLast - %s\n", CapsuleResultStr));\r
171 Status = gRT->SetVariable(\r
172 L"CapsuleLast",\r
173 &gEfiCapsuleReportGuid,\r
174 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
175 Size,\r
176 CapsuleResultStr\r
177 );\r
178 }\r
179\r
180 return Status;\r
181}\r
182\r
183/**\r
184 Record capsule status variable and to local cache.\r
185\r
186 @param[in] CapsuleHeader The capsule image header\r
187 @param[in] CapsuleStatus The capsule process stauts\r
188\r
189 @retval EFI_SUCCESS The capsule status variable is recorded.\r
190 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
191**/\r
192EFI_STATUS\r
193RecordCapsuleStatusVariable (\r
194 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
195 IN EFI_STATUS CapsuleStatus\r
196 )\r
197{\r
198 EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable;\r
199 EFI_STATUS Status;\r
200\r
201 CapsuleResultVariable.VariableTotalSize = sizeof(CapsuleResultVariable);\r
d8487a34 202 CapsuleResultVariable.Reserved = 0;\r
d2a16030
JY
203 CopyGuid (&CapsuleResultVariable.CapsuleGuid, &CapsuleHeader->CapsuleGuid);\r
204 ZeroMem(&CapsuleResultVariable.CapsuleProcessed, sizeof(CapsuleResultVariable.CapsuleProcessed));\r
205 gRT->GetTime(&CapsuleResultVariable.CapsuleProcessed, NULL);\r
206 CapsuleResultVariable.CapsuleStatus = CapsuleStatus;\r
207\r
3f31ea1b 208 Status = EFI_SUCCESS;\r
d2a16030
JY
209 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
210 Status = WriteNewCapsuleResultVariable(&CapsuleResultVariable, sizeof(CapsuleResultVariable));\r
211 }\r
212 return Status;\r
213}\r
214\r
215/**\r
216 Record FMP capsule status variable and to local cache.\r
217\r
218 @param[in] CapsuleHeader The capsule image header\r
219 @param[in] CapsuleStatus The capsule process stauts\r
220 @param[in] PayloadIndex FMP payload index\r
221 @param[in] ImageHeader FMP image header\r
8f6db161 222 @param[in] FmpDevicePath DevicePath associated with the FMP producer\r
28889a78 223 @param[in] CapFileName Capsule file name\r
d2a16030
JY
224\r
225 @retval EFI_SUCCESS The capsule status variable is recorded.\r
226 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
227**/\r
228EFI_STATUS\r
229RecordFmpCapsuleStatusVariable (\r
230 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
231 IN EFI_STATUS CapsuleStatus,\r
232 IN UINTN PayloadIndex,\r
8f6db161 233 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,\r
28889a78
WX
234 IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath, OPTIONAL\r
235 IN CHAR16 *CapFileName OPTIONAL\r
d2a16030
JY
236 )\r
237{\r
d2a16030
JY
238 EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResultVariableHeader;\r
239 EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultVariableFmp;\r
240 EFI_STATUS Status;\r
b857bf48 241 UINT8 *CapsuleResultVariable;\r
8f6db161
JY
242 UINTN CapsuleResultVariableSize;\r
243 CHAR16 *DevicePathStr;\r
244 UINTN DevicePathStrSize;\r
28889a78
WX
245 UINTN CapFileNameSize;\r
246\r
247 DevicePathStr = NULL;\r
248 CapFileNameSize = sizeof(CHAR16);\r
d2a16030 249\r
8f6db161
JY
250 if (FmpDevicePath != NULL) {\r
251 DevicePathStr = ConvertDevicePathToText (FmpDevicePath, FALSE, FALSE);\r
252 }\r
253 if (DevicePathStr != NULL) {\r
254 DevicePathStrSize = StrSize(DevicePathStr);\r
255 } else {\r
256 DevicePathStrSize = sizeof(CHAR16);\r
257 }\r
28889a78
WX
258\r
259 if (CapFileName != NULL) {\r
260 CapFileNameSize = StrSize(CapFileName);\r
261 }\r
262\r
d8487a34 263 //\r
28889a78 264 // Allocate room for CapsuleFileName.\r
d8487a34 265 //\r
28889a78
WX
266 CapsuleResultVariableSize = sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapFileNameSize + DevicePathStrSize;\r
267\r
d8487a34 268 CapsuleResultVariable = AllocateZeroPool (CapsuleResultVariableSize);\r
b857bf48
DB
269 if (CapsuleResultVariable == NULL) {\r
270 return EFI_OUT_OF_RESOURCES;\r
271 }\r
272 CapsuleResultVariableHeader = (VOID *)CapsuleResultVariable;\r
8f6db161 273 CapsuleResultVariableHeader->VariableTotalSize = (UINT32)CapsuleResultVariableSize;\r
d8487a34 274 CapsuleResultVariableHeader->Reserved = 0;\r
d2a16030
JY
275 CopyGuid(&CapsuleResultVariableHeader->CapsuleGuid, &CapsuleHeader->CapsuleGuid);\r
276 ZeroMem(&CapsuleResultVariableHeader->CapsuleProcessed, sizeof(CapsuleResultVariableHeader->CapsuleProcessed));\r
277 gRT->GetTime(&CapsuleResultVariableHeader->CapsuleProcessed, NULL);\r
278 CapsuleResultVariableHeader->CapsuleStatus = CapsuleStatus;\r
279\r
b857bf48 280 CapsuleResultVariableFmp = (VOID *)(CapsuleResultVariable + sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER));\r
d2a16030
JY
281 CapsuleResultVariableFmp->Version = 0x1;\r
282 CapsuleResultVariableFmp->PayloadIndex = (UINT8)PayloadIndex;\r
283 CapsuleResultVariableFmp->UpdateImageIndex = ImageHeader->UpdateImageIndex;\r
284 CopyGuid (&CapsuleResultVariableFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId);\r
28889a78
WX
285\r
286 if (CapFileName != NULL) {\r
287 CopyMem((UINT8 *)CapsuleResultVariableFmp + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP), CapFileName, CapFileNameSize);\r
288 }\r
289\r
8f6db161 290 if (DevicePathStr != NULL) {\r
28889a78 291 CopyMem ((UINT8 *)CapsuleResultVariableFmp + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapFileNameSize, DevicePathStr, DevicePathStrSize);\r
8f6db161
JY
292 FreePool (DevicePathStr);\r
293 DevicePathStr = NULL;\r
294 }\r
d2a16030 295\r
3f31ea1b 296 Status = EFI_SUCCESS;\r
d2a16030 297 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
b857bf48 298 Status = WriteNewCapsuleResultVariable(CapsuleResultVariable, CapsuleResultVariableSize);\r
d2a16030 299 }\r
b857bf48 300 FreePool (CapsuleResultVariable);\r
d2a16030
JY
301 return Status;\r
302}\r
303\r
304/**\r
305 Initialize CapsuleMax variables.\r
8c8867c5
YJ
306\r
307 @param[in] VariablePolicy The pointer of variable lock policy\r
d2a16030
JY
308**/\r
309VOID\r
310InitCapsuleMaxVariable (\r
8c8867c5 311 EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy\r
d2a16030
JY
312 )\r
313{\r
314 EFI_STATUS Status;\r
315 UINTN Size;\r
316 CHAR16 CapsuleMaxStr[sizeof("Capsule####")];\r
d2a16030
JY
317\r
318 UnicodeSPrint(\r
319 CapsuleMaxStr,\r
320 sizeof(CapsuleMaxStr),\r
321 L"Capsule%04x",\r
322 PcdGet16(PcdCapsuleMax)\r
323 );\r
324\r
325 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
326 Status = gRT->SetVariable(\r
327 L"CapsuleMax",\r
328 &gEfiCapsuleReportGuid,\r
329 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
330 Size,\r
331 CapsuleMaxStr\r
332 );\r
333 if (!EFI_ERROR(Status)) {\r
334 // Lock it per UEFI spec.\r
8c8867c5 335 LockVariable (gEfiCapsuleReportGuid, L"CapsuleMax", VariablePolicy);\r
d2a16030
JY
336 }\r
337}\r
338\r
339/**\r
340 Initialize CapsuleLast variables.\r
8c8867c5
YJ
341\r
342 @param[in] VariablePolicy The pointer of variable lock policy\r
d2a16030
JY
343**/\r
344VOID\r
345InitCapsuleLastVariable (\r
8c8867c5 346 EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy\r
d2a16030
JY
347 )\r
348{\r
349 EFI_STATUS Status;\r
350 EFI_BOOT_MODE BootMode;\r
d2a16030
JY
351 VOID *CapsuleResult;\r
352 UINTN Size;\r
353 CHAR16 CapsuleLastStr[sizeof("Capsule####")];\r
354\r
355 BootMode = GetBootModeHob();\r
356 if (BootMode == BOOT_ON_FLASH_UPDATE) {\r
357 Status = gRT->SetVariable(\r
358 L"CapsuleLast",\r
359 &gEfiCapsuleReportGuid,\r
360 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
361 0,\r
362 NULL\r
363 );\r
364 // Do not lock it because it will be updated later.\r
365 } else {\r
366 //\r
367 // Check if OS/APP cleared L"Capsule####"\r
368 //\r
369 ZeroMem(CapsuleLastStr, sizeof(CapsuleLastStr));\r
370 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
371 Status = gRT->GetVariable(\r
372 L"CapsuleLast",\r
373 &gEfiCapsuleReportGuid,\r
374 NULL,\r
375 &Size,\r
376 CapsuleLastStr\r
377 );\r
378 if (!EFI_ERROR(Status)) {\r
379 //\r
380 // L"CapsuleLast" is got, check if data is there.\r
381 //\r
382 Status = GetVariable2 (\r
383 CapsuleLastStr,\r
384 &gEfiCapsuleReportGuid,\r
385 (VOID **) &CapsuleResult,\r
386 NULL\r
387 );\r
388 if (EFI_ERROR(Status)) {\r
389 //\r
390 // If no data, delete L"CapsuleLast"\r
391 //\r
392 Status = gRT->SetVariable(\r
393 L"CapsuleLast",\r
394 &gEfiCapsuleReportGuid,\r
395 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
396 0,\r
397 NULL\r
398 );\r
dd4eaf15
HW
399 } else {\r
400 if (CapsuleResult != NULL) {\r
401 FreePool (CapsuleResult);\r
402 }\r
d2a16030
JY
403 }\r
404 }\r
405\r
406 // Lock it in normal boot path per UEFI spec.\r
8c8867c5 407 LockVariable (gEfiCapsuleReportGuid, L"CapsuleLast", VariablePolicy);\r
d2a16030
JY
408 }\r
409}\r
410\r
411/**\r
412 Initialize capsule update variables.\r
413**/\r
414VOID\r
415InitCapsuleUpdateVariable (\r
416 VOID\r
417 )\r
418{\r
419 EFI_STATUS Status;\r
420 UINTN Index;\r
421 CHAR16 CapsuleVarName[30];\r
422 CHAR16 *TempVarName;\r
423\r
424 //\r
425 // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...\r
426 // as early as possible which will avoid the next time boot after the capsule update\r
427 // will still into the capsule loop\r
428 //\r
429 StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), EFI_CAPSULE_VARIABLE_NAME);\r
430 TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
431 Index = 0;\r
432 while (TRUE) {\r
433 if (Index > 0) {\r
9f4048f7
HW
434 UnicodeValueToStringS (\r
435 TempVarName,\r
436 sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),\r
437 0,\r
438 Index,\r
439 0\r
440 );\r
d2a16030
JY
441 }\r
442 Status = gRT->SetVariable (\r
443 CapsuleVarName,\r
444 &gEfiCapsuleVendorGuid,\r
445 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
446 0,\r
447 (VOID *)NULL\r
448 );\r
449 if (EFI_ERROR (Status)) {\r
450 //\r
451 // There is no capsule variables, quit\r
452 //\r
453 break;\r
454 }\r
455 Index++;\r
456 }\r
457}\r
458\r
28889a78
WX
459/**\r
460 Initialize capsule relocation info variable.\r
8c8867c5
YJ
461\r
462 @param[in] VariablePolicy The pointer of variable lock policy\r
28889a78
WX
463**/\r
464VOID\r
465InitCapsuleRelocationInfo (\r
8c8867c5 466 EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy\r
28889a78
WX
467 )\r
468{\r
28889a78
WX
469 CoDClearCapsuleRelocationInfo();\r
470\r
471 //\r
472 // Unlock Capsule On Disk relocation Info variable only when Capsule On Disk flag is enabled\r
473 //\r
474 if (!CoDCheckCapsuleOnDiskFlag()) {\r
8c8867c5 475 LockVariable (gEfiCapsuleVendorGuid, COD_RELOCATION_INFO_VAR_NAME, VariablePolicy);\r
28889a78
WX
476 }\r
477}\r
478\r
d2a16030
JY
479/**\r
480 Initialize capsule related variables.\r
481**/\r
482VOID\r
483InitCapsuleVariable (\r
484 VOID\r
485 )\r
486{\r
8c8867c5
YJ
487 EFI_STATUS Status;\r
488 EDKII_VARIABLE_POLICY_PROTOCOL *VariablePolicy;\r
489\r
490 // Locate the VariablePolicy protocol\r
491 Status = gBS->LocateProtocol (&gEdkiiVariablePolicyProtocolGuid, NULL, (VOID**)&VariablePolicy);\r
492 if (EFI_ERROR (Status)) {\r
493 DEBUG ((DEBUG_ERROR, "DxeCapsuleReportLib %a - Could not locate VariablePolicy protocol! %r\n", __FUNCTION__, Status));\r
494 ASSERT_EFI_ERROR (Status);\r
495 }\r
d2a16030 496 InitCapsuleUpdateVariable();\r
8c8867c5
YJ
497 InitCapsuleMaxVariable (VariablePolicy);\r
498 InitCapsuleLastVariable (VariablePolicy);\r
499 InitCapsuleRelocationInfo (VariablePolicy);\r
28889a78 500\r
d2a16030
JY
501 //\r
502 // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"\r
503 // to check status and delete them.\r
504 //\r
505}\r