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