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