VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleLib.c

Last change on this file was 108794, checked in by vboxsync, 4 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 54.6 KB
Line 
1/** @file
2 DXE capsule library.
3
4 Caution: This module requires additional review when modified.
5 This module will have external input - capsule image.
6 This external input must be validated carefully to avoid security issue like
7 buffer overflow, integer overflow.
8
9 SupportCapsuleImage(), ProcessCapsuleImage(), IsValidCapsuleHeader(),
10 ValidateFmpCapsule(), and DisplayCapsuleImage() receives untrusted input and
11 performs basic validation.
12
13 Copyright (c) 2016 - 2024, Intel Corporation. All rights reserved.<BR>
14 Copyright (c) 2024, Ampere Computing LLC. All rights reserved.<BR>
15 SPDX-License-Identifier: BSD-2-Clause-Patent
16
17**/
18
19#include <PiDxe.h>
20
21#include <IndustryStandard/WindowsUxCapsule.h>
22
23#include <Guid/FmpCapsule.h>
24#include <Guid/SystemResourceTable.h>
25#include <Guid/EventGroup.h>
26
27#include <Library/BaseLib.h>
28#include <Library/DebugLib.h>
29#include <Library/BaseMemoryLib.h>
30#include <Library/DxeServicesTableLib.h>
31#include <Library/UefiBootServicesTableLib.h>
32#include <Library/UefiRuntimeServicesTableLib.h>
33#include <Library/MemoryAllocationLib.h>
34#include <Library/CapsuleLib.h>
35#include <Library/DevicePathLib.h>
36#include <Library/UefiLib.h>
37#include <Library/BmpSupportLib.h>
38
39#include <Protocol/GraphicsOutput.h>
40#include <Protocol/EsrtManagement.h>
41#include <Protocol/FirmwareManagement.h>
42#include <Protocol/FirmwareManagementProgress.h>
43#include <Protocol/DevicePath.h>
44
45EFI_SYSTEM_RESOURCE_TABLE *mEsrtTable = NULL;
46
47BOOLEAN mDxeCapsuleLibEndOfDxe = FALSE;
48EFI_EVENT mDxeCapsuleLibEndOfDxeEvent = NULL;
49
50EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL *mFmpProgress = NULL;
51
52BOOLEAN mDxeCapsuleLibIsExitBootService = FALSE;
53
54/**
55 Initialize capsule related variables.
56**/
57VOID
58InitCapsuleVariable (
59 VOID
60 );
61
62/**
63 Record capsule status variable.
64
65 @param[in] CapsuleHeader The capsule image header
66 @param[in] CapsuleStatus The capsule process stauts
67
68 @retval EFI_SUCCESS The capsule status variable is recorded.
69 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
70**/
71EFI_STATUS
72RecordCapsuleStatusVariable (
73 IN EFI_CAPSULE_HEADER *CapsuleHeader,
74 IN EFI_STATUS CapsuleStatus
75 );
76
77/**
78 Record FMP capsule status variable.
79
80 @param[in] CapsuleHeader The capsule image header
81 @param[in] CapsuleStatus The capsule process stauts
82 @param[in] PayloadIndex FMP payload index
83 @param[in] ImageHeader FMP image header
84 @param[in] FmpDevicePath DevicePath associated with the FMP producer
85 @param[in] CapFileName Capsule file name
86
87 @retval EFI_SUCCESS The capsule status variable is recorded.
88 @retval EFI_OUT_OF_RESOURCES No resource to record the capsule status variable.
89**/
90EFI_STATUS
91RecordFmpCapsuleStatusVariable (
92 IN EFI_CAPSULE_HEADER *CapsuleHeader,
93 IN EFI_STATUS CapsuleStatus,
94 IN UINTN PayloadIndex,
95 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
96 IN EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath OPTIONAL,
97 IN CHAR16 *CapFileName OPTIONAL
98 );
99
100/**
101 Function indicate the current completion progress of the firmware
102 update. Platform may override with own specific progress function.
103
104 @param[in] Completion A value between 1 and 100 indicating the current
105 completion progress of the firmware update
106
107 @retval EFI_SUCESS The capsule update progress was updated.
108 @retval EFI_INVALID_PARAMETER Completion is greater than 100%.
109**/
110EFI_STATUS
111EFIAPI
112UpdateImageProgress (
113 IN UINTN Completion
114 );
115
116/**
117 Return if this capsule is a capsule name capsule, based upon CapsuleHeader.
118
119 @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
120
121 @retval TRUE It is a capsule name capsule.
122 @retval FALSE It is not a capsule name capsule.
123**/
124BOOLEAN
125IsCapsuleNameCapsule (
126 IN EFI_CAPSULE_HEADER *CapsuleHeader
127 )
128{
129 return CompareGuid (&CapsuleHeader->CapsuleGuid, &gEdkiiCapsuleOnDiskNameGuid);
130}
131
132/**
133 Return if this CapsuleGuid is a FMP capsule GUID or not.
134
135 @param[in] CapsuleGuid A pointer to EFI_GUID
136
137 @retval TRUE It is a FMP capsule GUID.
138 @retval FALSE It is not a FMP capsule GUID.
139**/
140BOOLEAN
141IsFmpCapsuleGuid (
142 IN EFI_GUID *CapsuleGuid
143 )
144{
145 if (CompareGuid (&gEfiFmpCapsuleGuid, CapsuleGuid)) {
146 return TRUE;
147 }
148
149 return FALSE;
150}
151
152/**
153 Validate if it is valid capsule header
154
155 Caution: This function may receive untrusted input.
156
157 This function assumes the caller provided correct CapsuleHeader pointer
158 and CapsuleSize.
159
160 This function validates the fields in EFI_CAPSULE_HEADER.
161
162 @param[in] CapsuleHeader Points to a capsule header.
163 @param[in] CapsuleSize Size of the whole capsule image.
164
165**/
166BOOLEAN
167IsValidCapsuleHeader (
168 IN EFI_CAPSULE_HEADER *CapsuleHeader,
169 IN UINT64 CapsuleSize
170 )
171{
172 if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {
173 return FALSE;
174 }
175
176 if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
177 return FALSE;
178 }
179
180 return TRUE;
181}
182
183/**
184 Validate Fmp capsules layout.
185
186 Caution: This function may receive untrusted input.
187
188 This function assumes the caller validated the capsule by using
189 IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.
190 The capsule buffer size is CapsuleHeader->CapsuleImageSize.
191
192 This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
193 and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.
194
195 This function need support nested FMP capsule.
196
197 @param[in] CapsuleHeader Points to a capsule header.
198 @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.
199
200 @retval EFI_SUCESS Input capsule is a correct FMP capsule.
201 @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.
202**/
203EFI_STATUS
204ValidateFmpCapsule (
205 IN EFI_CAPSULE_HEADER *CapsuleHeader,
206 OUT UINT16 *EmbeddedDriverCount OPTIONAL
207 )
208{
209 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
210 UINT8 *EndOfCapsule;
211 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
212 UINT8 *EndOfPayload;
213 UINT64 *ItemOffsetList;
214 UINT32 ItemNum;
215 UINTN Index;
216 UINTN FmpCapsuleSize;
217 UINTN FmpCapsuleHeaderSize;
218 UINT64 FmpImageSize;
219 UINTN FmpImageHeaderSize;
220
221 if (!IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
222 return ValidateFmpCapsule ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), EmbeddedDriverCount);
223 }
224
225 if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {
226 DEBUG ((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));
227 return EFI_INVALID_PARAMETER;
228 }
229
230 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
231 EndOfCapsule = (UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize;
232 FmpCapsuleSize = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;
233
234 if (FmpCapsuleSize < sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {
235 DEBUG ((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));
236 return EFI_INVALID_PARAMETER;
237 }
238
239 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER
240 if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
241 DEBUG ((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));
242 return EFI_INVALID_PARAMETER;
243 }
244
245 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
246
247 // No overflow
248 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
249
250 if ((FmpCapsuleSize - sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof (UINT64) < ItemNum) {
251 DEBUG ((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));
252 return EFI_INVALID_PARAMETER;
253 }
254
255 FmpCapsuleHeaderSize = sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof (UINT64)*ItemNum;
256
257 // Check ItemOffsetList
258 for (Index = 0; Index < ItemNum; Index++) {
259 if (ItemOffsetList[Index] >= FmpCapsuleSize) {
260 DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));
261 return EFI_INVALID_PARAMETER;
262 }
263
264 if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {
265 DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));
266 return EFI_INVALID_PARAMETER;
267 }
268
269 //
270 // All the address in ItemOffsetList must be stored in ascending order
271 //
272 if (Index > 0) {
273 if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {
274 DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index - 1, ItemOffsetList[Index - 1]));
275 return EFI_INVALID_PARAMETER;
276 }
277 }
278 }
279
280 // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER
281 for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
282 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
283 if (Index == ItemNum - 1) {
284 EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader);
285 } else {
286 EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1];
287 }
288
289 FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];
290
291 FmpImageHeaderSize = sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);
292 if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||
293 (ImageHeader->Version < 1))
294 {
295 DEBUG ((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));
296 return EFI_INVALID_PARAMETER;
297 }
298
299 if (ImageHeader->Version == 1) {
300 FmpImageHeaderSize = OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
301 } else if (ImageHeader->Version == 2) {
302 FmpImageHeaderSize = OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
303 }
304
305 if (FmpImageSize < FmpImageHeaderSize) {
306 DEBUG ((DEBUG_ERROR, "FmpImageSize(0x%lx) < FmpImageHeaderSize(0x%x)\n", FmpImageSize, FmpImageHeaderSize));
307 return EFI_INVALID_PARAMETER;
308 }
309
310 // No overflow
311 if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {
312 DEBUG ((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize));
313 return EFI_INVALID_PARAMETER;
314 }
315 }
316
317 if (ItemNum == 0) {
318 //
319 // No driver & payload element in FMP
320 //
321 EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);
322 if (EndOfPayload != EndOfCapsule) {
323 DEBUG ((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule));
324 return EFI_INVALID_PARAMETER;
325 }
326
327 return EFI_UNSUPPORTED;
328 }
329
330 if (EmbeddedDriverCount != NULL) {
331 *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;
332 }
333
334 return EFI_SUCCESS;
335}
336
337/**
338 Those capsules supported by the firmwares.
339
340 Caution: This function may receive untrusted input.
341
342 @param[in] CapsuleHeader Points to a capsule header.
343
344 @retval EFI_SUCESS Input capsule is supported by firmware.
345 @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
346**/
347EFI_STATUS
348DisplayCapsuleImage (
349 IN EFI_CAPSULE_HEADER *CapsuleHeader
350 )
351{
352 DISPLAY_DISPLAY_PAYLOAD *ImagePayload;
353 UINTN PayloadSize;
354 EFI_STATUS Status;
355 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
356 UINTN BltSize;
357 UINTN Height;
358 UINTN Width;
359 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
360
361 //
362 // UX capsule doesn't have extended header entries.
363 //
364 if (CapsuleHeader->HeaderSize != sizeof (EFI_CAPSULE_HEADER)) {
365 return EFI_UNSUPPORTED;
366 }
367
368 ImagePayload = (DISPLAY_DISPLAY_PAYLOAD *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize);
369 //
370 // (CapsuleImageSize > HeaderSize) is guaranteed by IsValidCapsuleHeader().
371 //
372 PayloadSize = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
373
374 //
375 // Make sure the image payload at least contain the DISPLAY_DISPLAY_PAYLOAD header.
376 // Further size check is performed by the logic translating BMP to GOP BLT.
377 //
378 if (PayloadSize <= sizeof (DISPLAY_DISPLAY_PAYLOAD)) {
379 return EFI_INVALID_PARAMETER;
380 }
381
382 if (ImagePayload->Version != 1) {
383 return EFI_UNSUPPORTED;
384 }
385
386 if (CalculateCheckSum8 ((UINT8 *)CapsuleHeader, CapsuleHeader->CapsuleImageSize) != 0) {
387 return EFI_UNSUPPORTED;
388 }
389
390 //
391 // Only Support Bitmap by now
392 //
393 if (ImagePayload->ImageType != 0) {
394 return EFI_UNSUPPORTED;
395 }
396
397 //
398 // Try to open GOP
399 //
400 Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **)&GraphicsOutput);
401 if (EFI_ERROR (Status)) {
402 Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&GraphicsOutput);
403 if (EFI_ERROR (Status)) {
404 return EFI_UNSUPPORTED;
405 }
406 }
407
408 if (GraphicsOutput->Mode->Mode != ImagePayload->Mode) {
409 return EFI_UNSUPPORTED;
410 }
411
412 Blt = NULL;
413 Width = 0;
414 Height = 0;
415 Status = TranslateBmpToGopBlt (
416 ImagePayload + 1,
417 PayloadSize - sizeof (DISPLAY_DISPLAY_PAYLOAD),
418 &Blt,
419 &BltSize,
420 &Height,
421 &Width
422 );
423
424 if (EFI_ERROR (Status)) {
425 return Status;
426 }
427
428 Status = GraphicsOutput->Blt (
429 GraphicsOutput,
430 Blt,
431 EfiBltBufferToVideo,
432 0,
433 0,
434 (UINTN)ImagePayload->OffsetX,
435 (UINTN)ImagePayload->OffsetY,
436 Width,
437 Height,
438 Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
439 );
440
441 FreePool (Blt);
442
443 return Status;
444}
445
446/**
447 Dump FMP information.
448
449 @param[in] ImageInfoSize The size of ImageInfo, in bytes.
450 @param[in] ImageInfo A pointer to EFI_FIRMWARE_IMAGE_DESCRIPTOR.
451 @param[in] DescriptorVersion The version of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
452 @param[in] DescriptorCount The count of EFI_FIRMWARE_IMAGE_DESCRIPTOR.
453 @param[in] DescriptorSize The size of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR, in bytes.
454 @param[in] PackageVersion The version of package.
455 @param[in] PackageVersionName The version name of package.
456**/
457VOID
458DumpFmpImageInfo (
459 IN UINTN ImageInfoSize,
460 IN EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
461 IN UINT32 DescriptorVersion,
462 IN UINT8 DescriptorCount,
463 IN UINTN DescriptorSize,
464 IN UINT32 PackageVersion,
465 IN CHAR16 *PackageVersionName
466 )
467{
468 EFI_FIRMWARE_IMAGE_DESCRIPTOR *CurrentImageInfo;
469 UINTN Index;
470
471 DEBUG ((DEBUG_VERBOSE, " DescriptorVersion - 0x%x\n", DescriptorVersion));
472 DEBUG ((DEBUG_VERBOSE, " DescriptorCount - 0x%x\n", DescriptorCount));
473 DEBUG ((DEBUG_VERBOSE, " DescriptorSize - 0x%x\n", DescriptorSize));
474 DEBUG ((DEBUG_VERBOSE, " PackageVersion - 0x%x\n", PackageVersion));
475 DEBUG ((DEBUG_VERBOSE, " PackageVersionName - %s\n\n", PackageVersionName));
476 CurrentImageInfo = ImageInfo;
477 for (Index = 0; Index < DescriptorCount; Index++) {
478 DEBUG ((DEBUG_VERBOSE, " ImageDescriptor (%d)\n", Index));
479 DEBUG ((DEBUG_VERBOSE, " ImageIndex - 0x%x\n", CurrentImageInfo->ImageIndex));
480 DEBUG ((DEBUG_VERBOSE, " ImageTypeId - %g\n", &CurrentImageInfo->ImageTypeId));
481 DEBUG ((DEBUG_VERBOSE, " ImageId - 0x%lx\n", CurrentImageInfo->ImageId));
482 DEBUG ((DEBUG_VERBOSE, " ImageIdName - %s\n", CurrentImageInfo->ImageIdName));
483 DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", CurrentImageInfo->Version));
484 DEBUG ((DEBUG_VERBOSE, " VersionName - %s\n", CurrentImageInfo->VersionName));
485 DEBUG ((DEBUG_VERBOSE, " Size - 0x%x\n", CurrentImageInfo->Size));
486 DEBUG ((DEBUG_VERBOSE, " AttributesSupported - 0x%lx\n", CurrentImageInfo->AttributesSupported));
487 DEBUG ((DEBUG_VERBOSE, " AttributesSetting - 0x%lx\n", CurrentImageInfo->AttributesSetting));
488 DEBUG ((DEBUG_VERBOSE, " Compatibilities - 0x%lx\n", CurrentImageInfo->Compatibilities));
489 if (DescriptorVersion > 1) {
490 DEBUG ((DEBUG_VERBOSE, " LowestSupportedImageVersion - 0x%x\n", CurrentImageInfo->LowestSupportedImageVersion));
491 if (DescriptorVersion > 2) {
492 DEBUG ((DEBUG_VERBOSE, " LastAttemptVersion - 0x%x\n", CurrentImageInfo->LastAttemptVersion));
493 DEBUG ((DEBUG_VERBOSE, " LastAttemptStatus - 0x%x\n", CurrentImageInfo->LastAttemptStatus));
494 DEBUG ((DEBUG_VERBOSE, " HardwareInstance - 0x%lx\n", CurrentImageInfo->HardwareInstance));
495 }
496 }
497
498 //
499 // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
500 //
501 CurrentImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)CurrentImageInfo + DescriptorSize);
502 }
503}
504
505/**
506 Dump a non-nested FMP capsule.
507
508 @param[in] CapsuleHeader A pointer to CapsuleHeader
509**/
510VOID
511DumpFmpCapsule (
512 IN EFI_CAPSULE_HEADER *CapsuleHeader
513 )
514{
515 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
516 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
517 UINTN Index;
518 UINT64 *ItemOffsetList;
519
520 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
521
522 DEBUG ((DEBUG_VERBOSE, "FmpCapsule:\n"));
523 DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", FmpCapsuleHeader->Version));
524 DEBUG ((DEBUG_VERBOSE, " EmbeddedDriverCount - 0x%x\n", FmpCapsuleHeader->EmbeddedDriverCount));
525 DEBUG ((DEBUG_VERBOSE, " PayloadItemCount - 0x%x\n", FmpCapsuleHeader->PayloadItemCount));
526
527 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
528 for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
529 DEBUG ((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));
530 }
531
532 for ( ; Index < (UINT32)FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount; Index++) {
533 DEBUG ((DEBUG_VERBOSE, " ItemOffsetList[%d] - 0x%lx\n", Index, ItemOffsetList[Index]));
534 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
535
536 DEBUG ((DEBUG_VERBOSE, " ImageHeader:\n"));
537 DEBUG ((DEBUG_VERBOSE, " Version - 0x%x\n", ImageHeader->Version));
538 DEBUG ((DEBUG_VERBOSE, " UpdateImageTypeId - %g\n", &ImageHeader->UpdateImageTypeId));
539 DEBUG ((DEBUG_VERBOSE, " UpdateImageIndex - 0x%x\n", ImageHeader->UpdateImageIndex));
540 DEBUG ((DEBUG_VERBOSE, " UpdateImageSize - 0x%x\n", ImageHeader->UpdateImageSize));
541 DEBUG ((DEBUG_VERBOSE, " UpdateVendorCodeSize - 0x%x\n", ImageHeader->UpdateVendorCodeSize));
542 if (ImageHeader->Version >= 2) {
543 DEBUG ((DEBUG_VERBOSE, " UpdateHardwareInstance - 0x%lx\n", ImageHeader->UpdateHardwareInstance));
544 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
545 DEBUG ((DEBUG_VERBOSE, " ImageCapsuleSupport - 0x%lx\n", ImageHeader->ImageCapsuleSupport));
546 }
547 }
548 }
549}
550
551/**
552 Dump all FMP information.
553**/
554VOID
555DumpAllFmpInfo (
556 VOID
557 )
558{
559 EFI_STATUS Status;
560 EFI_HANDLE *HandleBuffer;
561 UINTN NumberOfHandles;
562 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
563 UINTN Index;
564 UINTN ImageInfoSize;
565 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
566 UINT32 FmpImageInfoDescriptorVer;
567 UINT8 FmpImageInfoCount;
568 UINTN DescriptorSize;
569 UINT32 PackageVersion;
570 CHAR16 *PackageVersionName;
571
572 Status = gBS->LocateHandleBuffer (
573 ByProtocol,
574 &gEfiFirmwareManagementProtocolGuid,
575 NULL,
576 &NumberOfHandles,
577 &HandleBuffer
578 );
579 if (EFI_ERROR (Status)) {
580 return;
581 }
582
583 for (Index = 0; Index < NumberOfHandles; Index++) {
584 Status = gBS->HandleProtocol (
585 HandleBuffer[Index],
586 &gEfiFirmwareManagementProtocolGuid,
587 (VOID **)&Fmp
588 );
589 if (EFI_ERROR (Status)) {
590 continue;
591 }
592
593 ImageInfoSize = 0;
594 Status = Fmp->GetImageInfo (
595 Fmp,
596 &ImageInfoSize,
597 NULL,
598 NULL,
599 NULL,
600 NULL,
601 NULL,
602 NULL
603 );
604 if (Status != EFI_BUFFER_TOO_SMALL) {
605 continue;
606 }
607
608 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
609 if (FmpImageInfoBuf == NULL) {
610 continue;
611 }
612
613 PackageVersionName = NULL;
614 Status = Fmp->GetImageInfo (
615 Fmp,
616 &ImageInfoSize, // ImageInfoSize
617 FmpImageInfoBuf, // ImageInfo
618 &FmpImageInfoDescriptorVer, // DescriptorVersion
619 &FmpImageInfoCount, // DescriptorCount
620 &DescriptorSize, // DescriptorSize
621 &PackageVersion, // PackageVersion
622 &PackageVersionName // PackageVersionName
623 );
624 if (EFI_ERROR (Status)) {
625 FreePool (FmpImageInfoBuf);
626 continue;
627 }
628
629 DEBUG ((DEBUG_INFO, "FMP (%d) ImageInfo:\n", Index));
630 DumpFmpImageInfo (
631 ImageInfoSize, // ImageInfoSize
632 FmpImageInfoBuf, // ImageInfo
633 FmpImageInfoDescriptorVer, // DescriptorVersion
634 FmpImageInfoCount, // DescriptorCount
635 DescriptorSize, // DescriptorSize
636 PackageVersion, // PackageVersion
637 PackageVersionName // PackageVersionName
638 );
639
640 if (PackageVersionName != NULL) {
641 FreePool (PackageVersionName);
642 }
643
644 FreePool (FmpImageInfoBuf);
645 }
646
647 FreePool (HandleBuffer);
648
649 return;
650}
651
652/**
653 Get FMP handle by ImageTypeId and HardwareInstance.
654
655 @param[in] UpdateImageTypeId Used to identify device firmware targeted by this update.
656 @param[in] UpdateHardwareInstance The HardwareInstance to target with this update.
657 @param[out] NoHandles The number of handles returned in HandleBuf.
658 @param[out] HandleBuf A pointer to the buffer to return the requested array of handles.
659 @param[out] ResetRequiredBuf A pointer to the buffer to return reset required flag for
660 the requested array of handles.
661
662 @retval EFI_SUCCESS The array of handles and their reset required flag were returned in
663 HandleBuf and ResetRequiredBuf, and the number of handles in HandleBuf
664 was returned in NoHandles.
665 @retval EFI_NOT_FOUND No handles match the search.
666 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
667**/
668EFI_STATUS
669GetFmpHandleBufferByType (
670 IN EFI_GUID *UpdateImageTypeId,
671 IN UINT64 UpdateHardwareInstance,
672 OUT UINTN *NoHandles OPTIONAL,
673 OUT EFI_HANDLE **HandleBuf OPTIONAL,
674 OUT BOOLEAN **ResetRequiredBuf OPTIONAL
675 )
676{
677 EFI_STATUS Status;
678 EFI_HANDLE *HandleBuffer;
679 UINTN NumberOfHandles;
680 EFI_HANDLE *MatchedHandleBuffer;
681 BOOLEAN *MatchedResetRequiredBuffer;
682 UINTN MatchedNumberOfHandles;
683 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
684 UINTN Index;
685 UINTN ImageInfoSize;
686 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
687 UINT32 FmpImageInfoDescriptorVer;
688 UINT8 FmpImageInfoCount;
689 UINTN DescriptorSize;
690 UINT32 PackageVersion;
691 CHAR16 *PackageVersionName;
692 UINTN Index2;
693 EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo;
694
695 if (NoHandles != NULL) {
696 *NoHandles = 0;
697 }
698
699 if (HandleBuf != NULL) {
700 *HandleBuf = NULL;
701 }
702
703 if (ResetRequiredBuf != NULL) {
704 *ResetRequiredBuf = NULL;
705 }
706
707 Status = gBS->LocateHandleBuffer (
708 ByProtocol,
709 &gEfiFirmwareManagementProtocolGuid,
710 NULL,
711 &NumberOfHandles,
712 &HandleBuffer
713 );
714 if (EFI_ERROR (Status)) {
715 return Status;
716 }
717
718 MatchedNumberOfHandles = 0;
719
720 MatchedHandleBuffer = NULL;
721 if (HandleBuf != NULL) {
722 MatchedHandleBuffer = AllocateZeroPool (sizeof (EFI_HANDLE) * NumberOfHandles);
723 if (MatchedHandleBuffer == NULL) {
724 FreePool (HandleBuffer);
725 return EFI_OUT_OF_RESOURCES;
726 }
727 }
728
729 MatchedResetRequiredBuffer = NULL;
730 if (ResetRequiredBuf != NULL) {
731 MatchedResetRequiredBuffer = AllocateZeroPool (sizeof (BOOLEAN) * NumberOfHandles);
732 if (MatchedResetRequiredBuffer == NULL) {
733 if (MatchedHandleBuffer != NULL) {
734 FreePool (MatchedHandleBuffer);
735 }
736
737 FreePool (HandleBuffer);
738 return EFI_OUT_OF_RESOURCES;
739 }
740 }
741
742 for (Index = 0; Index < NumberOfHandles; Index++) {
743 Status = gBS->HandleProtocol (
744 HandleBuffer[Index],
745 &gEfiFirmwareManagementProtocolGuid,
746 (VOID **)&Fmp
747 );
748 if (EFI_ERROR (Status)) {
749 continue;
750 }
751
752 ImageInfoSize = 0;
753 Status = Fmp->GetImageInfo (
754 Fmp,
755 &ImageInfoSize,
756 NULL,
757 NULL,
758 NULL,
759 NULL,
760 NULL,
761 NULL
762 );
763 if (Status != EFI_BUFFER_TOO_SMALL) {
764 continue;
765 }
766
767 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
768 if (FmpImageInfoBuf == NULL) {
769 continue;
770 }
771
772 PackageVersionName = NULL;
773 Status = Fmp->GetImageInfo (
774 Fmp,
775 &ImageInfoSize, // ImageInfoSize
776 FmpImageInfoBuf, // ImageInfo
777 &FmpImageInfoDescriptorVer, // DescriptorVersion
778 &FmpImageInfoCount, // DescriptorCount
779 &DescriptorSize, // DescriptorSize
780 &PackageVersion, // PackageVersion
781 &PackageVersionName // PackageVersionName
782 );
783 if (EFI_ERROR (Status)) {
784 FreePool (FmpImageInfoBuf);
785 continue;
786 }
787
788 if (PackageVersionName != NULL) {
789 FreePool (PackageVersionName);
790 }
791
792 TempFmpImageInfo = FmpImageInfoBuf;
793 for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {
794 //
795 // Check if this FMP instance matches
796 //
797 if (CompareGuid (UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId)) {
798 if ((UpdateHardwareInstance == 0) ||
799 ((FmpImageInfoDescriptorVer >= EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) &&
800 (UpdateHardwareInstance == TempFmpImageInfo->HardwareInstance)))
801 {
802 if (MatchedHandleBuffer != NULL) {
803 MatchedHandleBuffer[MatchedNumberOfHandles] = HandleBuffer[Index];
804 }
805
806 if (MatchedResetRequiredBuffer != NULL) {
807 MatchedResetRequiredBuffer[MatchedNumberOfHandles] = (((TempFmpImageInfo->AttributesSupported &
808 IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0) &&
809 ((TempFmpImageInfo->AttributesSetting &
810 IMAGE_ATTRIBUTE_RESET_REQUIRED) != 0));
811 }
812
813 MatchedNumberOfHandles++;
814 break;
815 }
816 }
817
818 TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);
819 }
820
821 FreePool (FmpImageInfoBuf);
822 }
823
824 FreePool (HandleBuffer);
825
826 if (MatchedNumberOfHandles == 0) {
827 return EFI_NOT_FOUND;
828 }
829
830 if (NoHandles != NULL) {
831 *NoHandles = MatchedNumberOfHandles;
832 }
833
834 if (HandleBuf != NULL) {
835 *HandleBuf = MatchedHandleBuffer;
836 }
837
838 if (ResetRequiredBuf != NULL) {
839 *ResetRequiredBuf = MatchedResetRequiredBuffer;
840 }
841
842 return EFI_SUCCESS;
843}
844
845/**
846 Return FmpImageInfoDescriptorVer by an FMP handle.
847
848 @param[in] Handle A FMP handle.
849
850 @return FmpImageInfoDescriptorVer associated with the FMP.
851**/
852UINT32
853GetFmpImageInfoDescriptorVer (
854 IN EFI_HANDLE Handle
855 )
856{
857 EFI_STATUS Status;
858 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
859 UINTN ImageInfoSize;
860 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
861 UINT32 FmpImageInfoDescriptorVer;
862 UINT8 FmpImageInfoCount;
863 UINTN DescriptorSize;
864 UINT32 PackageVersion;
865 CHAR16 *PackageVersionName;
866
867 Status = gBS->HandleProtocol (
868 Handle,
869 &gEfiFirmwareManagementProtocolGuid,
870 (VOID **)&Fmp
871 );
872 if (EFI_ERROR (Status)) {
873 return 0;
874 }
875
876 ImageInfoSize = 0;
877 Status = Fmp->GetImageInfo (
878 Fmp,
879 &ImageInfoSize,
880 NULL,
881 NULL,
882 NULL,
883 NULL,
884 NULL,
885 NULL
886 );
887 if (Status != EFI_BUFFER_TOO_SMALL) {
888 return 0;
889 }
890
891 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
892 if (FmpImageInfoBuf == NULL) {
893 return 0;
894 }
895
896 PackageVersionName = NULL;
897 Status = Fmp->GetImageInfo (
898 Fmp,
899 &ImageInfoSize, // ImageInfoSize
900 FmpImageInfoBuf, // ImageInfo
901 &FmpImageInfoDescriptorVer, // DescriptorVersion
902 &FmpImageInfoCount, // DescriptorCount
903 &DescriptorSize, // DescriptorSize
904 &PackageVersion, // PackageVersion
905 &PackageVersionName // PackageVersionName
906 );
907 if (EFI_ERROR (Status)) {
908 FreePool (FmpImageInfoBuf);
909 return 0;
910 }
911
912 return FmpImageInfoDescriptorVer;
913}
914
915/**
916 Set FMP image data.
917
918 @param[in] Handle A FMP handle.
919 @param[in] ImageHeader The payload image header.
920 @param[in] PayloadIndex The index of the payload.
921
922 @return The status of FMP->SetImage.
923**/
924EFI_STATUS
925SetFmpImageData (
926 IN EFI_HANDLE Handle,
927 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
928 IN UINTN PayloadIndex
929 )
930{
931 EFI_STATUS Status;
932 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
933 UINT8 *Image;
934 VOID *VendorCode;
935 CHAR16 *AbortReason;
936 EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS ProgressCallback;
937
938 Status = gBS->HandleProtocol (
939 Handle,
940 &gEfiFirmwareManagementProtocolGuid,
941 (VOID **)&Fmp
942 );
943 if (EFI_ERROR (Status)) {
944 return Status;
945 }
946
947 //
948 // Lookup Firmware Management Progress Protocol before SetImage() is called
949 // This is an optional protocol that may not be present on Handle.
950 //
951 Status = gBS->HandleProtocol (
952 Handle,
953 &gEdkiiFirmwareManagementProgressProtocolGuid,
954 (VOID **)&mFmpProgress
955 );
956 if (EFI_ERROR (Status)) {
957 mFmpProgress = NULL;
958 }
959
960 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
961 Image = (UINT8 *)(ImageHeader + 1);
962 } else {
963 //
964 // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1,
965 // Header should exclude UpdateHardwareInstance field, and
966 // ImageCapsuleSupport field if version is 2.
967 //
968 if (ImageHeader->Version == 1) {
969 Image = (UINT8 *)ImageHeader + OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);
970 } else {
971 Image = (UINT8 *)ImageHeader + OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);
972 }
973 }
974
975 if (ImageHeader->UpdateVendorCodeSize == 0) {
976 VendorCode = NULL;
977 } else {
978 VendorCode = Image + ImageHeader->UpdateImageSize;
979 }
980
981 AbortReason = NULL;
982 DEBUG ((DEBUG_INFO, "Fmp->SetImage ...\n"));
983 DEBUG ((DEBUG_INFO, "ImageTypeId - %g, ", &ImageHeader->UpdateImageTypeId));
984 DEBUG ((DEBUG_INFO, "PayloadIndex - 0x%x, ", PayloadIndex));
985 DEBUG ((DEBUG_INFO, "ImageIndex - 0x%x ", ImageHeader->UpdateImageIndex));
986 if (ImageHeader->Version >= 2) {
987 DEBUG ((DEBUG_INFO, "(UpdateHardwareInstance - 0x%x)", ImageHeader->UpdateHardwareInstance));
988 if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {
989 DEBUG ((DEBUG_INFO, "(ImageCapsuleSupport - 0x%x)", ImageHeader->ImageCapsuleSupport));
990 }
991 }
992
993 DEBUG ((DEBUG_INFO, "\n"));
994
995 //
996 // Before calling SetImage(), reset the progress bar to 0%
997 //
998 ProgressCallback = UpdateImageProgress;
999 Status = UpdateImageProgress (0);
1000 if (EFI_ERROR (Status)) {
1001 ProgressCallback = NULL;
1002 }
1003
1004 Status = Fmp->SetImage (
1005 Fmp,
1006 ImageHeader->UpdateImageIndex, // ImageIndex
1007 Image, // Image
1008 ImageHeader->UpdateImageSize, // ImageSize
1009 VendorCode, // VendorCode
1010 ProgressCallback, // Progress
1011 &AbortReason // AbortReason
1012 );
1013 //
1014 // Set the progress bar to 100% after returning from SetImage()
1015 //
1016 if (ProgressCallback != NULL) {
1017 UpdateImageProgress (100);
1018 }
1019
1020 DEBUG ((DEBUG_INFO, "Fmp->SetImage - %r\n", Status));
1021 if (AbortReason != NULL) {
1022 DEBUG ((DEBUG_ERROR, "%s\n", AbortReason));
1023 FreePool (AbortReason);
1024 }
1025
1026 //
1027 // Clear mFmpProgress after SetImage() returns
1028 //
1029 mFmpProgress = NULL;
1030
1031 return Status;
1032}
1033
1034/**
1035 Start a UEFI image in the FMP payload.
1036
1037 @param[in] ImageBuffer A pointer to the memory location containing a copy of the image to be loaded..
1038 @param[in] ImageSize The size in bytes of ImageBuffer.
1039
1040 @return The status of gBS->LoadImage and gBS->StartImage.
1041**/
1042EFI_STATUS
1043StartFmpImage (
1044 IN VOID *ImageBuffer,
1045 IN UINTN ImageSize
1046 )
1047{
1048 MEMMAP_DEVICE_PATH MemMapNode;
1049 EFI_STATUS Status;
1050 EFI_HANDLE ImageHandle;
1051 EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;
1052 UINTN ExitDataSize;
1053
1054 SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));
1055 MemMapNode.Header.Type = HARDWARE_DEVICE_PATH;
1056 MemMapNode.Header.SubType = HW_MEMMAP_DP;
1057 MemMapNode.MemoryType = EfiBootServicesCode;
1058 MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)ImageBuffer;
1059 MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)ImageBuffer + ImageSize - 1);
1060
1061 DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);
1062 if (DriverDevicePath == NULL) {
1063 return EFI_OUT_OF_RESOURCES;
1064 }
1065
1066 DEBUG ((DEBUG_INFO, "FmpCapsule: LoadImage ...\n"));
1067 Status = gBS->LoadImage (
1068 FALSE,
1069 gImageHandle,
1070 DriverDevicePath,
1071 ImageBuffer,
1072 ImageSize,
1073 &ImageHandle
1074 );
1075 DEBUG ((DEBUG_INFO, "FmpCapsule: LoadImage - %r\n", Status));
1076 if (EFI_ERROR (Status)) {
1077 //
1078 // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
1079 // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
1080 // If the caller doesn't have the option to defer the execution of an image, we should
1081 // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
1082 //
1083 if (Status == EFI_SECURITY_VIOLATION) {
1084 gBS->UnloadImage (ImageHandle);
1085 }
1086
1087 FreePool (DriverDevicePath);
1088 return Status;
1089 }
1090
1091 DEBUG ((DEBUG_INFO, "FmpCapsule: StartImage ...\n"));
1092 Status = gBS->StartImage (
1093 ImageHandle,
1094 &ExitDataSize,
1095 NULL
1096 );
1097 DEBUG ((DEBUG_INFO, "FmpCapsule: StartImage - %r\n", Status));
1098 if (EFI_ERROR (Status)) {
1099 DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
1100 }
1101
1102 FreePool (DriverDevicePath);
1103 return Status;
1104}
1105
1106/**
1107 Record FMP capsule status.
1108
1109 @param[in] Handle A FMP handle.
1110 @param[in] CapsuleHeader The capsule image header
1111 @param[in] CapsuleStatus The capsule process stauts
1112 @param[in] PayloadIndex FMP payload index
1113 @param[in] ImageHeader FMP image header
1114 @param[in] CapFileName Capsule file name
1115**/
1116VOID
1117RecordFmpCapsuleStatus (
1118 IN EFI_HANDLE Handle OPTIONAL,
1119 IN EFI_CAPSULE_HEADER *CapsuleHeader,
1120 IN EFI_STATUS CapsuleStatus,
1121 IN UINTN PayloadIndex,
1122 IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader,
1123 IN CHAR16 *CapFileName OPTIONAL
1124 )
1125{
1126 EFI_STATUS Status;
1127 EFI_DEVICE_PATH_PROTOCOL *FmpDevicePath;
1128 UINT32 FmpImageInfoDescriptorVer;
1129 EFI_STATUS StatusEsrt;
1130 ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;
1131 EFI_SYSTEM_RESOURCE_ENTRY EsrtEntry;
1132
1133 FmpDevicePath = NULL;
1134 if (Handle != NULL) {
1135 gBS->HandleProtocol (
1136 Handle,
1137 &gEfiDevicePathProtocolGuid,
1138 (VOID **)&FmpDevicePath
1139 );
1140 }
1141
1142 RecordFmpCapsuleStatusVariable (
1143 CapsuleHeader,
1144 CapsuleStatus,
1145 PayloadIndex,
1146 ImageHeader,
1147 FmpDevicePath,
1148 CapFileName
1149 );
1150
1151 //
1152 // Update corresponding ESRT entry LastAttemp Status
1153 //
1154 Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
1155 if (EFI_ERROR (Status)) {
1156 return;
1157 }
1158
1159 if (Handle == NULL) {
1160 return;
1161 }
1162
1163 //
1164 // Update EsrtEntry For V1, V2 FMP instance.
1165 // V3 FMP ESRT cache will be synced up through SyncEsrtFmp interface
1166 //
1167 FmpImageInfoDescriptorVer = GetFmpImageInfoDescriptorVer (Handle);
1168 if (FmpImageInfoDescriptorVer < EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION) {
1169 StatusEsrt = EsrtProtocol->GetEsrtEntry (&ImageHeader->UpdateImageTypeId, &EsrtEntry);
1170 if (!EFI_ERROR (StatusEsrt)) {
1171 if (!EFI_ERROR (CapsuleStatus)) {
1172 EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
1173 } else {
1174 EsrtEntry.LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
1175 }
1176
1177 EsrtEntry.LastAttemptVersion = 0;
1178 EsrtProtocol->UpdateEsrtEntry (&EsrtEntry);
1179 }
1180 }
1181}
1182
1183/**
1184 Process Firmware management protocol data capsule.
1185
1186 This function assumes the caller validated the capsule by using
1187 ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,
1188 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and
1189 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.
1190
1191 This function need support nested FMP capsule.
1192
1193 @param[in] CapsuleHeader Points to a capsule header.
1194 @param[in] CapFileName Capsule file name.
1195 @param[out] ResetRequired Indicates whether reset is required or not.
1196
1197 @retval EFI_SUCESS Process Capsule Image successfully.
1198 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
1199 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
1200 @retval EFI_OUT_OF_RESOURCES Not enough memory.
1201 @retval EFI_NOT_READY No FMP protocol to handle this FMP capsule.
1202**/
1203EFI_STATUS
1204ProcessFmpCapsuleImage (
1205 IN EFI_CAPSULE_HEADER *CapsuleHeader,
1206 IN CHAR16 *CapFileName OPTIONAL,
1207 OUT BOOLEAN *ResetRequired OPTIONAL
1208 )
1209{
1210 EFI_STATUS Status;
1211 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
1212 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
1213 UINT64 *ItemOffsetList;
1214 UINT32 ItemNum;
1215 UINTN Index;
1216 EFI_HANDLE *HandleBuffer;
1217 BOOLEAN *ResetRequiredBuffer;
1218 UINTN NumberOfHandles;
1219 UINTN DriverLen;
1220 UINT64 UpdateHardwareInstance;
1221 UINTN Index2;
1222 BOOLEAN NotReady;
1223 BOOLEAN Abort;
1224
1225 if (!IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
1226 return ProcessFmpCapsuleImage ((EFI_CAPSULE_HEADER *)((UINTN)CapsuleHeader + CapsuleHeader->HeaderSize), CapFileName, ResetRequired);
1227 }
1228
1229 NotReady = FALSE;
1230 Abort = FALSE;
1231
1232 DumpFmpCapsule (CapsuleHeader);
1233
1234 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
1235
1236 if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
1237 return EFI_INVALID_PARAMETER;
1238 }
1239
1240 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
1241
1242 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
1243
1244 //
1245 // capsule in which driver count and payload count are both zero is not processed.
1246 //
1247 if (ItemNum == 0) {
1248 return EFI_SUCCESS;
1249 }
1250
1251 //
1252 // 1. Try to load & start all the drivers within capsule
1253 //
1254 for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
1255 if ((FmpCapsuleHeader->PayloadItemCount == 0) &&
1256 (Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1))
1257 {
1258 //
1259 // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER
1260 //
1261 DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];
1262 } else {
1263 DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];
1264 }
1265
1266 Status = StartFmpImage (
1267 (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],
1268 DriverLen
1269 );
1270 if (EFI_ERROR (Status)) {
1271 DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
1272 return Status;
1273 }
1274 }
1275
1276 //
1277 // 2. Route payload to right FMP instance
1278 //
1279 DEBUG ((DEBUG_INFO, "FmpCapsule: route payload to right FMP instance ...\n"));
1280
1281 DumpAllFmpInfo ();
1282
1283 //
1284 // Check all the payload entry in capsule payload list
1285 //
1286 for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
1287 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
1288
1289 UpdateHardwareInstance = 0;
1290 ///
1291 /// UpdateHardwareInstance field was added in Version 2
1292 ///
1293 if (ImageHeader->Version >= 2) {
1294 UpdateHardwareInstance = ImageHeader->UpdateHardwareInstance;
1295 }
1296
1297 Status = GetFmpHandleBufferByType (
1298 &ImageHeader->UpdateImageTypeId,
1299 UpdateHardwareInstance,
1300 &NumberOfHandles,
1301 &HandleBuffer,
1302 &ResetRequiredBuffer
1303 );
1304 if (EFI_ERROR (Status) ||
1305 (HandleBuffer == NULL) ||
1306 (ResetRequiredBuffer == NULL))
1307 {
1308 NotReady = TRUE;
1309 RecordFmpCapsuleStatus (
1310 NULL,
1311 CapsuleHeader,
1312 EFI_NOT_READY,
1313 Index - FmpCapsuleHeader->EmbeddedDriverCount,
1314 ImageHeader,
1315 CapFileName
1316 );
1317 continue;
1318 }
1319
1320 for (Index2 = 0; Index2 < NumberOfHandles; Index2++) {
1321 if (Abort) {
1322 RecordFmpCapsuleStatus (
1323 HandleBuffer[Index2],
1324 CapsuleHeader,
1325 EFI_ABORTED,
1326 Index - FmpCapsuleHeader->EmbeddedDriverCount,
1327 ImageHeader,
1328 CapFileName
1329 );
1330 continue;
1331 }
1332
1333 Status = SetFmpImageData (
1334 HandleBuffer[Index2],
1335 ImageHeader,
1336 Index - FmpCapsuleHeader->EmbeddedDriverCount
1337 );
1338 if (Status != EFI_SUCCESS) {
1339 Abort = TRUE;
1340 } else {
1341 if (ResetRequired != NULL) {
1342 *ResetRequired |= ResetRequiredBuffer[Index2];
1343 }
1344 }
1345
1346 RecordFmpCapsuleStatus (
1347 HandleBuffer[Index2],
1348 CapsuleHeader,
1349 Status,
1350 Index - FmpCapsuleHeader->EmbeddedDriverCount,
1351 ImageHeader,
1352 CapFileName
1353 );
1354 }
1355
1356 if (HandleBuffer != NULL) {
1357 FreePool (HandleBuffer);
1358 }
1359
1360 if (ResetRequiredBuffer != NULL) {
1361 FreePool (ResetRequiredBuffer);
1362 }
1363 }
1364
1365 if (NotReady) {
1366 return EFI_NOT_READY;
1367 }
1368
1369 //
1370 // always return SUCCESS to indicate this capsule is processed.
1371 // The status of SetImage is recorded in capsule result variable.
1372 //
1373 return EFI_SUCCESS;
1374}
1375
1376/**
1377 Return if there is a FMP header below capsule header.
1378
1379 @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
1380
1381 @retval TRUE There is a FMP header below capsule header.
1382 @retval FALSE There is not a FMP header below capsule header
1383**/
1384BOOLEAN
1385IsNestedFmpCapsule (
1386 IN EFI_CAPSULE_HEADER *CapsuleHeader
1387 )
1388{
1389 EFI_STATUS Status;
1390 EFI_SYSTEM_RESOURCE_ENTRY *EsrtEntry;
1391 UINTN Index;
1392 BOOLEAN EsrtGuidFound;
1393 EFI_CAPSULE_HEADER *NestedCapsuleHeader;
1394 UINTN NestedCapsuleSize;
1395 ESRT_MANAGEMENT_PROTOCOL *EsrtProtocol;
1396 EFI_SYSTEM_RESOURCE_ENTRY Entry;
1397
1398 EsrtGuidFound = FALSE;
1399 if (mDxeCapsuleLibIsExitBootService) {
1400 if (mEsrtTable != NULL) {
1401 EsrtEntry = (EFI_SYSTEM_RESOURCE_ENTRY *)(mEsrtTable + 1);
1402 for (Index = 0; Index < mEsrtTable->FwResourceCount; Index++, EsrtEntry++) {
1403 if (CompareGuid (&EsrtEntry->FwClass, &CapsuleHeader->CapsuleGuid)) {
1404 EsrtGuidFound = TRUE;
1405 break;
1406 }
1407 }
1408 }
1409 } else {
1410 //
1411 // Check ESRT protocol
1412 //
1413 Status = gBS->LocateProtocol (&gEsrtManagementProtocolGuid, NULL, (VOID **)&EsrtProtocol);
1414 if (!EFI_ERROR (Status)) {
1415 Status = EsrtProtocol->GetEsrtEntry (&CapsuleHeader->CapsuleGuid, &Entry);
1416 if (!EFI_ERROR (Status)) {
1417 EsrtGuidFound = TRUE;
1418 }
1419 }
1420
1421 //
1422 // Check Firmware Management Protocols
1423 //
1424 if (!EsrtGuidFound) {
1425 Status = GetFmpHandleBufferByType (
1426 &CapsuleHeader->CapsuleGuid,
1427 0,
1428 NULL,
1429 NULL,
1430 NULL
1431 );
1432 if (!EFI_ERROR (Status)) {
1433 EsrtGuidFound = TRUE;
1434 }
1435 }
1436 }
1437
1438 if (!EsrtGuidFound) {
1439 return FALSE;
1440 }
1441
1442 //
1443 // Check nested capsule header
1444 // FMP GUID after ESRT one
1445 //
1446 NestedCapsuleHeader = (EFI_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);
1447 NestedCapsuleSize = (UINTN)CapsuleHeader + CapsuleHeader->CapsuleImageSize - (UINTN)NestedCapsuleHeader;
1448 if (NestedCapsuleSize < sizeof (EFI_CAPSULE_HEADER)) {
1449 return FALSE;
1450 }
1451
1452 if (!IsValidCapsuleHeader (NestedCapsuleHeader, NestedCapsuleSize)) {
1453 return FALSE;
1454 }
1455
1456 if (!IsFmpCapsuleGuid (&NestedCapsuleHeader->CapsuleGuid)) {
1457 return FALSE;
1458 }
1459
1460 DEBUG ((DEBUG_INFO, "IsNestedFmpCapsule\n"));
1461 return TRUE;
1462}
1463
1464/**
1465 Return if this FMP is a system FMP or a device FMP, based upon CapsuleHeader.
1466
1467 @param[in] CapsuleHeader A pointer to EFI_CAPSULE_HEADER
1468
1469 @retval TRUE It is a system FMP.
1470 @retval FALSE It is a device FMP.
1471**/
1472BOOLEAN
1473IsFmpCapsule (
1474 IN EFI_CAPSULE_HEADER *CapsuleHeader
1475 )
1476{
1477 if (IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {
1478 return TRUE;
1479 }
1480
1481 if (IsNestedFmpCapsule (CapsuleHeader)) {
1482 return TRUE;
1483 }
1484
1485 return FALSE;
1486}
1487
1488/**
1489 Those capsules supported by the firmwares.
1490
1491 Caution: This function may receive untrusted input.
1492
1493 @param[in] CapsuleHeader Points to a capsule header.
1494
1495 @retval EFI_SUCESS Input capsule is supported by firmware.
1496 @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
1497 @retval EFI_INVALID_PARAMETER Input capsule layout is not correct
1498**/
1499EFI_STATUS
1500EFIAPI
1501SupportCapsuleImage (
1502 IN EFI_CAPSULE_HEADER *CapsuleHeader
1503 )
1504{
1505 //
1506 // check Display Capsule Guid
1507 //
1508 if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
1509 return EFI_SUCCESS;
1510 }
1511
1512 //
1513 // Check capsule file name capsule
1514 //
1515 if (IsCapsuleNameCapsule (CapsuleHeader)) {
1516 return EFI_SUCCESS;
1517 }
1518
1519 if (IsFmpCapsule (CapsuleHeader)) {
1520 //
1521 // Fake capsule header is valid case in QueryCapsuleCpapbilities().
1522 //
1523 if (CapsuleHeader->HeaderSize == CapsuleHeader->CapsuleImageSize) {
1524 return EFI_SUCCESS;
1525 }
1526
1527 //
1528 // Check layout of FMP capsule
1529 //
1530 return ValidateFmpCapsule (CapsuleHeader, NULL);
1531 }
1532
1533 DEBUG ((DEBUG_ERROR, "Unknown Capsule Guid - %g\n", &CapsuleHeader->CapsuleGuid));
1534 return EFI_UNSUPPORTED;
1535}
1536
1537/**
1538 The firmware implements to process the capsule image.
1539
1540 Caution: This function may receive untrusted input.
1541
1542 @param[in] CapsuleHeader Points to a capsule header.
1543 @param[in] CapFileName Capsule file name.
1544 @param[out] ResetRequired Indicates whether reset is required or not.
1545
1546 @retval EFI_SUCESS Process Capsule Image successfully.
1547 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
1548 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
1549 @retval EFI_OUT_OF_RESOURCES Not enough memory.
1550**/
1551EFI_STATUS
1552EFIAPI
1553ProcessThisCapsuleImage (
1554 IN EFI_CAPSULE_HEADER *CapsuleHeader,
1555 IN CHAR16 *CapFileName OPTIONAL,
1556 OUT BOOLEAN *ResetRequired OPTIONAL
1557 )
1558{
1559 EFI_STATUS Status;
1560
1561 if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {
1562 RecordCapsuleStatusVariable (CapsuleHeader, EFI_UNSUPPORTED);
1563 return EFI_UNSUPPORTED;
1564 }
1565
1566 //
1567 // Display image in firmware update display capsule
1568 //
1569 if (CompareGuid (&gWindowsUxCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
1570 DEBUG ((DEBUG_INFO, "ProcessCapsuleImage for WindowsUxCapsule ...\n"));
1571 Status = DisplayCapsuleImage (CapsuleHeader);
1572 RecordCapsuleStatusVariable (CapsuleHeader, Status);
1573 return Status;
1574 }
1575
1576 //
1577 // Check FMP capsule layout
1578 //
1579 if (IsFmpCapsule (CapsuleHeader)) {
1580 DEBUG ((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));
1581 DEBUG ((DEBUG_INFO, "ValidateFmpCapsule ...\n"));
1582 Status = ValidateFmpCapsule (CapsuleHeader, NULL);
1583 DEBUG ((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));
1584 if (EFI_ERROR (Status)) {
1585 RecordCapsuleStatusVariable (CapsuleHeader, Status);
1586 return Status;
1587 }
1588
1589 //
1590 // Process EFI FMP Capsule
1591 //
1592 DEBUG ((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));
1593 Status = ProcessFmpCapsuleImage (CapsuleHeader, CapFileName, ResetRequired);
1594 DEBUG ((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));
1595
1596 return Status;
1597 }
1598
1599 return EFI_UNSUPPORTED;
1600}
1601
1602/**
1603 The firmware implements to process the capsule image.
1604
1605 Caution: This function may receive untrusted input.
1606
1607 @param[in] CapsuleHeader Points to a capsule header.
1608
1609 @retval EFI_SUCESS Process Capsule Image successfully.
1610 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
1611 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
1612 @retval EFI_OUT_OF_RESOURCES Not enough memory.
1613**/
1614EFI_STATUS
1615EFIAPI
1616ProcessCapsuleImage (
1617 IN EFI_CAPSULE_HEADER *CapsuleHeader
1618 )
1619{
1620 return ProcessThisCapsuleImage (CapsuleHeader, NULL, NULL);
1621}
1622
1623/**
1624 Callback function executed when the EndOfDxe event group is signaled.
1625
1626 @param[in] Event Event whose notification function is being invoked.
1627 @param[in] Context The pointer to the notification function's context, which
1628 is implementation-dependent.
1629**/
1630VOID
1631EFIAPI
1632DxeCapsuleLibEndOfDxe (
1633 IN EFI_EVENT Event,
1634 IN VOID *Context
1635 )
1636{
1637 mDxeCapsuleLibEndOfDxe = TRUE;
1638}
1639
1640/**
1641 The constructor function.
1642
1643 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1644 @param[in] SystemTable A pointer to the EFI System Table.
1645
1646 @retval EFI_SUCCESS The constructor successfully .
1647**/
1648EFI_STATUS
1649EFIAPI
1650DxeCapsuleLibConstructor (
1651 IN EFI_HANDLE ImageHandle,
1652 IN EFI_SYSTEM_TABLE *SystemTable
1653 )
1654{
1655 EFI_STATUS Status;
1656
1657 Status = gBS->CreateEventEx (
1658 EVT_NOTIFY_SIGNAL,
1659 TPL_CALLBACK,
1660 DxeCapsuleLibEndOfDxe,
1661 NULL,
1662 &gEfiEndOfDxeEventGroupGuid,
1663 &mDxeCapsuleLibEndOfDxeEvent
1664 );
1665 ASSERT_EFI_ERROR (Status);
1666
1667 InitCapsuleVariable ();
1668
1669 return EFI_SUCCESS;
1670}
1671
1672/**
1673 The destructor function closes the End of DXE event.
1674
1675 @param ImageHandle The firmware allocated handle for the EFI image.
1676 @param SystemTable A pointer to the EFI System Table.
1677
1678 @retval EFI_SUCCESS The destructor completed successfully.
1679**/
1680EFI_STATUS
1681EFIAPI
1682DxeCapsuleLibDestructor (
1683 IN EFI_HANDLE ImageHandle,
1684 IN EFI_SYSTEM_TABLE *SystemTable
1685 )
1686{
1687 EFI_STATUS Status;
1688
1689 //
1690 // Close the End of DXE event.
1691 //
1692 Status = gBS->CloseEvent (mDxeCapsuleLibEndOfDxeEvent);
1693 ASSERT_EFI_ERROR (Status);
1694
1695 return EFI_SUCCESS;
1696}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette