]> git.proxmox.com Git - mirror_edk2.git/blame - FatPkg/FatPei/FatLiteApi.c
FatPkg: Replace BSD License with BSD+Patent License
[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
796ef9da 4Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
2f4dfa84 5\r
eb6cb4ce 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
2f4dfa84
JJ
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
e38f26a2
LG
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
2f4dfa84
JJ
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
e38f26a2
LG
40 @param PrivateData Global memory map for accessing global\r
41 variables.\r
8a467be1 42 @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo\r
2f4dfa84
JJ
43\r
44 @retval EFI_SUCCESS The function completed successfully.\r
45\r
46**/\r
47EFI_STATUS\r
48UpdateBlocksAndVolumes (\r
8a467be1
FT
49 IN OUT PEI_FAT_PRIVATE_DATA *PrivateData,\r
50 IN BOOLEAN BlockIo2\r
2f4dfa84
JJ
51 )\r
52{\r
8a467be1
FT
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
2f4dfa84
JJ
64\r
65 PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer ();\r
4819b3e8
FT
66 BlockIo2Ppi = NULL;\r
67 BlockIoPpi = NULL;\r
2f4dfa84
JJ
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
8a467be1
FT
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
2f4dfa84
JJ
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
8a467be1
FT
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
2f4dfa84
JJ
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
8a467be1
FT
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
4819b3e8
FT
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
8a467be1
FT
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
4819b3e8
FT
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
2f4dfa84
JJ
151 }\r
152\r
4819b3e8 153 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].IoAlign = 0;\r
2f4dfa84
JJ
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
2f4dfa84 160 PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PhysicalDevNo = (UINT8) Index;\r
2f4dfa84
JJ
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
e38f26a2
LG
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
2f4dfa84
JJ
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
8a467be1
FT
218 if (CompareGuid (NotifyDescriptor->Guid, &gEfiPeiVirtualBlockIo2PpiGuid)) {\r
219 UpdateBlocksAndVolumes (mPrivateData, TRUE);\r
220 } else {\r
221 UpdateBlocksAndVolumes (mPrivateData, FALSE);\r
222 }\r
2f4dfa84
JJ
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
e38f26a2
LG
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
2f4dfa84 235\r
e38f26a2
LG
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
2f4dfa84
JJ
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
8a467be1 284 PrivateData->PpiDescriptor.Ppi = &PrivateData->DeviceRecoveryPpi;\r
2f4dfa84
JJ
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
8a467be1
FT
295 UpdateBlocksAndVolumes (PrivateData, TRUE);\r
296 UpdateBlocksAndVolumes (PrivateData, FALSE);\r
2f4dfa84
JJ
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
8a467be1
FT
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
2f4dfa84
JJ
313 (\r
314 EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |\r
315 EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST\r
316 );\r
8a467be1
FT
317 PrivateData->NotifyDescriptor[1].Guid = &gEfiPeiVirtualBlockIo2PpiGuid;\r
318 PrivateData->NotifyDescriptor[1].Notify = BlockIoNotifyEntry;\r
319 return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor[0]);\r
2f4dfa84
JJ
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
e38f26a2
LG
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
2f4dfa84
JJ
329 priority.\r
330\r
e38f26a2 331 @param[in] PeiServices General-purpose services that are available\r
2f4dfa84
JJ
332 to every PEIM\r
333 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
334 instance.\r
e38f26a2
LG
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
2f4dfa84
JJ
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
46cd2cb6 367 Status = FindRecoveryFile (PrivateData, Index, (CHAR16 *)PcdGetPtr(PcdRecoveryFileName), &Handle);\r
2f4dfa84
JJ
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
e38f26a2 391 @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
2f4dfa84 392 instance.\r
e38f26a2
LG
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
2f4dfa84 396 in NumberRecoveryCapsules.\r
e38f26a2
LG
397 @param[out] Size A pointer to a caller-allocated UINTN in which\r
398 the size of the requested recovery module is\r
2f4dfa84 399 returned.\r
e38f26a2
LG
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
2f4dfa84
JJ
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
46cd2cb6 449 Status = FindRecoveryFile (PrivateData, Index, (CHAR16 *)PcdGetPtr(PcdRecoveryFileName), &Handle);\r
2f4dfa84
JJ
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
8a467be1
FT
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
796ef9da
HW
482 case MSG_NVME_NAMESPACE_DP:\r
483 CopyGuid (CapsuleType, &gRecoveryOnFatNvmeDiskGuid);\r
484 break;\r
485\r
8a467be1
FT
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
2f4dfa84
JJ
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
e38f26a2 527 @param[in] PeiServices General-purpose services that are available\r
2f4dfa84
JJ
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
e38f26a2 532 @param[out] Buffer Specifies a caller-allocated buffer in which\r
2f4dfa84
JJ
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
46cd2cb6 577 Status = FindRecoveryFile (PrivateData, Index, (CHAR16 *)PcdGetPtr(PcdRecoveryFileName), &Handle);\r
2f4dfa84
JJ
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
e38f26a2
LG
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
2f4dfa84 610\r
e38f26a2
LG
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
2f4dfa84
JJ
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
1d951a30 641 ZeroMem (&Parent, sizeof (PEI_FAT_FILE));\r
2f4dfa84
JJ
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
1d951a30
FT
658 //\r
659 // Compare whether the file name is recovery file name.\r
660 //\r
2f4dfa84
JJ
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
1d951a30
FT
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
2f4dfa84
JJ
679 *Handle = File;\r
680\r
681 return EFI_SUCCESS;\r
682\r
683}\r