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