]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - FatPkg/FatPei/FatLiteApi.c
MdeModulePkg/UefiBootManagerLib: fix crash on uninitialized ExitData
[mirror_edk2.git] / FatPkg / FatPei / FatLiteApi.c
... / ...
CommitLineData
1/** @file\r
2 FAT recovery PEIM entry point, Ppi Functions and FAT Api functions.\r
3\r
4Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
5\r
6SPDX-License-Identifier: BSD-2-Clause-Patent\r
7\r
8**/\r
9\r
10#include "FatLitePeim.h"\r
11\r
12PEI_FAT_PRIVATE_DATA *mPrivateData = NULL;\r
13\r
14/**\r
15 BlockIo installation nofication function. Find out all the current BlockIO\r
16 PPIs in the system and add them into private data. Assume there is\r
17\r
18 @param PeiServices General purpose services available to every\r
19 PEIM.\r
20 @param NotifyDescriptor The typedef structure of the notification\r
21 descriptor. Not used in this function.\r
22 @param Ppi The typedef structure of the PPI descriptor.\r
23 Not used in this function.\r
24\r
25 @retval EFI_SUCCESS The function completed successfully.\r
26\r
27**/\r
28EFI_STATUS\r
29EFIAPI\r
30BlockIoNotifyEntry (\r
31 IN EFI_PEI_SERVICES **PeiServices,\r
32 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
33 IN VOID *Ppi\r
34 );\r
35\r
36\r
37/**\r
38 Discover all the block I/O devices to find the FAT volume.\r
39\r
40 @param PrivateData Global memory map for accessing global\r
41 variables.\r
42 @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo\r
43\r
44 @retval EFI_SUCCESS The function completed successfully.\r
45\r
46**/\r
47EFI_STATUS\r
48UpdateBlocksAndVolumes (\r
49 IN OUT PEI_FAT_PRIVATE_DATA *PrivateData,\r
50 IN BOOLEAN BlockIo2\r
51 )\r
52{\r
53 EFI_STATUS Status;\r
54 EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor;\r
55 UINTN BlockIoPpiInstance;\r
56 EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;\r
57 EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi;\r
58 UINTN NumberBlockDevices;\r
59 UINTN Index;\r
60 EFI_PEI_BLOCK_IO_MEDIA Media;\r
61 EFI_PEI_BLOCK_IO2_MEDIA Media2;\r
62 PEI_FAT_VOLUME Volume;\r
63 EFI_PEI_SERVICES **PeiServices;\r
64\r
65 PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer ();\r
66 BlockIo2Ppi = NULL;\r
67 BlockIoPpi = NULL;\r
68 //\r
69 // Clean up caches\r
70 //\r
71 for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {\r
72 PrivateData->CacheBuffer[Index].Valid = FALSE;\r
73 }\r
74\r
75 PrivateData->BlockDeviceCount = 0;\r
76\r
77 //\r
78 // Find out all Block Io Ppi instances within the system\r
79 // Assuming all device Block Io Peims are dispatched already\r
80 //\r
81 for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_FAT_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {\r
82 if (BlockIo2) {\r
83 Status = PeiServicesLocatePpi (\r
84 &gEfiPeiVirtualBlockIo2PpiGuid,\r
85 BlockIoPpiInstance,\r
86 &TempPpiDescriptor,\r
87 (VOID **) &BlockIo2Ppi\r
88 );\r
89 } else {\r
90 Status = PeiServicesLocatePpi (\r
91 &gEfiPeiVirtualBlockIoPpiGuid,\r
92 BlockIoPpiInstance,\r
93 &TempPpiDescriptor,\r
94 (VOID **) &BlockIoPpi\r
95 );\r
96 }\r
97 if (EFI_ERROR (Status)) {\r
98 //\r
99 // Done with all Block Io Ppis\r
100 //\r
101 break;\r
102 }\r
103\r
104 if (BlockIo2) {\r
105 Status = BlockIo2Ppi->GetNumberOfBlockDevices (\r
106 PeiServices,\r
107 BlockIo2Ppi,\r
108 &NumberBlockDevices\r
109 );\r
110 } else {\r
111 Status = BlockIoPpi->GetNumberOfBlockDevices (\r
112 PeiServices,\r
113 BlockIoPpi,\r
114 &NumberBlockDevices\r
115 );\r
116 }\r
117 if (EFI_ERROR (Status)) {\r
118 continue;\r
119 }\r
120\r
121 for (Index = 1; Index <= NumberBlockDevices && PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE; Index++) {\r
122\r
123 if (BlockIo2) {\r
124 Status = BlockIo2Ppi->GetBlockDeviceMediaInfo (\r
125 PeiServices,\r
126 BlockIo2Ppi,\r
127 Index,\r
128 &Media2\r
129 );\r
130 if (EFI_ERROR (Status) || !Media2.MediaPresent) {\r
131 continue;\r
132 }\r
133 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo2 = BlockIo2Ppi;\r
134 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].InterfaceType = Media2.InterfaceType;\r
135 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock = Media2.LastBlock;\r
136 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize = Media2.BlockSize;\r
137 } else {\r
138 Status = BlockIoPpi->GetBlockDeviceMediaInfo (\r
139 PeiServices,\r
140 BlockIoPpi,\r
141 Index,\r
142 &Media\r
143 );\r
144 if (EFI_ERROR (Status) || !Media.MediaPresent) {\r
145 continue;\r
146 }\r
147 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo = BlockIoPpi;\r
148 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].DevType = Media.DeviceType;\r
149 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock = Media.LastBlock;\r
150 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize = (UINT32) Media.BlockSize;\r
151 }\r
152\r
153 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].IoAlign = 0;\r
154 //\r
155 // Not used here\r
156 //\r
157 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].Logical = FALSE;\r
158 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PartitionChecked = FALSE;\r
159\r
160 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PhysicalDevNo = (UINT8) Index;\r
161 PrivateData->BlockDeviceCount++;\r
162 }\r
163 }\r
164 //\r
165 // Find out all logical devices\r
166 //\r
167 FatFindPartitions (PrivateData);\r
168\r
169 //\r
170 // Build up file system volume array\r
171 //\r
172 PrivateData->VolumeCount = 0;\r
173 for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) {\r
174 Volume.BlockDeviceNo = Index;\r
175 Status = FatGetBpbInfo (PrivateData, &Volume);\r
176 if (Status == EFI_SUCCESS) {\r
177 //\r
178 // Add the detected volume to the volume array\r
179 //\r
180 CopyMem (\r
181 (UINT8 *) &(PrivateData->Volume[PrivateData->VolumeCount]),\r
182 (UINT8 *) &Volume,\r
183 sizeof (PEI_FAT_VOLUME)\r
184 );\r
185 PrivateData->VolumeCount += 1;\r
186 if (PrivateData->VolumeCount >= PEI_FAT_MAX_VOLUME) {\r
187 break;\r
188 }\r
189 }\r
190 }\r
191\r
192 return EFI_SUCCESS;\r
193}\r
194\r
195\r
196/**\r
197 BlockIo installation notification function. Find out all the current BlockIO\r
198 PPIs in the system and add them into private data. Assume there is\r
199\r
200 @param PeiServices General purpose services available to every\r
201 PEIM.\r
202 @param NotifyDescriptor The typedef structure of the notification\r
203 descriptor. Not used in this function.\r
204 @param Ppi The typedef structure of the PPI descriptor.\r
205 Not used in this function.\r
206\r
207 @retval EFI_SUCCESS The function completed successfully.\r
208\r
209**/\r
210EFI_STATUS\r
211EFIAPI\r
212BlockIoNotifyEntry (\r
213 IN EFI_PEI_SERVICES **PeiServices,\r
214 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
215 IN VOID *Ppi\r
216 )\r
217{\r
218 if (CompareGuid (NotifyDescriptor->Guid, &gEfiPeiVirtualBlockIo2PpiGuid)) {\r
219 UpdateBlocksAndVolumes (mPrivateData, TRUE);\r
220 } else {\r
221 UpdateBlocksAndVolumes (mPrivateData, FALSE);\r
222 }\r
223 return EFI_SUCCESS;\r
224}\r
225\r
226\r
227/**\r
228 Installs the Device Recovery Module PPI, Initialize BlockIo Ppi\r
229 installation notification\r
230\r
231 @param FileHandle Handle of the file being invoked. Type\r
232 EFI_PEI_FILE_HANDLE is defined in\r
233 FfsFindNextFile().\r
234 @param PeiServices Describes the list of possible PEI Services.\r
235\r
236 @retval EFI_SUCCESS The entry point was executed successfully.\r
237 @retval EFI_OUT_OF_RESOURCES There is no enough memory to complete the\r
238 operations.\r
239\r
240**/\r
241EFI_STATUS\r
242EFIAPI\r
243FatPeimEntry (\r
244 IN EFI_PEI_FILE_HANDLE FileHandle,\r
245 IN CONST EFI_PEI_SERVICES **PeiServices\r
246 )\r
247{\r
248 EFI_STATUS Status;\r
249 EFI_PHYSICAL_ADDRESS Address;\r
250 PEI_FAT_PRIVATE_DATA *PrivateData;\r
251\r
252 Status = PeiServicesRegisterForShadow (FileHandle);\r
253 if (!EFI_ERROR (Status)) {\r
254 return Status;\r
255 }\r
256\r
257 Status = PeiServicesAllocatePages (\r
258 EfiBootServicesCode,\r
259 (sizeof (PEI_FAT_PRIVATE_DATA) - 1) / PEI_FAT_MEMMORY_PAGE_SIZE + 1,\r
260 &Address\r
261 );\r
262 if (EFI_ERROR (Status)) {\r
263 return EFI_OUT_OF_RESOURCES;\r
264 }\r
265\r
266 PrivateData = (PEI_FAT_PRIVATE_DATA *) (UINTN) Address;\r
267\r
268 //\r
269 // Initialize Private Data (to zero, as is required by subsequent operations)\r
270 //\r
271 ZeroMem ((UINT8 *) PrivateData, sizeof (PEI_FAT_PRIVATE_DATA));\r
272\r
273 PrivateData->Signature = PEI_FAT_PRIVATE_DATA_SIGNATURE;\r
274\r
275 //\r
276 // Installs Ppi\r
277 //\r
278 PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules = GetNumberRecoveryCapsules;\r
279 PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo = GetRecoveryCapsuleInfo;\r
280 PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule = LoadRecoveryCapsule;\r
281\r
282 PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
283 PrivateData->PpiDescriptor.Guid = &gEfiPeiDeviceRecoveryModulePpiGuid;\r
284 PrivateData->PpiDescriptor.Ppi = &PrivateData->DeviceRecoveryPpi;\r
285\r
286 Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor);\r
287 if (EFI_ERROR (Status)) {\r
288 return EFI_OUT_OF_RESOURCES;\r
289 }\r
290 //\r
291 // Other initializations\r
292 //\r
293 PrivateData->BlockDeviceCount = 0;\r
294\r
295 UpdateBlocksAndVolumes (PrivateData, TRUE);\r
296 UpdateBlocksAndVolumes (PrivateData, FALSE);\r
297\r
298 //\r
299 // PrivateData is allocated now, set it to the module variable\r
300 //\r
301 mPrivateData = PrivateData;\r
302\r
303 //\r
304 // Installs Block Io Ppi notification function\r
305 //\r
306 PrivateData->NotifyDescriptor[0].Flags =\r
307 (\r
308 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK\r
309 );\r
310 PrivateData->NotifyDescriptor[0].Guid = &gEfiPeiVirtualBlockIoPpiGuid;\r
311 PrivateData->NotifyDescriptor[0].Notify = BlockIoNotifyEntry;\r
312 PrivateData->NotifyDescriptor[1].Flags =\r
313 (\r
314 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |\r
315 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST\r
316 );\r
317 PrivateData->NotifyDescriptor[1].Guid = &gEfiPeiVirtualBlockIo2PpiGuid;\r
318 PrivateData->NotifyDescriptor[1].Notify = BlockIoNotifyEntry;\r
319 return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor[0]);\r
320}\r
321\r
322\r
323/**\r
324 Returns the number of DXE capsules residing on the device.\r
325\r
326 This function searches for DXE capsules from the associated device and returns\r
327 the number and maximum size in bytes of the capsules discovered. Entry 1 is\r
328 assumed to be the highest load priority and entry N is assumed to be the lowest\r
329 priority.\r
330\r
331 @param[in] PeiServices General-purpose services that are available\r
332 to every PEIM\r
333 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
334 instance.\r
335 @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On\r
336 output, *NumberRecoveryCapsules contains\r
337 the number of recovery capsule images\r
338 available for retrieval from this PEIM\r
339 instance.\r
340\r
341 @retval EFI_SUCCESS One or more capsules were discovered.\r
342 @retval EFI_DEVICE_ERROR A device error occurred.\r
343 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.\r
344\r
345**/\r
346EFI_STATUS\r
347EFIAPI\r
348GetNumberRecoveryCapsules (\r
349 IN EFI_PEI_SERVICES **PeiServices,\r
350 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
351 OUT UINTN *NumberRecoveryCapsules\r
352 )\r
353{\r
354 EFI_STATUS Status;\r
355 PEI_FAT_PRIVATE_DATA *PrivateData;\r
356 UINTN Index;\r
357 UINTN RecoveryCapsuleCount;\r
358 PEI_FILE_HANDLE Handle;\r
359\r
360 PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);\r
361\r
362 //\r
363 // Search each volume in the root directory for the Recovery capsule\r
364 //\r
365 RecoveryCapsuleCount = 0;\r
366 for (Index = 0; Index < PrivateData->VolumeCount; Index++) {\r
367 Status = FindRecoveryFile (PrivateData, Index, (CHAR16 *)PcdGetPtr(PcdRecoveryFileName), &Handle);\r
368 if (EFI_ERROR (Status)) {\r
369 continue;\r
370 }\r
371\r
372 RecoveryCapsuleCount++;\r
373 }\r
374\r
375 *NumberRecoveryCapsules = RecoveryCapsuleCount;\r
376\r
377 if (*NumberRecoveryCapsules == 0) {\r
378 return EFI_NOT_FOUND;\r
379 }\r
380\r
381 return EFI_SUCCESS;\r
382}\r
383\r
384\r
385/**\r
386 Returns the size and type of the requested recovery capsule.\r
387\r
388 This function gets the size and type of the capsule specified by CapsuleInstance.\r
389\r
390 @param[in] PeiServices General-purpose services that are available to every PEIM\r
391 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
392 instance.\r
393 @param[in] CapsuleInstance Specifies for which capsule instance to retrieve\r
394 the information. This parameter must be between\r
395 one and the value returned by GetNumberRecoveryCapsules()\r
396 in NumberRecoveryCapsules.\r
397 @param[out] Size A pointer to a caller-allocated UINTN in which\r
398 the size of the requested recovery module is\r
399 returned.\r
400 @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which\r
401 the type of the requested recovery capsule is\r
402 returned. The semantic meaning of the value\r
403 returned is defined by the implementation.\r
404\r
405 @retval EFI_SUCCESS One or more capsules were discovered.\r
406 @retval EFI_DEVICE_ERROR A device error occurred.\r
407 @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.\r
408\r
409**/\r
410EFI_STATUS\r
411EFIAPI\r
412GetRecoveryCapsuleInfo (\r
413 IN EFI_PEI_SERVICES **PeiServices,\r
414 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
415 IN UINTN CapsuleInstance,\r
416 OUT UINTN *Size,\r
417 OUT EFI_GUID *CapsuleType\r
418 )\r
419{\r
420 EFI_STATUS Status;\r
421 PEI_FAT_PRIVATE_DATA *PrivateData;\r
422 UINTN Index;\r
423 UINTN BlockDeviceNo;\r
424 UINTN RecoveryCapsuleCount;\r
425 PEI_FILE_HANDLE Handle;\r
426 UINTN NumberRecoveryCapsules;\r
427\r
428 Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);\r
429\r
430 if (EFI_ERROR (Status)) {\r
431 return Status;\r
432 }\r
433\r
434 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
435 CapsuleInstance = CapsuleInstance + 1;\r
436 }\r
437\r
438 if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {\r
439 return EFI_NOT_FOUND;\r
440 }\r
441\r
442 PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);\r
443\r
444 //\r
445 // Search each volume in the root directory for the Recovery capsule\r
446 //\r
447 RecoveryCapsuleCount = 0;\r
448 for (Index = 0; Index < PrivateData->VolumeCount; Index++) {\r
449 Status = FindRecoveryFile (PrivateData, Index, (CHAR16 *)PcdGetPtr(PcdRecoveryFileName), &Handle);\r
450\r
451 if (EFI_ERROR (Status)) {\r
452 continue;\r
453 }\r
454\r
455 if (CapsuleInstance - 1 == RecoveryCapsuleCount) {\r
456 //\r
457 // Get file size\r
458 //\r
459 *Size = (UINTN) (((PEI_FAT_FILE *) Handle)->FileSize);\r
460\r
461 //\r
462 // Find corresponding physical block device\r
463 //\r
464 BlockDeviceNo = PrivateData->Volume[Index].BlockDeviceNo;\r
465 while (PrivateData->BlockDevice[BlockDeviceNo].Logical && BlockDeviceNo < PrivateData->BlockDeviceCount) {\r
466 BlockDeviceNo = PrivateData->BlockDevice[BlockDeviceNo].ParentDevNo;\r
467 }\r
468 //\r
469 // Fill in the Capsule Type GUID according to the block device type\r
470 //\r
471 if (BlockDeviceNo < PrivateData->BlockDeviceCount) {\r
472 if (PrivateData->BlockDevice[BlockDeviceNo].BlockIo2 != NULL) {\r
473 switch (PrivateData->BlockDevice[BlockDeviceNo].InterfaceType) {\r
474 case MSG_ATAPI_DP:\r
475 CopyGuid (CapsuleType, &gRecoveryOnFatIdeDiskGuid);\r
476 break;\r
477\r
478 case MSG_USB_DP:\r
479 CopyGuid (CapsuleType, &gRecoveryOnFatUsbDiskGuid);\r
480 break;\r
481\r
482 case MSG_NVME_NAMESPACE_DP:\r
483 CopyGuid (CapsuleType, &gRecoveryOnFatNvmeDiskGuid);\r
484 break;\r
485\r
486 default:\r
487 break;\r
488 }\r
489 }\r
490 if (PrivateData->BlockDevice[BlockDeviceNo].BlockIo != NULL) {\r
491 switch (PrivateData->BlockDevice[BlockDeviceNo].DevType) {\r
492 case LegacyFloppy:\r
493 CopyGuid (CapsuleType, &gRecoveryOnFatFloppyDiskGuid);\r
494 break;\r
495\r
496 case IdeCDROM:\r
497 case IdeLS120:\r
498 CopyGuid (CapsuleType, &gRecoveryOnFatIdeDiskGuid);\r
499 break;\r
500\r
501 case UsbMassStorage:\r
502 CopyGuid (CapsuleType, &gRecoveryOnFatUsbDiskGuid);\r
503 break;\r
504\r
505 default:\r
506 break;\r
507 }\r
508 }\r
509 }\r
510\r
511 return EFI_SUCCESS;\r
512 }\r
513\r
514 RecoveryCapsuleCount++;\r
515 }\r
516\r
517 return EFI_NOT_FOUND;\r
518}\r
519\r
520\r
521/**\r
522 Loads a DXE capsule from some media into memory.\r
523\r
524 This function, by whatever mechanism, retrieves a DXE capsule from some device\r
525 and loads it into memory. Note that the published interface is device neutral.\r
526\r
527 @param[in] PeiServices General-purpose services that are available\r
528 to every PEIM\r
529 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
530 instance.\r
531 @param[in] CapsuleInstance Specifies which capsule instance to retrieve.\r
532 @param[out] Buffer Specifies a caller-allocated buffer in which\r
533 the requested recovery capsule will be returned.\r
534\r
535 @retval EFI_SUCCESS The capsule was loaded correctly.\r
536 @retval EFI_DEVICE_ERROR A device error occurred.\r
537 @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.\r
538\r
539**/\r
540EFI_STATUS\r
541EFIAPI\r
542LoadRecoveryCapsule (\r
543 IN EFI_PEI_SERVICES **PeiServices,\r
544 IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
545 IN UINTN CapsuleInstance,\r
546 OUT VOID *Buffer\r
547 )\r
548{\r
549 EFI_STATUS Status;\r
550 PEI_FAT_PRIVATE_DATA *PrivateData;\r
551 UINTN Index;\r
552 UINTN RecoveryCapsuleCount;\r
553 PEI_FILE_HANDLE Handle;\r
554 UINTN NumberRecoveryCapsules;\r
555\r
556 Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);\r
557\r
558 if (EFI_ERROR (Status)) {\r
559 return Status;\r
560 }\r
561\r
562 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
563 CapsuleInstance = CapsuleInstance + 1;\r
564 }\r
565\r
566 if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {\r
567 return EFI_NOT_FOUND;\r
568 }\r
569\r
570 PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);\r
571\r
572 //\r
573 // Search each volume in the root directory for the Recovery capsule\r
574 //\r
575 RecoveryCapsuleCount = 0;\r
576 for (Index = 0; Index < PrivateData->VolumeCount; Index++) {\r
577 Status = FindRecoveryFile (PrivateData, Index, (CHAR16 *)PcdGetPtr(PcdRecoveryFileName), &Handle);\r
578 if (EFI_ERROR (Status)) {\r
579 continue;\r
580 }\r
581\r
582 if (CapsuleInstance - 1 == RecoveryCapsuleCount) {\r
583\r
584 Status = FatReadFile (\r
585 PrivateData,\r
586 Handle,\r
587 (UINTN) (((PEI_FAT_FILE *) Handle)->FileSize),\r
588 Buffer\r
589 );\r
590 return Status;\r
591 }\r
592\r
593 RecoveryCapsuleCount++;\r
594 }\r
595\r
596 return EFI_NOT_FOUND;\r
597}\r
598\r
599\r
600/**\r
601 Finds the recovery file on a FAT volume.\r
602 This function finds the the recovery file named FileName on a specified FAT volume and returns\r
603 its FileHandle pointer.\r
604\r
605 @param PrivateData Global memory map for accessing global\r
606 variables.\r
607 @param VolumeIndex The index of the volume.\r
608 @param FileName The recovery file name to find.\r
609 @param Handle The output file handle.\r
610\r
611 @retval EFI_DEVICE_ERROR Some error occured when operating the FAT\r
612 volume.\r
613 @retval EFI_NOT_FOUND The recovery file was not found.\r
614 @retval EFI_SUCCESS The recovery file was successfully found on the\r
615 FAT volume.\r
616\r
617**/\r
618EFI_STATUS\r
619FindRecoveryFile (\r
620 IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
621 IN UINTN VolumeIndex,\r
622 IN CHAR16 *FileName,\r
623 OUT PEI_FILE_HANDLE *Handle\r
624 )\r
625{\r
626 EFI_STATUS Status;\r
627 PEI_FAT_FILE Parent;\r
628 PEI_FAT_FILE *File;\r
629\r
630 File = &PrivateData->File;\r
631\r
632 //\r
633 // VolumeIndex must be less than PEI_FAT_MAX_VOLUME because PrivateData->VolumeCount\r
634 // cannot be larger than PEI_FAT_MAX_VOLUME when detecting recovery volume.\r
635 //\r
636 ASSERT (VolumeIndex < PEI_FAT_MAX_VOLUME);\r
637\r
638 //\r
639 // Construct root directory file\r
640 //\r
641 ZeroMem (&Parent, sizeof (PEI_FAT_FILE));\r
642 Parent.IsFixedRootDir = (BOOLEAN) ((PrivateData->Volume[VolumeIndex].FatType == Fat32) ? FALSE : TRUE);\r
643 Parent.Attributes = FAT_ATTR_DIRECTORY;\r
644 Parent.CurrentPos = 0;\r
645 Parent.CurrentCluster = Parent.IsFixedRootDir ? 0 : PrivateData->Volume[VolumeIndex].RootDirCluster;\r
646 Parent.StartingCluster = Parent.CurrentCluster;\r
647 Parent.Volume = &PrivateData->Volume[VolumeIndex];\r
648\r
649 Status = FatSetFilePos (PrivateData, &Parent, 0);\r
650 if (EFI_ERROR (Status)) {\r
651 return EFI_DEVICE_ERROR;\r
652 }\r
653 //\r
654 // Search for recovery capsule in root directory\r
655 //\r
656 Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);\r
657 while (Status == EFI_SUCCESS) {\r
658 //\r
659 // Compare whether the file name is recovery file name.\r
660 //\r
661 if (EngStriColl (PrivateData, FileName, File->FileName)) {\r
662 break;\r
663 }\r
664\r
665 Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);\r
666 }\r
667\r
668 if (EFI_ERROR (Status)) {\r
669 return EFI_NOT_FOUND;\r
670 }\r
671\r
672 //\r
673 // Get the recovery file, set its file position to 0.\r
674 //\r
675 if (File->StartingCluster != 0) {\r
676 Status = FatSetFilePos (PrivateData, File, 0);\r
677 }\r
678\r
679 *Handle = File;\r
680\r
681 return EFI_SUCCESS;\r
682\r
683}\r