1 /** @file
2   Capsule Library instance to process capsule images.
3 
4   Copyright (c) 2007 - 2013, 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
Update_Image_Progress(IN UINTN Completion)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
ValidateFmpCapsule(IN EFI_CAPSULE_HEADER * CapsuleHeader)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
ProcessFmpCapsuleImage(IN EFI_CAPSULE_HEADER * CapsuleHeader)136 ProcessFmpCapsuleImage (
137   IN EFI_CAPSULE_HEADER *CapsuleHeader
138   )
139 {
140   EFI_STATUS                                    Status;
141   EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER        *FmpCapsuleHeader;
142   UINT8                                         *EndOfCapsule;
143   EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER  *ImageHeader;
144   EFI_HANDLE                                    ImageHandle;
145   UINT64                                        *ItemOffsetList;
146   UINT32                                        ItemNum;
147   UINTN                                         Index;
148   UINTN                                         ExitDataSize;
149   EFI_HANDLE                                    *HandleBuffer;
150   EFI_FIRMWARE_MANAGEMENT_PROTOCOL              *Fmp;
151   UINTN                                         NumberOfHandles;
152   UINTN                                         DescriptorSize;
153   UINT8                                         FmpImageInfoCount;
154   UINT32                                        FmpImageInfoDescriptorVer;
155   UINTN                                         ImageInfoSize;
156   UINT32                                        PackageVersion;
157   CHAR16                                        *PackageVersionName;
158   CHAR16                                        *AbortReason;
159   EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *FmpImageInfoBuf;
160   EFI_FIRMWARE_IMAGE_DESCRIPTOR                 *TempFmpImageInfo;
161   UINTN                                         DriverLen;
162   UINTN                                         Index1;
163   UINTN                                         Index2;
164   MEMMAP_DEVICE_PATH                            MemMapNode;
165   EFI_DEVICE_PATH_PROTOCOL                      *DriverDevicePath;
166 
167   Status           = EFI_SUCCESS;
168   HandleBuffer     = NULL;
169   ExitDataSize     = 0;
170   DriverDevicePath = NULL;
171 
172   FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
173   EndOfCapsule     = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;
174 
175   if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
176     return EFI_INVALID_PARAMETER;
177   }
178   ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
179 
180   ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
181 
182   //
183   // capsule in which driver count and payload count are both zero is not processed.
184   //
185   if (ItemNum == 0) {
186     return EFI_SUCCESS;
187   }
188 
189   //
190   // 1. ConnectAll to ensure
191   //    All the communication protocol required by driver in capsule installed
192   //    All FMP protocols are installed
193   //
194   BdsLibConnectAll();
195 
196 
197   //
198   // 2. Try to load & start all the drivers within capsule
199   //
200   SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));
201   MemMapNode.Header.Type     = HARDWARE_DEVICE_PATH;
202   MemMapNode.Header.SubType  = HW_MEMMAP_DP;
203   MemMapNode.MemoryType      = EfiBootServicesCode;
204   MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleHeader;
205   MemMapNode.EndingAddress   = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize - 1);
206 
207   DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);
208   if (DriverDevicePath == NULL) {
209     return EFI_OUT_OF_RESOURCES;
210   }
211 
212   for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
213     if (FmpCapsuleHeader->PayloadItemCount == 0 && Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1) {
214       //
215       // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER
216       //
217       DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];
218     } else {
219       DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];
220     }
221 
222     Status = gBS->LoadImage(
223                     FALSE,
224                     gImageHandle,
225                     DriverDevicePath,
226                     (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],
227                     DriverLen,
228                     &ImageHandle
229                     );
230     if (EFI_ERROR(Status)) {
231       goto EXIT;
232     }
233 
234     Status = gBS->StartImage(
235                     ImageHandle,
236                     &ExitDataSize,
237                     NULL
238                     );
239     if (EFI_ERROR(Status)) {
240       DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
241       goto EXIT;
242     }
243   }
244 
245   //
246   // Connnect all again to connect drivers within capsule
247   //
248   if (FmpCapsuleHeader->EmbeddedDriverCount > 0) {
249     BdsLibConnectAll();
250   }
251 
252   //
253   // 3. Route payload to right FMP instance
254   //
255   Status = gBS->LocateHandleBuffer (
256                   ByProtocol,
257                   &gEfiFirmwareManagementProtocolGuid,
258                   NULL,
259                   &NumberOfHandles,
260                   &HandleBuffer
261                   );
262 
263   if (!EFI_ERROR(Status)) {
264     for(Index1 = 0; Index1 < NumberOfHandles; Index1++) {
265       Status = gBS->HandleProtocol(
266                       HandleBuffer[Index1],
267                       &gEfiFirmwareManagementProtocolGuid,
268                       (VOID **)&Fmp
269                       );
270       if (EFI_ERROR(Status)) {
271         continue;
272       }
273 
274       ImageInfoSize = 0;
275       Status = Fmp->GetImageInfo (
276                       Fmp,
277                       &ImageInfoSize,
278                       NULL,
279                       NULL,
280                       NULL,
281                       NULL,
282                       NULL,
283                       NULL
284                       );
285       if (Status != EFI_BUFFER_TOO_SMALL) {
286         continue;
287       }
288 
289       FmpImageInfoBuf = NULL;
290       FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
291       if (FmpImageInfoBuf == NULL) {
292         Status = EFI_OUT_OF_RESOURCES;
293         goto EXIT;
294       }
295 
296       PackageVersionName = NULL;
297       Status = Fmp->GetImageInfo (
298                       Fmp,
299                       &ImageInfoSize,               // ImageInfoSize
300                       FmpImageInfoBuf,              // ImageInfo
301                       &FmpImageInfoDescriptorVer,   // DescriptorVersion
302                       &FmpImageInfoCount,           // DescriptorCount
303                       &DescriptorSize,              // DescriptorSize
304                       &PackageVersion,              // PackageVersion
305                       &PackageVersionName           // PackageVersionName
306                       );
307 
308       //
309       // If FMP GetInformation interface failed, skip this resource
310       //
311       if (EFI_ERROR(Status)) {
312         FreePool(FmpImageInfoBuf);
313         continue;
314       }
315 
316       if (PackageVersionName != NULL) {
317         FreePool(PackageVersionName);
318       }
319 
320       TempFmpImageInfo = FmpImageInfoBuf;
321       for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {
322         //
323         // Check all the payload entry in capsule payload list
324         //
325         for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
326           ImageHeader  = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
327           if (CompareGuid(&ImageHeader->UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId) &&
328               ImageHeader->UpdateImageIndex == TempFmpImageInfo->ImageIndex) {
329             AbortReason = NULL;
330             if (ImageHeader->UpdateVendorCodeSize == 0) {
331               Status = Fmp->SetImage(
332                               Fmp,
333                               TempFmpImageInfo->ImageIndex,           // ImageIndex
334                               (UINT8 *)(ImageHeader + 1),             // Image
335                               ImageHeader->UpdateImageSize,           // ImageSize
336                               NULL,                                   // VendorCode
337                               Update_Image_Progress,                  // Progress
338                               &AbortReason                            // AbortReason
339                               );
340             } else {
341               Status = Fmp->SetImage(
342                               Fmp,
343                               TempFmpImageInfo->ImageIndex,                                          // ImageIndex
344                               (UINT8 *)(ImageHeader + 1),                                            // Image
345                               ImageHeader->UpdateImageSize,                                          // ImageSize
346                               (UINT8 *)((UINT8 *) (ImageHeader + 1) + ImageHeader->UpdateImageSize), // VendorCode
347                               Update_Image_Progress,                                                 // Progress
348                               &AbortReason                                                           // AbortReason
349                               );
350             }
351             if (AbortReason != NULL) {
352               DEBUG ((EFI_D_ERROR, "%s\n", AbortReason));
353               FreePool(AbortReason);
354             }
355           }
356         }
357         //
358         // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
359         //
360         TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);
361       }
362       FreePool(FmpImageInfoBuf);
363     }
364   }
365 
366 EXIT:
367 
368   if (HandleBuffer != NULL) {
369     FreePool(HandleBuffer);
370   }
371 
372   if (DriverDevicePath != NULL) {
373     FreePool(DriverDevicePath);
374   }
375 
376   return Status;
377 }
378 
379 /**
380   Those capsules supported by the firmwares.
381 
382   @param  CapsuleHeader    Points to a capsule header.
383 
384   @retval EFI_SUCESS       Input capsule is supported by firmware.
385   @retval EFI_UNSUPPORTED  Input capsule is not supported by the firmware.
386   @retval EFI_INVALID_PARAMETER Input capsule layout is not correct
387 **/
388 EFI_STATUS
389 EFIAPI
SupportCapsuleImage(IN EFI_CAPSULE_HEADER * CapsuleHeader)390 SupportCapsuleImage (
391   IN EFI_CAPSULE_HEADER *CapsuleHeader
392   )
393 {
394   if (CompareGuid (&gEfiCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
395     return EFI_SUCCESS;
396   }
397 
398   if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
399     //
400     // Check layout of FMP capsule
401     //
402     return ValidateFmpCapsule(CapsuleHeader);
403   }
404 
405   return EFI_UNSUPPORTED;
406 }
407 
408 /**
409   The firmware implements to process the capsule image.
410 
411   @param  CapsuleHeader         Points to a capsule header.
412 
413   @retval EFI_SUCESS            Process Capsule Image successfully.
414   @retval EFI_UNSUPPORTED       Capsule image is not supported by the firmware.
415   @retval EFI_VOLUME_CORRUPTED  FV volume in the capsule is corrupted.
416   @retval EFI_OUT_OF_RESOURCES  Not enough memory.
417 **/
418 EFI_STATUS
419 EFIAPI
ProcessCapsuleImage(IN EFI_CAPSULE_HEADER * CapsuleHeader)420 ProcessCapsuleImage (
421   IN EFI_CAPSULE_HEADER *CapsuleHeader
422   )
423 {
424   UINT32                       Length;
425   EFI_FIRMWARE_VOLUME_HEADER   *FvImage;
426   EFI_FIRMWARE_VOLUME_HEADER   *ProcessedFvImage;
427   EFI_STATUS                   Status;
428   EFI_HANDLE                   FvProtocolHandle;
429   UINT32                       FvAlignment;
430 
431   FvImage = NULL;
432   ProcessedFvImage = NULL;
433   Status  = EFI_SUCCESS;
434 
435   if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {
436     return EFI_UNSUPPORTED;
437   }
438 
439   //
440   // Check FMP capsule layout
441   //
442   if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)){
443     Status = ValidateFmpCapsule(CapsuleHeader);
444     if (EFI_ERROR(Status)) {
445       return Status;
446     }
447 
448     //
449     // Press EFI FMP Capsule
450     //
451     return ProcessFmpCapsuleImage(CapsuleHeader);
452   }
453 
454   //
455   // Skip the capsule header, move to the Firware Volume
456   //
457   FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
458   Length  = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
459 
460   while (Length != 0) {
461     //
462     // Point to the next firmware volume header, and then
463     // call the DXE service to process it.
464     //
465     if (FvImage->FvLength > (UINTN) Length) {
466       //
467       // Notes: need to stuff this status somewhere so that the
468       // error can be detected at OS runtime
469       //
470       Status = EFI_VOLUME_CORRUPTED;
471       break;
472     }
473 
474     FvAlignment = 1 << ((FvImage->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
475     //
476     // FvAlignment must be more than 8 bytes required by FvHeader structure.
477     //
478     if (FvAlignment < 8) {
479       FvAlignment = 8;
480     }
481     //
482     // Check FvImage Align is required.
483     //
484     if (((UINTN) FvImage % FvAlignment) == 0) {
485       ProcessedFvImage = FvImage;
486     } else {
487       //
488       // Allocate new aligned buffer to store FvImage.
489       //
490       ProcessedFvImage = (EFI_FIRMWARE_VOLUME_HEADER *) AllocateAlignedPages ((UINTN) EFI_SIZE_TO_PAGES ((UINTN) FvImage->FvLength), (UINTN) FvAlignment);
491       if (ProcessedFvImage == NULL) {
492         Status = EFI_OUT_OF_RESOURCES;
493         break;
494       }
495       CopyMem (ProcessedFvImage, FvImage, (UINTN) FvImage->FvLength);
496     }
497 
498     Status = gDS->ProcessFirmwareVolume (
499                   (VOID *) ProcessedFvImage,
500                   (UINTN) ProcessedFvImage->FvLength,
501                   &FvProtocolHandle
502                   );
503     if (EFI_ERROR (Status)) {
504       break;
505     }
506     //
507     // Call the dispatcher to dispatch any drivers from the produced firmware volume
508     //
509     gDS->Dispatch ();
510     //
511     // On to the next FV in the capsule
512     //
513     Length -= (UINT32) FvImage->FvLength;
514     FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) FvImage + FvImage->FvLength);
515   }
516 
517   return Status;
518 }
519 
520 
521