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