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