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