]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Application/CapsuleApp/CapsuleApp.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Application / CapsuleApp / CapsuleApp.c
... / ...
CommitLineData
1/** @file\r
2 A shell application that triggers capsule update process.\r
3\r
4 Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>\r
5 SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "CapsuleApp.h"\r
10\r
11//\r
12// Define how many block descriptors we want to test with.\r
13//\r
14UINTN NumberOfDescriptors = 1;\r
15UINTN CapsuleFirstIndex;\r
16UINTN CapsuleLastIndex;\r
17\r
18/**\r
19 Create UX capsule.\r
20\r
21 @retval EFI_SUCCESS The capsule header is appended.\r
22 @retval EFI_UNSUPPORTED Input parameter is not valid.\r
23 @retval EFI_OUT_OF_RESOURCES No enough resource to create UX capsule.\r
24**/\r
25EFI_STATUS\r
26CreateBmpFmp (\r
27 VOID\r
28 )\r
29{\r
30 CHAR16 *OutputCapsuleName;\r
31 VOID *BmpBuffer;\r
32 UINTN FileSize;\r
33 CHAR16 *BmpName;\r
34 UINT8 *FullCapsuleBuffer;\r
35 UINTN FullCapsuleBufferSize;\r
36 EFI_DISPLAY_CAPSULE *DisplayCapsule;\r
37 EFI_STATUS Status;\r
38 EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;\r
39 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;\r
40 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *GopBlt;\r
41 UINTN GopBltSize;\r
42 UINTN Height;\r
43 UINTN Width;\r
44\r
45 Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&Gop);\r
46 if (EFI_ERROR (Status)) {\r
47 Print (L"CapsuleApp: NO GOP is found.\n");\r
48 return EFI_UNSUPPORTED;\r
49 }\r
50\r
51 Info = Gop->Mode->Info;\r
52 Print (L"Current GOP: Mode - %d, ", Gop->Mode->Mode);\r
53 Print (L"HorizontalResolution - %d, ", Info->HorizontalResolution);\r
54 Print (L"VerticalResolution - %d\n", Info->VerticalResolution);\r
55 // HorizontalResolution >= BMP_IMAGE_HEADER.PixelWidth\r
56 // VerticalResolution >= BMP_IMAGE_HEADER.PixelHeight\r
57\r
58 if (Argc != 5) {\r
59 Print (L"CapsuleApp: Incorrect parameter count.\n");\r
60 return EFI_UNSUPPORTED;\r
61 }\r
62\r
63 if (StrCmp (Argv[3], L"-O") != 0) {\r
64 Print (L"CapsuleApp: NO output capsule name.\n");\r
65 return EFI_UNSUPPORTED;\r
66 }\r
67\r
68 OutputCapsuleName = Argv[4];\r
69\r
70 BmpBuffer = NULL;\r
71 FileSize = 0;\r
72 FullCapsuleBuffer = NULL;\r
73\r
74 BmpName = Argv[2];\r
75 Status = ReadFileToBuffer (BmpName, &FileSize, &BmpBuffer);\r
76 if (EFI_ERROR (Status)) {\r
77 Print (L"CapsuleApp: BMP image (%s) is not found.\n", BmpName);\r
78 goto Done;\r
79 }\r
80\r
81 GopBlt = NULL;\r
82 Status = TranslateBmpToGopBlt (\r
83 BmpBuffer,\r
84 FileSize,\r
85 &GopBlt,\r
86 &GopBltSize,\r
87 &Height,\r
88 &Width\r
89 );\r
90 if (EFI_ERROR (Status)) {\r
91 Print (L"CapsuleApp: BMP image (%s) is not valid.\n", BmpName);\r
92 goto Done;\r
93 }\r
94\r
95 if (GopBlt != NULL) {\r
96 FreePool (GopBlt);\r
97 }\r
98\r
99 Print (L"BMP image (%s), Width - %d, Height - %d\n", BmpName, Width, Height);\r
100\r
101 if (Height > Info->VerticalResolution) {\r
102 Status = EFI_INVALID_PARAMETER;\r
103 Print (L"CapsuleApp: BMP image (%s) height is larger than current resolution.\n", BmpName);\r
104 goto Done;\r
105 }\r
106\r
107 if (Width > Info->HorizontalResolution) {\r
108 Status = EFI_INVALID_PARAMETER;\r
109 Print (L"CapsuleApp: BMP image (%s) width is larger than current resolution.\n", BmpName);\r
110 goto Done;\r
111 }\r
112\r
113 FullCapsuleBufferSize = sizeof (EFI_DISPLAY_CAPSULE) + FileSize;\r
114 FullCapsuleBuffer = AllocatePool (FullCapsuleBufferSize);\r
115 if (FullCapsuleBuffer == NULL) {\r
116 Print (L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);\r
117 Status = EFI_OUT_OF_RESOURCES;\r
118 goto Done;\r
119 }\r
120\r
121 DisplayCapsule = (EFI_DISPLAY_CAPSULE *)FullCapsuleBuffer;\r
122 CopyGuid (&DisplayCapsule->CapsuleHeader.CapsuleGuid, &gWindowsUxCapsuleGuid);\r
123 DisplayCapsule->CapsuleHeader.HeaderSize = sizeof (DisplayCapsule->CapsuleHeader);\r
124 DisplayCapsule->CapsuleHeader.Flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET;\r
125 DisplayCapsule->CapsuleHeader.CapsuleImageSize = (UINT32)FullCapsuleBufferSize;\r
126\r
127 DisplayCapsule->ImagePayload.Version = 1;\r
128 DisplayCapsule->ImagePayload.Checksum = 0;\r
129 DisplayCapsule->ImagePayload.ImageType = 0; // BMP\r
130 DisplayCapsule->ImagePayload.Reserved = 0;\r
131 DisplayCapsule->ImagePayload.Mode = Gop->Mode->Mode;\r
132\r
133 //\r
134 // Center the bitmap horizontally\r
135 //\r
136 DisplayCapsule->ImagePayload.OffsetX = (UINT32)((Info->HorizontalResolution - Width) / 2);\r
137\r
138 //\r
139 // Put bitmap 3/4 down the display. If bitmap is too tall, then align bottom\r
140 // of bitmap at bottom of display.\r
141 //\r
142 DisplayCapsule->ImagePayload.OffsetY =\r
143 MIN (\r
144 (UINT32)(Info->VerticalResolution - Height),\r
145 (UINT32)(((3 * Info->VerticalResolution) - (2 * Height)) / 4)\r
146 );\r
147\r
148 Print (\r
149 L"BMP image (%s), OffsetX - %d, OffsetY - %d\n",\r
150 BmpName,\r
151 DisplayCapsule->ImagePayload.OffsetX,\r
152 DisplayCapsule->ImagePayload.OffsetY\r
153 );\r
154\r
155 CopyMem ((DisplayCapsule + 1), BmpBuffer, FileSize);\r
156\r
157 DisplayCapsule->ImagePayload.Checksum = CalculateCheckSum8 (FullCapsuleBuffer, FullCapsuleBufferSize);\r
158\r
159 Status = WriteFileFromBuffer (OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);\r
160 Print (L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);\r
161\r
162Done:\r
163 if (BmpBuffer != NULL) {\r
164 FreePool (BmpBuffer);\r
165 }\r
166\r
167 if (FullCapsuleBuffer != NULL) {\r
168 FreePool (FullCapsuleBuffer);\r
169 }\r
170\r
171 return Status;\r
172}\r
173\r
174/**\r
175 Get ImageTypeId in the FMP capsule header.\r
176\r
177 @param[in] CapsuleHeader The FMP capsule image header.\r
178\r
179 @return ImageTypeId\r
180**/\r
181EFI_GUID *\r
182GetCapsuleImageTypeId (\r
183 IN EFI_CAPSULE_HEADER *CapsuleHeader\r
184 )\r
185{\r
186 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r
187 UINT64 *ItemOffsetList;\r
188 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r
189\r
190 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r
191 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r
192 if (FmpCapsuleHeader->PayloadItemCount == 0) {\r
193 return NULL;\r
194 }\r
195\r
196 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[FmpCapsuleHeader->EmbeddedDriverCount]);\r
197 return &ImageHeader->UpdateImageTypeId;\r
198}\r
199\r
200/**\r
201 Get ESRT FwType according to ImageTypeId\r
202\r
203 @param[in] ImageTypeId ImageTypeId of an FMP capsule.\r
204\r
205 @return ESRT FwType\r
206**/\r
207UINT32\r
208GetEsrtFwType (\r
209 IN EFI_GUID *ImageTypeId\r
210 )\r
211{\r
212 EFI_STATUS Status;\r
213 EFI_SYSTEM_RESOURCE_TABLE *Esrt;\r
214 EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;\r
215 UINTN Index;\r
216\r
217 //\r
218 // Check ESRT\r
219 //\r
220 Status = EfiGetSystemConfigurationTable (&gEfiSystemResourceTableGuid, (VOID **)&Esrt);\r
221 if (!EFI_ERROR (Status)) {\r
222 ASSERT (Esrt != NULL);\r
223 EsrtEntry = (VOID *)(Esrt + 1);\r
224 for (Index = 0; Index < Esrt->FwResourceCount; Index++, EsrtEntry++) {\r
225 if (CompareGuid (&EsrtEntry->FwClass, ImageTypeId)) {\r
226 return EsrtEntry->FwType;\r
227 }\r
228 }\r
229 }\r
230\r
231 return ESRT_FW_TYPE_UNKNOWN;\r
232}\r
233\r
234/**\r
235 Validate if it is valid capsule header\r
236\r
237 This function assumes the caller provided correct CapsuleHeader pointer\r
238 and CapsuleSize.\r
239\r
240 This function validates the fields in EFI_CAPSULE_HEADER.\r
241\r
242 @param[in] CapsuleHeader Points to a capsule header.\r
243 @param[in] CapsuleSize Size of the whole capsule image.\r
244\r
245**/\r
246BOOLEAN\r
247IsValidCapsuleHeader (\r
248 IN EFI_CAPSULE_HEADER *CapsuleHeader,\r
249 IN UINT64 CapsuleSize\r
250 )\r
251{\r
252 if (CapsuleSize < sizeof (EFI_CAPSULE_HEADER)) {\r
253 return FALSE;\r
254 }\r
255\r
256 if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {\r
257 return FALSE;\r
258 }\r
259\r
260 if (CapsuleHeader->HeaderSize > CapsuleHeader->CapsuleImageSize) {\r
261 return FALSE;\r
262 }\r
263\r
264 if (CapsuleHeader->HeaderSize < sizeof (EFI_CAPSULE_HEADER)) {\r
265 return FALSE;\r
266 }\r
267\r
268 return TRUE;\r
269}\r
270\r
271/**\r
272 Return if this CapsuleGuid is a FMP capsule GUID or not.\r
273\r
274 @param[in] CapsuleGuid A pointer to EFI_GUID\r
275\r
276 @retval TRUE It is a FMP capsule GUID.\r
277 @retval FALSE It is not a FMP capsule GUID.\r
278**/\r
279BOOLEAN\r
280IsFmpCapsuleGuid (\r
281 IN EFI_GUID *CapsuleGuid\r
282 )\r
283{\r
284 if (CompareGuid (&gEfiFmpCapsuleGuid, CapsuleGuid)) {\r
285 return TRUE;\r
286 }\r
287\r
288 return FALSE;\r
289}\r
290\r
291/**\r
292 Append a capsule header on top of current image.\r
293 This function follows Windows UEFI Firmware Update Platform document.\r
294\r
295 @retval EFI_SUCCESS The capsule header is appended.\r
296 @retval EFI_UNSUPPORTED Input parameter is not valid.\r
297 @retval EFI_OUT_OF_RESOURCES No enough resource to append capsule header.\r
298**/\r
299EFI_STATUS\r
300CreateNestedFmp (\r
301 VOID\r
302 )\r
303{\r
304 CHAR16 *OutputCapsuleName;\r
305 VOID *CapsuleBuffer;\r
306 UINTN FileSize;\r
307 CHAR16 *CapsuleName;\r
308 UINT8 *FullCapsuleBuffer;\r
309 UINTN FullCapsuleBufferSize;\r
310 EFI_CAPSULE_HEADER *NestedCapsuleHeader;\r
311 EFI_GUID *ImageTypeId;\r
312 UINT32 FwType;\r
313 EFI_STATUS Status;\r
314\r
315 if (Argc != 5) {\r
316 Print (L"CapsuleApp: Incorrect parameter count.\n");\r
317 return EFI_UNSUPPORTED;\r
318 }\r
319\r
320 if (StrCmp (Argv[3], L"-O") != 0) {\r
321 Print (L"CapsuleApp: NO output capsule name.\n");\r
322 return EFI_UNSUPPORTED;\r
323 }\r
324\r
325 OutputCapsuleName = Argv[4];\r
326\r
327 CapsuleBuffer = NULL;\r
328 FileSize = 0;\r
329 FullCapsuleBuffer = NULL;\r
330\r
331 CapsuleName = Argv[2];\r
332 Status = ReadFileToBuffer (CapsuleName, &FileSize, &CapsuleBuffer);\r
333 if (EFI_ERROR (Status)) {\r
334 Print (L"CapsuleApp: Capsule image (%s) is not found.\n", CapsuleName);\r
335 goto Done;\r
336 }\r
337\r
338 if (!IsValidCapsuleHeader (CapsuleBuffer, FileSize)) {\r
339 Print (L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);\r
340 Status = EFI_INVALID_PARAMETER;\r
341 goto Done;\r
342 }\r
343\r
344 if (!IsFmpCapsuleGuid (&((EFI_CAPSULE_HEADER *)CapsuleBuffer)->CapsuleGuid)) {\r
345 Print (L"CapsuleApp: Capsule image (%s) is not a FMP capsule.\n", CapsuleName);\r
346 Status = EFI_INVALID_PARAMETER;\r
347 goto Done;\r
348 }\r
349\r
350 ImageTypeId = GetCapsuleImageTypeId (CapsuleBuffer);\r
351 if (ImageTypeId == NULL) {\r
352 Print (L"CapsuleApp: Capsule ImageTypeId is not found.\n");\r
353 Status = EFI_INVALID_PARAMETER;\r
354 goto Done;\r
355 }\r
356\r
357 FwType = GetEsrtFwType (ImageTypeId);\r
358 if ((FwType != ESRT_FW_TYPE_SYSTEMFIRMWARE) && (FwType != ESRT_FW_TYPE_DEVICEFIRMWARE)) {\r
359 Print (L"CapsuleApp: Capsule FwType is invalid.\n");\r
360 Status = EFI_INVALID_PARAMETER;\r
361 goto Done;\r
362 }\r
363\r
364 FullCapsuleBufferSize = NESTED_CAPSULE_HEADER_SIZE + FileSize;\r
365 FullCapsuleBuffer = AllocatePool (FullCapsuleBufferSize);\r
366 if (FullCapsuleBuffer == NULL) {\r
367 Print (L"CapsuleApp: Capsule Buffer size (0x%x) too big.\n", FullCapsuleBufferSize);\r
368 Status = EFI_OUT_OF_RESOURCES;\r
369 goto Done;\r
370 }\r
371\r
372 NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)FullCapsuleBuffer;\r
373 ZeroMem (NestedCapsuleHeader, NESTED_CAPSULE_HEADER_SIZE);\r
374 CopyGuid (&NestedCapsuleHeader->CapsuleGuid, ImageTypeId);\r
375 NestedCapsuleHeader->HeaderSize = NESTED_CAPSULE_HEADER_SIZE;\r
376 NestedCapsuleHeader->Flags = (FwType == ESRT_FW_TYPE_SYSTEMFIRMWARE) ? SYSTEM_FIRMWARE_FLAG : DEVICE_FIRMWARE_FLAG;\r
377 NestedCapsuleHeader->CapsuleImageSize = (UINT32)FullCapsuleBufferSize;\r
378\r
379 CopyMem ((UINT8 *)NestedCapsuleHeader + NestedCapsuleHeader->HeaderSize, CapsuleBuffer, FileSize);\r
380\r
381 Status = WriteFileFromBuffer (OutputCapsuleName, FullCapsuleBufferSize, FullCapsuleBuffer);\r
382 Print (L"CapsuleApp: Write %s %r\n", OutputCapsuleName, Status);\r
383\r
384Done:\r
385 if (CapsuleBuffer != NULL) {\r
386 FreePool (CapsuleBuffer);\r
387 }\r
388\r
389 if (FullCapsuleBuffer != NULL) {\r
390 FreePool (FullCapsuleBuffer);\r
391 }\r
392\r
393 return Status;\r
394}\r
395\r
396/**\r
397 Clear capsule status variable.\r
398\r
399 @retval EFI_SUCCESS The capsule status variable is cleared.\r
400**/\r
401EFI_STATUS\r
402ClearCapsuleStatusVariable (\r
403 VOID\r
404 )\r
405{\r
406 EFI_STATUS Status;\r
407 UINT32 Index;\r
408 CHAR16 CapsuleVarName[20];\r
409 CHAR16 *TempVarName;\r
410 BOOLEAN Found;\r
411\r
412 StrCpyS (CapsuleVarName, sizeof (CapsuleVarName)/sizeof (CapsuleVarName[0]), L"Capsule");\r
413 TempVarName = CapsuleVarName + StrLen (CapsuleVarName);\r
414 Index = 0;\r
415\r
416 Found = FALSE;\r
417 while (TRUE) {\r
418 UnicodeSPrint (TempVarName, 5 * sizeof (CHAR16), L"%04x", Index);\r
419\r
420 Status = gRT->SetVariable (\r
421 CapsuleVarName,\r
422 &gEfiCapsuleReportGuid,\r
423 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
424 0,\r
425 (VOID *)NULL\r
426 );\r
427 if (Status == EFI_NOT_FOUND) {\r
428 //\r
429 // There is no more capsule variables, quit\r
430 //\r
431 break;\r
432 }\r
433\r
434 Found = TRUE;\r
435\r
436 Print (L"Clear %s %r\n", CapsuleVarName, Status);\r
437\r
438 Index++;\r
439 if (Index > 0xFFFF) {\r
440 break;\r
441 }\r
442 }\r
443\r
444 if (!Found) {\r
445 Print (L"No any Capsule#### variable found\n");\r
446 }\r
447\r
448 return EFI_SUCCESS;\r
449}\r
450\r
451/**\r
452 Build Gather list for a list of capsule images.\r
453\r
454 @param[in] CapsuleBuffer An array of pointer to capsule images\r
455 @param[in] FileSize An array of UINTN to capsule images size\r
456 @param[in] CapsuleNum The count of capsule images\r
457 @param[out] BlockDescriptors The block descriptors for the capsule images\r
458\r
459 @retval EFI_SUCCESS The block descriptors for the capsule images are constructed.\r
460**/\r
461EFI_STATUS\r
462BuildGatherList (\r
463 IN VOID **CapsuleBuffer,\r
464 IN UINTN *FileSize,\r
465 IN UINTN CapsuleNum,\r
466 OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors\r
467 )\r
468{\r
469 EFI_STATUS Status;\r
470 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1;\r
471 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors2;\r
472 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre;\r
473 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader;\r
474 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;\r
475 UINT8 *TempDataPtr;\r
476 UINTN SizeLeft;\r
477 UINTN Size;\r
478 INT32 Count;\r
479 INT32 Number;\r
480 UINTN Index;\r
481\r
482 TempBlockPtr = NULL;\r
483 BlockDescriptors1 = NULL;\r
484 BlockDescriptors2 = NULL;\r
485 BlockDescriptorPre = NULL;\r
486 BlockDescriptorsHeader = NULL;\r
487\r
488 for (Index = 0; Index < CapsuleNum; Index++) {\r
489 //\r
490 // Allocate memory for the descriptors.\r
491 //\r
492 if (NumberOfDescriptors == 1) {\r
493 Count = 2;\r
494 } else {\r
495 Count = (INT32)(NumberOfDescriptors + 2) / 2;\r
496 }\r
497\r
498 Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
499 BlockDescriptors1 = AllocateRuntimeZeroPool (Size);\r
500 if (BlockDescriptors1 == NULL) {\r
501 Print (L"CapsuleApp: failed to allocate memory for descriptors\n");\r
502 Status = EFI_OUT_OF_RESOURCES;\r
503 goto ERREXIT;\r
504 } else {\r
505 Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN)BlockDescriptors1);\r
506 Print (L"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN)CapsuleBuffer[Index], FileSize[Index]);\r
507 }\r
508\r
509 //\r
510 // Record descriptor header\r
511 //\r
512 if (Index == 0) {\r
513 BlockDescriptorsHeader = BlockDescriptors1;\r
514 }\r
515\r
516 if (BlockDescriptorPre != NULL) {\r
517 BlockDescriptorPre->Union.ContinuationPointer = (UINTN)BlockDescriptors1;\r
518 BlockDescriptorPre->Length = 0;\r
519 }\r
520\r
521 //\r
522 // Fill them in\r
523 //\r
524 TempBlockPtr = BlockDescriptors1;\r
525 TempDataPtr = CapsuleBuffer[Index];\r
526 SizeLeft = FileSize[Index];\r
527 for (Number = 0; (Number < Count - 1) && (SizeLeft != 0); Number++) {\r
528 //\r
529 // Divide remaining data in half\r
530 //\r
531 if (NumberOfDescriptors != 1) {\r
532 if (SizeLeft == 1) {\r
533 Size = 1;\r
534 } else {\r
535 Size = SizeLeft / 2;\r
536 }\r
537 } else {\r
538 Size = SizeLeft;\r
539 }\r
540\r
541 TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;\r
542 TempBlockPtr->Length = Size;\r
543 Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN)TempDataPtr, Size);\r
544 SizeLeft -= Size;\r
545 TempDataPtr += Size;\r
546 TempBlockPtr++;\r
547 }\r
548\r
549 //\r
550 // Allocate the second list, point the first block's last entry to point\r
551 // to this one, and fill this one in. Worst case is that the previous\r
552 // list only had one element that pointed here, so we need at least two\r
553 // elements -- one to point to all the data, another to terminate the list.\r
554 //\r
555 if ((NumberOfDescriptors != 1) && (SizeLeft != 0)) {\r
556 Count = (INT32)(NumberOfDescriptors + 2) - Count;\r
557 if (Count == 1) {\r
558 Count++;\r
559 }\r
560\r
561 Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR);\r
562 BlockDescriptors2 = AllocateRuntimeZeroPool (Size);\r
563 if (BlockDescriptors2 == NULL) {\r
564 Print (L"CapsuleApp: failed to allocate memory for descriptors\n");\r
565 Status = EFI_OUT_OF_RESOURCES;\r
566 goto ERREXIT;\r
567 }\r
568\r
569 //\r
570 // Point the first list's last element to point to this second list.\r
571 //\r
572 TempBlockPtr->Union.ContinuationPointer = (UINTN)BlockDescriptors2;\r
573\r
574 TempBlockPtr->Length = 0;\r
575 TempBlockPtr = BlockDescriptors2;\r
576 for (Number = 0; Number < Count - 1; Number++) {\r
577 //\r
578 // If second-to-last one, then dump rest to this element\r
579 //\r
580 if (Number == (Count - 2)) {\r
581 Size = SizeLeft;\r
582 } else {\r
583 //\r
584 // Divide remaining data in half\r
585 //\r
586 if (SizeLeft == 1) {\r
587 Size = 1;\r
588 } else {\r
589 Size = SizeLeft / 2;\r
590 }\r
591 }\r
592\r
593 TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr;\r
594 TempBlockPtr->Length = Size;\r
595 Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN)TempDataPtr, Size);\r
596 SizeLeft -= Size;\r
597 TempDataPtr += Size;\r
598 TempBlockPtr++;\r
599 if (SizeLeft == 0) {\r
600 break;\r
601 }\r
602 }\r
603 }\r
604\r
605 BlockDescriptorPre = TempBlockPtr;\r
606 BlockDescriptors1 = NULL;\r
607 }\r
608\r
609 //\r
610 // Null-terminate.\r
611 //\r
612 if (TempBlockPtr != NULL) {\r
613 TempBlockPtr->Union.ContinuationPointer = (UINTN)NULL;\r
614 TempBlockPtr->Length = 0;\r
615 *BlockDescriptors = BlockDescriptorsHeader;\r
616 }\r
617\r
618 return EFI_SUCCESS;\r
619\r
620ERREXIT:\r
621 if (BlockDescriptors1 != NULL) {\r
622 FreePool (BlockDescriptors1);\r
623 }\r
624\r
625 if (BlockDescriptors2 != NULL) {\r
626 FreePool (BlockDescriptors2);\r
627 }\r
628\r
629 return Status;\r
630}\r
631\r
632/**\r
633 Clear the Gather list for a list of capsule images.\r
634\r
635 @param[in] BlockDescriptors The block descriptors for the capsule images\r
636 @param[in] CapsuleNum The count of capsule images\r
637**/\r
638VOID\r
639CleanGatherList (\r
640 IN EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors,\r
641 IN UINTN CapsuleNum\r
642 )\r
643{\r
644 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr;\r
645 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr1;\r
646 EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr2;\r
647 UINTN Index;\r
648\r
649 if (BlockDescriptors != NULL) {\r
650 TempBlockPtr1 = BlockDescriptors;\r
651 while (1) {\r
652 TempBlockPtr = TempBlockPtr1;\r
653 for (Index = 0; Index < CapsuleNum; Index++) {\r
654 if (TempBlockPtr[Index].Length == 0) {\r
655 break;\r
656 }\r
657 }\r
658\r
659 if (TempBlockPtr[Index].Union.ContinuationPointer == (UINTN)NULL) {\r
660 break;\r
661 }\r
662\r
663 TempBlockPtr2 = (VOID *)((UINTN)TempBlockPtr[Index].Union.ContinuationPointer);\r
664 FreePool (TempBlockPtr1);\r
665 TempBlockPtr1 = TempBlockPtr2;\r
666 }\r
667 }\r
668}\r
669\r
670/**\r
671 Print APP usage.\r
672**/\r
673VOID\r
674PrintUsage (\r
675 VOID\r
676 )\r
677{\r
678 Print (L"CapsuleApp: usage\n");\r
679 Print (L" CapsuleApp <Capsule...> [-NR] [-OD [FSx]]\n");\r
680 Print (L" CapsuleApp -S\n");\r
681 Print (L" CapsuleApp -C\n");\r
682 Print (L" CapsuleApp -P\n");\r
683 Print (L" CapsuleApp -E\n");\r
684 Print (L" CapsuleApp -L\n");\r
685 Print (L" CapsuleApp -L INFO\n");\r
686 Print (L" CapsuleApp -F\n");\r
687 Print (L" CapsuleApp -G <BMP> -O <Capsule>\n");\r
688 Print (L" CapsuleApp -N <Capsule> -O <NestedCapsule>\n");\r
689 Print (L" CapsuleApp -D <Capsule>\n");\r
690 Print (L" CapsuleApp -P GET <ImageTypeId> <Index> -O <FileName>\n");\r
691 Print (L"Parameter:\n");\r
692 Print (L" -NR: No reset will be triggered for the capsule\n");\r
693 Print (L" with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET.\n");\r
694 Print (L" -OD: Delivery of Capsules via file on Mass Storage device.\n");\r
695 Print (L" -S: Dump capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");\r
696 Print (L" which is defined in UEFI specification.\n");\r
697 Print (L" -C: Clear capsule report variable (EFI_CAPSULE_REPORT_GUID),\n");\r
698 Print (L" which is defined in UEFI specification.\n");\r
699 Print (L" -P: Dump UEFI FMP protocol info, or get image with specified\n");\r
700 Print (L" ImageTypeId and Index (decimal format) to a file if 'GET'\n");\r
701 Print (L" option is used.\n");\r
702 Print (L" -E: Dump UEFI ESRT table info.\n");\r
703 Print (L" -L: Dump provisioned capsule image information.\n");\r
704 Print (L" -F: Dump all EFI System Partition.\n");\r
705 Print (L" -G: Convert a BMP file to be an UX capsule,\n");\r
706 Print (L" according to Windows Firmware Update document\n");\r
707 Print (L" -N: Append a Capsule Header to an existing FMP capsule image\n");\r
708 Print (L" with its ImageTypeId supported by the system,\n");\r
709 Print (L" according to Windows Firmware Update document\n");\r
710 Print (L" -O: Output new Capsule file name\n");\r
711 Print (L" -D: Dump Capsule image header information, image payload\n");\r
712 Print (L" information if it is an UX capsule and FMP header\n");\r
713 Print (L" information if it is a FMP capsule.\n");\r
714}\r
715\r
716/**\r
717 Update Capsule image.\r
718\r
719 @param[in] ImageHandle The image handle.\r
720 @param[in] SystemTable The system table.\r
721\r
722 @retval EFI_SUCCESS Command completed successfully.\r
723 @retval EFI_UNSUPPORTED Command usage unsupported.\r
724 @retval EFI_INVALID_PARAMETER Command usage invalid.\r
725 @retval EFI_NOT_FOUND The input file can't be found.\r
726**/\r
727EFI_STATUS\r
728EFIAPI\r
729UefiMain (\r
730 IN EFI_HANDLE ImageHandle,\r
731 IN EFI_SYSTEM_TABLE *SystemTable\r
732 )\r
733{\r
734 EFI_STATUS Status;\r
735 RETURN_STATUS RStatus;\r
736 UINTN CapsuleBufferSize[MAX_CAPSULE_NUM];\r
737 VOID *CapsuleBuffer[MAX_CAPSULE_NUM];\r
738 EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors;\r
739 EFI_CAPSULE_HEADER *CapsuleHeaderArray[MAX_CAPSULE_NUM + 1];\r
740 UINT64 MaxCapsuleSize;\r
741 EFI_RESET_TYPE ResetType;\r
742 BOOLEAN NeedReset;\r
743 BOOLEAN NoReset;\r
744 BOOLEAN CapsuleOnDisk;\r
745 CHAR16 *CapsuleName;\r
746 CHAR16 *CapsuleNames[MAX_CAPSULE_NUM];\r
747 CHAR16 *MapFsStr;\r
748 UINTN CapsuleNum;\r
749 UINTN Index;\r
750 UINTN ParaOdIndex;\r
751 UINTN ParaNrIndex;\r
752 EFI_GUID ImageTypeId;\r
753 UINTN ImageIndex;\r
754\r
755 BlockDescriptors = NULL;\r
756 MapFsStr = NULL;\r
757 CapsuleNum = 0;\r
758\r
759 Status = GetArg ();\r
760 if (EFI_ERROR (Status)) {\r
761 Print (L"Please use UEFI SHELL to run this application!\n", Status);\r
762 return Status;\r
763 }\r
764\r
765 if (Argc < 2) {\r
766 PrintUsage ();\r
767 return EFI_UNSUPPORTED;\r
768 }\r
769\r
770 if (StrCmp (Argv[1], L"-D") == 0) {\r
771 if (Argc != 3) {\r
772 Print (L"CapsuleApp: Incorrect parameter count.\n");\r
773 return EFI_UNSUPPORTED;\r
774 }\r
775\r
776 Status = DumpCapsule (Argv[2]);\r
777 return Status;\r
778 }\r
779\r
780 if (StrCmp (Argv[1], L"-G") == 0) {\r
781 Status = CreateBmpFmp ();\r
782 return Status;\r
783 }\r
784\r
785 if (StrCmp (Argv[1], L"-N") == 0) {\r
786 Status = CreateNestedFmp ();\r
787 return Status;\r
788 }\r
789\r
790 if (StrCmp (Argv[1], L"-S") == 0) {\r
791 Status = DumpCapsuleStatusVariable ();\r
792 return EFI_SUCCESS;\r
793 }\r
794\r
795 if (StrCmp (Argv[1], L"-C") == 0) {\r
796 Status = ClearCapsuleStatusVariable ();\r
797 return Status;\r
798 }\r
799\r
800 if (StrCmp (Argv[1], L"-P") == 0) {\r
801 if (Argc == 2) {\r
802 DumpFmpData ();\r
803 }\r
804\r
805 if (Argc >= 3) {\r
806 if (StrCmp (Argv[2], L"GET") != 0) {\r
807 Print (L"CapsuleApp: Unrecognized option(%s).\n", Argv[2]);\r
808 return EFI_UNSUPPORTED;\r
809 } else {\r
810 if (Argc != 7) {\r
811 Print (L"CapsuleApp: Incorrect parameter count.\n");\r
812 return EFI_UNSUPPORTED;\r
813 }\r
814\r
815 //\r
816 // FMP->GetImage()\r
817 //\r
818 RStatus = StrToGuid (Argv[3], &ImageTypeId);\r
819 if (RETURN_ERROR (RStatus) || (Argv[3][GUID_STRING_LENGTH] != L'\0')) {\r
820 Print (L"Invalid ImageTypeId - %s\n", Argv[3]);\r
821 return EFI_INVALID_PARAMETER;\r
822 }\r
823\r
824 ImageIndex = StrDecimalToUintn (Argv[4]);\r
825 if (StrCmp (Argv[5], L"-O") != 0) {\r
826 Print (L"CapsuleApp: NO output file name.\n");\r
827 return EFI_UNSUPPORTED;\r
828 }\r
829\r
830 DumpFmpImage (&ImageTypeId, ImageIndex, Argv[6]);\r
831 }\r
832 }\r
833\r
834 return EFI_SUCCESS;\r
835 }\r
836\r
837 if (StrCmp (Argv[1], L"-E") == 0) {\r
838 DumpEsrtData ();\r
839 return EFI_SUCCESS;\r
840 }\r
841\r
842 if (StrCmp (Argv[1], L"-L") == 0) {\r
843 if ((Argc >= 3) && (StrCmp (Argv[2], L"INFO") == 0)) {\r
844 DumpProvisionedCapsule (TRUE);\r
845 } else {\r
846 DumpProvisionedCapsule (FALSE);\r
847 }\r
848\r
849 return EFI_SUCCESS;\r
850 }\r
851\r
852 if (StrCmp (Argv[1], L"-F") == 0) {\r
853 DumpAllEfiSysPartition ();\r
854 return EFI_SUCCESS;\r
855 }\r
856\r
857 if (Argv[1][0] == L'-') {\r
858 Print (L"CapsuleApp: Unrecognized option(%s).\n", Argv[1]);\r
859 return EFI_UNSUPPORTED;\r
860 }\r
861\r
862 CapsuleFirstIndex = 1;\r
863 NoReset = FALSE;\r
864 CapsuleOnDisk = FALSE;\r
865 ParaOdIndex = 0;\r
866 ParaNrIndex = 0;\r
867\r
868 for (Index = 1; Index < Argc; Index++) {\r
869 if (StrCmp (Argv[Index], L"-OD") == 0) {\r
870 ParaOdIndex = Index;\r
871 CapsuleOnDisk = TRUE;\r
872 } else if (StrCmp (Argv[Index], L"-NR") == 0) {\r
873 ParaNrIndex = Index;\r
874 NoReset = TRUE;\r
875 }\r
876 }\r
877\r
878 if (ParaOdIndex > ParaNrIndex) {\r
879 if (ParaNrIndex != 0) {\r
880 CapsuleLastIndex = ParaNrIndex - 1;\r
881 } else {\r
882 CapsuleLastIndex = ParaOdIndex - 1;\r
883 }\r
884\r
885 if (ParaOdIndex == Argc -1) {\r
886 MapFsStr = NULL;\r
887 } else if (ParaOdIndex == Argc - 2) {\r
888 MapFsStr = Argv[Argc-1];\r
889 } else {\r
890 Print (L"CapsuleApp: Cannot specify more than one FS mapping!\n");\r
891 Status = EFI_INVALID_PARAMETER;\r
892 goto Done;\r
893 }\r
894 } else if (ParaOdIndex < ParaNrIndex) {\r
895 if (ParaOdIndex != 0) {\r
896 CapsuleLastIndex = ParaOdIndex - 1;\r
897 if (ParaOdIndex == ParaNrIndex - 1) {\r
898 MapFsStr = NULL;\r
899 } else if (ParaOdIndex == ParaNrIndex - 2) {\r
900 MapFsStr = Argv[ParaOdIndex + 1];\r
901 } else {\r
902 Print (L"CapsuleApp: Cannot specify more than one FS mapping!\n");\r
903 Status = EFI_INVALID_PARAMETER;\r
904 goto Done;\r
905 }\r
906 } else {\r
907 CapsuleLastIndex = ParaNrIndex - 1;\r
908 }\r
909 } else {\r
910 CapsuleLastIndex = Argc - 1;\r
911 }\r
912\r
913 CapsuleNum = CapsuleLastIndex - CapsuleFirstIndex + 1;\r
914\r
915 if (CapsuleFirstIndex > CapsuleLastIndex) {\r
916 Print (L"CapsuleApp: NO capsule image.\n");\r
917 return EFI_UNSUPPORTED;\r
918 }\r
919\r
920 if (CapsuleNum > MAX_CAPSULE_NUM) {\r
921 Print (L"CapsuleApp: Too many capsule images.\n");\r
922 return EFI_UNSUPPORTED;\r
923 }\r
924\r
925 ZeroMem (&CapsuleBuffer, sizeof (CapsuleBuffer));\r
926 ZeroMem (&CapsuleBufferSize, sizeof (CapsuleBufferSize));\r
927 BlockDescriptors = NULL;\r
928\r
929 for (Index = 0; Index < CapsuleNum; Index++) {\r
930 CapsuleName = Argv[CapsuleFirstIndex + Index];\r
931 Status = ReadFileToBuffer (CapsuleName, &CapsuleBufferSize[Index], &CapsuleBuffer[Index]);\r
932 if (EFI_ERROR (Status)) {\r
933 Print (L"CapsuleApp: capsule image (%s) is not found.\n", CapsuleName);\r
934 goto Done;\r
935 }\r
936\r
937 if (!IsValidCapsuleHeader (CapsuleBuffer[Index], CapsuleBufferSize[Index])) {\r
938 Print (L"CapsuleApp: Capsule image (%s) is not a valid capsule.\n", CapsuleName);\r
939 return EFI_INVALID_PARAMETER;\r
940 }\r
941\r
942 CapsuleNames[Index] = CapsuleName;\r
943 }\r
944\r
945 //\r
946 // Every capsule use 2 descriptor 1 for data 1 for end\r
947 //\r
948 Status = BuildGatherList (CapsuleBuffer, CapsuleBufferSize, CapsuleNum, &BlockDescriptors);\r
949 if (EFI_ERROR (Status)) {\r
950 goto Done;\r
951 }\r
952\r
953 //\r
954 // Call the runtime service capsule.\r
955 //\r
956 NeedReset = FALSE;\r
957 for (Index = 0; Index < CapsuleNum; Index++) {\r
958 CapsuleHeaderArray[Index] = (EFI_CAPSULE_HEADER *)CapsuleBuffer[Index];\r
959 if ((CapsuleHeaderArray[Index]->Flags & CAPSULE_FLAGS_PERSIST_ACROSS_RESET) != 0) {\r
960 NeedReset = TRUE;\r
961 }\r
962 }\r
963\r
964 CapsuleHeaderArray[CapsuleNum] = NULL;\r
965\r
966 //\r
967 // Inquire platform capability of UpdateCapsule.\r
968 //\r
969 Status = gRT->QueryCapsuleCapabilities (CapsuleHeaderArray, CapsuleNum, &MaxCapsuleSize, &ResetType);\r
970 if (EFI_ERROR (Status)) {\r
971 Print (L"CapsuleApp: failed to query capsule capability - %r\n", Status);\r
972 goto Done;\r
973 }\r
974\r
975 for (Index = 0; Index < CapsuleNum; Index++) {\r
976 if (CapsuleBufferSize[Index] > MaxCapsuleSize) {\r
977 Print (L"CapsuleApp: capsule is too large to update, %ld is allowed\n", MaxCapsuleSize);\r
978 Status = EFI_UNSUPPORTED;\r
979 goto Done;\r
980 }\r
981 }\r
982\r
983 //\r
984 // Check whether is capsule on disk.\r
985 //\r
986 if (CapsuleOnDisk) {\r
987 Status = ProcessCapsuleOnDisk (CapsuleBuffer, CapsuleBufferSize, CapsuleNames, MapFsStr, CapsuleNum);\r
988 if (Status != EFI_SUCCESS) {\r
989 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
990 goto Done;\r
991 } else {\r
992 if (!NoReset) {\r
993 gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
994 } else {\r
995 goto Done;\r
996 }\r
997 }\r
998 }\r
999\r
1000 //\r
1001 // Check whether the input capsule image has the flag of persist across system reset.\r
1002 //\r
1003 if (NeedReset) {\r
1004 Status = gRT->UpdateCapsule (CapsuleHeaderArray, CapsuleNum, (UINTN)BlockDescriptors);\r
1005 if (Status != EFI_SUCCESS) {\r
1006 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
1007 goto Done;\r
1008 }\r
1009\r
1010 //\r
1011 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET + CAPSULE_FLAGS_INITIATE_RESET,\r
1012 // a system reset should have been triggered by gRT->UpdateCapsule() calling above.\r
1013 //\r
1014 // For capsule with CAPSULE_FLAGS_PERSIST_ACROSS_RESET and without CAPSULE_FLAGS_INITIATE_RESET,\r
1015 // check if -NR (no-reset) has been specified or not.\r
1016 //\r
1017 if (!NoReset) {\r
1018 //\r
1019 // For capsule who has reset flag and no -NR (no-reset) has been specified, after calling UpdateCapsule service,\r
1020 // trigger a system reset to process capsule persist across a system reset.\r
1021 //\r
1022 gRT->ResetSystem (ResetType, EFI_SUCCESS, 0, NULL);\r
1023 }\r
1024 } else {\r
1025 //\r
1026 // For capsule who has no reset flag, only call UpdateCapsule Service without a\r
1027 // system reset. The service will process the capsule immediately.\r
1028 //\r
1029 Status = gRT->UpdateCapsule (CapsuleHeaderArray, CapsuleNum, (UINTN)BlockDescriptors);\r
1030 if (Status != EFI_SUCCESS) {\r
1031 Print (L"CapsuleApp: failed to update capsule - %r\n", Status);\r
1032 }\r
1033 }\r
1034\r
1035 Status = EFI_SUCCESS;\r
1036\r
1037Done:\r
1038 for (Index = 0; Index < CapsuleNum; Index++) {\r
1039 if (CapsuleBuffer[Index] != NULL) {\r
1040 FreePool (CapsuleBuffer[Index]);\r
1041 }\r
1042 }\r
1043\r
1044 CleanGatherList (BlockDescriptors, CapsuleNum);\r
1045\r
1046 return Status;\r
1047}\r