]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.c
IntelFrameworkModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelFrameworkModulePkg / Library / DxeCapsuleLib / DxeCapsuleLib.c
1 /** @file
2 Capsule Library instance to process capsule images.
3
4 Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9 #include <PiDxe.h>
10
11 #include <Guid/Capsule.h>
12 #include <Guid/FmpCapsule.h>
13
14 #include <Library/DebugLib.h>
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/DxeServicesTableLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/CapsuleLib.h>
19 #include <Library/GenericBdsLib.h>
20 #include <Library/UefiBootServicesTableLib.h>
21 #include <Library/BaseLib.h>
22 #include <Library/DevicePathLib.h>
23
24 #include <Protocol/FirmwareManagement.h>
25 #include <Protocol/DevicePath.h>
26
27
28 /**
29 Function indicate the current completion progress of the firmware
30 update. Platform may override with own specific progress function.
31
32 @param Completion A value between 1 and 100 indicating the current completion progress of the firmware update
33
34 @retval EFI_SUCESS Input capsule is a correct FMP capsule.
35 **/
36 EFI_STATUS
37 EFIAPI
38 Update_Image_Progress (
39 IN UINTN Completion
40 )
41 {
42 return EFI_SUCCESS;
43 }
44
45
46 /**
47 Validate Fmp capsules layout.
48
49 @param CapsuleHeader Points to a capsule header.
50
51 @retval EFI_SUCESS Input capsule is a correct FMP capsule.
52 @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.
53 **/
54 EFI_STATUS
55 ValidateFmpCapsule (
56 IN EFI_CAPSULE_HEADER *CapsuleHeader
57 )
58 {
59 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
60 UINT8 *EndOfCapsule;
61 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
62 UINT8 *EndOfPayload;
63 UINT64 *ItemOffsetList;
64 UINT32 ItemNum;
65 UINTN Index;
66
67 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
68 EndOfCapsule = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;
69
70 if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
71 return EFI_INVALID_PARAMETER;
72 }
73 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
74
75 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
76
77 if (ItemNum == FmpCapsuleHeader->EmbeddedDriverCount) {
78 //
79 // No payload element
80 //
81 if (((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemNum - 1]) < EndOfCapsule) {
82 return EFI_SUCCESS;
83 } else {
84 return EFI_INVALID_PARAMETER;
85 }
86 }
87
88 if (FmpCapsuleHeader->PayloadItemCount != 0) {
89 //
90 // Check if the last payload is within capsule image range
91 //
92 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemNum - 1]);
93 EndOfPayload = (UINT8 *)(ImageHeader + 1) + ImageHeader->UpdateImageSize + ImageHeader->UpdateVendorCodeSize;
94 } else {
95 //
96 // No driver & payload element in FMP
97 //
98 EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);
99 }
100
101 if (EndOfPayload != EndOfCapsule) {
102 return EFI_INVALID_PARAMETER;
103 }
104
105 //
106 // All the address in ItemOffsetList must be stored in ascending order
107 //
108 if (ItemNum >= 2) {
109 for (Index = 0; Index < ItemNum - 1; Index++) {
110 if (ItemOffsetList[Index] >= ItemOffsetList[Index + 1]) {
111 return EFI_INVALID_PARAMETER;
112 }
113 }
114 }
115
116 return EFI_SUCCESS;
117 }
118
119 /**
120 Process Firmware management protocol data capsule.
121
122 @param CapsuleHeader Points to a capsule header.
123
124 @retval EFI_SUCESS Process Capsule Image successfully.
125 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
126 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
127 @retval EFI_OUT_OF_RESOURCES Not enough memory.
128 **/
129 EFI_STATUS
130 ProcessFmpCapsuleImage (
131 IN EFI_CAPSULE_HEADER *CapsuleHeader
132 )
133 {
134 EFI_STATUS Status;
135 EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
136 EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
137 EFI_HANDLE ImageHandle;
138 UINT64 *ItemOffsetList;
139 UINT32 ItemNum;
140 UINTN Index;
141 UINTN ExitDataSize;
142 EFI_HANDLE *HandleBuffer;
143 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
144 UINTN NumberOfHandles;
145 UINTN DescriptorSize;
146 UINT8 FmpImageInfoCount;
147 UINT32 FmpImageInfoDescriptorVer;
148 UINTN ImageInfoSize;
149 UINT32 PackageVersion;
150 CHAR16 *PackageVersionName;
151 CHAR16 *AbortReason;
152 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
153 EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo;
154 UINTN DriverLen;
155 UINTN Index1;
156 UINTN Index2;
157 MEMMAP_DEVICE_PATH MemMapNode;
158 EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;
159
160 Status = EFI_SUCCESS;
161 HandleBuffer = NULL;
162 ExitDataSize = 0;
163 DriverDevicePath = NULL;
164
165 FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
166
167 if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
168 return EFI_INVALID_PARAMETER;
169 }
170 ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
171
172 ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
173
174 //
175 // capsule in which driver count and payload count are both zero is not processed.
176 //
177 if (ItemNum == 0) {
178 return EFI_SUCCESS;
179 }
180
181 //
182 // 1. ConnectAll to ensure
183 // All the communication protocol required by driver in capsule installed
184 // All FMP protocols are installed
185 //
186 BdsLibConnectAll();
187
188
189 //
190 // 2. Try to load & start all the drivers within capsule
191 //
192 SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));
193 MemMapNode.Header.Type = HARDWARE_DEVICE_PATH;
194 MemMapNode.Header.SubType = HW_MEMMAP_DP;
195 MemMapNode.MemoryType = EfiBootServicesCode;
196 MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleHeader;
197 MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize - 1);
198
199 DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);
200 if (DriverDevicePath == NULL) {
201 return EFI_OUT_OF_RESOURCES;
202 }
203
204 for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
205 if (FmpCapsuleHeader->PayloadItemCount == 0 && Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1) {
206 //
207 // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER
208 //
209 DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];
210 } else {
211 DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];
212 }
213
214 Status = gBS->LoadImage(
215 FALSE,
216 gImageHandle,
217 DriverDevicePath,
218 (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],
219 DriverLen,
220 &ImageHandle
221 );
222 if (EFI_ERROR(Status)) {
223 goto EXIT;
224 }
225
226 Status = gBS->StartImage(
227 ImageHandle,
228 &ExitDataSize,
229 NULL
230 );
231 if (EFI_ERROR(Status)) {
232 DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
233 goto EXIT;
234 }
235 }
236
237 //
238 // Connnect all again to connect drivers within capsule
239 //
240 if (FmpCapsuleHeader->EmbeddedDriverCount > 0) {
241 BdsLibConnectAll();
242 }
243
244 //
245 // 3. Route payload to right FMP instance
246 //
247 Status = gBS->LocateHandleBuffer (
248 ByProtocol,
249 &gEfiFirmwareManagementProtocolGuid,
250 NULL,
251 &NumberOfHandles,
252 &HandleBuffer
253 );
254
255 if (!EFI_ERROR(Status)) {
256 for(Index1 = 0; Index1 < NumberOfHandles; Index1++) {
257 Status = gBS->HandleProtocol(
258 HandleBuffer[Index1],
259 &gEfiFirmwareManagementProtocolGuid,
260 (VOID **)&Fmp
261 );
262 if (EFI_ERROR(Status)) {
263 continue;
264 }
265
266 ImageInfoSize = 0;
267 Status = Fmp->GetImageInfo (
268 Fmp,
269 &ImageInfoSize,
270 NULL,
271 NULL,
272 NULL,
273 NULL,
274 NULL,
275 NULL
276 );
277 if (Status != EFI_BUFFER_TOO_SMALL) {
278 continue;
279 }
280
281 FmpImageInfoBuf = NULL;
282 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
283 if (FmpImageInfoBuf == NULL) {
284 Status = EFI_OUT_OF_RESOURCES;
285 goto EXIT;
286 }
287
288 PackageVersionName = NULL;
289 Status = Fmp->GetImageInfo (
290 Fmp,
291 &ImageInfoSize, // ImageInfoSize
292 FmpImageInfoBuf, // ImageInfo
293 &FmpImageInfoDescriptorVer, // DescriptorVersion
294 &FmpImageInfoCount, // DescriptorCount
295 &DescriptorSize, // DescriptorSize
296 &PackageVersion, // PackageVersion
297 &PackageVersionName // PackageVersionName
298 );
299
300 //
301 // If FMP GetInformation interface failed, skip this resource
302 //
303 if (EFI_ERROR(Status)) {
304 FreePool(FmpImageInfoBuf);
305 continue;
306 }
307
308 if (PackageVersionName != NULL) {
309 FreePool(PackageVersionName);
310 }
311
312 TempFmpImageInfo = FmpImageInfoBuf;
313 for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {
314 //
315 // Check all the payload entry in capsule payload list
316 //
317 for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
318 ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
319 if (CompareGuid(&ImageHeader->UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId) &&
320 ImageHeader->UpdateImageIndex == TempFmpImageInfo->ImageIndex) {
321 AbortReason = NULL;
322 if (ImageHeader->UpdateVendorCodeSize == 0) {
323 Status = Fmp->SetImage(
324 Fmp,
325 TempFmpImageInfo->ImageIndex, // ImageIndex
326 (UINT8 *)(ImageHeader + 1), // Image
327 ImageHeader->UpdateImageSize, // ImageSize
328 NULL, // VendorCode
329 Update_Image_Progress, // Progress
330 &AbortReason // AbortReason
331 );
332 } else {
333 Status = Fmp->SetImage(
334 Fmp,
335 TempFmpImageInfo->ImageIndex, // ImageIndex
336 (UINT8 *)(ImageHeader + 1), // Image
337 ImageHeader->UpdateImageSize, // ImageSize
338 (UINT8 *)((UINT8 *) (ImageHeader + 1) + ImageHeader->UpdateImageSize), // VendorCode
339 Update_Image_Progress, // Progress
340 &AbortReason // AbortReason
341 );
342 }
343 if (AbortReason != NULL) {
344 DEBUG ((EFI_D_ERROR, "%s\n", AbortReason));
345 FreePool(AbortReason);
346 }
347 }
348 }
349 //
350 // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
351 //
352 TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);
353 }
354 FreePool(FmpImageInfoBuf);
355 }
356 }
357
358 EXIT:
359
360 if (HandleBuffer != NULL) {
361 FreePool(HandleBuffer);
362 }
363
364 if (DriverDevicePath != NULL) {
365 FreePool(DriverDevicePath);
366 }
367
368 return Status;
369 }
370
371 /**
372 Those capsules supported by the firmwares.
373
374 @param CapsuleHeader Points to a capsule header.
375
376 @retval EFI_SUCESS Input capsule is supported by firmware.
377 @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
378 @retval EFI_INVALID_PARAMETER Input capsule layout is not correct
379 **/
380 EFI_STATUS
381 EFIAPI
382 SupportCapsuleImage (
383 IN EFI_CAPSULE_HEADER *CapsuleHeader
384 )
385 {
386 if (CompareGuid (&gEfiCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
387 return EFI_SUCCESS;
388 }
389
390 if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
391 //
392 // Check layout of FMP capsule
393 //
394 return ValidateFmpCapsule(CapsuleHeader);
395 }
396
397 return EFI_UNSUPPORTED;
398 }
399
400 /**
401 The firmware implements to process the capsule image.
402
403 @param CapsuleHeader Points to a capsule header.
404
405 @retval EFI_SUCESS Process Capsule Image successfully.
406 @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
407 @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
408 @retval EFI_OUT_OF_RESOURCES Not enough memory.
409 **/
410 EFI_STATUS
411 EFIAPI
412 ProcessCapsuleImage (
413 IN EFI_CAPSULE_HEADER *CapsuleHeader
414 )
415 {
416 UINT32 Length;
417 EFI_FIRMWARE_VOLUME_HEADER *FvImage;
418 EFI_FIRMWARE_VOLUME_HEADER *ProcessedFvImage;
419 EFI_STATUS Status;
420 EFI_HANDLE FvProtocolHandle;
421 UINT32 FvAlignment;
422
423 FvImage = NULL;
424 ProcessedFvImage = NULL;
425 Status = EFI_SUCCESS;
426
427 if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {
428 return EFI_UNSUPPORTED;
429 }
430
431 //
432 // Check FMP capsule layout
433 //
434 if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)){
435 Status = ValidateFmpCapsule(CapsuleHeader);
436 if (EFI_ERROR(Status)) {
437 return Status;
438 }
439
440 //
441 // Press EFI FMP Capsule
442 //
443 return ProcessFmpCapsuleImage(CapsuleHeader);
444 }
445
446 //
447 // Skip the capsule header, move to the Firware Volume
448 //
449 FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
450 Length = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
451
452 while (Length != 0) {
453 //
454 // Point to the next firmware volume header, and then
455 // call the DXE service to process it.
456 //
457 if (FvImage->FvLength > (UINTN) Length) {
458 //
459 // Notes: need to stuff this status somewhere so that the
460 // error can be detected at OS runtime
461 //
462 Status = EFI_VOLUME_CORRUPTED;
463 break;
464 }
465
466 FvAlignment = 1 << ((FvImage->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
467 //
468 // FvAlignment must be more than 8 bytes required by FvHeader structure.
469 //
470 if (FvAlignment < 8) {
471 FvAlignment = 8;
472 }
473 //
474 // Check FvImage Align is required.
475 //
476 if (((UINTN) FvImage % FvAlignment) == 0) {
477 ProcessedFvImage = FvImage;
478 } else {
479 //
480 // Allocate new aligned buffer to store FvImage.
481 //
482 ProcessedFvImage = (EFI_FIRMWARE_VOLUME_HEADER *) AllocateAlignedPages ((UINTN) EFI_SIZE_TO_PAGES ((UINTN) FvImage->FvLength), (UINTN) FvAlignment);
483 if (ProcessedFvImage == NULL) {
484 Status = EFI_OUT_OF_RESOURCES;
485 break;
486 }
487 CopyMem (ProcessedFvImage, FvImage, (UINTN) FvImage->FvLength);
488 }
489
490 Status = gDS->ProcessFirmwareVolume (
491 (VOID *) ProcessedFvImage,
492 (UINTN) ProcessedFvImage->FvLength,
493 &FvProtocolHandle
494 );
495 if (EFI_ERROR (Status)) {
496 break;
497 }
498 //
499 // Call the dispatcher to dispatch any drivers from the produced firmware volume
500 //
501 gDS->Dispatch ();
502 //
503 // On to the next FV in the capsule
504 //
505 Length -= (UINT32) FvImage->FvLength;
506 FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) FvImage + FvImage->FvLength);
507 }
508
509 return Status;
510 }
511
512 /**
513
514 This routine is called to process capsules.
515
516 Caution: This function may receive untrusted input.
517
518 The capsules reported in EFI_HOB_UEFI_CAPSULE are processed.
519 If there is no EFI_HOB_UEFI_CAPSULE, this routine does nothing.
520
521 This routine should be called twice in BDS.
522 1) The first call must be before EndOfDxe. The system capsules is processed.
523 If device capsule FMP protocols are exposted at this time and device FMP
524 capsule has zero EmbeddedDriverCount, the device capsules are processed.
525 Each individual capsule result is recorded in capsule record variable.
526 System may reset in this function, if reset is required by capsule and
527 all capsules are processed.
528 If not all capsules are processed, reset will be defered to second call.
529
530 2) The second call must be after EndOfDxe and after ConnectAll, so that all
531 device capsule FMP protocols are exposed.
532 The system capsules are skipped. If the device capsules are NOT processed
533 in first call, they are processed here.
534 Each individual capsule result is recorded in capsule record variable.
535 System may reset in this function, if reset is required by capsule
536 processed in first call and second call.
537
538 @retval EFI_SUCCESS There is no error when processing capsules.
539 @retval EFI_OUT_OF_RESOURCES No enough resource to process capsules.
540
541 **/
542 EFI_STATUS
543 EFIAPI
544 ProcessCapsules (
545 VOID
546 )
547 {
548 return EFI_UNSUPPORTED;
549 }
550