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