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