]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleReportLib.c
MdeModulePkg: Add Capsule On Disk APIs into CapsuleLib.
[mirror_edk2.git] / MdeModulePkg / Library / DxeCapsuleLibFmp / DxeCapsuleReportLib.c
CommitLineData
d2a16030
JY
1/** @file\r
2 DXE capsule report related function.\r
3\r
28889a78 4 Copyright (c) 2016 - 2019, 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
11#include <Protocol/VariableLock.h>\r
12#include <Guid/CapsuleReport.h>\r
13#include <Guid/FmpCapsule.h>\r
14#include <Guid/CapsuleVendor.h>\r
15\r
16#include <Library/BaseLib.h>\r
17#include <Library/DebugLib.h>\r
18#include <Library/BaseMemoryLib.h>\r
19#include <Library/UefiBootServicesTableLib.h>\r
20#include <Library/UefiRuntimeServicesTableLib.h>\r
21#include <Library/MemoryAllocationLib.h>\r
22#include <Library/UefiLib.h>\r
23#include <Library/PcdLib.h>\r
24#include <Library/HobLib.h>\r
25#include <Library/PrintLib.h>\r
26#include <Library/ReportStatusCodeLib.h>\r
8f6db161 27#include <Library/DevicePathLib.h>\r
d2a16030
JY
28#include <Library/CapsuleLib.h>\r
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
97/**\r
98 Write a new capsule status variable.\r
99\r
100 @param[in] CapsuleResult The capsule status variable\r
101 @param[in] CapsuleResultSize The size of the capsule stauts variable in bytes\r
102\r
103 @retval EFI_SUCCESS The capsule status variable is recorded.\r
104 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
105**/\r
106EFI_STATUS\r
107WriteNewCapsuleResultVariable (\r
108 IN VOID *CapsuleResult,\r
109 IN UINTN CapsuleResultSize\r
110 )\r
111{\r
112 INTN CapsuleResultIndex;\r
113 CHAR16 CapsuleResultStr[sizeof("Capsule####")];\r
114 UINTN Size;\r
115 EFI_STATUS Status;\r
116\r
117 CapsuleResultIndex = GetNewCapsuleResultIndex();\r
118 DEBUG((DEBUG_INFO, "New CapsuleResultIndex - 0x%x\n", CapsuleResultIndex));\r
777034ce 119\r
d2a16030
JY
120 UnicodeSPrint(\r
121 CapsuleResultStr,\r
122 sizeof(CapsuleResultStr),\r
123 L"Capsule%04x",\r
124 CapsuleResultIndex\r
125 );\r
126\r
127 Status = gRT->SetVariable(\r
128 CapsuleResultStr,\r
129 &gEfiCapsuleReportGuid,\r
130 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
131 CapsuleResultSize,\r
132 CapsuleResult\r
133 );\r
134 if (!EFI_ERROR(Status)) {\r
135 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
136 DEBUG((DEBUG_INFO, "Set CapsuleLast - %s\n", CapsuleResultStr));\r
137 Status = gRT->SetVariable(\r
138 L"CapsuleLast",\r
139 &gEfiCapsuleReportGuid,\r
140 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
141 Size,\r
142 CapsuleResultStr\r
143 );\r
144 }\r
145\r
146 return Status;\r
147}\r
148\r
149/**\r
150 Record capsule status variable and to local cache.\r
151\r
152 @param[in] CapsuleHeader The capsule image header\r
153 @param[in] CapsuleStatus The capsule process stauts\r
154\r
155 @retval EFI_SUCCESS The capsule status variable is recorded.\r
156 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
157**/\r
158EFI_STATUS\r
159RecordCapsuleStatusVariable (\r
160 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
161 IN EFI_STATUS CapsuleStatus\r
162 )\r
163{\r
164 EFI_CAPSULE_RESULT_VARIABLE_HEADER CapsuleResultVariable;\r
165 EFI_STATUS Status;\r
166\r
167 CapsuleResultVariable.VariableTotalSize = sizeof(CapsuleResultVariable);\r
d8487a34 168 CapsuleResultVariable.Reserved = 0;\r
d2a16030
JY
169 CopyGuid (&CapsuleResultVariable.CapsuleGuid, &CapsuleHeader->CapsuleGuid);\r
170 ZeroMem(&CapsuleResultVariable.CapsuleProcessed, sizeof(CapsuleResultVariable.CapsuleProcessed));\r
171 gRT->GetTime(&CapsuleResultVariable.CapsuleProcessed, NULL);\r
172 CapsuleResultVariable.CapsuleStatus = CapsuleStatus;\r
173\r
3f31ea1b 174 Status = EFI_SUCCESS;\r
d2a16030
JY
175 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
176 Status = WriteNewCapsuleResultVariable(&CapsuleResultVariable, sizeof(CapsuleResultVariable));\r
177 }\r
178 return Status;\r
179}\r
180\r
181/**\r
182 Record FMP capsule status variable and to local cache.\r
183\r
184 @param[in] CapsuleHeader The capsule image header\r
185 @param[in] CapsuleStatus The capsule process stauts\r
186 @param[in] PayloadIndex FMP payload index\r
187 @param[in] ImageHeader FMP image header\r
8f6db161 188 @param[in] FmpDevicePath DevicePath associated with the FMP producer\r
28889a78 189 @param[in] CapFileName Capsule file name\r
d2a16030
JY
190\r
191 @retval EFI_SUCCESS The capsule status variable is recorded.\r
192 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.\r
193**/\r
194EFI_STATUS\r
195RecordFmpCapsuleStatusVariable (\r
196 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
197 IN EFI_STATUS CapsuleStatus,\r
198 IN UINTN PayloadIndex,\r
8f6db161 199 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,\r
28889a78
WX
200 IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath, OPTIONAL\r
201 IN CHAR16 *CapFileName OPTIONAL\r
d2a16030
JY
202 )\r
203{\r
d2a16030
JY
204 EFI_CAPSULE_RESULT_VARIABLE_HEADER *CapsuleResultVariableHeader;\r
205 EFI_CAPSULE_RESULT_VARIABLE_FMP *CapsuleResultVariableFmp;\r
206 EFI_STATUS Status;\r
b857bf48 207 UINT8 *CapsuleResultVariable;\r
8f6db161
JY
208 UINTN CapsuleResultVariableSize;\r
209 CHAR16 *DevicePathStr;\r
210 UINTN DevicePathStrSize;\r
28889a78
WX
211 UINTN CapFileNameSize;\r
212\r
213 DevicePathStr = NULL;\r
214 CapFileNameSize = sizeof(CHAR16);\r
d2a16030 215\r
8f6db161
JY
216 if (FmpDevicePath != NULL) {\r
217 DevicePathStr = ConvertDevicePathToText (FmpDevicePath, FALSE, FALSE);\r
218 }\r
219 if (DevicePathStr != NULL) {\r
220 DevicePathStrSize = StrSize(DevicePathStr);\r
221 } else {\r
222 DevicePathStrSize = sizeof(CHAR16);\r
223 }\r
28889a78
WX
224\r
225 if (CapFileName != NULL) {\r
226 CapFileNameSize = StrSize(CapFileName);\r
227 }\r
228\r
d8487a34 229 //\r
28889a78 230 // Allocate room for CapsuleFileName.\r
d8487a34 231 //\r
28889a78
WX
232 CapsuleResultVariableSize = sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER) + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapFileNameSize + DevicePathStrSize;\r
233\r
d8487a34 234 CapsuleResultVariable = AllocateZeroPool (CapsuleResultVariableSize);\r
b857bf48
DB
235 if (CapsuleResultVariable == NULL) {\r
236 return EFI_OUT_OF_RESOURCES;\r
237 }\r
238 CapsuleResultVariableHeader = (VOID *)CapsuleResultVariable;\r
8f6db161 239 CapsuleResultVariableHeader->VariableTotalSize = (UINT32)CapsuleResultVariableSize;\r
d8487a34 240 CapsuleResultVariableHeader->Reserved = 0;\r
d2a16030
JY
241 CopyGuid(&CapsuleResultVariableHeader->CapsuleGuid, &CapsuleHeader->CapsuleGuid);\r
242 ZeroMem(&CapsuleResultVariableHeader->CapsuleProcessed, sizeof(CapsuleResultVariableHeader->CapsuleProcessed));\r
243 gRT->GetTime(&CapsuleResultVariableHeader->CapsuleProcessed, NULL);\r
244 CapsuleResultVariableHeader->CapsuleStatus = CapsuleStatus;\r
245\r
b857bf48 246 CapsuleResultVariableFmp = (VOID *)(CapsuleResultVariable + sizeof(EFI_CAPSULE_RESULT_VARIABLE_HEADER));\r
d2a16030
JY
247 CapsuleResultVariableFmp->Version = 0x1;\r
248 CapsuleResultVariableFmp->PayloadIndex = (UINT8)PayloadIndex;\r
249 CapsuleResultVariableFmp->UpdateImageIndex = ImageHeader->UpdateImageIndex;\r
250 CopyGuid (&CapsuleResultVariableFmp->UpdateImageTypeId, &ImageHeader->UpdateImageTypeId);\r
28889a78
WX
251\r
252 if (CapFileName != NULL) {\r
253 CopyMem((UINT8 *)CapsuleResultVariableFmp + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP), CapFileName, CapFileNameSize);\r
254 }\r
255\r
8f6db161 256 if (DevicePathStr != NULL) {\r
28889a78 257 CopyMem ((UINT8 *)CapsuleResultVariableFmp + sizeof(EFI_CAPSULE_RESULT_VARIABLE_FMP) + CapFileNameSize, DevicePathStr, DevicePathStrSize);\r
8f6db161
JY
258 FreePool (DevicePathStr);\r
259 DevicePathStr = NULL;\r
260 }\r
d2a16030 261\r
3f31ea1b 262 Status = EFI_SUCCESS;\r
d2a16030 263 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
b857bf48 264 Status = WriteNewCapsuleResultVariable(CapsuleResultVariable, CapsuleResultVariableSize);\r
d2a16030 265 }\r
b857bf48 266 FreePool (CapsuleResultVariable);\r
d2a16030
JY
267 return Status;\r
268}\r
269\r
270/**\r
271 Initialize CapsuleMax variables.\r
272**/\r
273VOID\r
274InitCapsuleMaxVariable (\r
275 VOID\r
276 )\r
277{\r
278 EFI_STATUS Status;\r
279 UINTN Size;\r
280 CHAR16 CapsuleMaxStr[sizeof("Capsule####")];\r
281 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
282\r
283 UnicodeSPrint(\r
284 CapsuleMaxStr,\r
285 sizeof(CapsuleMaxStr),\r
286 L"Capsule%04x",\r
287 PcdGet16(PcdCapsuleMax)\r
288 );\r
289\r
290 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
291 Status = gRT->SetVariable(\r
292 L"CapsuleMax",\r
293 &gEfiCapsuleReportGuid,\r
294 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
295 Size,\r
296 CapsuleMaxStr\r
297 );\r
298 if (!EFI_ERROR(Status)) {\r
299 // Lock it per UEFI spec.\r
300 Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);\r
301 if (!EFI_ERROR(Status)) {\r
302 Status = VariableLock->RequestToLock(VariableLock, L"CapsuleMax", &gEfiCapsuleReportGuid);\r
303 ASSERT_EFI_ERROR(Status);\r
304 }\r
305 }\r
306}\r
307\r
308/**\r
309 Initialize CapsuleLast variables.\r
310**/\r
311VOID\r
312InitCapsuleLastVariable (\r
313 VOID\r
314 )\r
315{\r
316 EFI_STATUS Status;\r
317 EFI_BOOT_MODE BootMode;\r
318 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
319 VOID *CapsuleResult;\r
320 UINTN Size;\r
321 CHAR16 CapsuleLastStr[sizeof("Capsule####")];\r
322\r
323 BootMode = GetBootModeHob();\r
324 if (BootMode == BOOT_ON_FLASH_UPDATE) {\r
325 Status = gRT->SetVariable(\r
326 L"CapsuleLast",\r
327 &gEfiCapsuleReportGuid,\r
328 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
329 0,\r
330 NULL\r
331 );\r
332 // Do not lock it because it will be updated later.\r
333 } else {\r
334 //\r
335 // Check if OS/APP cleared L"Capsule####"\r
336 //\r
337 ZeroMem(CapsuleLastStr, sizeof(CapsuleLastStr));\r
338 Size = sizeof(L"Capsule####") - sizeof(CHAR16); // no zero terminator\r
339 Status = gRT->GetVariable(\r
340 L"CapsuleLast",\r
341 &gEfiCapsuleReportGuid,\r
342 NULL,\r
343 &Size,\r
344 CapsuleLastStr\r
345 );\r
346 if (!EFI_ERROR(Status)) {\r
347 //\r
348 // L"CapsuleLast" is got, check if data is there.\r
349 //\r
350 Status = GetVariable2 (\r
351 CapsuleLastStr,\r
352 &gEfiCapsuleReportGuid,\r
353 (VOID **) &CapsuleResult,\r
354 NULL\r
355 );\r
356 if (EFI_ERROR(Status)) {\r
357 //\r
358 // If no data, delete L"CapsuleLast"\r
359 //\r
360 Status = gRT->SetVariable(\r
361 L"CapsuleLast",\r
362 &gEfiCapsuleReportGuid,\r
363 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
364 0,\r
365 NULL\r
366 );\r
dd4eaf15
HW
367 } else {\r
368 if (CapsuleResult != NULL) {\r
369 FreePool (CapsuleResult);\r
370 }\r
d2a16030
JY
371 }\r
372 }\r
373\r
374 // Lock it in normal boot path per UEFI spec.\r
375 Status = gBS->LocateProtocol(&gEdkiiVariableLockProtocolGuid, NULL, (VOID **)&VariableLock);\r
376 if (!EFI_ERROR(Status)) {\r
377 Status = VariableLock->RequestToLock(VariableLock, L"CapsuleLast", &gEfiCapsuleReportGuid);\r
378 ASSERT_EFI_ERROR(Status);\r
379 }\r
380 }\r
381}\r
382\r
383/**\r
384 Initialize capsule update variables.\r
385**/\r
386VOID\r
387InitCapsuleUpdateVariable (\r
388 VOID\r
389 )\r
390{\r
391 EFI_STATUS Status;\r
392 UINTN Index;\r
393 CHAR16 CapsuleVarName[30];\r
394 CHAR16 *TempVarName;\r
395\r
396 //\r
397 // Clear all the capsule variables CapsuleUpdateData, CapsuleUpdateData1, CapsuleUpdateData2...\r
398 // as early as possible which will avoid the next time boot after the capsule update\r
399 // will still into the capsule loop\r
400 //\r
401 StrCpyS (CapsuleVarName, sizeof(CapsuleVarName)/sizeof(CapsuleVarName[0]), EFI_CAPSULE_VARIABLE_NAME);\r
402 TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
403 Index = 0;\r
404 while (TRUE) {\r
405 if (Index > 0) {\r
9f4048f7
HW
406 UnicodeValueToStringS (\r
407 TempVarName,\r
408 sizeof (CapsuleVarName) - ((UINTN)TempVarName - (UINTN)CapsuleVarName),\r
409 0,\r
410 Index,\r
411 0\r
412 );\r
d2a16030
JY
413 }\r
414 Status = gRT->SetVariable (\r
415 CapsuleVarName,\r
416 &gEfiCapsuleVendorGuid,\r
417 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
418 0,\r
419 (VOID *)NULL\r
420 );\r
421 if (EFI_ERROR (Status)) {\r
422 //\r
423 // There is no capsule variables, quit\r
424 //\r
425 break;\r
426 }\r
427 Index++;\r
428 }\r
429}\r
430\r
28889a78
WX
431/**\r
432 Initialize capsule relocation info variable.\r
433**/\r
434VOID\r
435InitCapsuleRelocationInfo (\r
436 VOID\r
437 )\r
438{\r
439 EFI_STATUS Status;\r
440 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;\r
441\r
442 CoDClearCapsuleRelocationInfo();\r
443\r
444 //\r
445 // Unlock Capsule On Disk relocation Info variable only when Capsule On Disk flag is enabled\r
446 //\r
447 if (!CoDCheckCapsuleOnDiskFlag()) {\r
448 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);\r
449 if (!EFI_ERROR (Status)) {\r
450 Status = VariableLock->RequestToLock (VariableLock, COD_RELOCATION_INFO_VAR_NAME, &gEfiCapsuleVendorGuid);\r
451 ASSERT_EFI_ERROR (Status);\r
452 }\r
453 }\r
454}\r
455\r
d2a16030
JY
456/**\r
457 Initialize capsule related variables.\r
458**/\r
459VOID\r
460InitCapsuleVariable (\r
461 VOID\r
462 )\r
463{\r
464 InitCapsuleUpdateVariable();\r
465 InitCapsuleMaxVariable();\r
466 InitCapsuleLastVariable();\r
28889a78
WX
467 InitCapsuleRelocationInfo();\r
468\r
d2a16030
JY
469 //\r
470 // No need to clear L"Capsule####", because OS/APP should refer L"CapsuleLast"\r
471 // to check status and delete them.\r
472 //\r
473}\r