]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.c
fc9b533f2ce22ed1bbb848f12ae297d41fde35de
[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 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