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