]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
MdeModulePkg: Apply uncrustify changes
[mirror_edk2.git] / MdeModulePkg / Library / DxeCapsuleLibFmp / DxeCapsuleProcessLib.c
CommitLineData
d2a16030
JY
1/** @file\r
2 DXE capsule process.\r
3\r
4 Caution: This module requires additional review when modified.\r
5 This module will have external input - capsule image.\r
6 This external input must be validated carefully to avoid security issue like\r
7 buffer overflow, integer overflow.\r
8\r
9 ProcessCapsules(), ProcessTheseCapsules() will receive untrusted\r
10 input and do basic validation.\r
11\r
28889a78 12 Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>\r
9d510e61 13 SPDX-License-Identifier: BSD-2-Clause-Patent\r
d2a16030
JY
14\r
15**/\r
16\r
17#include <PiDxe.h>\r
18#include <Protocol/EsrtManagement.h>\r
57476106 19#include <Protocol/FirmwareManagementProgress.h>\r
d2a16030
JY
20\r
21#include <Library/BaseLib.h>\r
22#include <Library/DebugLib.h>\r
23#include <Library/BaseMemoryLib.h>\r
24#include <Library/UefiBootServicesTableLib.h>\r
25#include <Library/UefiRuntimeServicesTableLib.h>\r
26#include <Library/MemoryAllocationLib.h>\r
27#include <Library/UefiLib.h>\r
28#include <Library/PcdLib.h>\r
29#include <Library/HobLib.h>\r
30#include <Library/ReportStatusCodeLib.h>\r
31#include <Library/CapsuleLib.h>\r
57476106 32#include <Library/DisplayUpdateProgressLib.h>\r
d2a16030
JY
33\r
34#include <IndustryStandard/WindowsUxCapsule.h>\r
35\r
57476106
KM
36extern EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL *mFmpProgress;\r
37\r
d2a16030
JY
38/**\r
39 Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.\r
40\r
41 @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER\r
42\r
43 @retval TRUE It is a system FMP.\r
44 @retval FALSE It is a device FMP.\r
45**/\r
46BOOLEAN\r
47IsFmpCapsule (\r
48 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
49 );\r
50\r
51/**\r
52 Validate Fmp capsules layout.\r
53\r
54 Caution: This function may receive untrusted input.\r
55\r
56 This function assumes the caller validated the capsule by using\r
57 IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.\r
58 The capsule buffer size is CapsuleHeader->CapsuleImageSize.\r
59\r
60 This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\r
61 and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.\r
62\r
63 This function need support nested FMP capsule.\r
64\r
65 @param[in] CapsuleHeader Points to a capsule header.\r
66 @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.\r
67\r
68 @retval EFI_SUCESS Input capsule is a correct FMP capsule.\r
69 @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.\r
70**/\r
71EFI_STATUS\r
72ValidateFmpCapsule (\r
73 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
74 OUT UINT16 *EmbeddedDriverCount OPTIONAL\r
75 );\r
76\r
77/**\r
78 Validate if it is valid capsule header\r
79\r
80 This function assumes the caller provided correct CapsuleHeader pointer\r
81 and CapsuleSize.\r
82\r
83 This function validates the fields in EFI_CAPSULE_HEADER.\r
84\r
85 @param[in] CapsuleHeader Points to a capsule header.\r
86 @param[in] CapsuleSize Size of the whole capsule image.\r
87\r
88**/\r
89BOOLEAN\r
90IsValidCapsuleHeader (\r
91 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
92 IN UINT64 CapsuleSize\r
93 );\r
94\r
28889a78
WX
95/**\r
96 Return if this capsule is a capsule name capsule, based upon CapsuleHeader.\r
97\r
98 @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER\r
99\r
100 @retval TRUE It is a capsule name capsule.\r
101 @retval FALSE It is not a capsule name capsule.\r
102**/\r
103BOOLEAN\r
104IsCapsuleNameCapsule (\r
1436aea4 105 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
28889a78
WX
106 );\r
107\r
108/**\r
109 Check the integrity of the capsule name capsule.\r
110 If the capsule is vaild, return the physical address of each capsule name string.\r
111\r
112 @param[in] CapsuleHeader Pointer to the capsule header of a capsule name capsule.\r
113 @param[out] CapsuleNameNum Number of capsule name.\r
114\r
115 @retval NULL Capsule name capsule is not valid.\r
116 @retval CapsuleNameBuf Array of capsule name physical address.\r
117\r
118**/\r
119EFI_PHYSICAL_ADDRESS *\r
120ValidateCapsuleNameCapsuleIntegrity (\r
1436aea4
MK
121 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
122 OUT UINTN *CapsuleNameNum\r
28889a78
WX
123 );\r
124\r
1436aea4
MK
125extern BOOLEAN mDxeCapsuleLibEndOfDxe;\r
126BOOLEAN mNeedReset = FALSE;\r
d2a16030 127\r
1436aea4
MK
128VOID **mCapsulePtr;\r
129CHAR16 **mCapsuleNamePtr;\r
130EFI_STATUS *mCapsuleStatusArray;\r
131UINT32 mCapsuleTotalNumber;\r
d2a16030 132\r
69feaa37
SZ
133/**\r
134 The firmware implements to process the capsule image.\r
135\r
136 Caution: This function may receive untrusted input.\r
137\r
138 @param[in] CapsuleHeader Points to a capsule header.\r
111bbcf8 139 @param[in] CapFileName Capsule file name.\r
69feaa37
SZ
140 @param[out] ResetRequired Indicates whether reset is required or not.\r
141\r
142 @retval EFI_SUCESS Process Capsule Image successfully.\r
143 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.\r
144 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.\r
145 @retval EFI_OUT_OF_RESOURCES Not enough memory.\r
146**/\r
147EFI_STATUS\r
148EFIAPI\r
149ProcessThisCapsuleImage (\r
150 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
e3917e22 151 IN CHAR16 *CapFileName OPTIONAL,\r
69feaa37
SZ
152 OUT BOOLEAN *ResetRequired OPTIONAL\r
153 );\r
154\r
57476106
KM
155/**\r
156 Function indicate the current completion progress of the firmware\r
157 update. Platform may override with own specific progress function.\r
158\r
159 @param[in] Completion A value between 1 and 100 indicating the current\r
160 completion progress of the firmware update\r
161\r
162 @retval EFI_SUCESS The capsule update progress was updated.\r
163 @retval EFI_INVALID_PARAMETER Completion is greater than 100%.\r
164**/\r
165EFI_STATUS\r
166EFIAPI\r
167UpdateImageProgress (\r
168 IN UINTN Completion\r
169 )\r
170{\r
171 EFI_STATUS Status;\r
172 UINTN Seconds;\r
173 EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION *Color;\r
174\r
1436aea4 175 DEBUG ((DEBUG_INFO, "Update Progress - %d%%\n", Completion));\r
57476106
KM
176\r
177 if (Completion > 100) {\r
178 return EFI_INVALID_PARAMETER;\r
179 }\r
180\r
181 //\r
182 // Use a default timeout of 5 minutes if there is not FMP Progress Protocol.\r
183 //\r
184 Seconds = 5 * 60;\r
185 Color = NULL;\r
186 if (mFmpProgress != NULL) {\r
187 Seconds = mFmpProgress->WatchdogSeconds;\r
188 Color = &mFmpProgress->ProgressBarForegroundColor;\r
189 }\r
190\r
191 //\r
192 // Cancel the watchdog timer\r
193 //\r
194 gBS->SetWatchdogTimer (0, 0x0000, 0, NULL);\r
195\r
196 if (Completion != 100) {\r
197 //\r
198 // Arm the watchdog timer from PCD setting\r
199 //\r
200 if (Seconds != 0) {\r
201 DEBUG ((DEBUG_VERBOSE, "Arm watchdog timer %d seconds\n", Seconds));\r
202 gBS->SetWatchdogTimer (Seconds, 0x0000, 0, NULL);\r
203 }\r
204 }\r
205\r
206 Status = DisplayUpdateProgress (Completion, Color);\r
207\r
208 return Status;\r
209}\r
210\r
3f31ea1b
JY
211/**\r
212 This function initializes the mCapsulePtr, mCapsuleStatusArray and mCapsuleTotalNumber.\r
d2a16030 213**/\r
3f31ea1b
JY
214VOID\r
215InitCapsulePtr (\r
216 VOID\r
d2a16030
JY
217 )\r
218{\r
1436aea4
MK
219 EFI_PEI_HOB_POINTERS HobPointer;\r
220 UINTN Index;\r
221 UINTN Index2;\r
222 UINTN Index3;\r
223 UINTN CapsuleNameNumber;\r
224 UINTN CapsuleNameTotalNumber;\r
225 UINTN CapsuleNameCapsuleTotalNumber;\r
226 VOID **CapsuleNameCapsulePtr;\r
227 EFI_PHYSICAL_ADDRESS *CapsuleNameAddress;\r
28889a78
WX
228\r
229 CapsuleNameNumber = 0;\r
230 CapsuleNameTotalNumber = 0;\r
231 CapsuleNameCapsuleTotalNumber = 0;\r
232 CapsuleNameCapsulePtr = NULL;\r
d2a16030 233\r
d2a16030
JY
234 //\r
235 // Find all capsule images from hob\r
236 //\r
237 HobPointer.Raw = GetHobList ();\r
238 while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {\r
1436aea4 239 if (!IsValidCapsuleHeader ((VOID *)(UINTN)HobPointer.Capsule->BaseAddress, HobPointer.Capsule->Length)) {\r
d2a16030
JY
240 HobPointer.Header->HobType = EFI_HOB_TYPE_UNUSED; // Mark this hob as invalid\r
241 } else {\r
1436aea4 242 if (IsCapsuleNameCapsule ((VOID *)(UINTN)HobPointer.Capsule->BaseAddress)) {\r
28889a78
WX
243 CapsuleNameCapsuleTotalNumber++;\r
244 } else {\r
245 mCapsuleTotalNumber++;\r
246 }\r
d2a16030 247 }\r
1436aea4 248\r
d2a16030
JY
249 HobPointer.Raw = GET_NEXT_HOB (HobPointer);\r
250 }\r
251\r
3f31ea1b
JY
252 DEBUG ((DEBUG_INFO, "mCapsuleTotalNumber - 0x%x\n", mCapsuleTotalNumber));\r
253\r
254 if (mCapsuleTotalNumber == 0) {\r
1436aea4 255 return;\r
d2a16030
JY
256 }\r
257\r
258 //\r
259 // Init temp Capsule Data table.\r
260 //\r
1436aea4 261 mCapsulePtr = (VOID **)AllocateZeroPool (sizeof (VOID *) * mCapsuleTotalNumber);\r
3f31ea1b
JY
262 if (mCapsulePtr == NULL) {\r
263 DEBUG ((DEBUG_ERROR, "Allocate mCapsulePtr fail!\n"));\r
264 mCapsuleTotalNumber = 0;\r
1436aea4 265 return;\r
d2a16030 266 }\r
1436aea4
MK
267\r
268 mCapsuleStatusArray = (EFI_STATUS *)AllocateZeroPool (sizeof (EFI_STATUS) * mCapsuleTotalNumber);\r
3f31ea1b
JY
269 if (mCapsuleStatusArray == NULL) {\r
270 DEBUG ((DEBUG_ERROR, "Allocate mCapsuleStatusArray fail!\n"));\r
271 FreePool (mCapsulePtr);\r
1436aea4 272 mCapsulePtr = NULL;\r
3f31ea1b 273 mCapsuleTotalNumber = 0;\r
1436aea4 274 return;\r
d2a16030 275 }\r
1436aea4 276\r
3f31ea1b 277 SetMemN (mCapsuleStatusArray, sizeof (EFI_STATUS) * mCapsuleTotalNumber, EFI_NOT_READY);\r
d2a16030 278\r
1436aea4 279 CapsuleNameCapsulePtr = (VOID **)AllocateZeroPool (sizeof (VOID *) * CapsuleNameCapsuleTotalNumber);\r
28889a78
WX
280 if (CapsuleNameCapsulePtr == NULL) {\r
281 DEBUG ((DEBUG_ERROR, "Allocate CapsuleNameCapsulePtr fail!\n"));\r
282 FreePool (mCapsulePtr);\r
283 FreePool (mCapsuleStatusArray);\r
284 mCapsulePtr = NULL;\r
285 mCapsuleStatusArray = NULL;\r
286 mCapsuleTotalNumber = 0;\r
1436aea4 287 return;\r
28889a78
WX
288 }\r
289\r
d2a16030
JY
290 //\r
291 // Find all capsule images from hob\r
292 //\r
293 HobPointer.Raw = GetHobList ();\r
1436aea4
MK
294 Index = 0;\r
295 Index2 = 0;\r
d2a16030 296 while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {\r
1436aea4
MK
297 if (IsCapsuleNameCapsule ((VOID *)(UINTN)HobPointer.Capsule->BaseAddress)) {\r
298 CapsuleNameCapsulePtr[Index2++] = (VOID *)(UINTN)HobPointer.Capsule->BaseAddress;\r
28889a78 299 } else {\r
1436aea4 300 mCapsulePtr[Index++] = (VOID *)(UINTN)HobPointer.Capsule->BaseAddress;\r
28889a78 301 }\r
1436aea4 302\r
d2a16030
JY
303 HobPointer.Raw = GET_NEXT_HOB (HobPointer);\r
304 }\r
28889a78
WX
305\r
306 //\r
307 // Find Capsule On Disk Names\r
308 //\r
1436aea4 309 for (Index = 0; Index < CapsuleNameCapsuleTotalNumber; Index++) {\r
28889a78
WX
310 CapsuleNameAddress = ValidateCapsuleNameCapsuleIntegrity (CapsuleNameCapsulePtr[Index], &CapsuleNameNumber);\r
311 if (CapsuleNameAddress != NULL ) {\r
312 CapsuleNameTotalNumber += CapsuleNameNumber;\r
313 }\r
314 }\r
315\r
316 if (CapsuleNameTotalNumber == mCapsuleTotalNumber) {\r
1436aea4 317 mCapsuleNamePtr = (CHAR16 **)AllocateZeroPool (sizeof (CHAR16 *) * mCapsuleTotalNumber);\r
28889a78
WX
318 if (mCapsuleNamePtr == NULL) {\r
319 DEBUG ((DEBUG_ERROR, "Allocate mCapsuleNamePtr fail!\n"));\r
320 FreePool (mCapsulePtr);\r
321 FreePool (mCapsuleStatusArray);\r
322 FreePool (CapsuleNameCapsulePtr);\r
323 mCapsulePtr = NULL;\r
324 mCapsuleStatusArray = NULL;\r
325 mCapsuleTotalNumber = 0;\r
1436aea4 326 return;\r
28889a78
WX
327 }\r
328\r
1436aea4 329 for (Index = 0, Index3 = 0; Index < CapsuleNameCapsuleTotalNumber; Index++) {\r
28889a78
WX
330 CapsuleNameAddress = ValidateCapsuleNameCapsuleIntegrity (CapsuleNameCapsulePtr[Index], &CapsuleNameNumber);\r
331 if (CapsuleNameAddress != NULL ) {\r
1436aea4
MK
332 for (Index2 = 0; Index2 < CapsuleNameNumber; Index2++) {\r
333 mCapsuleNamePtr[Index3++] = (CHAR16 *)(UINTN)CapsuleNameAddress[Index2];\r
28889a78
WX
334 }\r
335 }\r
336 }\r
337 } else {\r
338 mCapsuleNamePtr = NULL;\r
339 }\r
340\r
341 FreePool (CapsuleNameCapsulePtr);\r
3f31ea1b 342}\r
d2a16030 343\r
3f31ea1b
JY
344/**\r
345 This function returns if all capsule images are processed.\r
346\r
347 @retval TRUE All capsule images are processed.\r
348 @retval FALSE Not all capsule images are processed.\r
349**/\r
350BOOLEAN\r
351AreAllImagesProcessed (\r
352 VOID\r
353 )\r
354{\r
355 UINTN Index;\r
356\r
357 for (Index = 0; Index < mCapsuleTotalNumber; Index++) {\r
358 if (mCapsuleStatusArray[Index] == EFI_NOT_READY) {\r
359 return FALSE;\r
360 }\r
361 }\r
362\r
363 return TRUE;\r
364}\r
365\r
366/**\r
367 This function populates capsule in the configuration table.\r
368**/\r
369VOID\r
370PopulateCapsuleInConfigurationTable (\r
371 VOID\r
372 )\r
373{\r
1436aea4
MK
374 VOID **CapsulePtrCache;\r
375 EFI_GUID *CapsuleGuidCache;\r
376 EFI_CAPSULE_HEADER *CapsuleHeader;\r
377 EFI_CAPSULE_TABLE *CapsuleTable;\r
378 UINT32 CacheIndex;\r
379 UINT32 CacheNumber;\r
380 UINT32 CapsuleNumber;\r
381 UINTN Index;\r
382 UINTN Size;\r
383 EFI_STATUS Status;\r
3f31ea1b
JY
384\r
385 if (mCapsuleTotalNumber == 0) {\r
1436aea4 386 return;\r
3f31ea1b
JY
387 }\r
388\r
1436aea4
MK
389 CapsulePtrCache = NULL;\r
390 CapsuleGuidCache = NULL;\r
391 CacheIndex = 0;\r
392 CacheNumber = 0;\r
3f31ea1b 393\r
1436aea4 394 CapsulePtrCache = (VOID **)AllocateZeroPool (sizeof (VOID *) * mCapsuleTotalNumber);\r
3f31ea1b
JY
395 if (CapsulePtrCache == NULL) {\r
396 DEBUG ((DEBUG_ERROR, "Allocate CapsulePtrCache fail!\n"));\r
1436aea4 397 return;\r
3f31ea1b 398 }\r
1436aea4
MK
399\r
400 CapsuleGuidCache = (EFI_GUID *)AllocateZeroPool (sizeof (EFI_GUID) * mCapsuleTotalNumber);\r
3f31ea1b
JY
401 if (CapsuleGuidCache == NULL) {\r
402 DEBUG ((DEBUG_ERROR, "Allocate CapsuleGuidCache fail!\n"));\r
403 FreePool (CapsulePtrCache);\r
1436aea4 404 return;\r
3f31ea1b 405 }\r
d2a16030
JY
406\r
407 //\r
408 // Capsules who have CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE always are used for operating\r
409 // System to have information persist across a system reset. EFI System Table must\r
410 // point to an array of capsules that contains the same CapsuleGuid value. And agents\r
411 // searching for this type capsule will look in EFI System Table and search for the\r
412 // capsule's Guid and associated pointer to retrieve the data. Two steps below describes\r
413 // how to sorting the capsules by the unique guid and install the array to EFI System Table.\r
414 // Firstly, Loop for all coalesced capsules, record unique CapsuleGuids and cache them in an\r
415 // array for later sorting capsules by CapsuleGuid.\r
416 //\r
3f31ea1b 417 for (Index = 0; Index < mCapsuleTotalNumber; Index++) {\r
1436aea4 418 CapsuleHeader = (EFI_CAPSULE_HEADER *)mCapsulePtr[Index];\r
d2a16030
JY
419 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {\r
420 //\r
421 // For each capsule, we compare it with known CapsuleGuid in the CacheArray.\r
422 // If already has the Guid, skip it. Whereas, record it in the CacheArray as\r
423 // an additional one.\r
424 //\r
425 CacheIndex = 0;\r
426 while (CacheIndex < CacheNumber) {\r
1436aea4 427 if (CompareGuid (&CapsuleGuidCache[CacheIndex], &CapsuleHeader->CapsuleGuid)) {\r
d2a16030
JY
428 break;\r
429 }\r
1436aea4 430\r
d2a16030
JY
431 CacheIndex++;\r
432 }\r
1436aea4 433\r
d2a16030 434 if (CacheIndex == CacheNumber) {\r
1436aea4 435 CopyMem (&CapsuleGuidCache[CacheNumber++], &CapsuleHeader->CapsuleGuid, sizeof (EFI_GUID));\r
d2a16030
JY
436 }\r
437 }\r
438 }\r
439\r
440 //\r
441 // Secondly, for each unique CapsuleGuid in CacheArray, gather all coalesced capsules\r
442 // whose guid is the same as it, and malloc memory for an array which preceding\r
443 // with UINT32. The array fills with entry point of capsules that have the same\r
444 // CapsuleGuid, and UINT32 represents the size of the array of capsules. Then install\r
445 // this array into EFI System Table, so that agents searching for this type capsule\r
446 // will look in EFI System Table and search for the capsule's Guid and associated\r
447 // pointer to retrieve the data.\r
448 //\r
3f31ea1b 449 for (CacheIndex = 0; CacheIndex < CacheNumber; CacheIndex++) {\r
d2a16030 450 CapsuleNumber = 0;\r
3f31ea1b 451 for (Index = 0; Index < mCapsuleTotalNumber; Index++) {\r
1436aea4 452 CapsuleHeader = (EFI_CAPSULE_HEADER *)mCapsulePtr[Index];\r
d2a16030
JY
453 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {\r
454 if (CompareGuid (&CapsuleGuidCache[CacheIndex], &CapsuleHeader->CapsuleGuid)) {\r
455 //\r
456 // Cache Caspuleheader to the array, this array is uniqued with certain CapsuleGuid.\r
457 //\r
1436aea4 458 CapsulePtrCache[CapsuleNumber++] = (VOID *)CapsuleHeader;\r
d2a16030
JY
459 }\r
460 }\r
461 }\r
1436aea4 462\r
d2a16030 463 if (CapsuleNumber != 0) {\r
1436aea4 464 Size = sizeof (EFI_CAPSULE_TABLE) + (CapsuleNumber - 1) * sizeof (VOID *);\r
d2a16030 465 CapsuleTable = AllocateRuntimePool (Size);\r
d2a16030 466 if (CapsuleTable == NULL) {\r
3f31ea1b
JY
467 DEBUG ((DEBUG_ERROR, "Allocate CapsuleTable (%g) fail!\n", &CapsuleGuidCache[CacheIndex]));\r
468 continue;\r
d2a16030 469 }\r
1436aea4 470\r
d2a16030 471 CapsuleTable->CapsuleArrayNumber = CapsuleNumber;\r
1436aea4
MK
472 CopyMem (&CapsuleTable->CapsulePtr[0], CapsulePtrCache, CapsuleNumber * sizeof (VOID *));\r
473 Status = gBS->InstallConfigurationTable (&CapsuleGuidCache[CacheIndex], (VOID *)CapsuleTable);\r
3f31ea1b
JY
474 if (EFI_ERROR (Status)) {\r
475 DEBUG ((DEBUG_ERROR, "InstallConfigurationTable (%g) fail!\n", &CapsuleGuidCache[CacheIndex]));\r
476 }\r
d2a16030 477 }\r
3f31ea1b
JY
478 }\r
479\r
1436aea4
MK
480 FreePool (CapsuleGuidCache);\r
481 FreePool (CapsulePtrCache);\r
3f31ea1b
JY
482}\r
483\r
484/**\r
485\r
486 This routine is called to process capsules.\r
487\r
488 Caution: This function may receive untrusted input.\r
489\r
490 Each individual capsule result is recorded in capsule record variable.\r
491\r
492 @param[in] FirstRound TRUE: First round. Need skip the FMP capsules with non zero EmbeddedDriverCount.\r
493 FALSE: Process rest FMP capsules.\r
494\r
495 @retval EFI_SUCCESS There is no error when processing capsules.\r
496 @retval EFI_OUT_OF_RESOURCES No enough resource to process capsules.\r
497\r
498**/\r
499EFI_STATUS\r
500ProcessTheseCapsules (\r
501 IN BOOLEAN FirstRound\r
502 )\r
503{\r
1436aea4
MK
504 EFI_STATUS Status;\r
505 EFI_CAPSULE_HEADER *CapsuleHeader;\r
506 UINT32 Index;\r
507 ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;\r
508 UINT16 EmbeddedDriverCount;\r
509 BOOLEAN ResetRequired;\r
510 CHAR16 *CapsuleName;\r
3f31ea1b 511\r
1436aea4 512 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32 (PcdStatusCodeSubClassCapsule) | PcdGet32 (PcdCapsuleStatusCodeProcessCapsulesBegin)));\r
3f31ea1b
JY
513\r
514 if (FirstRound) {\r
515 InitCapsulePtr ();\r
516 }\r
517\r
518 if (mCapsuleTotalNumber == 0) {\r
519 //\r
520 // We didn't find a hob, so had no errors.\r
521 //\r
522 DEBUG ((DEBUG_ERROR, "We can not find capsule data in capsule update boot mode.\n"));\r
28889a78 523 mNeedReset = TRUE;\r
3f31ea1b
JY
524 return EFI_SUCCESS;\r
525 }\r
526\r
527 if (AreAllImagesProcessed ()) {\r
528 return EFI_SUCCESS;\r
529 }\r
530\r
531 //\r
532 // Check the capsule flags,if contains CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE, install\r
533 // capsuleTable to configure table with EFI_CAPSULE_GUID\r
534 //\r
535 if (FirstRound) {\r
536 PopulateCapsuleInConfigurationTable ();\r
d2a16030
JY
537 }\r
538\r
1436aea4 539 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32 (PcdStatusCodeSubClassCapsule) | PcdGet32 (PcdCapsuleStatusCodeUpdatingFirmware)));\r
d2a16030
JY
540\r
541 //\r
542 // If Windows UX capsule exist, process it first\r
543 //\r
3f31ea1b 544 for (Index = 0; Index < mCapsuleTotalNumber; Index++) {\r
1436aea4
MK
545 CapsuleHeader = (EFI_CAPSULE_HEADER *)mCapsulePtr[Index];\r
546 CapsuleName = (mCapsuleNamePtr == NULL) ? NULL : mCapsuleNamePtr[Index];\r
3f31ea1b 547 if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {\r
69feaa37 548 DEBUG ((DEBUG_INFO, "ProcessThisCapsuleImage (Ux) - 0x%x\n", CapsuleHeader));\r
d2a16030 549 DEBUG ((DEBUG_INFO, "Display logo capsule is found.\n"));\r
1436aea4
MK
550 Status = ProcessThisCapsuleImage (CapsuleHeader, CapsuleName, NULL);\r
551 mCapsuleStatusArray[Index] = EFI_SUCCESS;\r
552 DEBUG ((DEBUG_INFO, "ProcessThisCapsuleImage (Ux) - %r\n", Status));\r
d2a16030
JY
553 break;\r
554 }\r
555 }\r
556\r
57476106 557 DEBUG ((DEBUG_INFO, "Updating the firmware ......\n"));\r
d2a16030
JY
558\r
559 //\r
560 // All capsules left are recognized by platform.\r
561 //\r
3f31ea1b 562 for (Index = 0; Index < mCapsuleTotalNumber; Index++) {\r
1436aea4 563 if (mCapsuleStatusArray[Index] != EFI_NOT_READY) {\r
3f31ea1b
JY
564 // already processed\r
565 continue;\r
566 }\r
1436aea4
MK
567\r
568 CapsuleHeader = (EFI_CAPSULE_HEADER *)mCapsulePtr[Index];\r
569 CapsuleName = (mCapsuleNamePtr == NULL) ? NULL : mCapsuleNamePtr[Index];\r
3f31ea1b 570 if (!CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {\r
d2a16030
JY
571 //\r
572 // Call capsule library to process capsule image.\r
573 //\r
574 EmbeddedDriverCount = 0;\r
1436aea4 575 if (IsFmpCapsule (CapsuleHeader)) {\r
3f31ea1b 576 Status = ValidateFmpCapsule (CapsuleHeader, &EmbeddedDriverCount);\r
1436aea4
MK
577 if (EFI_ERROR (Status)) {\r
578 DEBUG ((DEBUG_ERROR, "ValidateFmpCapsule failed. Ignore!\n"));\r
579 mCapsuleStatusArray[Index] = EFI_ABORTED;\r
d2a16030
JY
580 continue;\r
581 }\r
3f31ea1b 582 } else {\r
1436aea4 583 mCapsuleStatusArray[Index] = EFI_ABORTED;\r
3f31ea1b 584 continue;\r
d2a16030
JY
585 }\r
586\r
3f31ea1b 587 if ((!FirstRound) || (EmbeddedDriverCount == 0)) {\r
1436aea4
MK
588 DEBUG ((DEBUG_INFO, "ProcessThisCapsuleImage - 0x%x\n", CapsuleHeader));\r
589 ResetRequired = FALSE;\r
590 Status = ProcessThisCapsuleImage (CapsuleHeader, CapsuleName, &ResetRequired);\r
591 mCapsuleStatusArray[Index] = Status;\r
592 DEBUG ((DEBUG_INFO, "ProcessThisCapsuleImage - %r\n", Status));\r
d2a16030 593\r
3f31ea1b 594 if (Status != EFI_NOT_READY) {\r
1436aea4
MK
595 if (EFI_ERROR (Status)) {\r
596 REPORT_STATUS_CODE (EFI_ERROR_CODE, (EFI_SOFTWARE | PcdGet32 (PcdStatusCodeSubClassCapsule) | PcdGet32 (PcdCapsuleStatusCodeUpdateFirmwareFailed)));\r
3f31ea1b 597 DEBUG ((DEBUG_ERROR, "Capsule process failed!\n"));\r
3f31ea1b 598 } else {\r
1436aea4 599 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32 (PcdStatusCodeSubClassCapsule) | PcdGet32 (PcdCapsuleStatusCodeUpdateFirmwareSuccess)));\r
3f31ea1b
JY
600 }\r
601\r
69feaa37 602 mNeedReset |= ResetRequired;\r
1436aea4 603 if ((CapsuleHeader->Flags & PcdGet16 (PcdSystemRebootAfterCapsuleProcessFlag)) != 0) {\r
3f31ea1b
JY
604 mNeedReset = TRUE;\r
605 }\r
d2a16030
JY
606 }\r
607 }\r
608 }\r
609 }\r
610\r
1436aea4 611 Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement);\r
d2a16030
JY
612 //\r
613 // Always sync ESRT Cache from FMP Instance\r
614 //\r
1436aea4
MK
615 if (!EFI_ERROR (Status)) {\r
616 EsrtManagement->SyncEsrtFmp ();\r
d2a16030 617 }\r
1436aea4 618\r
d2a16030
JY
619 Status = EFI_SUCCESS;\r
620\r
1436aea4 621 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32 (PcdStatusCodeSubClassCapsule) | PcdGet32 (PcdCapsuleStatusCodeProcessCapsulesEnd)));\r
d2a16030
JY
622\r
623 return Status;\r
624}\r
625\r
626/**\r
627 Do reset system.\r
628**/\r
629VOID\r
630DoResetSystem (\r
631 VOID\r
632 )\r
633{\r
1436aea4 634 DEBUG ((DEBUG_INFO, "Capsule Request Cold Reboot."));\r
d2a16030 635\r
1436aea4 636 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32 (PcdStatusCodeSubClassCapsule) | PcdGet32 (PcdCapsuleStatusCodeResettingSystem)));\r
d2a16030 637\r
1436aea4 638 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
d2a16030 639\r
1436aea4 640 CpuDeadLoop ();\r
d2a16030
JY
641}\r
642\r
643/**\r
644\r
645 This routine is called to process capsules.\r
646\r
647 Caution: This function may receive untrusted input.\r
648\r
649 The capsules reported in EFI_HOB_UEFI_CAPSULE are processed.\r
28889a78
WX
650 If there is no EFI_HOB_UEFI_CAPSULE, it means error occurs, force reset to\r
651 normal boot path.\r
d2a16030
JY
652\r
653 This routine should be called twice in BDS.\r
654 1) The first call must be before EndOfDxe. The system capsules is processed.\r
655 If device capsule FMP protocols are exposted at this time and device FMP\r
656 capsule has zero EmbeddedDriverCount, the device capsules are processed.\r
657 Each individual capsule result is recorded in capsule record variable.\r
658 System may reset in this function, if reset is required by capsule and\r
659 all capsules are processed.\r
660 If not all capsules are processed, reset will be defered to second call.\r
661\r
662 2) The second call must be after EndOfDxe and after ConnectAll, so that all\r
663 device capsule FMP protocols are exposed.\r
664 The system capsules are skipped. If the device capsules are NOT processed\r
665 in first call, they are processed here.\r
666 Each individual capsule result is recorded in capsule record variable.\r
667 System may reset in this function, if reset is required by capsule\r
668 processed in first call and second call.\r
669\r
670 @retval EFI_SUCCESS There is no error when processing capsules.\r
671 @retval EFI_OUT_OF_RESOURCES No enough resource to process capsules.\r
672\r
673**/\r
674EFI_STATUS\r
675EFIAPI\r
676ProcessCapsules (\r
677 VOID\r
678 )\r
679{\r
1436aea4 680 EFI_STATUS Status;\r
d2a16030
JY
681\r
682 if (!mDxeCapsuleLibEndOfDxe) {\r
1436aea4 683 Status = ProcessTheseCapsules (TRUE);\r
3f31ea1b 684\r
d2a16030
JY
685 //\r
686 // Reboot System if and only if all capsule processed.\r
687 // If not, defer reset to 2nd process.\r
688 //\r
1436aea4
MK
689 if (mNeedReset && AreAllImagesProcessed ()) {\r
690 DoResetSystem ();\r
d2a16030
JY
691 }\r
692 } else {\r
1436aea4 693 Status = ProcessTheseCapsules (FALSE);\r
d2a16030
JY
694 //\r
695 // Reboot System if required after all capsule processed\r
696 //\r
697 if (mNeedReset) {\r
1436aea4 698 DoResetSystem ();\r
d2a16030
JY
699 }\r
700 }\r
1436aea4 701\r
d2a16030
JY
702 return Status;\r
703}\r