Commit | Line | Data |
---|---|---|
e470ee6d JY |
1 | /** @file\r |
2 | Recovery module.\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 | ProcessRecoveryCapsule(), ProcessFmpCapsuleImage(), ProcessRecoveryImage(),\r | |
10 | ValidateFmpCapsule() will receive untrusted input and do basic validation.\r | |
11 | \r | |
868f139b | 12 | Copyright (c) 2016 - 2019, Intel Corporation. All rights reserved.<BR>\r |
fbf06957 | 13 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
e470ee6d JY |
14 | \r |
15 | **/\r | |
16 | \r | |
17 | //\r | |
18 | // The package level header files this module uses\r | |
19 | //\r | |
20 | #include <Uefi.h>\r | |
21 | #include <PiPei.h>\r | |
22 | //\r | |
c38f0816 | 23 | // The protocols, PPI and GUID definitions for this module\r |
e470ee6d JY |
24 | //\r |
25 | #include <Ppi/MasterBootMode.h>\r | |
26 | #include <Ppi/BootInRecoveryMode.h>\r | |
27 | #include <Ppi/RecoveryModule.h>\r | |
28 | #include <Ppi/DeviceRecoveryModule.h>\r | |
29 | #include <Ppi/FirmwareVolumeInfo.h>\r | |
30 | #include <Guid/FirmwareFileSystem2.h>\r | |
31 | #include <Guid/FmpCapsule.h>\r | |
32 | #include <Guid/EdkiiSystemFmpCapsule.h>\r | |
33 | \r | |
34 | //\r | |
35 | // The Library classes this module consumes\r | |
36 | //\r | |
37 | #include <Library/DebugLib.h>\r | |
38 | #include <Library/PeimEntryPoint.h>\r | |
39 | #include <Library/PeiServicesLib.h>\r | |
40 | #include <Library/HobLib.h>\r | |
41 | #include <Library/BaseMemoryLib.h>\r | |
42 | #include <Library/MemoryAllocationLib.h>\r | |
43 | #include <Library/PcdLib.h>\r | |
44 | \r | |
45 | #include "RecoveryModuleLoadPei.h"\r | |
46 | \r | |
47 | /**\r | |
48 | Loads a DXE capsule from some media into memory and updates the HOB table\r | |
49 | with the DXE firmware volume information.\r | |
50 | \r | |
51 | @param[in] PeiServices General-purpose services that are available to every PEIM.\r | |
52 | @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.\r | |
53 | \r | |
54 | @retval EFI_SUCCESS The capsule was loaded correctly.\r | |
55 | @retval EFI_DEVICE_ERROR A device error occurred.\r | |
56 | @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.\r | |
57 | \r | |
58 | **/\r | |
59 | EFI_STATUS\r | |
60 | EFIAPI\r | |
61 | LoadRecoveryCapsule (\r | |
b8786489 MK |
62 | IN EFI_PEI_SERVICES **PeiServices,\r |
63 | IN EFI_PEI_RECOVERY_MODULE_PPI *This\r | |
e470ee6d JY |
64 | );\r |
65 | \r | |
b8786489 | 66 | EFI_PEI_RECOVERY_MODULE_PPI mRecoveryPpi = {\r |
e470ee6d JY |
67 | LoadRecoveryCapsule\r |
68 | };\r | |
69 | \r | |
b8786489 | 70 | EFI_PEI_PPI_DESCRIPTOR mRecoveryPpiList = {\r |
e470ee6d JY |
71 | (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r |
72 | &gEfiPeiRecoveryModulePpiGuid,\r | |
73 | &mRecoveryPpi\r | |
74 | };\r | |
75 | \r | |
76 | /**\r | |
77 | Parse Config data file to get the updated data array.\r | |
78 | \r | |
79 | @param[in] DataBuffer Config raw file buffer.\r | |
80 | @param[in] BufferSize Size of raw buffer.\r | |
81 | @param[in, out] ConfigHeader Pointer to the config header.\r | |
82 | @param[in, out] RecoveryArray Pointer to the config of recovery data.\r | |
83 | \r | |
84 | @retval EFI_NOT_FOUND No config data is found.\r | |
85 | @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.\r | |
86 | @retval EFI_SUCCESS Parse the config file successfully.\r | |
87 | \r | |
88 | **/\r | |
89 | EFI_STATUS\r | |
90 | ParseRecoveryDataFile (\r | |
b8786489 MK |
91 | IN UINT8 *DataBuffer,\r |
92 | IN UINTN BufferSize,\r | |
93 | IN OUT CONFIG_HEADER *ConfigHeader,\r | |
94 | IN OUT RECOVERY_CONFIG_DATA **RecoveryArray\r | |
e470ee6d JY |
95 | );\r |
96 | \r | |
97 | /**\r | |
98 | Return if this FMP is a system FMP or a device FMP, based upon FmpImageInfo.\r | |
99 | \r | |
100 | @param[in] FmpImageHeader A pointer to EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\r | |
101 | \r | |
102 | @return TRUE It is a system FMP.\r | |
103 | @return FALSE It is a device FMP.\r | |
104 | **/\r | |
105 | BOOLEAN\r | |
106 | IsSystemFmpImage (\r | |
b8786489 | 107 | IN EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *FmpImageHeader\r |
e470ee6d JY |
108 | )\r |
109 | {\r | |
b8786489 MK |
110 | GUID *Guid;\r |
111 | UINTN Count;\r | |
112 | UINTN Index;\r | |
e470ee6d | 113 | \r |
b8786489 MK |
114 | Guid = PcdGetPtr (PcdSystemFmpCapsuleImageTypeIdGuid);\r |
115 | Count = PcdGetSize (PcdSystemFmpCapsuleImageTypeIdGuid) / sizeof (GUID);\r | |
e470ee6d JY |
116 | \r |
117 | for (Index = 0; Index < Count; Index++, Guid++) {\r | |
b8786489 | 118 | if (CompareGuid (&FmpImageHeader->UpdateImageTypeId, Guid)) {\r |
e470ee6d JY |
119 | return TRUE;\r |
120 | }\r | |
121 | }\r | |
122 | \r | |
123 | return FALSE;\r | |
124 | }\r | |
125 | \r | |
126 | /**\r | |
127 | Return if this CapsuleGuid is a FMP capsule GUID or not.\r | |
128 | \r | |
129 | @param[in] CapsuleGuid A pointer to EFI_GUID\r | |
130 | \r | |
131 | @return TRUE It is a FMP capsule GUID.\r | |
132 | @return FALSE It is not a FMP capsule GUID.\r | |
133 | **/\r | |
134 | BOOLEAN\r | |
135 | IsFmpCapsuleGuid (\r | |
136 | IN EFI_GUID *CapsuleGuid\r | |
137 | )\r | |
138 | {\r | |
b8786489 | 139 | if (CompareGuid (&gEfiFmpCapsuleGuid, CapsuleGuid)) {\r |
e470ee6d JY |
140 | return TRUE;\r |
141 | }\r | |
142 | \r | |
143 | return FALSE;\r | |
144 | }\r | |
145 | \r | |
146 | /**\r | |
c38f0816 | 147 | This function assumes the input Capsule image already passes basic check in\r |
e470ee6d JY |
148 | ValidateFmpCapsule().\r |
149 | \r | |
150 | Criteria of system FMP capsule is:\r | |
151 | 1) FmpCapsuleHeader->EmbeddedDriverCount is 0.\r | |
152 | 2) FmpCapsuleHeader->PayloadItemCount is not 0.\r | |
153 | 3) All ImageHeader->UpdateImageTypeId matches PcdSystemFmpCapsuleImageTypeIdGuid.\r | |
154 | \r | |
155 | @param[in] CapsuleHeader Points to a capsule header.\r | |
156 | \r | |
157 | @retval TRUE Input capsule is a correct system FMP capsule.\r | |
158 | @retval FALSE Input capsule is not a correct system FMP capsule.\r | |
159 | **/\r | |
160 | BOOLEAN\r | |
161 | IsSystemFmpCapsuleImage (\r | |
b8786489 | 162 | IN EFI_CAPSULE_HEADER *CapsuleHeader\r |
e470ee6d JY |
163 | )\r |
164 | {\r | |
b8786489 MK |
165 | EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r |
166 | EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r | |
167 | UINT64 *ItemOffsetList;\r | |
168 | UINT32 ItemNum;\r | |
169 | UINTN Index;\r | |
e470ee6d | 170 | \r |
b8786489 | 171 | FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r |
e470ee6d JY |
172 | \r |
173 | if (FmpCapsuleHeader->EmbeddedDriverCount != 0) {\r | |
174 | return FALSE;\r | |
175 | }\r | |
176 | \r | |
177 | if (FmpCapsuleHeader->PayloadItemCount == 0) {\r | |
178 | return FALSE;\r | |
179 | }\r | |
180 | \r | |
181 | ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;\r | |
182 | \r | |
183 | ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r | |
184 | \r | |
185 | for (Index = 0; Index < ItemNum; Index++) {\r | |
b8786489 MK |
186 | ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r |
187 | if (!IsSystemFmpImage (ImageHeader)) {\r | |
e470ee6d JY |
188 | return FALSE;\r |
189 | }\r | |
190 | }\r | |
191 | \r | |
192 | return TRUE;\r | |
193 | }\r | |
194 | \r | |
195 | /**\r | |
196 | Validate if it is valid capsule header\r | |
197 | \r | |
198 | This function assumes the caller provided correct CapsuleHeader pointer\r | |
199 | and CapsuleSize.\r | |
200 | \r | |
201 | This function validates the fields in EFI_CAPSULE_HEADER.\r | |
202 | \r | |
203 | @param[in] CapsuleHeader Points to a capsule header.\r | |
204 | @param[in] CapsuleSize Size of the whole capsule image.\r | |
205 | \r | |
206 | **/\r | |
207 | BOOLEAN\r | |
208 | IsValidCapsuleHeader (\r | |
209 | IN EFI_CAPSULE_HEADER *CapsuleHeader,\r | |
210 | IN UINT64 CapsuleSize\r | |
211 | )\r | |
212 | {\r | |
213 | if (CapsuleHeader->CapsuleImageSize != CapsuleSize) {\r | |
214 | return FALSE;\r | |
215 | }\r | |
b8786489 | 216 | \r |
e470ee6d JY |
217 | if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {\r |
218 | return FALSE;\r | |
219 | }\r | |
b8786489 | 220 | \r |
e470ee6d JY |
221 | return TRUE;\r |
222 | }\r | |
223 | \r | |
224 | /**\r | |
225 | Validate Fmp capsules layout.\r | |
226 | \r | |
227 | Caution: This function may receive untrusted input.\r | |
228 | \r | |
229 | This function assumes the caller validated the capsule by using\r | |
230 | IsValidCapsuleHeader(), so that all fields in EFI_CAPSULE_HEADER are correct.\r | |
231 | The capsule buffer size is CapsuleHeader->CapsuleImageSize.\r | |
232 | \r | |
233 | This function validates the fields in EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\r | |
234 | and EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER.\r | |
235 | \r | |
236 | @param[in] CapsuleHeader Points to a capsule header.\r | |
237 | @param[out] IsSystemFmp If it is a system FMP.\r | |
238 | @param[out] EmbeddedDriverCount The EmbeddedDriverCount in the FMP capsule.\r | |
239 | \r | |
c38f0816 | 240 | @retval EFI_SUCCESS Input capsule is a correct FMP capsule.\r |
e470ee6d JY |
241 | @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.\r |
242 | **/\r | |
243 | EFI_STATUS\r | |
244 | ValidateFmpCapsule (\r | |
b8786489 MK |
245 | IN EFI_CAPSULE_HEADER *CapsuleHeader,\r |
246 | OUT BOOLEAN *IsSystemFmp OPTIONAL,\r | |
247 | OUT UINT16 *EmbeddedDriverCount OPTIONAL\r | |
e470ee6d JY |
248 | )\r |
249 | {\r | |
b8786489 MK |
250 | EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r |
251 | UINT8 *EndOfCapsule;\r | |
252 | EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r | |
253 | UINT8 *EndOfPayload;\r | |
254 | UINT64 *ItemOffsetList;\r | |
255 | UINT32 ItemNum;\r | |
256 | UINTN Index;\r | |
257 | UINTN FmpCapsuleSize;\r | |
258 | UINTN FmpCapsuleHeaderSize;\r | |
259 | UINT64 FmpImageSize;\r | |
260 | UINTN FmpImageHeaderSize;\r | |
e470ee6d JY |
261 | \r |
262 | if (CapsuleHeader->HeaderSize >= CapsuleHeader->CapsuleImageSize) {\r | |
b8786489 | 263 | DEBUG ((DEBUG_ERROR, "HeaderSize(0x%x) >= CapsuleImageSize(0x%x)\n", CapsuleHeader->HeaderSize, CapsuleHeader->CapsuleImageSize));\r |
e470ee6d JY |
264 | return EFI_INVALID_PARAMETER;\r |
265 | }\r | |
266 | \r | |
b8786489 MK |
267 | FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r |
268 | EndOfCapsule = (UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize;\r | |
e470ee6d JY |
269 | FmpCapsuleSize = (UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader;\r |
270 | \r | |
b8786489 MK |
271 | if (FmpCapsuleSize < sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER)) {\r |
272 | DEBUG ((DEBUG_ERROR, "FmpCapsuleSize(0x%x) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\n", FmpCapsuleSize));\r | |
e470ee6d JY |
273 | return EFI_INVALID_PARAMETER;\r |
274 | }\r | |
275 | \r | |
276 | // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER\r | |
277 | if (FmpCapsuleHeader->Version != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {\r | |
b8786489 | 278 | DEBUG ((DEBUG_ERROR, "FmpCapsuleHeader->Version(0x%x) != EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION\n", FmpCapsuleHeader->Version));\r |
e470ee6d JY |
279 | return EFI_INVALID_PARAMETER;\r |
280 | }\r | |
b8786489 | 281 | \r |
e470ee6d JY |
282 | ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r |
283 | \r | |
284 | // No overflow\r | |
285 | ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;\r | |
286 | \r | |
b8786489 MK |
287 | if ((FmpCapsuleSize - sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER))/sizeof (UINT64) < ItemNum) {\r |
288 | DEBUG ((DEBUG_ERROR, "ItemNum(0x%x) too big\n", ItemNum));\r | |
e470ee6d JY |
289 | return EFI_INVALID_PARAMETER;\r |
290 | }\r | |
b8786489 MK |
291 | \r |
292 | FmpCapsuleHeaderSize = sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER) + sizeof (UINT64)*ItemNum;\r | |
e470ee6d JY |
293 | \r |
294 | // Check ItemOffsetList\r | |
295 | for (Index = 0; Index < ItemNum; Index++) {\r | |
296 | if (ItemOffsetList[Index] >= FmpCapsuleSize) {\r | |
b8786489 | 297 | DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) >= FmpCapsuleSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleSize));\r |
e470ee6d JY |
298 | return EFI_INVALID_PARAMETER;\r |
299 | }\r | |
b8786489 | 300 | \r |
e470ee6d | 301 | if (ItemOffsetList[Index] < FmpCapsuleHeaderSize) {\r |
b8786489 | 302 | DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < FmpCapsuleHeaderSize(0x%x)\n", Index, ItemOffsetList[Index], FmpCapsuleHeaderSize));\r |
e470ee6d JY |
303 | return EFI_INVALID_PARAMETER;\r |
304 | }\r | |
b8786489 | 305 | \r |
e470ee6d JY |
306 | //\r |
307 | // All the address in ItemOffsetList must be stored in ascending order\r | |
308 | //\r | |
309 | if (Index > 0) {\r | |
310 | if (ItemOffsetList[Index] <= ItemOffsetList[Index - 1]) {\r | |
b8786489 | 311 | DEBUG ((DEBUG_ERROR, "ItemOffsetList[%d](0x%lx) < ItemOffsetList[%d](0x%x)\n", Index, ItemOffsetList[Index], Index, ItemOffsetList[Index - 1]));\r |
e470ee6d JY |
312 | return EFI_INVALID_PARAMETER;\r |
313 | }\r | |
314 | }\r | |
315 | }\r | |
316 | \r | |
317 | // Check EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\r | |
318 | for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {\r | |
b8786489 | 319 | ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);\r |
e470ee6d JY |
320 | if (Index == ItemNum - 1) {\r |
321 | EndOfPayload = (UINT8 *)((UINTN)EndOfCapsule - (UINTN)FmpCapsuleHeader);\r | |
322 | } else {\r | |
323 | EndOfPayload = (UINT8 *)(UINTN)ItemOffsetList[Index+1];\r | |
324 | }\r | |
b8786489 | 325 | \r |
e470ee6d JY |
326 | FmpImageSize = (UINTN)EndOfPayload - ItemOffsetList[Index];\r |
327 | \r | |
b8786489 MK |
328 | if (FmpImageSize < OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance)) {\r |
329 | DEBUG ((DEBUG_ERROR, "FmpImageSize(0x%lx) < EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER\n", FmpImageSize));\r | |
e470ee6d JY |
330 | return EFI_INVALID_PARAMETER;\r |
331 | }\r | |
b8786489 MK |
332 | \r |
333 | FmpImageHeaderSize = sizeof (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER);\r | |
e470ee6d | 334 | if ((ImageHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) ||\r |
b8786489 MK |
335 | (ImageHeader->Version < 1))\r |
336 | {\r | |
337 | DEBUG ((DEBUG_ERROR, "ImageHeader->Version(0x%x) Unknown\n", ImageHeader->Version));\r | |
e470ee6d JY |
338 | return EFI_INVALID_PARAMETER;\r |
339 | }\r | |
b8786489 | 340 | \r |
bc5012b8 OY |
341 | ///\r |
342 | /// Current Init ImageHeader version is 3. UpdateHardwareInstance field was added in version 2\r | |
343 | /// and ImageCapsuleSupport field was added in version 3\r | |
344 | ///\r | |
345 | if (ImageHeader->Version == 1) {\r | |
b8786489 MK |
346 | FmpImageHeaderSize = OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);\r |
347 | } else if (ImageHeader->Version == 2) {\r | |
348 | FmpImageHeaderSize = OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);\r | |
e470ee6d JY |
349 | }\r |
350 | \r | |
351 | // No overflow\r | |
352 | if (FmpImageSize != (UINT64)FmpImageHeaderSize + (UINT64)ImageHeader->UpdateImageSize + (UINT64)ImageHeader->UpdateVendorCodeSize) {\r | |
b8786489 | 353 | DEBUG ((DEBUG_ERROR, "FmpImageSize(0x%lx) mismatch, UpdateImageSize(0x%x) UpdateVendorCodeSize(0x%x)\n", FmpImageSize, ImageHeader->UpdateImageSize, ImageHeader->UpdateVendorCodeSize));\r |
e470ee6d JY |
354 | return EFI_INVALID_PARAMETER;\r |
355 | }\r | |
356 | }\r | |
357 | \r | |
358 | if (ItemNum == 0) {\r | |
359 | //\r | |
360 | // No driver & payload element in FMP\r | |
361 | //\r | |
362 | EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);\r | |
363 | if (EndOfPayload != EndOfCapsule) {\r | |
b8786489 | 364 | DEBUG ((DEBUG_ERROR, "EndOfPayload(0x%x) mismatch, EndOfCapsule(0x%x)\n", EndOfPayload, EndOfCapsule));\r |
e470ee6d JY |
365 | return EFI_INVALID_PARAMETER;\r |
366 | }\r | |
b8786489 | 367 | \r |
e470ee6d JY |
368 | return EFI_UNSUPPORTED;\r |
369 | }\r | |
370 | \r | |
371 | //\r | |
372 | // Check in system FMP capsule\r | |
373 | //\r | |
374 | if (IsSystemFmp != NULL) {\r | |
b8786489 | 375 | *IsSystemFmp = IsSystemFmpCapsuleImage (CapsuleHeader);\r |
e470ee6d JY |
376 | }\r |
377 | \r | |
378 | if (EmbeddedDriverCount != NULL) {\r | |
379 | *EmbeddedDriverCount = FmpCapsuleHeader->EmbeddedDriverCount;\r | |
380 | }\r | |
381 | \r | |
382 | return EFI_SUCCESS;\r | |
383 | }\r | |
384 | \r | |
385 | /**\r | |
386 | Recovery module entrypoint\r | |
387 | \r | |
388 | @param[in] FileHandle Handle of the file being invoked.\r | |
389 | @param[in] PeiServices Describes the list of possible PEI Services.\r | |
390 | \r | |
391 | @return EFI_SUCCESS Recovery module is initialized.\r | |
392 | **/\r | |
393 | EFI_STATUS\r | |
394 | EFIAPI\r | |
395 | InitializeRecoveryModule (\r | |
396 | IN EFI_PEI_FILE_HANDLE FileHandle,\r | |
397 | IN CONST EFI_PEI_SERVICES **PeiServices\r | |
398 | )\r | |
399 | {\r | |
400 | EFI_STATUS Status;\r | |
401 | UINTN BootMode;\r | |
402 | \r | |
b8786489 MK |
403 | BootMode = GetBootModeHob ();\r |
404 | ASSERT (BootMode == BOOT_IN_RECOVERY_MODE);\r | |
e470ee6d JY |
405 | \r |
406 | Status = (**PeiServices).InstallPpi (PeiServices, &mRecoveryPpiList);\r | |
407 | ASSERT_EFI_ERROR (Status);\r | |
408 | \r | |
409 | return Status;\r | |
410 | }\r | |
411 | \r | |
412 | /**\r | |
413 | Create hob and install FvInfo PPI for recovery capsule.\r | |
414 | \r | |
415 | @param[in] FvImage Points to the DXE FV image.\r | |
416 | @param[in] FvImageSize The length of the DXE FV image in bytes.\r | |
417 | \r | |
c38f0816 | 418 | @retval EFI_SUCCESS Create hob and install FvInfo PPI successfully.\r |
e470ee6d JY |
419 | @retval EFI_VOLUME_CORRUPTED The input data is not an FV.\r |
420 | @retval EFI_OUT_OF_RESOURCES No enough resource to process the input data.\r | |
421 | **/\r | |
422 | EFI_STATUS\r | |
423 | EFIAPI\r | |
424 | CreateHobForRecoveryCapsule (\r | |
b8786489 MK |
425 | IN VOID *FvImage,\r |
426 | IN UINTN FvImageSize\r | |
e470ee6d JY |
427 | )\r |
428 | {\r | |
429 | EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r | |
430 | UINT32 FvAlignment;\r | |
431 | UINT64 FvLength;\r | |
432 | VOID *NewFvBuffer;\r | |
433 | \r | |
434 | //\r | |
435 | // FvImage should be at its required alignment.\r | |
436 | //\r | |
b8786489 | 437 | FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvImage;\r |
e470ee6d JY |
438 | //\r |
439 | // Validate FV Header, if not as expected, return\r | |
440 | //\r | |
441 | if (ReadUnaligned32 (&FvHeader->Signature) != EFI_FVH_SIGNATURE) {\r | |
b8786489 | 442 | DEBUG ((DEBUG_ERROR, "CreateHobForRecoveryCapsule (Fv Signature Error)\n"));\r |
e470ee6d JY |
443 | return EFI_VOLUME_CORRUPTED;\r |
444 | }\r | |
b8786489 | 445 | \r |
e470ee6d JY |
446 | //\r |
447 | // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume\r | |
448 | // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from\r | |
449 | // its initial linked location and maintain its alignment.\r | |
450 | //\r | |
451 | if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {\r | |
452 | //\r | |
453 | // Get FvHeader alignment\r | |
454 | //\r | |
455 | FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ALIGNMENT) >> 16);\r | |
456 | //\r | |
457 | // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.\r | |
458 | //\r | |
459 | if (FvAlignment < 8) {\r | |
460 | FvAlignment = 8;\r | |
461 | }\r | |
b8786489 | 462 | \r |
e470ee6d JY |
463 | //\r |
464 | // Allocate the aligned buffer for the FvImage.\r | |
465 | //\r | |
b8786489 MK |
466 | if ((UINTN)FvHeader % FvAlignment != 0) {\r |
467 | DEBUG ((DEBUG_INFO, "CreateHobForRecoveryCapsule (FvHeader 0x%lx is not aligned)\n", (UINT64)(UINTN)FvHeader));\r | |
e470ee6d | 468 | FvLength = ReadUnaligned64 (&FvHeader->FvLength);\r |
b8786489 | 469 | NewFvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINTN)FvLength), FvAlignment);\r |
e470ee6d | 470 | if (NewFvBuffer == NULL) {\r |
b8786489 | 471 | DEBUG ((DEBUG_ERROR, "CreateHobForRecoveryCapsule (Not enough resource to allocate 0x%lx bytes)\n", FvLength));\r |
e470ee6d JY |
472 | return EFI_OUT_OF_RESOURCES;\r |
473 | }\r | |
b8786489 MK |
474 | \r |
475 | CopyMem (NewFvBuffer, FvHeader, (UINTN)FvLength);\r | |
476 | FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)NewFvBuffer;\r | |
e470ee6d JY |
477 | }\r |
478 | }\r | |
479 | \r | |
b8786489 MK |
480 | BuildFvHob ((UINT64)(UINTN)FvHeader, FvHeader->FvLength);\r |
481 | DEBUG ((DEBUG_INFO, "BuildFvHob (FV in recovery) - 0x%lx - 0x%lx\n", (UINT64)(UINTN)FvHeader, FvHeader->FvLength));\r | |
e470ee6d | 482 | \r |
b8786489 | 483 | PeiServicesInstallFvInfoPpi (\r |
2ed235fc | 484 | &FvHeader->FileSystemGuid,\r |
e470ee6d JY |
485 | (VOID *)FvHeader,\r |
486 | (UINT32)FvHeader->FvLength,\r | |
487 | NULL,\r | |
488 | NULL\r | |
489 | );\r | |
490 | \r | |
491 | return EFI_SUCCESS;\r | |
492 | }\r | |
493 | \r | |
494 | /**\r | |
495 | Create recovery context based upon System Firmware image and config file.\r | |
496 | \r | |
497 | @param[in] SystemFirmwareImage Points to the System Firmware image.\r | |
498 | @param[in] SystemFirmwareImageSize The length of the System Firmware image in bytes.\r | |
499 | @param[in] ConfigImage Points to the config file image.\r | |
500 | @param[in] ConfigImageSize The length of the config file image in bytes.\r | |
501 | \r | |
c38f0816 | 502 | @retval EFI_SUCCESS Process Recovery Image successfully.\r |
e470ee6d JY |
503 | **/\r |
504 | EFI_STATUS\r | |
505 | RecoverImage (\r | |
b8786489 MK |
506 | IN VOID *SystemFirmwareImage,\r |
507 | IN UINTN SystemFirmwareImageSize,\r | |
508 | IN VOID *ConfigImage,\r | |
509 | IN UINTN ConfigImageSize\r | |
e470ee6d JY |
510 | )\r |
511 | {\r | |
b8786489 MK |
512 | EFI_STATUS Status;\r |
513 | RECOVERY_CONFIG_DATA *ConfigData;\r | |
514 | RECOVERY_CONFIG_DATA *RecoveryConfigData;\r | |
515 | CONFIG_HEADER ConfigHeader;\r | |
516 | UINTN Index;\r | |
e470ee6d JY |
517 | \r |
518 | if (ConfigImage == NULL) {\r | |
b8786489 MK |
519 | DEBUG ((DEBUG_INFO, "RecoverImage (NoConfig)\n"));\r |
520 | Status = CreateHobForRecoveryCapsule (\r | |
e470ee6d JY |
521 | SystemFirmwareImage,\r |
522 | SystemFirmwareImageSize\r | |
523 | );\r | |
524 | return Status;\r | |
525 | }\r | |
526 | \r | |
b8786489 MK |
527 | ConfigData = NULL;\r |
528 | ZeroMem (&ConfigHeader, sizeof (ConfigHeader));\r | |
529 | Status = ParseRecoveryDataFile (\r | |
530 | ConfigImage,\r | |
531 | ConfigImageSize,\r | |
532 | &ConfigHeader,\r | |
533 | &ConfigData\r | |
534 | );\r | |
535 | DEBUG ((DEBUG_INFO, "ParseRecoveryDataFile - %r\n", Status));\r | |
536 | if (EFI_ERROR (Status)) {\r | |
e470ee6d JY |
537 | return Status;\r |
538 | }\r | |
e470ee6d | 539 | \r |
b8786489 MK |
540 | DEBUG ((DEBUG_INFO, "ConfigHeader.NumOfRecovery - 0x%x\n", ConfigHeader.NumOfRecovery));\r |
541 | DEBUG ((DEBUG_INFO, "PcdEdkiiSystemFirmwareFileGuid - %g\n", PcdGetPtr (PcdEdkiiSystemFirmwareFileGuid)));\r | |
542 | \r | |
543 | Index = 0;\r | |
e470ee6d JY |
544 | RecoveryConfigData = ConfigData;\r |
545 | while (Index < ConfigHeader.NumOfRecovery) {\r | |
b8786489 MK |
546 | if (CompareGuid (&RecoveryConfigData->FileGuid, PcdGetPtr (PcdEdkiiSystemFirmwareFileGuid))) {\r |
547 | DEBUG ((DEBUG_INFO, "FileGuid - %g (processing)\n", &RecoveryConfigData->FileGuid));\r | |
e470ee6d JY |
548 | Status = CreateHobForRecoveryCapsule (\r |
549 | (UINT8 *)SystemFirmwareImage + RecoveryConfigData->ImageOffset,\r | |
550 | RecoveryConfigData->Length\r | |
551 | );\r | |
552 | //\r | |
553 | // Shall updates be serialized so that if a recovery FV is not successfully completed,\r | |
554 | // the remaining updates won't be performed.\r | |
555 | //\r | |
556 | if (EFI_ERROR (Status)) {\r | |
557 | break;\r | |
558 | }\r | |
559 | } else {\r | |
b8786489 | 560 | DEBUG ((DEBUG_INFO, "FileGuid - %g (ignored)\n", &RecoveryConfigData->FileGuid));\r |
e470ee6d JY |
561 | }\r |
562 | \r | |
563 | Index++;\r | |
564 | RecoveryConfigData++;\r | |
565 | }\r | |
566 | \r | |
567 | return Status;\r | |
568 | }\r | |
569 | \r | |
570 | /**\r | |
571 | Process recovery image.\r | |
572 | \r | |
573 | Caution: This function may receive untrusted input.\r | |
574 | \r | |
575 | @param[in] Image Points to the recovery image.\r | |
576 | @param[in] Length The length of the recovery image in bytes.\r | |
577 | \r | |
c38f0816 | 578 | @retval EFI_SUCCESS Process Recovery Image successfully.\r |
e470ee6d JY |
579 | @retval EFI_SECURITY_VIOLATION Recovery image is not processed due to security violation.\r |
580 | **/\r | |
581 | EFI_STATUS\r | |
582 | ProcessRecoveryImage (\r | |
583 | IN VOID *Image,\r | |
584 | IN UINTN Length\r | |
585 | )\r | |
586 | {\r | |
b8786489 MK |
587 | UINT32 LastAttemptVersion;\r |
588 | UINT32 LastAttemptStatus;\r | |
589 | EFI_STATUS Status;\r | |
590 | VOID *SystemFirmwareImage;\r | |
591 | UINTN SystemFirmwareImageSize;\r | |
592 | VOID *ConfigImage;\r | |
593 | UINTN ConfigImageSize;\r | |
594 | VOID *AuthenticatedImage;\r | |
595 | UINTN AuthenticatedImageSize;\r | |
e470ee6d | 596 | \r |
8b66342c HW |
597 | AuthenticatedImage = NULL;\r |
598 | AuthenticatedImageSize = 0;\r | |
599 | \r | |
b8786489 MK |
600 | Status = CapsuleAuthenticateSystemFirmware (Image, Length, TRUE, &LastAttemptVersion, &LastAttemptStatus, &AuthenticatedImage, &AuthenticatedImageSize);\r |
601 | if (EFI_ERROR (Status)) {\r | |
602 | DEBUG ((DEBUG_INFO, "CapsuleAuthenticateSystemFirmware - %r\n", Status));\r | |
e470ee6d JY |
603 | return Status;\r |
604 | }\r | |
605 | \r | |
b8786489 MK |
606 | ExtractSystemFirmwareImage (AuthenticatedImage, AuthenticatedImageSize, &SystemFirmwareImage, &SystemFirmwareImageSize);\r |
607 | ExtractConfigImage (AuthenticatedImage, AuthenticatedImageSize, &ConfigImage, &ConfigImageSize);\r | |
e470ee6d | 608 | \r |
b8786489 MK |
609 | Status = RecoverImage (SystemFirmwareImage, SystemFirmwareImageSize, ConfigImage, ConfigImageSize);\r |
610 | if (EFI_ERROR (Status)) {\r | |
611 | DEBUG ((DEBUG_INFO, "RecoverImage - %r\n", Status));\r | |
e470ee6d JY |
612 | return Status;\r |
613 | }\r | |
614 | \r | |
615 | return EFI_SUCCESS;\r | |
616 | }\r | |
617 | \r | |
618 | /**\r | |
619 | Process Firmware management protocol data capsule.\r | |
620 | \r | |
621 | Caution: This function may receive untrusted input.\r | |
622 | \r | |
623 | This function assumes the caller validated the capsule by using\r | |
624 | ValidateFmpCapsule(), so that all fields in EFI_CAPSULE_HEADER,\r | |
625 | EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER and\r | |
626 | EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER are correct.\r | |
627 | \r | |
628 | @param[in] CapsuleHeader Points to a capsule header.\r | |
629 | @param[in] IsSystemFmp If this capsule is a system FMP capsule.\r | |
630 | \r | |
c38f0816 | 631 | @retval EFI_SUCCESS Process Capsule Image successfully.\r |
e470ee6d JY |
632 | @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.\r |
633 | @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.\r | |
634 | @retval EFI_OUT_OF_RESOURCES Not enough memory.\r | |
635 | **/\r | |
636 | EFI_STATUS\r | |
637 | ProcessFmpCapsuleImage (\r | |
638 | IN EFI_CAPSULE_HEADER *CapsuleHeader,\r | |
639 | IN BOOLEAN IsSystemFmp\r | |
640 | )\r | |
641 | {\r | |
642 | EFI_STATUS Status;\r | |
643 | EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;\r | |
644 | EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;\r | |
645 | UINT8 *Image;\r | |
646 | UINT64 *ItemOffsetList;\r | |
647 | UINTN ItemIndex;\r | |
648 | \r | |
649 | if (!IsSystemFmp) {\r | |
650 | return EFI_UNSUPPORTED;\r | |
651 | }\r | |
652 | \r | |
653 | FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *)((UINT8 *)CapsuleHeader + CapsuleHeader->HeaderSize);\r | |
b8786489 | 654 | ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);\r |
e470ee6d JY |
655 | \r |
656 | for (ItemIndex = 0; ItemIndex < FmpCapsuleHeader->PayloadItemCount; ItemIndex++) {\r | |
657 | ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemIndex]);\r | |
658 | if (ImageHeader->Version >= EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER_INIT_VERSION) {\r | |
659 | Image = (UINT8 *)(ImageHeader + 1);\r | |
660 | } else {\r | |
661 | //\r | |
662 | // If the EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER is version 1, only match ImageTypeId.\r | |
bc5012b8 OY |
663 | // Header should exclude UpdateHardwareInstance field.\r |
664 | // If version is 2 Header should exclude ImageCapsuleSupport field.\r | |
e470ee6d | 665 | //\r |
bc5012b8 | 666 | if (ImageHeader->Version == 1) {\r |
b8786489 | 667 | Image = (UINT8 *)ImageHeader + OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, UpdateHardwareInstance);\r |
bc5012b8 | 668 | } else {\r |
b8786489 | 669 | Image = (UINT8 *)ImageHeader + OFFSET_OF (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER, ImageCapsuleSupport);\r |
bc5012b8 | 670 | }\r |
e470ee6d JY |
671 | }\r |
672 | \r | |
673 | Status = ProcessRecoveryImage (Image, ImageHeader->UpdateImageSize);\r | |
b8786489 | 674 | if (EFI_ERROR (Status)) {\r |
e470ee6d JY |
675 | return Status;\r |
676 | }\r | |
677 | }\r | |
678 | \r | |
679 | return EFI_SUCCESS;\r | |
680 | }\r | |
681 | \r | |
682 | /**\r | |
683 | Process recovery capsule image.\r | |
684 | \r | |
685 | Caution: This function may receive untrusted input.\r | |
686 | \r | |
687 | @param[in] CapsuleBuffer The capsule image buffer.\r | |
688 | @param[in] CapsuleSize The size of the capsule image in bytes.\r | |
689 | \r | |
690 | @retval EFI_SUCCESS The recovery capsule is processed.\r | |
691 | @retval EFI_SECURITY_VIOLATION The recovery capsule is not process because of security violation.\r | |
692 | @retval EFI_NOT_FOUND The recovery capsule is not process because of unrecognization.\r | |
693 | **/\r | |
694 | EFI_STATUS\r | |
695 | EFIAPI\r | |
696 | ProcessRecoveryCapsule (\r | |
b8786489 MK |
697 | IN VOID *CapsuleBuffer,\r |
698 | IN UINTN CapsuleSize\r | |
e470ee6d JY |
699 | )\r |
700 | {\r | |
b8786489 MK |
701 | EFI_STATUS Status;\r |
702 | BOOLEAN IsSystemFmp;\r | |
703 | EFI_CAPSULE_HEADER *CapsuleHeader;\r | |
e470ee6d JY |
704 | \r |
705 | CapsuleHeader = CapsuleBuffer;\r | |
706 | if (!IsValidCapsuleHeader (CapsuleHeader, CapsuleSize)) {\r | |
b8786489 | 707 | DEBUG ((DEBUG_ERROR, "CapsuleImageSize incorrect\n"));\r |
e470ee6d JY |
708 | return EFI_SECURITY_VIOLATION;\r |
709 | }\r | |
710 | \r | |
711 | //\r | |
712 | // Check FMP capsule layout\r | |
713 | //\r | |
b8786489 MK |
714 | if (IsFmpCapsuleGuid (&CapsuleHeader->CapsuleGuid)) {\r |
715 | DEBUG ((DEBUG_INFO, "CreateHobForRecoveryCapsule\n"));\r | |
716 | \r | |
717 | DEBUG ((DEBUG_INFO, "ProcessCapsuleImage for FmpCapsule ...\n"));\r | |
718 | DEBUG ((DEBUG_INFO, "ValidateFmpCapsule ...\n"));\r | |
719 | Status = ValidateFmpCapsule (CapsuleHeader, &IsSystemFmp, NULL);\r | |
720 | DEBUG ((DEBUG_INFO, "ValidateFmpCapsule - %r\n", Status));\r | |
721 | if (EFI_ERROR (Status)) {\r | |
e470ee6d JY |
722 | return Status;\r |
723 | }\r | |
724 | \r | |
725 | //\r | |
70bd2a85 | 726 | // Process EFI FMP Capsule\r |
e470ee6d | 727 | //\r |
b8786489 MK |
728 | DEBUG ((DEBUG_INFO, "ProcessFmpCapsuleImage ...\n"));\r |
729 | Status = ProcessFmpCapsuleImage (CapsuleHeader, IsSystemFmp);\r | |
730 | DEBUG ((DEBUG_INFO, "ProcessFmpCapsuleImage - %r\n", Status));\r | |
e470ee6d | 731 | \r |
b8786489 | 732 | DEBUG ((DEBUG_INFO, "CreateHobForRecoveryCapsule Done\n"));\r |
e470ee6d JY |
733 | return Status;\r |
734 | }\r | |
735 | \r | |
736 | return EFI_UNSUPPORTED;\r | |
737 | }\r | |
738 | \r | |
739 | /**\r | |
740 | Loads a DXE capsule from some media into memory and updates the HOB table\r | |
741 | with the DXE firmware volume information.\r | |
742 | \r | |
743 | @param[in] PeiServices General-purpose services that are available to every PEIM.\r | |
744 | @param[in] This Indicates the EFI_PEI_RECOVERY_MODULE_PPI instance.\r | |
745 | \r | |
746 | @retval EFI_SUCCESS The capsule was loaded correctly.\r | |
747 | @retval EFI_DEVICE_ERROR A device error occurred.\r | |
748 | @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.\r | |
749 | \r | |
750 | **/\r | |
751 | EFI_STATUS\r | |
752 | EFIAPI\r | |
753 | LoadRecoveryCapsule (\r | |
b8786489 MK |
754 | IN EFI_PEI_SERVICES **PeiServices,\r |
755 | IN EFI_PEI_RECOVERY_MODULE_PPI *This\r | |
e470ee6d JY |
756 | )\r |
757 | {\r | |
758 | EFI_STATUS Status;\r | |
759 | EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *DeviceRecoveryPpi;\r | |
760 | UINTN NumberRecoveryCapsules;\r | |
761 | UINTN Instance;\r | |
762 | UINTN CapsuleInstance;\r | |
763 | UINTN CapsuleSize;\r | |
764 | EFI_GUID CapsuleType;\r | |
765 | VOID *CapsuleBuffer;\r | |
766 | \r | |
b8786489 | 767 | DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Recovery Entry\n"));\r |
e470ee6d JY |
768 | \r |
769 | for (Instance = 0; ; Instance++) {\r | |
770 | Status = PeiServicesLocatePpi (\r | |
771 | &gEfiPeiDeviceRecoveryModulePpiGuid,\r | |
772 | Instance,\r | |
773 | NULL,\r | |
774 | (VOID **)&DeviceRecoveryPpi\r | |
775 | );\r | |
776 | DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - LocateRecoveryPpi (%d) - %r\n", Instance, Status));\r | |
777 | if (EFI_ERROR (Status)) {\r | |
778 | break;\r | |
779 | }\r | |
b8786489 | 780 | \r |
e470ee6d | 781 | NumberRecoveryCapsules = 0;\r |
b8786489 MK |
782 | Status = DeviceRecoveryPpi->GetNumberRecoveryCapsules (\r |
783 | (EFI_PEI_SERVICES **)PeiServices,\r | |
784 | DeviceRecoveryPpi,\r | |
785 | &NumberRecoveryCapsules\r | |
786 | );\r | |
e470ee6d JY |
787 | DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - GetNumberRecoveryCapsules (%d) - %r\n", NumberRecoveryCapsules, Status));\r |
788 | if (EFI_ERROR (Status)) {\r | |
789 | continue;\r | |
790 | }\r | |
b8786489 | 791 | \r |
e470ee6d JY |
792 | for (CapsuleInstance = 1; CapsuleInstance <= NumberRecoveryCapsules; CapsuleInstance++) {\r |
793 | CapsuleSize = 0;\r | |
b8786489 MK |
794 | Status = DeviceRecoveryPpi->GetRecoveryCapsuleInfo (\r |
795 | (EFI_PEI_SERVICES **)PeiServices,\r | |
796 | DeviceRecoveryPpi,\r | |
797 | CapsuleInstance,\r | |
798 | &CapsuleSize,\r | |
799 | &CapsuleType\r | |
800 | );\r | |
e470ee6d JY |
801 | DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - GetRecoveryCapsuleInfo (%d - %x) - %r\n", CapsuleInstance, CapsuleSize, Status));\r |
802 | if (EFI_ERROR (Status)) {\r | |
803 | break;\r | |
804 | }\r | |
805 | \r | |
b8786489 | 806 | CapsuleBuffer = AllocatePages (EFI_SIZE_TO_PAGES (CapsuleSize));\r |
e470ee6d JY |
807 | if (CapsuleBuffer == NULL) {\r |
808 | DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - AllocatePool fail\n"));\r | |
809 | continue;\r | |
810 | }\r | |
b8786489 | 811 | \r |
e470ee6d JY |
812 | Status = DeviceRecoveryPpi->LoadRecoveryCapsule (\r |
813 | (EFI_PEI_SERVICES **)PeiServices,\r | |
814 | DeviceRecoveryPpi,\r | |
868f139b | 815 | CapsuleInstance,\r |
e470ee6d JY |
816 | CapsuleBuffer\r |
817 | );\r | |
818 | DEBUG ((DEBUG_ERROR, "LoadRecoveryCapsule - LoadRecoveryCapsule (%d) - %r\n", CapsuleInstance, Status));\r | |
819 | if (EFI_ERROR (Status)) {\r | |
b8786489 | 820 | FreePages (CapsuleBuffer, EFI_SIZE_TO_PAGES (CapsuleSize));\r |
e470ee6d JY |
821 | break;\r |
822 | }\r | |
b8786489 | 823 | \r |
e470ee6d JY |
824 | //\r |
825 | // good, load capsule buffer\r | |
826 | //\r | |
827 | Status = ProcessRecoveryCapsule (CapsuleBuffer, CapsuleSize);\r | |
828 | return Status;\r | |
829 | }\r | |
830 | }\r | |
831 | \r | |
832 | return EFI_NOT_FOUND;\r | |
833 | }\r |