]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.c
104b1943697d1d555a09e1e21c9305d0bc413bbc
[mirror_edk2.git] / IntelFrameworkModulePkg / Library / DxeCapsuleLib / DxeCapsuleLib.c
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
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 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)CapsuleHeader;
205 MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)((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 == 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 - ItemOffsetList[Index];
218 } else {
219 DriverLen = ItemOffsetList[Index + 1] - 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 &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
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
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