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