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