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