]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c
MdeModulePkg: Change OPTIONAL keyword usage style
[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
105 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
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
121 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
122 OUT UINTN *CapsuleNameNum\r
123 );\r
124\r
d2a16030 125extern BOOLEAN mDxeCapsuleLibEndOfDxe;\r
69feaa37 126BOOLEAN mNeedReset = FALSE;\r
d2a16030 127\r
3f31ea1b 128VOID **mCapsulePtr;\r
28889a78 129CHAR16 **mCapsuleNamePtr;\r
3f31ea1b
JY
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
175 DEBUG((DEBUG_INFO, "Update Progress - %d%%\n", Completion));\r
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
d2a16030 219 EFI_PEI_HOB_POINTERS HobPointer;\r
3f31ea1b 220 UINTN Index;\r
28889a78
WX
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
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
239 if (!IsValidCapsuleHeader((VOID *)(UINTN)HobPointer.Capsule->BaseAddress, HobPointer.Capsule->Length)) {\r
240 HobPointer.Header->HobType = EFI_HOB_TYPE_UNUSED; // Mark this hob as invalid\r
241 } else {\r
28889a78
WX
242 if (IsCapsuleNameCapsule((VOID *)(UINTN)HobPointer.Capsule->BaseAddress)) {\r
243 CapsuleNameCapsuleTotalNumber++;\r
244 } else {\r
245 mCapsuleTotalNumber++;\r
246 }\r
d2a16030
JY
247 }\r
248 HobPointer.Raw = GET_NEXT_HOB (HobPointer);\r
249 }\r
250\r
3f31ea1b
JY
251 DEBUG ((DEBUG_INFO, "mCapsuleTotalNumber - 0x%x\n", mCapsuleTotalNumber));\r
252\r
253 if (mCapsuleTotalNumber == 0) {\r
254 return ;\r
d2a16030
JY
255 }\r
256\r
257 //\r
258 // Init temp Capsule Data table.\r
259 //\r
3f31ea1b
JY
260 mCapsulePtr = (VOID **) AllocateZeroPool (sizeof (VOID *) * mCapsuleTotalNumber);\r
261 if (mCapsulePtr == NULL) {\r
262 DEBUG ((DEBUG_ERROR, "Allocate mCapsulePtr fail!\n"));\r
263 mCapsuleTotalNumber = 0;\r
264 return ;\r
d2a16030 265 }\r
3f31ea1b
JY
266 mCapsuleStatusArray = (EFI_STATUS *) AllocateZeroPool (sizeof (EFI_STATUS) * mCapsuleTotalNumber);\r
267 if (mCapsuleStatusArray == NULL) {\r
268 DEBUG ((DEBUG_ERROR, "Allocate mCapsuleStatusArray fail!\n"));\r
269 FreePool (mCapsulePtr);\r
270 mCapsulePtr = NULL;\r
271 mCapsuleTotalNumber = 0;\r
272 return ;\r
d2a16030 273 }\r
3f31ea1b 274 SetMemN (mCapsuleStatusArray, sizeof (EFI_STATUS) * mCapsuleTotalNumber, EFI_NOT_READY);\r
d2a16030 275\r
28889a78
WX
276 CapsuleNameCapsulePtr = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleNameCapsuleTotalNumber);\r
277 if (CapsuleNameCapsulePtr == NULL) {\r
278 DEBUG ((DEBUG_ERROR, "Allocate CapsuleNameCapsulePtr fail!\n"));\r
279 FreePool (mCapsulePtr);\r
280 FreePool (mCapsuleStatusArray);\r
281 mCapsulePtr = NULL;\r
282 mCapsuleStatusArray = NULL;\r
283 mCapsuleTotalNumber = 0;\r
284 return ;\r
285 }\r
286\r
d2a16030
JY
287 //\r
288 // Find all capsule images from hob\r
289 //\r
290 HobPointer.Raw = GetHobList ();\r
28889a78
WX
291 Index = 0;\r
292 Index2 = 0;\r
d2a16030 293 while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {\r
28889a78
WX
294 if (IsCapsuleNameCapsule ((VOID *) (UINTN) HobPointer.Capsule->BaseAddress)) {\r
295 CapsuleNameCapsulePtr [Index2++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress;\r
296 } else {\r
297 mCapsulePtr [Index++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress;\r
298 }\r
d2a16030
JY
299 HobPointer.Raw = GET_NEXT_HOB (HobPointer);\r
300 }\r
28889a78
WX
301\r
302 //\r
303 // Find Capsule On Disk Names\r
304 //\r
305 for (Index = 0; Index < CapsuleNameCapsuleTotalNumber; Index ++) {\r
306 CapsuleNameAddress = ValidateCapsuleNameCapsuleIntegrity (CapsuleNameCapsulePtr[Index], &CapsuleNameNumber);\r
307 if (CapsuleNameAddress != NULL ) {\r
308 CapsuleNameTotalNumber += CapsuleNameNumber;\r
309 }\r
310 }\r
311\r
312 if (CapsuleNameTotalNumber == mCapsuleTotalNumber) {\r
313 mCapsuleNamePtr = (CHAR16 **) AllocateZeroPool (sizeof (CHAR16 *) * mCapsuleTotalNumber);\r
314 if (mCapsuleNamePtr == NULL) {\r
315 DEBUG ((DEBUG_ERROR, "Allocate mCapsuleNamePtr fail!\n"));\r
316 FreePool (mCapsulePtr);\r
317 FreePool (mCapsuleStatusArray);\r
318 FreePool (CapsuleNameCapsulePtr);\r
319 mCapsulePtr = NULL;\r
320 mCapsuleStatusArray = NULL;\r
321 mCapsuleTotalNumber = 0;\r
322 return ;\r
323 }\r
324\r
325 for (Index = 0, Index3 = 0; Index < CapsuleNameCapsuleTotalNumber; Index ++) {\r
326 CapsuleNameAddress = ValidateCapsuleNameCapsuleIntegrity (CapsuleNameCapsulePtr[Index], &CapsuleNameNumber);\r
327 if (CapsuleNameAddress != NULL ) {\r
328 for (Index2 = 0; Index2 < CapsuleNameNumber; Index2 ++) {\r
329 mCapsuleNamePtr[Index3 ++] = (CHAR16 *)(UINTN) CapsuleNameAddress[Index2];\r
330 }\r
331 }\r
332 }\r
333 } else {\r
334 mCapsuleNamePtr = NULL;\r
335 }\r
336\r
337 FreePool (CapsuleNameCapsulePtr);\r
3f31ea1b 338}\r
d2a16030 339\r
3f31ea1b
JY
340/**\r
341 This function returns if all capsule images are processed.\r
342\r
343 @retval TRUE All capsule images are processed.\r
344 @retval FALSE Not all capsule images are processed.\r
345**/\r
346BOOLEAN\r
347AreAllImagesProcessed (\r
348 VOID\r
349 )\r
350{\r
351 UINTN Index;\r
352\r
353 for (Index = 0; Index < mCapsuleTotalNumber; Index++) {\r
354 if (mCapsuleStatusArray[Index] == EFI_NOT_READY) {\r
355 return FALSE;\r
356 }\r
357 }\r
358\r
359 return TRUE;\r
360}\r
361\r
362/**\r
363 This function populates capsule in the configuration table.\r
364**/\r
365VOID\r
366PopulateCapsuleInConfigurationTable (\r
367 VOID\r
368 )\r
369{\r
370 VOID **CapsulePtrCache;\r
371 EFI_GUID *CapsuleGuidCache;\r
372 EFI_CAPSULE_HEADER *CapsuleHeader;\r
373 EFI_CAPSULE_TABLE *CapsuleTable;\r
374 UINT32 CacheIndex;\r
375 UINT32 CacheNumber;\r
376 UINT32 CapsuleNumber;\r
377 UINTN Index;\r
378 UINTN Size;\r
379 EFI_STATUS Status;\r
380\r
381 if (mCapsuleTotalNumber == 0) {\r
382 return ;\r
383 }\r
384\r
385 CapsulePtrCache = NULL;\r
386 CapsuleGuidCache = NULL;\r
387 CacheIndex = 0;\r
388 CacheNumber = 0;\r
389\r
390 CapsulePtrCache = (VOID **) AllocateZeroPool (sizeof (VOID *) * mCapsuleTotalNumber);\r
391 if (CapsulePtrCache == NULL) {\r
392 DEBUG ((DEBUG_ERROR, "Allocate CapsulePtrCache fail!\n"));\r
393 return ;\r
394 }\r
395 CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * mCapsuleTotalNumber);\r
396 if (CapsuleGuidCache == NULL) {\r
397 DEBUG ((DEBUG_ERROR, "Allocate CapsuleGuidCache fail!\n"));\r
398 FreePool (CapsulePtrCache);\r
399 return ;\r
400 }\r
d2a16030
JY
401\r
402 //\r
403 // Capsules who have CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE always are used for operating\r
404 // System to have information persist across a system reset. EFI System Table must\r
405 // point to an array of capsules that contains the same CapsuleGuid value. And agents\r
406 // searching for this type capsule will look in EFI System Table and search for the\r
407 // capsule's Guid and associated pointer to retrieve the data. Two steps below describes\r
408 // how to sorting the capsules by the unique guid and install the array to EFI System Table.\r
409 // Firstly, Loop for all coalesced capsules, record unique CapsuleGuids and cache them in an\r
410 // array for later sorting capsules by CapsuleGuid.\r
411 //\r
3f31ea1b
JY
412 for (Index = 0; Index < mCapsuleTotalNumber; Index++) {\r
413 CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];\r
d2a16030
JY
414 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {\r
415 //\r
416 // For each capsule, we compare it with known CapsuleGuid in the CacheArray.\r
417 // If already has the Guid, skip it. Whereas, record it in the CacheArray as\r
418 // an additional one.\r
419 //\r
420 CacheIndex = 0;\r
421 while (CacheIndex < CacheNumber) {\r
422 if (CompareGuid(&CapsuleGuidCache[CacheIndex],&CapsuleHeader->CapsuleGuid)) {\r
423 break;\r
424 }\r
425 CacheIndex++;\r
426 }\r
427 if (CacheIndex == CacheNumber) {\r
428 CopyMem(&CapsuleGuidCache[CacheNumber++],&CapsuleHeader->CapsuleGuid,sizeof(EFI_GUID));\r
429 }\r
430 }\r
431 }\r
432\r
433 //\r
434 // Secondly, for each unique CapsuleGuid in CacheArray, gather all coalesced capsules\r
435 // whose guid is the same as it, and malloc memory for an array which preceding\r
436 // with UINT32. The array fills with entry point of capsules that have the same\r
437 // CapsuleGuid, and UINT32 represents the size of the array of capsules. Then install\r
438 // this array into EFI System Table, so that agents searching for this type capsule\r
439 // will look in EFI System Table and search for the capsule's Guid and associated\r
440 // pointer to retrieve the data.\r
441 //\r
3f31ea1b 442 for (CacheIndex = 0; CacheIndex < CacheNumber; CacheIndex++) {\r
d2a16030 443 CapsuleNumber = 0;\r
3f31ea1b
JY
444 for (Index = 0; Index < mCapsuleTotalNumber; Index++) {\r
445 CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];\r
d2a16030
JY
446 if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {\r
447 if (CompareGuid (&CapsuleGuidCache[CacheIndex], &CapsuleHeader->CapsuleGuid)) {\r
448 //\r
449 // Cache Caspuleheader to the array, this array is uniqued with certain CapsuleGuid.\r
450 //\r
451 CapsulePtrCache[CapsuleNumber++] = (VOID*)CapsuleHeader;\r
d2a16030
JY
452 }\r
453 }\r
454 }\r
455 if (CapsuleNumber != 0) {\r
456 Size = sizeof(EFI_CAPSULE_TABLE) + (CapsuleNumber - 1) * sizeof(VOID*);\r
457 CapsuleTable = AllocateRuntimePool (Size);\r
d2a16030 458 if (CapsuleTable == NULL) {\r
3f31ea1b
JY
459 DEBUG ((DEBUG_ERROR, "Allocate CapsuleTable (%g) fail!\n", &CapsuleGuidCache[CacheIndex]));\r
460 continue;\r
d2a16030
JY
461 }\r
462 CapsuleTable->CapsuleArrayNumber = CapsuleNumber;\r
463 CopyMem(&CapsuleTable->CapsulePtr[0], CapsulePtrCache, CapsuleNumber * sizeof(VOID*));\r
464 Status = gBS->InstallConfigurationTable (&CapsuleGuidCache[CacheIndex], (VOID*)CapsuleTable);\r
3f31ea1b
JY
465 if (EFI_ERROR (Status)) {\r
466 DEBUG ((DEBUG_ERROR, "InstallConfigurationTable (%g) fail!\n", &CapsuleGuidCache[CacheIndex]));\r
467 }\r
d2a16030 468 }\r
3f31ea1b
JY
469 }\r
470\r
471 FreePool(CapsuleGuidCache);\r
472 FreePool(CapsulePtrCache);\r
473}\r
474\r
475/**\r
476\r
477 This routine is called to process capsules.\r
478\r
479 Caution: This function may receive untrusted input.\r
480\r
481 Each individual capsule result is recorded in capsule record variable.\r
482\r
483 @param[in] FirstRound TRUE: First round. Need skip the FMP capsules with non zero EmbeddedDriverCount.\r
484 FALSE: Process rest FMP capsules.\r
485\r
486 @retval EFI_SUCCESS There is no error when processing capsules.\r
487 @retval EFI_OUT_OF_RESOURCES No enough resource to process capsules.\r
488\r
489**/\r
490EFI_STATUS\r
491ProcessTheseCapsules (\r
492 IN BOOLEAN FirstRound\r
493 )\r
494{\r
495 EFI_STATUS Status;\r
496 EFI_CAPSULE_HEADER *CapsuleHeader;\r
497 UINT32 Index;\r
3f31ea1b
JY
498 ESRT_MANAGEMENT_PROTOCOL *EsrtManagement;\r
499 UINT16 EmbeddedDriverCount;\r
69feaa37 500 BOOLEAN ResetRequired;\r
28889a78 501 CHAR16 *CapsuleName;\r
3f31ea1b
JY
502\r
503 REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesBegin)));\r
504\r
505 if (FirstRound) {\r
506 InitCapsulePtr ();\r
507 }\r
508\r
509 if (mCapsuleTotalNumber == 0) {\r
510 //\r
511 // We didn't find a hob, so had no errors.\r
512 //\r
513 DEBUG ((DEBUG_ERROR, "We can not find capsule data in capsule update boot mode.\n"));\r
28889a78 514 mNeedReset = TRUE;\r
3f31ea1b
JY
515 return EFI_SUCCESS;\r
516 }\r
517\r
518 if (AreAllImagesProcessed ()) {\r
519 return EFI_SUCCESS;\r
520 }\r
521\r
522 //\r
523 // Check the capsule flags,if contains CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE, install\r
524 // capsuleTable to configure table with EFI_CAPSULE_GUID\r
525 //\r
526 if (FirstRound) {\r
527 PopulateCapsuleInConfigurationTable ();\r
d2a16030
JY
528 }\r
529\r
530 REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdatingFirmware)));\r
531\r
532 //\r
533 // If Windows UX capsule exist, process it first\r
534 //\r
3f31ea1b
JY
535 for (Index = 0; Index < mCapsuleTotalNumber; Index++) {\r
536 CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];\r
28889a78 537 CapsuleName = (mCapsuleNamePtr == NULL) ? NULL : mCapsuleNamePtr[Index];\r
3f31ea1b 538 if (CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {\r
69feaa37 539 DEBUG ((DEBUG_INFO, "ProcessThisCapsuleImage (Ux) - 0x%x\n", CapsuleHeader));\r
d2a16030 540 DEBUG ((DEBUG_INFO, "Display logo capsule is found.\n"));\r
28889a78 541 Status = ProcessThisCapsuleImage (CapsuleHeader, CapsuleName, NULL);\r
3f31ea1b 542 mCapsuleStatusArray [Index] = EFI_SUCCESS;\r
69feaa37 543 DEBUG((DEBUG_INFO, "ProcessThisCapsuleImage (Ux) - %r\n", Status));\r
d2a16030
JY
544 break;\r
545 }\r
546 }\r
547\r
57476106 548 DEBUG ((DEBUG_INFO, "Updating the firmware ......\n"));\r
d2a16030
JY
549\r
550 //\r
551 // All capsules left are recognized by platform.\r
552 //\r
3f31ea1b
JY
553 for (Index = 0; Index < mCapsuleTotalNumber; Index++) {\r
554 if (mCapsuleStatusArray [Index] != EFI_NOT_READY) {\r
555 // already processed\r
556 continue;\r
557 }\r
558 CapsuleHeader = (EFI_CAPSULE_HEADER*) mCapsulePtr [Index];\r
28889a78 559 CapsuleName = (mCapsuleNamePtr == NULL) ? NULL : mCapsuleNamePtr[Index];\r
3f31ea1b 560 if (!CompareGuid (&CapsuleHeader->CapsuleGuid, &gWindowsUxCapsuleGuid)) {\r
d2a16030
JY
561 //\r
562 // Call capsule library to process capsule image.\r
563 //\r
564 EmbeddedDriverCount = 0;\r
565 if (IsFmpCapsule(CapsuleHeader)) {\r
3f31ea1b 566 Status = ValidateFmpCapsule (CapsuleHeader, &EmbeddedDriverCount);\r
d2a16030
JY
567 if (EFI_ERROR(Status)) {\r
568 DEBUG((DEBUG_ERROR, "ValidateFmpCapsule failed. Ignore!\n"));\r
3f31ea1b 569 mCapsuleStatusArray [Index] = EFI_ABORTED;\r
d2a16030
JY
570 continue;\r
571 }\r
3f31ea1b
JY
572 } else {\r
573 mCapsuleStatusArray [Index] = EFI_ABORTED;\r
574 continue;\r
d2a16030
JY
575 }\r
576\r
3f31ea1b 577 if ((!FirstRound) || (EmbeddedDriverCount == 0)) {\r
69feaa37
SZ
578 DEBUG((DEBUG_INFO, "ProcessThisCapsuleImage - 0x%x\n", CapsuleHeader));\r
579 ResetRequired = FALSE;\r
28889a78 580 Status = ProcessThisCapsuleImage (CapsuleHeader, CapsuleName, &ResetRequired);\r
3f31ea1b 581 mCapsuleStatusArray [Index] = Status;\r
69feaa37 582 DEBUG((DEBUG_INFO, "ProcessThisCapsuleImage - %r\n", Status));\r
d2a16030 583\r
3f31ea1b
JY
584 if (Status != EFI_NOT_READY) {\r
585 if (EFI_ERROR(Status)) {\r
586 REPORT_STATUS_CODE(EFI_ERROR_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareFailed)));\r
587 DEBUG ((DEBUG_ERROR, "Capsule process failed!\n"));\r
3f31ea1b
JY
588 } else {\r
589 REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeUpdateFirmwareSuccess)));\r
590 }\r
591\r
69feaa37
SZ
592 mNeedReset |= ResetRequired;\r
593 if ((CapsuleHeader->Flags & PcdGet16(PcdSystemRebootAfterCapsuleProcessFlag)) != 0) {\r
3f31ea1b
JY
594 mNeedReset = TRUE;\r
595 }\r
d2a16030
JY
596 }\r
597 }\r
598 }\r
599 }\r
600\r
601 Status = gBS->LocateProtocol(&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtManagement);\r
602 //\r
603 // Always sync ESRT Cache from FMP Instance\r
604 //\r
605 if (!EFI_ERROR(Status)) {\r
606 EsrtManagement->SyncEsrtFmp();\r
607 }\r
608 Status = EFI_SUCCESS;\r
609\r
d2a16030
JY
610 REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeProcessCapsulesEnd)));\r
611\r
612 return Status;\r
613}\r
614\r
615/**\r
616 Do reset system.\r
617**/\r
618VOID\r
619DoResetSystem (\r
620 VOID\r
621 )\r
622{\r
d2a16030
JY
623 DEBUG((DEBUG_INFO, "Capsule Request Cold Reboot."));\r
624\r
57476106 625 REPORT_STATUS_CODE(EFI_PROGRESS_CODE, (EFI_SOFTWARE | PcdGet32(PcdStatusCodeSubClassCapsule) | PcdGet32(PcdCapsuleStatusCodeResettingSystem)));\r
d2a16030
JY
626\r
627 gRT->ResetSystem(EfiResetCold, EFI_SUCCESS, 0, NULL);\r
628\r
629 CpuDeadLoop();\r
630}\r
631\r
632/**\r
633\r
634 This routine is called to process capsules.\r
635\r
636 Caution: This function may receive untrusted input.\r
637\r
638 The capsules reported in EFI_HOB_UEFI_CAPSULE are processed.\r
28889a78
WX
639 If there is no EFI_HOB_UEFI_CAPSULE, it means error occurs, force reset to\r
640 normal boot path.\r
d2a16030
JY
641\r
642 This routine should be called twice in BDS.\r
643 1) The first call must be before EndOfDxe. The system capsules is processed.\r
644 If device capsule FMP protocols are exposted at this time and device FMP\r
645 capsule has zero EmbeddedDriverCount, the device capsules are processed.\r
646 Each individual capsule result is recorded in capsule record variable.\r
647 System may reset in this function, if reset is required by capsule and\r
648 all capsules are processed.\r
649 If not all capsules are processed, reset will be defered to second call.\r
650\r
651 2) The second call must be after EndOfDxe and after ConnectAll, so that all\r
652 device capsule FMP protocols are exposed.\r
653 The system capsules are skipped. If the device capsules are NOT processed\r
654 in first call, they are processed here.\r
655 Each individual capsule result is recorded in capsule record variable.\r
656 System may reset in this function, if reset is required by capsule\r
657 processed in first call and second call.\r
658\r
659 @retval EFI_SUCCESS There is no error when processing capsules.\r
660 @retval EFI_OUT_OF_RESOURCES No enough resource to process capsules.\r
661\r
662**/\r
663EFI_STATUS\r
664EFIAPI\r
665ProcessCapsules (\r
666 VOID\r
667 )\r
668{\r
669 EFI_STATUS Status;\r
670\r
671 if (!mDxeCapsuleLibEndOfDxe) {\r
d2a16030 672 Status = ProcessTheseCapsules(TRUE);\r
3f31ea1b 673\r
d2a16030
JY
674 //\r
675 // Reboot System if and only if all capsule processed.\r
676 // If not, defer reset to 2nd process.\r
677 //\r
3f31ea1b 678 if (mNeedReset && AreAllImagesProcessed()) {\r
d2a16030
JY
679 DoResetSystem();\r
680 }\r
681 } else {\r
682 Status = ProcessTheseCapsules(FALSE);\r
683 //\r
684 // Reboot System if required after all capsule processed\r
685 //\r
686 if (mNeedReset) {\r
687 DoResetSystem();\r
688 }\r
689 }\r
690 return Status;\r
691}\r