]> git.proxmox.com Git - mirror_edk2.git/blob - SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.c
SignedCapsulePkg/SystemFirmwareUpdateDxe: Fix ECC issues
[mirror_edk2.git] / SignedCapsulePkg / Universal / SystemFirmwareUpdate / SystemFirmwareUpdateDxe.c
1 /** @file
2 SetImage instance to update system firmware.
3
4 Caution: This module requires additional review when modified.
5 This module will have external input - capsule image.
6 This external input must be validated carefully to avoid security issue like
7 buffer overflow, integer overflow.
8
9 FmpSetImage() will receive untrusted input and do basic validation.
10
11 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
12 This program and the accompanying materials
13 are licensed and made available under the terms and conditions of the BSD License
14 which accompanies this distribution. The full text of the license may be found at
15 http://opensource.org/licenses/bsd-license.php
16
17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19
20 **/
21
22 #include "SystemFirmwareDxe.h"
23
24 //
25 // SystemFmp driver private data
26 //
27 SYSTEM_FMP_PRIVATE_DATA *mSystemFmpPrivate = NULL;
28
29 EFI_GUID mCurrentImageTypeId;
30
31 BOOLEAN mNvRamUpdated = FALSE;
32
33 /**
34 Parse Config data file to get the updated data array.
35
36 @param[in] DataBuffer Config raw file buffer.
37 @param[in] BufferSize Size of raw buffer.
38 @param[in, out] ConfigHeader Pointer to the config header.
39 @param[in, out] UpdateArray Pointer to the config of update data.
40
41 @retval EFI_NOT_FOUND No config data is found.
42 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
43 @retval EFI_SUCCESS Parse the config file successfully.
44
45 **/
46 EFI_STATUS
47 ParseUpdateDataFile (
48 IN UINT8 *DataBuffer,
49 IN UINTN BufferSize,
50 IN OUT CONFIG_HEADER *ConfigHeader,
51 IN OUT UPDATE_CONFIG_DATA **UpdateArray
52 );
53
54 /**
55 Update System Firmware image component.
56
57 @param[in] SystemFirmwareImage Points to the System Firmware image.
58 @param[in] SystemFirmwareImageSize The length of the System Firmware image in bytes.
59 @param[in] ConfigData Points to the component configuration structure.
60 @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
61 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
62 @param[in] Progress A function used by the driver to report the progress of the firmware update.
63 @param[in] StartPercentage The start completion percentage value that may be used to report progress during the flash write operation.
64 @param[in] EndPercentage The end completion percentage value that may be used to report progress during the flash write operation.
65
66 @retval EFI_SUCCESS The System Firmware image is updated.
67 @retval EFI_WRITE_PROTECTED The flash device is read only.
68 **/
69 EFI_STATUS
70 PerformUpdate (
71 IN VOID *SystemFirmwareImage,
72 IN UINTN SystemFirmwareImageSize,
73 IN UPDATE_CONFIG_DATA *ConfigData,
74 OUT UINT32 *LastAttemptVersion,
75 OUT UINT32 *LastAttemptStatus,
76 IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,
77 IN UINTN StartPercentage,
78 IN UINTN EndPercentage
79 )
80 {
81 EFI_STATUS Status;
82
83 DEBUG((DEBUG_INFO, "PlatformUpdate:"));
84 DEBUG((DEBUG_INFO, " BaseAddress - 0x%lx,", ConfigData->BaseAddress));
85 DEBUG((DEBUG_INFO, " ImageOffset - 0x%x,", ConfigData->ImageOffset));
86 DEBUG((DEBUG_INFO, " Legnth - 0x%x\n", ConfigData->Length));
87 if (Progress != NULL) {
88 Progress (StartPercentage);
89 }
90 Status = PerformFlashWriteWithProgress (
91 ConfigData->FirmwareType,
92 ConfigData->BaseAddress,
93 ConfigData->AddressType,
94 (VOID *)((UINTN)SystemFirmwareImage + (UINTN)ConfigData->ImageOffset),
95 ConfigData->Length,
96 Progress,
97 StartPercentage,
98 EndPercentage
99 );
100 if (Progress != NULL) {
101 Progress (EndPercentage);
102 }
103 if (!EFI_ERROR(Status)) {
104 *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
105 if (ConfigData->FirmwareType == PlatformFirmwareTypeNvRam) {
106 mNvRamUpdated = TRUE;
107 }
108 } else {
109 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
110 }
111 return Status;
112 }
113
114 /**
115 Update System Firmware image.
116
117 @param[in] SystemFirmwareImage Points to the System Firmware image.
118 @param[in] SystemFirmwareImageSize The length of the System Firmware image in bytes.
119 @param[in] ConfigImage Points to the config file image.
120 @param[in] ConfigImageSize The length of the config file image in bytes.
121 @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
122 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
123 @param[in] Progress A function used by the driver to report the progress of the firmware update.
124
125 @retval EFI_SUCCESS The System Firmware image is updated.
126 @retval EFI_WRITE_PROTECTED The flash device is read only.
127 **/
128 EFI_STATUS
129 UpdateImage (
130 IN VOID *SystemFirmwareImage,
131 IN UINTN SystemFirmwareImageSize,
132 IN VOID *ConfigImage,
133 IN UINTN ConfigImageSize,
134 OUT UINT32 *LastAttemptVersion,
135 OUT UINT32 *LastAttemptStatus,
136 IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress
137 )
138 {
139 EFI_STATUS Status;
140 UPDATE_CONFIG_DATA *ConfigData;
141 UPDATE_CONFIG_DATA *UpdateConfigData;
142 CONFIG_HEADER ConfigHeader;
143 UINTN Index;
144 UINTN TotalSize;
145 UINTN BytesWritten;
146 UINTN StartPercentage;
147 UINTN EndPercentage;
148
149 if (ConfigImage == NULL) {
150 DEBUG((DEBUG_INFO, "PlatformUpdate (NoConfig):"));
151 DEBUG((DEBUG_INFO, " BaseAddress - 0x%x,", 0));
152 DEBUG((DEBUG_INFO, " Length - 0x%x\n", SystemFirmwareImageSize));
153 // ASSUME the whole System Firmware include NVRAM region.
154 StartPercentage = 0;
155 EndPercentage = 100;
156 if (Progress != NULL) {
157 Progress (StartPercentage);
158 }
159 Status = PerformFlashWriteWithProgress (
160 PlatformFirmwareTypeNvRam,
161 0,
162 FlashAddressTypeRelativeAddress,
163 SystemFirmwareImage,
164 SystemFirmwareImageSize,
165 Progress,
166 StartPercentage,
167 EndPercentage
168 );
169 if (Progress != NULL) {
170 Progress (EndPercentage);
171 }
172 if (!EFI_ERROR(Status)) {
173 *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
174 mNvRamUpdated = TRUE;
175 } else {
176 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
177 }
178 return Status;
179 }
180
181 DEBUG((DEBUG_INFO, "PlatformUpdate (With Config):\n"));
182 ConfigData = NULL;
183 ZeroMem (&ConfigHeader, sizeof(ConfigHeader));
184 Status = ParseUpdateDataFile (
185 ConfigImage,
186 ConfigImageSize,
187 &ConfigHeader,
188 &ConfigData
189 );
190 DEBUG((DEBUG_INFO, "ParseUpdateDataFile - %r\n", Status));
191 if (EFI_ERROR(Status)) {
192 *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
193 return EFI_INVALID_PARAMETER;
194 }
195 DEBUG((DEBUG_INFO, "ConfigHeader.NumOfUpdates - 0x%x\n", ConfigHeader.NumOfUpdates));
196 DEBUG((DEBUG_INFO, "PcdEdkiiSystemFirmwareFileGuid - %g\n", PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid)));
197
198 TotalSize = 0;
199 for (Index = 0; Index < ConfigHeader.NumOfUpdates; Index++) {
200 if (CompareGuid(&ConfigData[Index].FileGuid, PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid))) {
201 TotalSize = TotalSize + ConfigData[Index].Length;
202 }
203 }
204
205 BytesWritten = 0;
206 Index = 0;
207 UpdateConfigData = ConfigData;
208 while (Index < ConfigHeader.NumOfUpdates) {
209 if (CompareGuid(&UpdateConfigData->FileGuid, PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid))) {
210 DEBUG((DEBUG_INFO, "FileGuid - %g (processing)\n", &UpdateConfigData->FileGuid));
211 StartPercentage = (BytesWritten * 100) / TotalSize;
212 EndPercentage = ((BytesWritten + UpdateConfigData->Length) * 100) / TotalSize;
213 Status = PerformUpdate (
214 SystemFirmwareImage,
215 SystemFirmwareImageSize,
216 UpdateConfigData,
217 LastAttemptVersion,
218 LastAttemptStatus,
219 Progress,
220 StartPercentage,
221 EndPercentage
222 );
223 //
224 // Shall updates be serialized so that if an update is not successfully completed,
225 // the remaining updates won't be performed.
226 //
227 if (EFI_ERROR (Status)) {
228 break;
229 }
230 } else {
231 DEBUG((DEBUG_INFO, "FileGuid - %g (ignored)\n", &UpdateConfigData->FileGuid));
232 }
233
234 BytesWritten += UpdateConfigData->Length;
235
236 Index++;
237 UpdateConfigData++;
238 }
239
240 return Status;
241 }
242
243 /**
244 Authenticate and update System Firmware image.
245
246 Caution: This function may receive untrusted input.
247
248 @param[in] Image The EDKII system FMP capsule image.
249 @param[in] ImageSize The size of the EDKII system FMP capsule image in bytes.
250 @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
251 @param[out] LastAttemptStatus The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.
252 @param[in] Progress A function used by the driver to report the progress of the firmware update.
253
254 @retval EFI_SUCCESS EDKII system FMP capsule passes authentication and the System Firmware image is updated.
255 @retval EFI_SECURITY_VIOLATION EDKII system FMP capsule fails authentication and the System Firmware image is not updated.
256 @retval EFI_WRITE_PROTECTED The flash device is read only.
257 **/
258 EFI_STATUS
259 SystemFirmwareAuthenticatedUpdate (
260 IN VOID *Image,
261 IN UINTN ImageSize,
262 OUT UINT32 *LastAttemptVersion,
263 OUT UINT32 *LastAttemptStatus,
264 IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress
265 )
266 {
267 EFI_STATUS Status;
268 VOID *SystemFirmwareImage;
269 UINTN SystemFirmwareImageSize;
270 VOID *ConfigImage;
271 UINTN ConfigImageSize;
272 VOID *AuthenticatedImage;
273 UINTN AuthenticatedImageSize;
274
275 AuthenticatedImage = NULL;
276 AuthenticatedImageSize = 0;
277
278 DEBUG((DEBUG_INFO, "SystemFirmwareAuthenticatedUpdate...\n"));
279
280 Status = CapsuleAuthenticateSystemFirmware(Image, ImageSize, FALSE, LastAttemptVersion, LastAttemptStatus, &AuthenticatedImage, &AuthenticatedImageSize);
281 if (EFI_ERROR(Status)) {
282 DEBUG((DEBUG_INFO, "SystemFirmwareAuthenticateImage - %r\n", Status));
283 return Status;
284 }
285
286 DEBUG((DEBUG_INFO, "ExtractSystemFirmwareImage ...\n"));
287 ExtractSystemFirmwareImage(AuthenticatedImage, AuthenticatedImageSize, &SystemFirmwareImage, &SystemFirmwareImageSize);
288 DEBUG((DEBUG_INFO, "ExtractConfigImage ...\n"));
289 ExtractConfigImage(AuthenticatedImage, AuthenticatedImageSize, &ConfigImage, &ConfigImageSize);
290
291 DEBUG((DEBUG_INFO, "UpdateImage ...\n"));
292 Status = UpdateImage(SystemFirmwareImage, SystemFirmwareImageSize, ConfigImage, ConfigImageSize, LastAttemptVersion, LastAttemptStatus, Progress);
293 if (EFI_ERROR(Status)) {
294 DEBUG((DEBUG_INFO, "UpdateImage - %r\n", Status));
295 return Status;
296 }
297
298 DEBUG((DEBUG_INFO, "SystemFirmwareAuthenticatedUpdate Done\n"));
299
300 return EFI_SUCCESS;
301 }
302
303 /**
304
305 This code finds variable in storage blocks (Volatile or Non-Volatile).
306
307 @param[in] VariableName Name of Variable to be found.
308 @param[in] VendorGuid Variable vendor GUID.
309 @param[out] Attributes Attribute value of the variable found.
310 @param[in, out] DataSize Size of Data found. If size is less than the
311 data, this value contains the required size.
312 @param[out] Data Data pointer.
313
314 @return EFI_INVALID_PARAMETER Invalid parameter.
315 @return EFI_SUCCESS Find the specified variable.
316 @return EFI_NOT_FOUND Not found.
317 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
318
319 **/
320 EFI_STATUS
321 EFIAPI
322 GetVariableHook (
323 IN CHAR16 *VariableName,
324 IN EFI_GUID *VendorGuid,
325 OUT UINT32 *Attributes OPTIONAL,
326 IN OUT UINTN *DataSize,
327 OUT VOID *Data
328 )
329 {
330 DEBUG((DEBUG_INFO, "GetVariableHook - %S, %g\n", VariableName, VendorGuid));
331 return EFI_NOT_AVAILABLE_YET;
332 }
333
334 /**
335
336 This code Finds the Next available variable.
337
338 @param[in, out] VariableNameSize Size of the variable name.
339 @param[in, out] VariableName Pointer to variable name.
340 @param[in, out] VendorGuid Variable Vendor Guid.
341
342 @return EFI_INVALID_PARAMETER Invalid parameter.
343 @return EFI_SUCCESS Find the specified variable.
344 @return EFI_NOT_FOUND Not found.
345 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
346
347 **/
348 EFI_STATUS
349 EFIAPI
350 GetNextVariableNameHook (
351 IN OUT UINTN *VariableNameSize,
352 IN OUT CHAR16 *VariableName,
353 IN OUT EFI_GUID *VendorGuid
354 )
355 {
356 DEBUG((DEBUG_INFO, "GetNextVariableNameHook - %S, %g\n", VariableName, VendorGuid));
357 return EFI_NOT_AVAILABLE_YET;
358 }
359
360 /**
361
362 This code sets variable in storage blocks (Volatile or Non-Volatile).
363
364 @param[in] VariableName Name of Variable to be found.
365 @param[in] VendorGuid Variable vendor GUID.
366 @param[in] Attributes Attribute value of the variable found
367 @param[in] DataSize Size of Data found. If size is less than the
368 data, this value contains the required size.
369 @param[in] Data Data pointer.
370
371 @return EFI_INVALID_PARAMETER Invalid parameter.
372 @return EFI_SUCCESS Set successfully.
373 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
374 @return EFI_NOT_FOUND Not found.
375 @return EFI_WRITE_PROTECTED Variable is read-only.
376
377 **/
378 EFI_STATUS
379 EFIAPI
380 SetVariableHook (
381 IN CHAR16 *VariableName,
382 IN EFI_GUID *VendorGuid,
383 IN UINT32 Attributes,
384 IN UINTN DataSize,
385 IN VOID *Data
386 )
387 {
388 DEBUG((DEBUG_INFO, "SetVariableHook - %S, %g, 0x%x (0x%x)\n", VariableName, VendorGuid, Attributes, DataSize));
389 return EFI_NOT_AVAILABLE_YET;
390 }
391
392 /**
393
394 This code returns information about the EFI variables.
395
396 @param[in] Attributes Attributes bitmask to specify the type of variables
397 on which to return information.
398 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
399 for the EFI variables associated with the attributes specified.
400 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
401 for EFI variables associated with the attributes specified.
402 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
403 associated with the attributes specified.
404
405 @return EFI_SUCCESS Query successfully.
406
407 **/
408 EFI_STATUS
409 EFIAPI
410 QueryVariableInfoHook (
411 IN UINT32 Attributes,
412 OUT UINT64 *MaximumVariableStorageSize,
413 OUT UINT64 *RemainingVariableStorageSize,
414 OUT UINT64 *MaximumVariableSize
415 )
416 {
417 DEBUG((DEBUG_INFO, "QueryVariableInfoHook - 0x%x\n", Attributes));
418 return EFI_NOT_AVAILABLE_YET;
419 }
420
421 /**
422 Updates the firmware image of the device.
423
424 This function updates the hardware with the new firmware image.
425 This function returns EFI_UNSUPPORTED if the firmware image is not updatable.
426 If the firmware image is updatable, the function should perform the following minimal validations
427 before proceeding to do the firmware image update.
428 - Validate the image authentication if image has attribute
429 IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED. The function returns
430 EFI_SECURITY_VIOLATION if the validation fails.
431 - Validate the image is a supported image for this device. The function returns EFI_ABORTED if
432 the image is unsupported. The function can optionally provide more detailed information on
433 why the image is not a supported image.
434 - Validate the data from VendorCode if not null. Image validation must be performed before
435 VendorCode data validation. VendorCode data is ignored or considered invalid if image
436 validation failed. The function returns EFI_ABORTED if the data is invalid.
437
438 VendorCode enables vendor to implement vendor-specific firmware image update policy. Null if
439 the caller did not specify the policy or use the default policy. As an example, vendor can implement
440 a policy to allow an option to force a firmware image update when the abort reason is due to the new
441 firmware image version is older than the current firmware image version or bad image checksum.
442 Sensitive operations such as those wiping the entire firmware image and render the device to be
443 non-functional should be encoded in the image itself rather than passed with the VendorCode.
444 AbortReason enables vendor to have the option to provide a more detailed description of the abort
445 reason to the caller.
446
447 @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
448 @param[in] ImageIndex A unique number identifying the firmware image(s) within the device.
449 The number is between 1 and DescriptorCount.
450 @param[in] Image Points to the new image.
451 @param[in] ImageSize Size of the new image in bytes.
452 @param[in] VendorCode This enables vendor to implement vendor-specific firmware image update policy.
453 Null indicates the caller did not specify the policy or use the default policy.
454 @param[in] Progress A function used by the driver to report the progress of the firmware update.
455 @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
456 details for the aborted operation. The buffer is allocated by this function
457 with AllocatePool(), and it is the caller's responsibility to free it with a
458 call to FreePool().
459
460 @retval EFI_SUCCESS The device was successfully updated with the new image.
461 @retval EFI_ABORTED The operation is aborted.
462 @retval EFI_INVALID_PARAMETER The Image was NULL.
463 @retval EFI_UNSUPPORTED The operation is not supported.
464 @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.
465
466 **/
467 EFI_STATUS
468 EFIAPI
469 FmpSetImage (
470 IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
471 IN UINT8 ImageIndex,
472 IN CONST VOID *Image,
473 IN UINTN ImageSize,
474 IN CONST VOID *VendorCode,
475 IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,
476 OUT CHAR16 **AbortReason
477 )
478 {
479 EFI_STATUS Status;
480 EFI_STATUS VarStatus;
481 SYSTEM_FMP_PRIVATE_DATA *SystemFmpPrivate;
482
483 if (Image == NULL || ImageSize == 0 || AbortReason == NULL) {
484 return EFI_INVALID_PARAMETER;
485 }
486
487 SystemFmpPrivate = SYSTEM_FMP_PRIVATE_DATA_FROM_FMP(This);
488 *AbortReason = NULL;
489
490 if (ImageIndex == 0 || ImageIndex > SystemFmpPrivate->DescriptorCount) {
491 return EFI_INVALID_PARAMETER;
492 }
493
494 Status = SystemFirmwareAuthenticatedUpdate((VOID *)Image, ImageSize, &SystemFmpPrivate->LastAttempt.LastAttemptVersion, &SystemFmpPrivate->LastAttempt.LastAttemptStatus, Progress);
495 DEBUG((DEBUG_INFO, "SetImage - LastAttempt Version - 0x%x, State - 0x%x\n", SystemFmpPrivate->LastAttempt.LastAttemptVersion, SystemFmpPrivate->LastAttempt.LastAttemptStatus));
496
497 //
498 // If NVRAM is updated, we should no longer touch variable services, because
499 // the current variable driver may not manage the new NVRAM region.
500 //
501 if (mNvRamUpdated) {
502 DEBUG ((DEBUG_INFO, "NvRamUpdated, Update Variable Serivces\n"));
503 gRT->GetVariable = GetVariableHook;
504 gRT->GetNextVariableName = GetNextVariableNameHook;
505 gRT->SetVariable = SetVariableHook;
506 gRT->QueryVariableInfo = QueryVariableInfoHook;
507
508 gRT->Hdr.CRC32 = 0;
509 gBS->CalculateCrc32 (
510 (UINT8 *) &gRT->Hdr,
511 gRT->Hdr.HeaderSize,
512 &gRT->Hdr.CRC32
513 );
514 }
515
516 VarStatus = gRT->SetVariable(
517 SYSTEM_FMP_LAST_ATTEMPT_VARIABLE_NAME,
518 &gSystemFmpLastAttemptVariableGuid,
519 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
520 sizeof(SystemFmpPrivate->LastAttempt),
521 &SystemFmpPrivate->LastAttempt
522 );
523 DEBUG((DEBUG_INFO, "SetLastAttemp - %r\n", VarStatus));
524
525 return Status;
526 }
527
528 /**
529 Get the set of EFI_FIRMWARE_IMAGE_DESCRIPTOR structures from an FMP Protocol.
530
531 @param[in] Handle Handle with an FMP Protocol or a System FMP
532 Protocol.
533 @param[in] ProtocolGuid Pointer to the FMP Protocol GUID or System FMP
534 Protocol GUID.
535 @param[out] FmpImageInfoCount Pointer to the number of
536 EFI_FIRMWARE_IMAGE_DESCRIPTOR structures.
537 @param[out] DescriptorSize Pointer to the size, in bytes, of each
538 EFI_FIRMWARE_IMAGE_DESCRIPTOR structure.
539
540 @return NULL No EFI_FIRMWARE_IMAGE_DESCRIPTOR structures found.
541 @return !NULL Pointer to a buffer of EFI_FIRMWARE_IMAGE_DESCRIPTOR structures
542 allocated using AllocatePool(). Caller must free buffer with
543 FreePool().
544 **/
545 EFI_FIRMWARE_IMAGE_DESCRIPTOR *
546 GetFmpImageDescriptors (
547 IN EFI_HANDLE Handle,
548 IN EFI_GUID *ProtocolGuid,
549 OUT UINT8 *FmpImageInfoCount,
550 OUT UINTN *DescriptorSize
551 )
552 {
553 EFI_STATUS Status;
554 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
555 UINTN ImageInfoSize;
556 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
557 UINT32 FmpImageInfoDescriptorVer;
558 UINT32 PackageVersion;
559 CHAR16 *PackageVersionName;
560
561 *FmpImageInfoCount = 0;
562 *DescriptorSize = 0;
563
564 Status = gBS->HandleProtocol (
565 Handle,
566 ProtocolGuid,
567 (VOID **)&Fmp
568 );
569 if (EFI_ERROR (Status)) {
570 return NULL;
571 }
572
573 //
574 // Determine the size required for the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
575 //
576 ImageInfoSize = 0;
577 Status = Fmp->GetImageInfo (
578 Fmp, // FMP Pointer
579 &ImageInfoSize, // Buffer Size (in this case 0)
580 NULL, // NULL so we can get size
581 &FmpImageInfoDescriptorVer, // DescriptorVersion
582 FmpImageInfoCount, // DescriptorCount
583 DescriptorSize, // DescriptorSize
584 &PackageVersion, // PackageVersion
585 &PackageVersionName // PackageVersionName
586 );
587 if (Status != EFI_BUFFER_TOO_SMALL) {
588 DEBUG ((DEBUG_ERROR, "SystemFirmwareUpdateDxe: Unexpected Failure. Status = %r\n", Status));
589 return NULL;
590 }
591
592 //
593 // Allocate buffer for the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
594 //
595 FmpImageInfoBuf = NULL;
596 FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
597 if (FmpImageInfoBuf == NULL) {
598 DEBUG ((DEBUG_ERROR, "SystemFirmwareUpdateDxe: Failed to allocate memory for descriptors.\n"));
599 return NULL;
600 }
601
602 //
603 // Retrieve the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
604 //
605 PackageVersionName = NULL;
606 Status = Fmp->GetImageInfo (
607 Fmp,
608 &ImageInfoSize, // ImageInfoSize
609 FmpImageInfoBuf, // ImageInfo
610 &FmpImageInfoDescriptorVer, // DescriptorVersion
611 FmpImageInfoCount, // DescriptorCount
612 DescriptorSize, // DescriptorSize
613 &PackageVersion, // PackageVersion
614 &PackageVersionName // PackageVersionName
615 );
616
617 //
618 // Free unused PackageVersionName return buffer
619 //
620 if (PackageVersionName != NULL) {
621 FreePool (PackageVersionName);
622 PackageVersionName = NULL;
623 }
624
625 if (EFI_ERROR (Status)) {
626 DEBUG ((DEBUG_ERROR, "SystemFirmwareUpdateDxe: Failure in GetImageInfo. Status = %r\n", Status));
627 if (FmpImageInfoBuf != NULL) {
628 FreePool (FmpImageInfoBuf);
629 }
630 return NULL;
631 }
632
633 return FmpImageInfoBuf;
634 }
635
636 /**
637 Search for handles with an FMP protocol whose EFI_FIRMWARE_IMAGE_DESCRIPTOR
638 ImageTypeId matches the ImageTypeId produced by this module.
639
640 @param[in] ProtocolGuid Pointer to the GUID of the protocol to search.
641 @param[out] HandleCount Pointer to the number of returned handles.
642
643 @return NULL No matching handles found.
644 @return !NULL Pointer to a buffer of handles allocated using AllocatePool().
645 Caller must free buffer with FreePool().
646 **/
647 EFI_HANDLE *
648 FindMatchingFmpHandles (
649 IN EFI_GUID *ProtocolGuid,
650 OUT UINTN *HandleCount
651 )
652 {
653 EFI_STATUS Status;
654 UINTN TempHandleCount;
655 EFI_HANDLE *HandleBuffer;
656 UINTN Index;
657 UINTN Index2;
658 UINTN Index3;
659 EFI_FIRMWARE_IMAGE_DESCRIPTOR *OriginalFmpImageInfoBuf;
660 EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
661 UINT8 FmpImageInfoCount;
662 UINTN DescriptorSize;
663 BOOLEAN MatchFound;
664
665 *HandleCount = 0;
666 TempHandleCount = 0;
667 HandleBuffer = NULL;
668 Status = gBS->LocateHandleBuffer (
669 ByProtocol,
670 ProtocolGuid,
671 NULL,
672 &TempHandleCount,
673 &HandleBuffer
674 );
675 if (EFI_ERROR (Status)) {
676 return NULL;
677 }
678
679 for (Index = 0; Index < TempHandleCount; Index++) {
680 OriginalFmpImageInfoBuf = GetFmpImageDescriptors (
681 HandleBuffer[Index],
682 ProtocolGuid,
683 &FmpImageInfoCount,
684 &DescriptorSize
685 );
686
687 //
688 // Loop through the set of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
689 //
690 FmpImageInfoBuf = OriginalFmpImageInfoBuf;
691 MatchFound = FALSE;
692 for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {
693 for (Index3 = 0; Index3 < mSystemFmpPrivate->DescriptorCount; Index3++) {
694 MatchFound = CompareGuid (
695 &FmpImageInfoBuf->ImageTypeId,
696 &mSystemFmpPrivate->ImageDescriptor[Index3].ImageTypeId
697 );
698 if (MatchFound) {
699 break;
700 }
701 }
702 if (MatchFound) {
703 break;
704 }
705 //
706 // Increment the buffer pointer ahead by the size of the descriptor
707 //
708 FmpImageInfoBuf = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)(((UINT8 *)FmpImageInfoBuf) + DescriptorSize);
709 }
710 if (MatchFound) {
711 HandleBuffer[*HandleCount] = HandleBuffer[Index];
712 (*HandleCount)++;
713 }
714
715 FreePool (OriginalFmpImageInfoBuf);
716 }
717
718 if ((*HandleCount) == 0) {
719 //
720 // No any matching handle.
721 //
722 FreePool (HandleBuffer);
723 return NULL;
724 }
725 return HandleBuffer;
726 }
727
728 /**
729 Uninstall System FMP Protocol instances that may have been installed by
730 SystemFirmwareUpdateDxe drivers dispatches by other capsules.
731
732 @retval EFI_SUCCESS All System FMP Protocols found were uninstalled.
733 @return Other One or more System FMP Protocols could not be uninstalled.
734
735 **/
736 EFI_STATUS
737 UninstallMatchingSystemFmpProtocols (
738 VOID
739 )
740 {
741 EFI_STATUS Status;
742 EFI_HANDLE *HandleBuffer;
743 UINTN HandleCount;
744 UINTN Index;
745 EFI_FIRMWARE_MANAGEMENT_PROTOCOL *SystemFmp;
746
747 //
748 // Uninstall SystemFmpProtocol instances that may have been produced by
749 // the SystemFirmwareUpdate drivers in FVs dispatched by other capsules.
750 //
751 HandleBuffer = FindMatchingFmpHandles (
752 &gSystemFmpProtocolGuid,
753 &HandleCount
754 );
755 DEBUG ((DEBUG_INFO, "SystemFirmwareUpdateDxe: Found %d matching System FMP instances\n", HandleCount));
756
757 for (Index = 0; Index < HandleCount; Index++) {
758 Status = gBS->HandleProtocol(
759 HandleBuffer[Index],
760 &gSystemFmpProtocolGuid,
761 (VOID **)&SystemFmp
762 );
763 if (EFI_ERROR (Status)) {
764 continue;
765 }
766 DEBUG ((DEBUG_INFO, "SystemFirmwareUpdateDxe: Uninstall SystemFmp produced by another capsule\n"));
767 Status = gBS->UninstallProtocolInterface (
768 HandleBuffer[Index],
769 &gSystemFmpProtocolGuid,
770 SystemFmp
771 );
772 if (EFI_ERROR (Status)) {
773 DEBUG ((DEBUG_ERROR, "SystemFirmwareUpdateDxe: Failed to uninstall SystemFmp %r. Exiting.\n", Status));
774 FreePool (HandleBuffer);
775 return Status;
776 }
777 }
778 if (HandleBuffer != NULL) {
779 FreePool (HandleBuffer);
780 }
781
782 return EFI_SUCCESS;
783 }
784
785 /**
786 System FMP module entrypoint
787
788 @param[in] ImageHandle The firmware allocated handle for the EFI image.
789 @param[in] SystemTable A pointer to the EFI System Table.
790
791 @retval EFI_SUCCESS System FMP module is initialized.
792 @retval EFI_OUT_OF_RESOURCES There are not enough resources avaulable to
793 initialize this module.
794 @retval Other System FMP Protocols could not be uninstalled.
795 @retval Other System FMP Protocol could not be installed.
796 @retval Other FMP Protocol could not be installed.
797 **/
798 EFI_STATUS
799 EFIAPI
800 SystemFirmwareUpdateMainDxe (
801 IN EFI_HANDLE ImageHandle,
802 IN EFI_SYSTEM_TABLE *SystemTable
803 )
804 {
805 EFI_STATUS Status;
806 EFI_HANDLE *HandleBuffer;
807 UINTN HandleCount;
808
809 //
810 // Initialize SystemFmpPrivateData
811 //
812 mSystemFmpPrivate = AllocateZeroPool (sizeof (SYSTEM_FMP_PRIVATE_DATA));
813 if (mSystemFmpPrivate == NULL) {
814 return EFI_OUT_OF_RESOURCES;
815 }
816
817 Status = InitializePrivateData (mSystemFmpPrivate);
818 if (EFI_ERROR (Status)) {
819 FreePool (mSystemFmpPrivate);
820 mSystemFmpPrivate = NULL;
821 return Status;
822 }
823
824 //
825 // Uninstall SystemFmpProtocol instances that may have been produced by
826 // the SystemFirmwareUpdate drivers in FVs dispatched by other capsules.
827 //
828 Status = UninstallMatchingSystemFmpProtocols ();
829 if (EFI_ERROR (Status)) {
830 FreePool (mSystemFmpPrivate);
831 mSystemFmpPrivate = NULL;
832 return Status;
833 }
834
835 //
836 // Look for a handle with matching Firmware Management Protocol
837 //
838 HandleCount = 0;
839 HandleBuffer = FindMatchingFmpHandles (
840 &gEfiFirmwareManagementProtocolGuid,
841 &HandleCount
842 );
843 DEBUG ((DEBUG_INFO, "SystemFirmwareUpdateDxe: Found %d matching FMP instances\n", HandleCount));
844
845 switch (HandleCount) {
846 case 0:
847 //
848 // Install FMP protocol onto a new handle.
849 //
850 DEBUG ((DEBUG_INFO, "SystemFirmwareUpdateDxe: Install FMP onto a new handle\n"));
851 Status = gBS->InstallMultipleProtocolInterfaces (
852 &mSystemFmpPrivate->Handle,
853 &gEfiFirmwareManagementProtocolGuid,
854 &mSystemFmpPrivate->Fmp,
855 NULL
856 );
857 break;
858 case 1:
859 //
860 // Install System FMP protocol onto handle with matching FMP Protocol
861 //
862 DEBUG ((DEBUG_INFO, "SystemFirmwareUpdateDxe: Install System FMP onto matching FMP handle\n"));
863 mSystemFmpPrivate->Handle = HandleBuffer[0];
864 Status = gBS->InstallMultipleProtocolInterfaces (
865 &HandleBuffer[0],
866 &gSystemFmpProtocolGuid,
867 &mSystemFmpPrivate->Fmp,
868 NULL
869 );
870 break;
871 default:
872 //
873 // More than one matching handle is not expected. Unload driver.
874 //
875 DEBUG ((DEBUG_ERROR, "SystemFirmwareUpdateDxe: More than one matching FMP handle. Unload driver.\n"));
876 Status = EFI_DEVICE_ERROR;
877 break;
878 }
879
880 if (HandleBuffer != NULL) {
881 FreePool (HandleBuffer);
882 }
883
884 if (EFI_ERROR (Status)) {
885 FreePool (mSystemFmpPrivate);
886 mSystemFmpPrivate = NULL;
887 }
888
889 return Status;
890 }