SignedCapsulePkg/SystemFirmwareUpdateDxe: Fix ECC issues
[mirror_edk2.git] / SignedCapsulePkg / Universal / SystemFirmwareUpdate / SystemFirmwareUpdateDxe.c
CommitLineData
f6f91d38
JY
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
d69d9227 11 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>\r
f6f91d38
JY
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
2e108303
DB
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
f6f91d38
JY
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
eb594313
KM
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
f6f91d38
JY
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
eb594313
KM
87 if (Progress != NULL) {\r
88 Progress (StartPercentage);\r
89 }\r
90 Status = PerformFlashWriteWithProgress (\r
f6f91d38
JY
91 ConfigData->FirmwareType,\r
92 ConfigData->BaseAddress,\r
93 ConfigData->AddressType,\r
94 (VOID *)((UINTN)SystemFirmwareImage + (UINTN)ConfigData->ImageOffset),\r
eb594313
KM
95 ConfigData->Length,\r
96 Progress,\r
97 StartPercentage,\r
98 EndPercentage\r
f6f91d38 99 );\r
eb594313
KM
100 if (Progress != NULL) {\r
101 Progress (EndPercentage);\r
102 }\r
f6f91d38
JY
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
2e108303 123 @param[in] Progress A function used by the driver to report the progress of the firmware update.\r
f6f91d38
JY
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
eb594313
KM
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
f6f91d38
JY
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
eb594313
KM
144 UINTN TotalSize;\r
145 UINTN BytesWritten;\r
146 UINTN StartPercentage;\r
147 UINTN EndPercentage;\r
f6f91d38
JY
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
eb594313
KM
154 StartPercentage = 0;\r
155 EndPercentage = 100;\r
156 if (Progress != NULL) {\r
157 Progress (StartPercentage);\r
158 }\r
159 Status = PerformFlashWriteWithProgress (\r
f6f91d38
JY
160 PlatformFirmwareTypeNvRam,\r
161 0,\r
162 FlashAddressTypeRelativeAddress,\r
163 SystemFirmwareImage,\r
eb594313
KM
164 SystemFirmwareImageSize,\r
165 Progress,\r
166 StartPercentage,\r
167 EndPercentage\r
f6f91d38 168 );\r
eb594313
KM
169 if (Progress != NULL) {\r
170 Progress (EndPercentage);\r
171 }\r
f6f91d38
JY
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
eb594313
KM
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
f6f91d38
JY
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
eb594313
KM
211 StartPercentage = (BytesWritten * 100) / TotalSize;\r
212 EndPercentage = ((BytesWritten + UpdateConfigData->Length) * 100) / TotalSize;\r
f6f91d38
JY
213 Status = PerformUpdate (\r
214 SystemFirmwareImage,\r
215 SystemFirmwareImageSize,\r
216 UpdateConfigData,\r
217 LastAttemptVersion,\r
eb594313
KM
218 LastAttemptStatus,\r
219 Progress,\r
220 StartPercentage,\r
221 EndPercentage\r
f6f91d38
JY
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
eb594313
KM
234 BytesWritten += UpdateConfigData->Length;\r
235\r
f6f91d38
JY
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
2e108303 252 @param[in] Progress A function used by the driver to report the progress of the firmware update.\r
f6f91d38
JY
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
eb594313
KM
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
f6f91d38
JY
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
8b66342c
HW
275 AuthenticatedImage = NULL;\r
276 AuthenticatedImageSize = 0;\r
277\r
f6f91d38
JY
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
eb594313 292 Status = UpdateImage(SystemFirmwareImage, SystemFirmwareImageSize, ConfigImage, ConfigImageSize, LastAttemptVersion, LastAttemptStatus, Progress);\r
f6f91d38
JY
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
c8dca871 464 @retval EFI_SECURITY_VIOLATION The operation could not be performed due to an authentication failure.\r
f6f91d38
JY
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
eb594313
KM
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
f6f91d38
JY
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
d69d9227
KM
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
665bfd41 654 UINTN TempHandleCount;\r
d69d9227
KM
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
665bfd41 666 TempHandleCount = 0;\r
d69d9227
KM
667 HandleBuffer = NULL;\r
668 Status = gBS->LocateHandleBuffer (\r
669 ByProtocol,\r
670 ProtocolGuid,\r
671 NULL,\r
665bfd41 672 &TempHandleCount,\r
d69d9227
KM
673 &HandleBuffer\r
674 );\r
675 if (EFI_ERROR (Status)) {\r
d69d9227
KM
676 return NULL;\r
677 }\r
678\r
665bfd41 679 for (Index = 0; Index < TempHandleCount; Index++) {\r
d69d9227
KM
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
665bfd41
SZ
710 if (MatchFound) {\r
711 HandleBuffer[*HandleCount] = HandleBuffer[Index];\r
712 (*HandleCount)++;\r
d69d9227
KM
713 }\r
714\r
715 FreePool (OriginalFmpImageInfoBuf);\r
716 }\r
665bfd41
SZ
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
d69d9227
KM
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
f6f91d38
JY
785/**\r
786 System FMP module entrypoint\r
787\r
d69d9227
KM
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
f6f91d38 790\r
d69d9227
KM
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
f6f91d38
JY
797**/\r
798EFI_STATUS\r
799EFIAPI\r
800SystemFirmwareUpdateMainDxe (\r
d69d9227
KM
801 IN EFI_HANDLE ImageHandle,\r
802 IN EFI_SYSTEM_TABLE *SystemTable\r
f6f91d38
JY
803 )\r
804{\r
d69d9227
KM
805 EFI_STATUS Status;\r
806 EFI_HANDLE *HandleBuffer;\r
807 UINTN HandleCount;\r
f6f91d38
JY
808\r
809 //\r
810 // Initialize SystemFmpPrivateData\r
811 //\r
d69d9227 812 mSystemFmpPrivate = AllocateZeroPool (sizeof (SYSTEM_FMP_PRIVATE_DATA));\r
f6f91d38
JY
813 if (mSystemFmpPrivate == NULL) {\r
814 return EFI_OUT_OF_RESOURCES;\r
815 }\r
816\r
d69d9227
KM
817 Status = InitializePrivateData (mSystemFmpPrivate);\r
818 if (EFI_ERROR (Status)) {\r
819 FreePool (mSystemFmpPrivate);\r
f6f91d38
JY
820 mSystemFmpPrivate = NULL;\r
821 return Status;\r
822 }\r
823\r
824 //\r
d69d9227
KM
825 // Uninstall SystemFmpProtocol instances that may have been produced by\r
826 // the SystemFirmwareUpdate drivers in FVs dispatched by other capsules.\r
f6f91d38 827 //\r
d69d9227 828 Status = UninstallMatchingSystemFmpProtocols ();\r
f6f91d38 829 if (EFI_ERROR (Status)) {\r
d69d9227 830 FreePool (mSystemFmpPrivate);\r
f6f91d38
JY
831 mSystemFmpPrivate = NULL;\r
832 return Status;\r
833 }\r
834\r
d69d9227
KM
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
665bfd41 863 mSystemFmpPrivate->Handle = HandleBuffer[0];\r
d69d9227
KM
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
f6f91d38
JY
889 return Status;\r
890}\r