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