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