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