--- /dev/null
+/** @file\r
+ FAT file system access routines for FAT recovery PEIM\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FatLitePeim.h"\r
+\r
+\r
+/**\r
+ Check if there is a valid FAT in the corresponding Block device\r
+ of the volume and if yes, fill in the relevant fields for the\r
+ volume structure. Note there should be a valid Block device number\r
+ already set.\r
+\r
+ @param PrivateData Global memory map for accessing global \r
+ variables. \r
+ @param Volume On input, the BlockDeviceNumber field of the \r
+ Volume should be a valid value. On successful \r
+ output, all fields except the VolumeNumber \r
+ field is initialized. \r
+\r
+ @retval EFI_SUCCESS A FAT is found and the volume structure is \r
+ initialized. \r
+ @retval EFI_NOT_FOUND There is no FAT on the corresponding device. \r
+ @retval EFI_DEVICE_ERROR There is something error while accessing device.\r
+\r
+**/\r
+EFI_STATUS\r
+FatGetBpbInfo (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN OUT PEI_FAT_VOLUME *Volume\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_FAT_BOOT_SECTOR Bpb;\r
+ PEI_FAT_BOOT_SECTOR_EX BpbEx;\r
+ UINT32 Sectors;\r
+ UINT32 SectorsPerFat;\r
+ UINT32 RootDirSectors;\r
+ UINT64 FatLba;\r
+ UINT64 RootLba;\r
+ UINT64 FirstClusterLba;\r
+\r
+ //\r
+ // Read in the BPB\r
+ //\r
+ Status = FatReadDisk (\r
+ PrivateData,\r
+ Volume->BlockDeviceNo,\r
+ 0,\r
+ sizeof (PEI_FAT_BOOT_SECTOR_EX),\r
+ &BpbEx\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ CopyMem (\r
+ (UINT8 *) (&Bpb),\r
+ (UINT8 *) (&BpbEx),\r
+ sizeof (PEI_FAT_BOOT_SECTOR)\r
+ );\r
+\r
+ Volume->FatType = FatUnknown;\r
+\r
+ Sectors = Bpb.Sectors;\r
+ if (Sectors == 0) {\r
+ Sectors = Bpb.LargeSectors;\r
+ }\r
+\r
+ SectorsPerFat = Bpb.SectorsPerFat;\r
+ if (SectorsPerFat == 0) {\r
+ SectorsPerFat = BpbEx.LargeSectorsPerFat;\r
+ Volume->FatType = Fat32;\r
+ }\r
+ //\r
+ // Filter out those not a FAT\r
+ //\r
+ if (Bpb.Ia32Jump[0] != 0xe9 && Bpb.Ia32Jump[0] != 0xeb && Bpb.Ia32Jump[0] != 0x49) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (Bpb.ReservedSectors == 0 || Bpb.NoFats == 0 || Sectors == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (Bpb.SectorsPerCluster != 1 &&\r
+ Bpb.SectorsPerCluster != 2 &&\r
+ Bpb.SectorsPerCluster != 4 &&\r
+ Bpb.SectorsPerCluster != 8 &&\r
+ Bpb.SectorsPerCluster != 16 &&\r
+ Bpb.SectorsPerCluster != 32 &&\r
+ Bpb.SectorsPerCluster != 64 &&\r
+ Bpb.SectorsPerCluster != 128\r
+ ) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (Volume->FatType == Fat32 && (SectorsPerFat == 0 || BpbEx.FsVersion != 0)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (Bpb.Media != 0xf0 &&\r
+ Bpb.Media != 0xf8 &&\r
+ Bpb.Media != 0xf9 &&\r
+ Bpb.Media != 0xfb &&\r
+ Bpb.Media != 0xfc &&\r
+ Bpb.Media != 0xfd &&\r
+ Bpb.Media != 0xfe &&\r
+ Bpb.Media != 0xff &&\r
+ //\r
+ // FujitsuFMR\r
+ //\r
+ Bpb.Media != 0x00 &&\r
+ Bpb.Media != 0x01 &&\r
+ Bpb.Media != 0xfa\r
+ ) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ if (Volume->FatType != Fat32 && Bpb.RootEntries == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // If this is fat32, refuse to mount mirror-disabled volumes\r
+ //\r
+ if (Volume->FatType == Fat32 && ((BpbEx.ExtendedFlags & 0x80) != 0)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Fill in the volume structure fields\r
+ // (Sectors & SectorsPerFat is computed earlier already)\r
+ //\r
+ Volume->ClusterSize = Bpb.SectorSize * Bpb.SectorsPerCluster;\r
+ Volume->RootEntries = Bpb.RootEntries;\r
+ Volume->SectorSize = Bpb.SectorSize;\r
+\r
+ RootDirSectors = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (Volume->SectorSize - 1)) / Volume->SectorSize;\r
+\r
+ FatLba = Bpb.ReservedSectors;\r
+ RootLba = Bpb.NoFats * SectorsPerFat + FatLba;\r
+ FirstClusterLba = RootLba + RootDirSectors;\r
+\r
+ Volume->VolumeSize = MultU64x32 (Sectors, Volume->SectorSize);\r
+ Volume->FatPos = MultU64x32 (FatLba, Volume->SectorSize);\r
+ Volume->RootDirPos = MultU64x32 (RootLba, Volume->SectorSize);\r
+ Volume->FirstClusterPos = MultU64x32 (FirstClusterLba, Volume->SectorSize);\r
+ Volume->MaxCluster = (UINT32) (Sectors - FirstClusterLba) / Bpb.SectorsPerCluster;\r
+ Volume->RootDirCluster = BpbEx.RootDirFirstCluster;\r
+\r
+ //\r
+ // If this is not a fat32, determine if it's a fat16 or fat12\r
+ //\r
+ if (Volume->FatType != Fat32) {\r
+\r
+ if (Volume->MaxCluster >= 65525) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Volume->FatType = Volume->MaxCluster < 4085 ? Fat12 : Fat16;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Gets the next cluster in the cluster chain\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param Volume The volume \r
+ @param Cluster The cluster \r
+ @param NextCluster The cluster number of the next cluster \r
+\r
+ @retval EFI_SUCCESS The address is got \r
+ @retval EFI_INVALID_PARAMETER ClusterNo exceeds the MaxCluster of the volume. \r
+ @retval EFI_DEVICE_ERROR Read disk error\r
+\r
+**/\r
+EFI_STATUS\r
+FatGetNextCluster (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN PEI_FAT_VOLUME *Volume,\r
+ IN UINT32 Cluster,\r
+ OUT UINT32 *NextCluster\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT64 FatEntryPos;\r
+ UINT32 Dummy;\r
+\r
+ *NextCluster = 0;\r
+\r
+ if (Volume->FatType == Fat32) {\r
+ FatEntryPos = Volume->FatPos + MultU64x32 (4, Cluster);\r
+\r
+ Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 4, NextCluster);\r
+ *NextCluster &= 0x0fffffff;\r
+\r
+ //\r
+ // Pad high bits for our FAT_CLUSTER_... macro definitions to work\r
+ //\r
+ if ((*NextCluster) >= 0x0ffffff7) {\r
+ *NextCluster |= (-1 &~0xf);\r
+ }\r
+\r
+ } else if (Volume->FatType == Fat16) {\r
+ FatEntryPos = Volume->FatPos + MultU64x32 (2, Cluster);\r
+\r
+ Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);\r
+\r
+ //\r
+ // Pad high bits for our FAT_CLUSTER_... macro definitions to work\r
+ //\r
+ if ((*NextCluster) >= 0xfff7) {\r
+ *NextCluster |= (-1 &~0xf);\r
+ }\r
+\r
+ } else {\r
+ FatEntryPos = Volume->FatPos + DivU64x32Remainder (MultU64x32 (3, Cluster), 2, &Dummy);\r
+\r
+ Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);\r
+\r
+ if ((Cluster & 0x01) != 0) {\r
+ *NextCluster = (*NextCluster) >> 4;\r
+ } else {\r
+ *NextCluster = (*NextCluster) & 0x0fff;\r
+ }\r
+ //\r
+ // Pad high bits for our FAT_CLUSTER_... macro definitions to work\r
+ //\r
+ if ((*NextCluster) >= 0x0ff7) {\r
+ *NextCluster |= (-1 &~0xf);\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+/**\r
+ Set a file's CurrentPos and CurrentCluster, then compute StraightReadAmount.\r
+\r
+ @param PrivateData the global memory map \r
+ @param File the file \r
+ @param Pos the Position which is offset from the file's \r
+ CurrentPos \r
+\r
+ @retval EFI_SUCCESS Success. \r
+ @retval EFI_INVALID_PARAMETER Pos is beyond file's size. \r
+ @retval EFI_DEVICE_ERROR Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatSetFilePos (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN PEI_FAT_FILE *File,\r
+ IN UINT32 Pos\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 AlignedPos;\r
+ UINT32 Offset;\r
+ UINT32 Cluster;\r
+ UINT32 PrevCluster;\r
+\r
+ if (File->IsFixedRootDir) {\r
+\r
+ if (Pos >= MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ File->CurrentPos += Pos;\r
+ File->StraightReadAmount = (UINT32) (MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos);\r
+\r
+ } else {\r
+\r
+ DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);\r
+ AlignedPos = (UINT32) File->CurrentPos - (UINT32) Offset;\r
+\r
+ while\r
+ (\r
+ !FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster) &&\r
+ AlignedPos + File->Volume->ClusterSize <= File->CurrentPos + Pos\r
+ ) {\r
+ AlignedPos += File->Volume->ClusterSize;\r
+ Status = FatGetNextCluster (\r
+ PrivateData,\r
+ File->Volume,\r
+ File->CurrentCluster,\r
+ &File->CurrentCluster\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+ if (FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ File->CurrentPos += Pos;\r
+\r
+ File->StraightReadAmount = 0;\r
+ Cluster = File->CurrentCluster;\r
+ while (!FAT_CLUSTER_FUNCTIONAL (Cluster)) {\r
+ File->StraightReadAmount += File->Volume->ClusterSize;\r
+ PrevCluster = Cluster;\r
+ Status = FatGetNextCluster (PrivateData, File->Volume, Cluster, &Cluster);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (Cluster != PrevCluster + 1) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);\r
+ File->StraightReadAmount -= (UINT32) Offset;\r
+\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Reads file data. Updates the file's CurrentPos.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param File The file. \r
+ @param Size The amount of data to read. \r
+ @param Buffer The buffer storing the data. \r
+\r
+ @retval EFI_SUCCESS The data is read. \r
+ @retval EFI_INVALID_PARAMETER File is invalid. \r
+ @retval EFI_DEVICE_ERROR Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadFile (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN PEI_FAT_FILE *File,\r
+ IN UINTN Size,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR8 *BufferPtr;\r
+ UINT32 Offset;\r
+ UINT64 PhysicalAddr;\r
+ UINTN Amount;\r
+\r
+ BufferPtr = Buffer;\r
+\r
+ if (File->IsFixedRootDir) {\r
+ //\r
+ // This is the fixed root dir in FAT12 and FAT16\r
+ //\r
+ if (File->CurrentPos + Size > File->Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ Status = FatReadDisk (\r
+ PrivateData,\r
+ File->Volume->BlockDeviceNo,\r
+ File->Volume->RootDirPos + File->CurrentPos,\r
+ Size,\r
+ Buffer\r
+ );\r
+ File->CurrentPos += (UINT32) Size;\r
+ return Status;\r
+\r
+ } else {\r
+\r
+ if ((File->Attributes & FAT_ATTR_DIRECTORY) == 0) {\r
+ Size = Size < (File->FileSize - File->CurrentPos) ? Size : (UINTN) (File->FileSize - File->CurrentPos);\r
+ }\r
+ //\r
+ // This is a normal cluster based file\r
+ //\r
+ while (Size != 0) {\r
+ DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);\r
+ PhysicalAddr = File->Volume->FirstClusterPos + MultU64x32 (File->Volume->ClusterSize, File->CurrentCluster - 2);\r
+\r
+ Amount = File->StraightReadAmount;\r
+ Amount = Size > Amount ? Amount : Size;\r
+ Status = FatReadDisk (\r
+ PrivateData,\r
+ File->Volume->BlockDeviceNo,\r
+ PhysicalAddr + Offset,\r
+ Amount,\r
+ BufferPtr\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Advance the file's current pos and current cluster\r
+ //\r
+ FatSetFilePos (PrivateData, File, (UINT32) Amount);\r
+\r
+ BufferPtr += Amount;\r
+ Size -= Amount;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ This function reads the next item in the parent directory and\r
+ initializes the output parameter SubFile (CurrentPos is initialized to 0).\r
+ The function updates the CurrentPos of the parent dir to after the item read.\r
+ If no more items were found, the function returns EFI_NOT_FOUND.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param ParentDir The parent directory. \r
+ @param SubFile The File structure containing the sub file that \r
+ is caught. \r
+\r
+ @retval EFI_SUCCESS The next sub file is obtained. \r
+ @retval EFI_INVALID_PARAMETER The ParentDir is not a directory. \r
+ @retval EFI_NOT_FOUND No more sub file exists. \r
+ @retval EFI_DEVICE_ERROR Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadNextDirectoryEntry (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN PEI_FAT_FILE *ParentDir,\r
+ OUT PEI_FAT_FILE *SubFile\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ FAT_DIRECTORY_ENTRY DirEntry;\r
+ CHAR16 *Pos;\r
+ CHAR16 BaseName[9];\r
+ CHAR16 Ext[4];\r
+\r
+ ZeroMem ((UINT8 *) SubFile, sizeof (PEI_FAT_FILE));\r
+\r
+ //\r
+ // Pick a valid directory entry\r
+ //\r
+ while (1) {\r
+ //\r
+ // Read one entry\r
+ //\r
+ Status = FatReadFile (PrivateData, ParentDir, 32, &DirEntry);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // We only search for *FILE* in root directory\r
+ // Long file name entry is *NOT* supported\r
+ //\r
+ if ((DirEntry.Attributes == FAT_ATTR_DIRECTORY) || (DirEntry.Attributes == FAT_ATTR_LFN)) {\r
+ continue;\r
+ }\r
+ //\r
+ // if this is a terminator dir entry, just return EFI_NOT_FOUND\r
+ //\r
+ if (DirEntry.FileName[0] == EMPTY_ENTRY_MARK) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // If this not an invalid entry neither an empty entry, this is what we want.\r
+ // otherwise we will start a new loop to continue to find something meaningful\r
+ //\r
+ if ((UINT8) DirEntry.FileName[0] != DELETE_ENTRY_MARK) {\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // fill in the output parameter\r
+ //\r
+ EngFatToStr (8, DirEntry.FileName, BaseName);\r
+ EngFatToStr (3, DirEntry.FileName + 8, Ext);\r
+\r
+ Pos = (UINT16 *) SubFile->FileName;\r
+ SetMem ((UINT8 *) Pos, FAT_MAX_FILE_NAME_LENGTH, 0);\r
+ CopyMem ((UINT8 *) Pos, (UINT8 *) BaseName, 2 * (StrLen (BaseName) + 1));\r
+\r
+ if (Ext[0] != 0) {\r
+ Pos += StrLen (BaseName);\r
+ *Pos = '.';\r
+ Pos++;\r
+ CopyMem ((UINT8 *) Pos, (UINT8 *) Ext, 2 * (StrLen (Ext) + 1));\r
+ }\r
+\r
+ SubFile->Attributes = DirEntry.Attributes;\r
+ SubFile->CurrentCluster = DirEntry.FileCluster;\r
+ if (ParentDir->Volume->FatType == Fat32) {\r
+ SubFile->CurrentCluster |= DirEntry.FileClusterHigh << 16;\r
+ }\r
+\r
+ SubFile->CurrentPos = 0;\r
+ SubFile->FileSize = DirEntry.FileSize;\r
+ SubFile->StartingCluster = SubFile->CurrentCluster;\r
+ SubFile->Volume = ParentDir->Volume;\r
+\r
+ if (SubFile->StartingCluster != 0) {\r
+ Status = FatSetFilePos (PrivateData, SubFile, 0);\r
+ }\r
+ //\r
+ // in Pei phase, time parameters do not need to be filled for minimum use.\r
+ //\r
+ return Status;\r
+}\r
--- /dev/null
+/** @file\r
+ FAT recovery PEIM entry point, Ppi Functions and FAT Api functions.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FatLitePeim.h"\r
+\r
+PEI_FAT_PRIVATE_DATA *mPrivateData = NULL;\r
+\r
+/**\r
+ BlockIo installation nofication function. Find out all the current BlockIO\r
+ PPIs in the system and add them into private data. Assume there is\r
+\r
+ @param PeiServices General purpose services available to every \r
+ PEIM. \r
+ @param NotifyDescriptor The typedef structure of the notification \r
+ descriptor. Not used in this function. \r
+ @param Ppi The typedef structure of the PPI descriptor. \r
+ Not used in this function. \r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BlockIoNotifyEntry (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
+ IN VOID *Ppi\r
+ );\r
+\r
+\r
+/**\r
+ Discover all the block I/O devices to find the FAT volume.\r
+\r
+ @param PrivateData Global memory map for accessing global \r
+ variables. \r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateBlocksAndVolumes (\r
+ IN OUT PEI_FAT_PRIVATE_DATA *PrivateData\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor;\r
+ UINTN BlockIoPpiInstance;\r
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;\r
+ UINTN NumberBlockDevices;\r
+ UINTN Index;\r
+ EFI_PEI_BLOCK_IO_MEDIA Media;\r
+ PEI_FAT_VOLUME Volume;\r
+ EFI_PEI_SERVICES **PeiServices;\r
+\r
+ PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer ();\r
+\r
+ //\r
+ // Clean up caches\r
+ //\r
+ for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {\r
+ PrivateData->CacheBuffer[Index].Valid = FALSE;\r
+ }\r
+\r
+ PrivateData->BlockDeviceCount = 0;\r
+\r
+ //\r
+ // Find out all Block Io Ppi instances within the system\r
+ // Assuming all device Block Io Peims are dispatched already\r
+ //\r
+ for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_FAT_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {\r
+ Status = PeiServicesLocatePpi (\r
+ &gEfiPeiVirtualBlockIoPpiGuid,\r
+ BlockIoPpiInstance,\r
+ &TempPpiDescriptor,\r
+ (VOID **) &BlockIoPpi\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Done with all Block Io Ppis\r
+ //\r
+ break;\r
+ }\r
+\r
+ Status = BlockIoPpi->GetNumberOfBlockDevices (\r
+ PeiServices,\r
+ BlockIoPpi,\r
+ &NumberBlockDevices\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ for (Index = 1; Index <= NumberBlockDevices && PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE; Index++) {\r
+\r
+ Status = BlockIoPpi->GetBlockDeviceMediaInfo (\r
+ PeiServices,\r
+ BlockIoPpi,\r
+ Index,\r
+ &Media\r
+ );\r
+ if (EFI_ERROR (Status) || !Media.MediaPresent) {\r
+ continue;\r
+ }\r
+\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize = (UINT32) Media.BlockSize;\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock = Media.LastBlock;\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].IoAlign = 0;\r
+ //\r
+ // Not used here\r
+ //\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].Logical = FALSE;\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PartitionChecked = FALSE;\r
+\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo = BlockIoPpi;\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PhysicalDevNo = (UINT8) Index;\r
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].DevType = Media.DeviceType;\r
+\r
+ PrivateData->BlockDeviceCount++;\r
+ }\r
+ }\r
+ //\r
+ // Find out all logical devices\r
+ //\r
+ FatFindPartitions (PrivateData);\r
+\r
+ //\r
+ // Build up file system volume array\r
+ //\r
+ PrivateData->VolumeCount = 0;\r
+ for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) {\r
+ Volume.BlockDeviceNo = Index;\r
+ Status = FatGetBpbInfo (PrivateData, &Volume);\r
+ if (Status == EFI_SUCCESS) {\r
+ //\r
+ // Add the detected volume to the volume array\r
+ //\r
+ CopyMem (\r
+ (UINT8 *) &(PrivateData->Volume[PrivateData->VolumeCount]),\r
+ (UINT8 *) &Volume,\r
+ sizeof (PEI_FAT_VOLUME)\r
+ );\r
+ PrivateData->VolumeCount += 1;\r
+ if (PrivateData->VolumeCount >= PEI_FAT_MAX_VOLUME) {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ BlockIo installation notification function. Find out all the current BlockIO\r
+ PPIs in the system and add them into private data. Assume there is\r
+\r
+ @param PeiServices General purpose services available to every \r
+ PEIM. \r
+ @param NotifyDescriptor The typedef structure of the notification \r
+ descriptor. Not used in this function. \r
+ @param Ppi The typedef structure of the PPI descriptor. \r
+ Not used in this function. \r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BlockIoNotifyEntry (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
+ IN VOID *Ppi\r
+ )\r
+{\r
+ UpdateBlocksAndVolumes (mPrivateData);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Installs the Device Recovery Module PPI, Initialize BlockIo Ppi\r
+ installation notification\r
+\r
+ @param FileHandle Handle of the file being invoked. Type \r
+ EFI_PEI_FILE_HANDLE is defined in \r
+ FfsFindNextFile(). \r
+ @param PeiServices Describes the list of possible PEI Services. \r
+\r
+ @retval EFI_SUCCESS The entry point was executed successfully. \r
+ @retval EFI_OUT_OF_RESOURCES There is no enough memory to complete the \r
+ operations.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FatPeimEntry (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS Address;\r
+ PEI_FAT_PRIVATE_DATA *PrivateData;\r
+\r
+ Status = PeiServicesRegisterForShadow (FileHandle);\r
+ if (!EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = PeiServicesAllocatePages (\r
+ EfiBootServicesCode,\r
+ (sizeof (PEI_FAT_PRIVATE_DATA) - 1) / PEI_FAT_MEMMORY_PAGE_SIZE + 1,\r
+ &Address\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ PrivateData = (PEI_FAT_PRIVATE_DATA *) (UINTN) Address;\r
+\r
+ //\r
+ // Initialize Private Data (to zero, as is required by subsequent operations)\r
+ //\r
+ ZeroMem ((UINT8 *) PrivateData, sizeof (PEI_FAT_PRIVATE_DATA));\r
+\r
+ PrivateData->Signature = PEI_FAT_PRIVATE_DATA_SIGNATURE;\r
+\r
+ //\r
+ // Installs Ppi\r
+ //\r
+ PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules = GetNumberRecoveryCapsules;\r
+ PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo = GetRecoveryCapsuleInfo;\r
+ PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule = LoadRecoveryCapsule;\r
+\r
+ PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+ PrivateData->PpiDescriptor.Guid = &gEfiPeiDeviceRecoveryModulePpiGuid;\r
+ PrivateData->PpiDescriptor.Ppi = &PrivateData->DeviceRecoveryPpi;\r
+\r
+ Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Other initializations\r
+ //\r
+ PrivateData->BlockDeviceCount = 0;\r
+\r
+ UpdateBlocksAndVolumes (PrivateData);\r
+\r
+ //\r
+ // PrivateData is allocated now, set it to the module variable\r
+ //\r
+ mPrivateData = PrivateData;\r
+\r
+ //\r
+ // Installs Block Io Ppi notification function\r
+ //\r
+ PrivateData->NotifyDescriptor.Flags =\r
+ (\r
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |\r
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST\r
+ );\r
+ PrivateData->NotifyDescriptor.Guid = &gEfiPeiVirtualBlockIoPpiGuid;\r
+ PrivateData->NotifyDescriptor.Notify = BlockIoNotifyEntry;\r
+ return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor);\r
+}\r
+\r
+\r
+/**\r
+ Returns the number of DXE capsules residing on the device.\r
+\r
+ This function searches for DXE capsules from the associated device and returns\r
+ the number and maximum size in bytes of the capsules discovered. Entry 1 is \r
+ assumed to be the highest load priority and entry N is assumed to be the lowest \r
+ priority.\r
+\r
+ @param[in] PeiServices General-purpose services that are available \r
+ to every PEIM\r
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
+ instance.\r
+ @param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On \r
+ output, *NumberRecoveryCapsules contains \r
+ the number of recovery capsule images \r
+ available for retrieval from this PEIM \r
+ instance.\r
+\r
+ @retval EFI_SUCCESS One or more capsules were discovered.\r
+ @retval EFI_DEVICE_ERROR A device error occurred.\r
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetNumberRecoveryCapsules (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ OUT UINTN *NumberRecoveryCapsules\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_FAT_PRIVATE_DATA *PrivateData;\r
+ UINTN Index;\r
+ UINTN RecoveryCapsuleCount;\r
+ PEI_FILE_HANDLE Handle;\r
+\r
+ PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ //\r
+ // Search each volume in the root directory for the Recovery capsule\r
+ //\r
+ RecoveryCapsuleCount = 0;\r
+ for (Index = 0; Index < PrivateData->VolumeCount; Index++) {\r
+ Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ RecoveryCapsuleCount++;\r
+ }\r
+\r
+ *NumberRecoveryCapsules = RecoveryCapsuleCount;\r
+\r
+ if (*NumberRecoveryCapsules == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Returns the size and type of the requested recovery capsule.\r
+\r
+ This function gets the size and type of the capsule specified by CapsuleInstance.\r
+\r
+ @param[in] PeiServices General-purpose services that are available to every PEIM\r
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI \r
+ instance.\r
+ @param[in] CapsuleInstance Specifies for which capsule instance to retrieve \r
+ the information. This parameter must be between \r
+ one and the value returned by GetNumberRecoveryCapsules() \r
+ in NumberRecoveryCapsules.\r
+ @param[out] Size A pointer to a caller-allocated UINTN in which \r
+ the size of the requested recovery module is \r
+ returned.\r
+ @param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which \r
+ the type of the requested recovery capsule is \r
+ returned. The semantic meaning of the value \r
+ returned is defined by the implementation.\r
+\r
+ @retval EFI_SUCCESS One or more capsules were discovered.\r
+ @retval EFI_DEVICE_ERROR A device error occurred.\r
+ @retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetRecoveryCapsuleInfo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ IN UINTN CapsuleInstance,\r
+ OUT UINTN *Size,\r
+ OUT EFI_GUID *CapsuleType\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_FAT_PRIVATE_DATA *PrivateData;\r
+ UINTN Index;\r
+ UINTN BlockDeviceNo;\r
+ UINTN RecoveryCapsuleCount;\r
+ PEI_FILE_HANDLE Handle;\r
+ UINTN NumberRecoveryCapsules;\r
+\r
+ Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
+ CapsuleInstance = CapsuleInstance + 1;\r
+ }\r
+\r
+ if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ //\r
+ // Search each volume in the root directory for the Recovery capsule\r
+ //\r
+ RecoveryCapsuleCount = 0;\r
+ for (Index = 0; Index < PrivateData->VolumeCount; Index++) {\r
+ Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ if (CapsuleInstance - 1 == RecoveryCapsuleCount) {\r
+ //\r
+ // Get file size\r
+ //\r
+ *Size = (UINTN) (((PEI_FAT_FILE *) Handle)->FileSize);\r
+\r
+ //\r
+ // Find corresponding physical block device\r
+ //\r
+ BlockDeviceNo = PrivateData->Volume[Index].BlockDeviceNo;\r
+ while (PrivateData->BlockDevice[BlockDeviceNo].Logical && BlockDeviceNo < PrivateData->BlockDeviceCount) {\r
+ BlockDeviceNo = PrivateData->BlockDevice[BlockDeviceNo].ParentDevNo;\r
+ }\r
+ //\r
+ // Fill in the Capsule Type GUID according to the block device type\r
+ //\r
+ if (BlockDeviceNo < PrivateData->BlockDeviceCount) {\r
+ switch (PrivateData->BlockDevice[BlockDeviceNo].DevType) {\r
+ case LegacyFloppy:\r
+ CopyGuid (CapsuleType, &gRecoveryOnFatFloppyDiskGuid);\r
+ break;\r
+\r
+ case IdeCDROM:\r
+ case IdeLS120:\r
+ CopyGuid (CapsuleType, &gRecoveryOnFatIdeDiskGuid);\r
+ break;\r
+\r
+ case UsbMassStorage:\r
+ CopyGuid (CapsuleType, &gRecoveryOnFatUsbDiskGuid);\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ RecoveryCapsuleCount++;\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+ Loads a DXE capsule from some media into memory.\r
+\r
+ This function, by whatever mechanism, retrieves a DXE capsule from some device\r
+ and loads it into memory. Note that the published interface is device neutral.\r
+\r
+ @param[in] PeiServices General-purpose services that are available \r
+ to every PEIM\r
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
+ instance.\r
+ @param[in] CapsuleInstance Specifies which capsule instance to retrieve.\r
+ @param[out] Buffer Specifies a caller-allocated buffer in which \r
+ the requested recovery capsule will be returned.\r
+\r
+ @retval EFI_SUCCESS The capsule was loaded correctly.\r
+ @retval EFI_DEVICE_ERROR A device error occurred.\r
+ @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LoadRecoveryCapsule (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ IN UINTN CapsuleInstance,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_FAT_PRIVATE_DATA *PrivateData;\r
+ UINTN Index;\r
+ UINTN RecoveryCapsuleCount;\r
+ PEI_FILE_HANDLE Handle;\r
+ UINTN NumberRecoveryCapsules;\r
+\r
+ Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
+ CapsuleInstance = CapsuleInstance + 1;\r
+ }\r
+\r
+ if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+ //\r
+ // Search each volume in the root directory for the Recovery capsule\r
+ //\r
+ RecoveryCapsuleCount = 0;\r
+ for (Index = 0; Index < PrivateData->VolumeCount; Index++) {\r
+ Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ if (CapsuleInstance - 1 == RecoveryCapsuleCount) {\r
+\r
+ Status = FatReadFile (\r
+ PrivateData,\r
+ Handle,\r
+ (UINTN) (((PEI_FAT_FILE *) Handle)->FileSize),\r
+ Buffer\r
+ );\r
+ return Status;\r
+ }\r
+\r
+ RecoveryCapsuleCount++;\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+ Finds the recovery file on a FAT volume.\r
+ This function finds the the recovery file named FileName on a specified FAT volume and returns\r
+ its FileHandle pointer.\r
+\r
+ @param PrivateData Global memory map for accessing global \r
+ variables. \r
+ @param VolumeIndex The index of the volume. \r
+ @param FileName The recovery file name to find. \r
+ @param Handle The output file handle. \r
+\r
+ @retval EFI_DEVICE_ERROR Some error occured when operating the FAT \r
+ volume. \r
+ @retval EFI_NOT_FOUND The recovery file was not found. \r
+ @retval EFI_SUCCESS The recovery file was successfully found on the \r
+ FAT volume.\r
+\r
+**/\r
+EFI_STATUS\r
+FindRecoveryFile (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN VolumeIndex,\r
+ IN CHAR16 *FileName,\r
+ OUT PEI_FILE_HANDLE *Handle\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_FAT_FILE Parent;\r
+ PEI_FAT_FILE *File;\r
+\r
+ File = &PrivateData->File;\r
+\r
+ //\r
+ // VolumeIndex must be less than PEI_FAT_MAX_VOLUME because PrivateData->VolumeCount\r
+ // cannot be larger than PEI_FAT_MAX_VOLUME when detecting recovery volume.\r
+ //\r
+ ASSERT (VolumeIndex < PEI_FAT_MAX_VOLUME);\r
+\r
+ //\r
+ // Construct root directory file\r
+ //\r
+ Parent.IsFixedRootDir = (BOOLEAN) ((PrivateData->Volume[VolumeIndex].FatType == Fat32) ? FALSE : TRUE);\r
+ Parent.Attributes = FAT_ATTR_DIRECTORY;\r
+ Parent.CurrentPos = 0;\r
+ Parent.CurrentCluster = Parent.IsFixedRootDir ? 0 : PrivateData->Volume[VolumeIndex].RootDirCluster;\r
+ Parent.StartingCluster = Parent.CurrentCluster;\r
+ Parent.Volume = &PrivateData->Volume[VolumeIndex];\r
+\r
+ Status = FatSetFilePos (PrivateData, &Parent, 0);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ //\r
+ // Search for recovery capsule in root directory\r
+ //\r
+ Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);\r
+ while (Status == EFI_SUCCESS) {\r
+ if (EngStriColl (PrivateData, FileName, File->FileName)) {\r
+ break;\r
+ }\r
+\r
+ Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ *Handle = File;\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
--- /dev/null
+/** @file\r
+ Definitions for FAT recovery PEIM API functions\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _FAT_API_H_\r
+#define _FAT_API_H_\r
+\r
+//\r
+// API data structures\r
+//\r
+typedef VOID *PEI_FILE_HANDLE;\r
+\r
+typedef enum {\r
+ Fat12,\r
+ Fat16,\r
+ Fat32,\r
+ FatUnknown\r
+} PEI_FAT_TYPE;\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ FAT format data structures\r
+\r
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _FAT_FMT_H_\r
+#define _FAT_FMT_H_\r
+\r
+//\r
+// Definitions\r
+//\r
+#define FAT_ATTR_READ_ONLY 0x01\r
+#define FAT_ATTR_HIDDEN 0x02\r
+#define FAT_ATTR_SYSTEM 0x04\r
+#define FAT_ATTR_VOLUME_ID 0x08\r
+#define FAT_ATTR_DIRECTORY 0x10\r
+#define FAT_ATTR_ARCHIVE 0x20\r
+#define FAT_ATTR_LFN (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)\r
+\r
+#define FAT_CLUSTER_SPECIAL ((-1 &~0xF) | 0x7)\r
+#define FAT_CLUSTER_FREE 0\r
+#define FAT_CLUSTER_RESERVED (FAT_CLUSTER_SPECIAL)\r
+#define FAT_CLUSTER_BAD (FAT_CLUSTER_SPECIAL)\r
+#define FAT_CLUSTER_LAST (-1)\r
+\r
+#define DELETE_ENTRY_MARK 0xE5\r
+#define EMPTY_ENTRY_MARK 0x00\r
+\r
+#define FAT_CLUSTER_FUNCTIONAL(Cluster) (((Cluster) == 0) || ((Cluster) >= FAT_CLUSTER_SPECIAL))\r
+#define FAT_CLUSTER_END_OF_CHAIN(Cluster) ((Cluster) > (FAT_CLUSTER_SPECIAL))\r
+\r
+//\r
+// Directory Entry\r
+//\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+ UINT16 Day : 5;\r
+ UINT16 Month : 4;\r
+ UINT16 Year : 7; // From 1980\r
+} FAT_DATE;\r
+\r
+typedef struct {\r
+ UINT16 DoubleSecond : 5;\r
+ UINT16 Minute : 6;\r
+ UINT16 Hour : 5;\r
+} FAT_TIME;\r
+\r
+typedef struct {\r
+ FAT_TIME Time;\r
+ FAT_DATE Date;\r
+} FAT_DATE_TIME;\r
+\r
+typedef struct {\r
+ CHAR8 FileName[11]; // 8.3 filename\r
+ UINT8 Attributes;\r
+ UINT8 CaseFlag;\r
+ UINT8 CreateMillisecond; // (creation milliseconds - ignored)\r
+ FAT_DATE_TIME FileCreateTime;\r
+ FAT_DATE FileLastAccess;\r
+ UINT16 FileClusterHigh; // >= FAT32\r
+ FAT_DATE_TIME FileModificationTime;\r
+ UINT16 FileCluster;\r
+ UINT32 FileSize;\r
+} FAT_DIRECTORY_ENTRY;\r
+\r
+#pragma pack()\r
+//\r
+// Boot Sector\r
+//\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+\r
+ UINT8 Ia32Jump[3];\r
+ CHAR8 OemId[8];\r
+\r
+ UINT16 SectorSize;\r
+ UINT8 SectorsPerCluster;\r
+ UINT16 ReservedSectors;\r
+ UINT8 NoFats;\r
+ UINT16 RootEntries; // < FAT32, root dir is fixed size\r
+ UINT16 Sectors;\r
+ UINT8 Media; // (ignored)\r
+ UINT16 SectorsPerFat; // < FAT32\r
+ UINT16 SectorsPerTrack; // (ignored)\r
+ UINT16 Heads; // (ignored)\r
+ UINT32 HiddenSectors; // (ignored)\r
+ UINT32 LargeSectors; // => FAT32\r
+ UINT8 PhysicalDriveNumber; // (ignored)\r
+ UINT8 CurrentHead; // holds boot_sector_dirty bit\r
+ UINT8 Signature; // (ignored)\r
+ CHAR8 Id[4];\r
+ CHAR8 FatLabel[11];\r
+ CHAR8 SystemId[8];\r
+\r
+} PEI_FAT_BOOT_SECTOR;\r
+\r
+typedef struct {\r
+\r
+ UINT8 Ia32Jump[3];\r
+ CHAR8 OemId[8];\r
+\r
+ UINT16 SectorSize;\r
+ UINT8 SectorsPerCluster;\r
+ UINT16 ReservedSectors;\r
+ UINT8 NoFats;\r
+ UINT16 RootEntries; // < FAT32, root dir is fixed size\r
+ UINT16 Sectors;\r
+ UINT8 Media; // (ignored)\r
+ UINT16 SectorsPerFat; // < FAT32\r
+ UINT16 SectorsPerTrack; // (ignored)\r
+ UINT16 Heads; // (ignored)\r
+ UINT32 HiddenSectors; // (ignored)\r
+ UINT32 LargeSectors; // Used if Sectors==0\r
+ UINT32 LargeSectorsPerFat; // FAT32\r
+ UINT16 ExtendedFlags; // FAT32 (ignored)\r
+ UINT16 FsVersion; // FAT32 (ignored)\r
+ UINT32 RootDirFirstCluster; // FAT32\r
+ UINT16 FsInfoSector; // FAT32\r
+ UINT16 BackupBootSector; // FAT32\r
+ UINT8 Reserved[12]; // FAT32 (ignored)\r
+ UINT8 PhysicalDriveNumber; // (ignored)\r
+ UINT8 CurrentHead; // holds boot_sector_dirty bit\r
+ UINT8 Signature; // (ignored)\r
+ CHAR8 Id[4];\r
+ CHAR8 FatLabel[11];\r
+ CHAR8 SystemId[8];\r
+\r
+} PEI_FAT_BOOT_SECTOR_EX;\r
+\r
+#pragma pack()\r
+\r
+#endif\r
--- /dev/null
+/** @file\r
+ General purpose supporting routines for FAT recovery PEIM\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FatLitePeim.h"\r
+\r
+\r
+#define CHAR_FAT_VALID 0x01\r
+\r
+\r
+/**\r
+ Converts a union code character to upper case.\r
+ This functions converts a unicode character to upper case.\r
+ If the input Letter is not a lower-cased letter,\r
+ the original value is returned.\r
+\r
+ @param Letter The input unicode character. \r
+\r
+ @return The upper cased letter.\r
+\r
+**/\r
+CHAR16\r
+ToUpper (\r
+ IN CHAR16 Letter\r
+ )\r
+{\r
+ if ('a' <= Letter && Letter <= 'z') {\r
+ Letter = (CHAR16) (Letter - 0x20);\r
+ }\r
+\r
+ return Letter;\r
+}\r
+\r
+\r
+/**\r
+ Reads a block of data from the block device by calling\r
+ underlying Block I/O service.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param BlockDeviceNo The index for the block device number. \r
+ @param Lba The logic block address to read data from. \r
+ @param BufferSize The size of data in byte to read. \r
+ @param Buffer The buffer of the \r
+\r
+ @retval EFI_DEVICE_ERROR The specified block device number exceeds the maximum \r
+ device number. \r
+ @retval EFI_DEVICE_ERROR The maximum address has exceeded the maximum address \r
+ of the block device.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadBlock (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN BlockDeviceNo,\r
+ IN EFI_PEI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_FAT_BLOCK_DEVICE *BlockDev;\r
+\r
+ if (BlockDeviceNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Status = EFI_SUCCESS;\r
+ BlockDev = &(PrivateData->BlockDevice[BlockDeviceNo]);\r
+\r
+ if (BufferSize > MultU64x32 (BlockDev->LastBlock - Lba + 1, BlockDev->BlockSize)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ if (!BlockDev->Logical) {\r
+ //\r
+ // Status = BlockDev->ReadFunc\r
+ // (PrivateData->PeiServices, BlockDev->PhysicalDevNo, Lba, BufferSize, Buffer);\r
+ //\r
+ Status = BlockDev->BlockIo->ReadBlocks (\r
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),\r
+ BlockDev->BlockIo,\r
+ BlockDev->PhysicalDevNo,\r
+ Lba,\r
+ BufferSize,\r
+ Buffer\r
+ );\r
+\r
+ } else {\r
+ Status = FatReadDisk (\r
+ PrivateData,\r
+ BlockDev->ParentDevNo,\r
+ BlockDev->StartingPos + MultU64x32 (Lba, BlockDev->BlockSize),\r
+ BufferSize,\r
+ Buffer\r
+ );\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Find a cache block designated to specific Block device and Lba.\r
+ If not found, invalidate an oldest one and use it. (LRU cache)\r
+\r
+ @param PrivateData the global memory map. \r
+ @param BlockDeviceNo the Block device. \r
+ @param Lba the Logical Block Address \r
+ @param CachePtr Ptr to the starting address of the memory holding the \r
+ data; \r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_DEVICE_ERROR Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatGetCacheBlock (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN BlockDeviceNo,\r
+ IN UINT64 Lba,\r
+ OUT CHAR8 **CachePtr\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PEI_FAT_CACHE_BUFFER *CacheBuffer;\r
+ INTN Index;\r
+ STATIC UINT8 Seed;\r
+\r
+ Status = EFI_SUCCESS;\r
+ CacheBuffer = NULL;\r
+\r
+ //\r
+ // go through existing cache buffers\r
+ //\r
+ for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {\r
+ CacheBuffer = &(PrivateData->CacheBuffer[Index]);\r
+ if (CacheBuffer->Valid && CacheBuffer->BlockDeviceNo == BlockDeviceNo && CacheBuffer->Lba == Lba) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Index < PEI_FAT_CACHE_SIZE) {\r
+ *CachePtr = (CHAR8 *) CacheBuffer->Buffer;\r
+ return EFI_SUCCESS;\r
+ }\r
+ //\r
+ // We have to find an invalid cache buffer\r
+ //\r
+ for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {\r
+ if (!PrivateData->CacheBuffer[Index].Valid) {\r
+ break;\r
+ }\r
+ }\r
+ //\r
+ // Use the cache buffer\r
+ //\r
+ if (Index == PEI_FAT_CACHE_SIZE) {\r
+ Index = (Seed++) % PEI_FAT_CACHE_SIZE;\r
+ }\r
+ \r
+ //\r
+ // Current device ID should be less than maximum device ID. \r
+ //\r
+ if (BlockDeviceNo >= PEI_FAT_MAX_BLOCK_DEVICE) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ CacheBuffer = &(PrivateData->CacheBuffer[Index]);\r
+\r
+ CacheBuffer->BlockDeviceNo = BlockDeviceNo;\r
+ CacheBuffer->Lba = Lba;\r
+ CacheBuffer->Size = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;\r
+\r
+ //\r
+ // Read in the data\r
+ //\r
+ Status = FatReadBlock (\r
+ PrivateData,\r
+ BlockDeviceNo,\r
+ Lba,\r
+ CacheBuffer->Size,\r
+ CacheBuffer->Buffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ CacheBuffer->Valid = TRUE;\r
+ *CachePtr = (CHAR8 *) CacheBuffer->Buffer;\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Disk reading.\r
+\r
+ @param PrivateData the global memory map; \r
+ @param BlockDeviceNo the block device to read; \r
+ @param StartingAddress the starting address. \r
+ @param Size the amount of data to read. \r
+ @param Buffer the buffer holding the data \r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_DEVICE_ERROR Something error.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadDisk (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN BlockDeviceNo,\r
+ IN UINT64 StartingAddress,\r
+ IN UINTN Size,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 BlockSize;\r
+ CHAR8 *BufferPtr;\r
+ CHAR8 *CachePtr;\r
+ UINT32 Offset;\r
+ UINT64 Lba;\r
+ UINT64 OverRunLba;\r
+ UINTN Amount;\r
+\r
+ Status = EFI_SUCCESS;\r
+ BufferPtr = Buffer;\r
+ BlockSize = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;\r
+\r
+ //\r
+ // Read underrun\r
+ //\r
+ Lba = DivU64x32Remainder (StartingAddress, BlockSize, &Offset);\r
+ Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, Lba, &CachePtr);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ Amount = Size < (BlockSize - Offset) ? Size : (BlockSize - Offset);\r
+ CopyMem (BufferPtr, CachePtr + Offset, Amount);\r
+\r
+ if (Size == Amount) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Size -= Amount;\r
+ BufferPtr += Amount;\r
+ StartingAddress += Amount;\r
+ Lba += 1;\r
+\r
+ //\r
+ // Read aligned parts\r
+ //\r
+ OverRunLba = Lba + DivU64x32Remainder (Size, BlockSize, &Offset);\r
+\r
+ Size -= Offset;\r
+ Status = FatReadBlock (PrivateData, BlockDeviceNo, Lba, Size, BufferPtr);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ BufferPtr += Size;\r
+\r
+ //\r
+ // Read overrun\r
+ //\r
+ if (Offset != 0) {\r
+ Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, OverRunLba, &CachePtr);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+\r
+ CopyMem (BufferPtr, CachePtr, Offset);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ This version is different from the version in Unicode collation\r
+ protocol in that this version strips off trailing blanks.\r
+ Converts an 8.3 FAT file name using an OEM character set\r
+ to a Null-terminated Unicode string.\r
+ Here does not expand DBCS FAT chars.\r
+\r
+ @param FatSize The size of the string Fat in bytes. \r
+ @param Fat A pointer to a Null-terminated string that contains \r
+ an 8.3 file name using an OEM character set. \r
+ @param Str A pointer to a Null-terminated Unicode string. The \r
+ string must be allocated in advance to hold FatSize \r
+ Unicode characters\r
+\r
+**/\r
+VOID\r
+EngFatToStr (\r
+ IN UINTN FatSize,\r
+ IN CHAR8 *Fat,\r
+ OUT CHAR16 *Str\r
+ )\r
+{\r
+ CHAR16 *String;\r
+\r
+ String = Str;\r
+ //\r
+ // No DBCS issues, just expand and add null terminate to end of string\r
+ //\r
+ while (*Fat != 0 && FatSize != 0) {\r
+ *String = *Fat;\r
+ String += 1;\r
+ Fat += 1;\r
+ FatSize -= 1;\r
+ if (*Fat == ' ') {\r
+ *String = 0;\r
+ return ;\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Performs a case-insensitive comparison of two Null-terminated Unicode strings.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param Str1 First string to perform case insensitive comparison. \r
+ @param Str2 Second string to perform case insensitive comparison.\r
+\r
+**/\r
+BOOLEAN\r
+EngStriColl (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN CHAR16 *Str1,\r
+ IN CHAR16 *Str2\r
+ )\r
+{\r
+ CHAR16 UpperS1;\r
+ CHAR16 UpperS2;\r
+\r
+ UpperS1 = ToUpper (*Str1);\r
+ UpperS2 = ToUpper (*Str2);\r
+ while (*Str1 != 0) {\r
+ if (UpperS1 != UpperS2) {\r
+ return FALSE;\r
+ }\r
+\r
+ Str1++;\r
+ Str2++;\r
+ UpperS1 = ToUpper (*Str1);\r
+ UpperS2 = ToUpper (*Str2);\r
+ }\r
+\r
+ return (BOOLEAN) ((*Str2 != 0) ? FALSE : TRUE);\r
+}\r
--- /dev/null
+/** @file\r
+ Data structures for FAT recovery PEIM\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _FAT_PEIM_H_\r
+#define _FAT_PEIM_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Guid/RecoveryDevice.h>\r
+#include <Ppi/BlockIo.h>\r
+#include <Ppi/DeviceRecoveryModule.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/PeiServicesTablePointerLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+#include "FatLiteApi.h"\r
+#include "FatLiteFmt.h"\r
+\r
+//\r
+// Definitions\r
+//\r
+#define PEI_FAT_RECOVERY_CAPSULE_WITH_NT_EMULATOR L"fv0001.fv"\r
+#define PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR L"fvmain.fv"\r
+\r
+#define PEI_FAT_CACHE_SIZE 4\r
+#define PEI_FAT_MAX_BLOCK_SIZE 8192\r
+#define FAT_MAX_FILE_NAME_LENGTH 128\r
+#define PEI_FAT_MAX_BLOCK_DEVICE 64\r
+#define PEI_FAT_MAX_BLOCK_IO_PPI 32\r
+#define PEI_FAT_MAX_VOLUME 64\r
+\r
+#define PEI_FAT_MEMMORY_PAGE_SIZE 0x1000\r
+\r
+//\r
+// Data Structures\r
+//\r
+//\r
+// The block device\r
+//\r
+typedef struct {\r
+\r
+ UINT32 BlockSize;\r
+ UINT64 LastBlock;\r
+ UINT32 IoAlign;\r
+ BOOLEAN Logical;\r
+ BOOLEAN PartitionChecked;\r
+\r
+ //\r
+ // Following fields only valid for logical device\r
+ //\r
+ CHAR8 PartitionFlag[8];\r
+ UINT64 StartingPos;\r
+ UINTN ParentDevNo;\r
+\r
+ //\r
+ // Following fields only valid for physical device\r
+ //\r
+ EFI_PEI_BLOCK_DEVICE_TYPE DevType;\r
+ //\r
+ // EFI_PEI_READ_BLOCKS ReadFunc;\r
+ //\r
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIo;\r
+ UINT8 PhysicalDevNo;\r
+} PEI_FAT_BLOCK_DEVICE;\r
+\r
+//\r
+// the Volume structure\r
+//\r
+typedef struct {\r
+\r
+ UINTN BlockDeviceNo;\r
+ UINTN VolumeNo;\r
+ UINT64 VolumeSize;\r
+ UINTN MaxCluster;\r
+ CHAR16 VolumeLabel[FAT_MAX_FILE_NAME_LENGTH];\r
+ PEI_FAT_TYPE FatType;\r
+ UINT64 FatPos;\r
+ UINT32 SectorSize;\r
+ UINT32 ClusterSize;\r
+ UINT64 FirstClusterPos;\r
+ UINT64 RootDirPos;\r
+ UINT32 RootEntries;\r
+ UINT32 RootDirCluster;\r
+\r
+} PEI_FAT_VOLUME;\r
+\r
+//\r
+// File instance\r
+//\r
+typedef struct {\r
+\r
+ PEI_FAT_VOLUME *Volume;\r
+ CHAR16 FileName[FAT_MAX_FILE_NAME_LENGTH];\r
+\r
+ BOOLEAN IsFixedRootDir;\r
+\r
+ UINT32 StartingCluster;\r
+ UINT32 CurrentPos;\r
+ UINT32 StraightReadAmount;\r
+ UINT32 CurrentCluster;\r
+\r
+ UINT8 Attributes;\r
+ UINT32 FileSize;\r
+\r
+} PEI_FAT_FILE;\r
+\r
+//\r
+// Cache Buffer\r
+//\r
+typedef struct {\r
+\r
+ BOOLEAN Valid;\r
+ UINTN BlockDeviceNo;\r
+ UINT64 Lba;\r
+ UINT32 Lru;\r
+ UINT64 Buffer[PEI_FAT_MAX_BLOCK_SIZE / 8];\r
+ UINTN Size;\r
+\r
+} PEI_FAT_CACHE_BUFFER;\r
+\r
+//\r
+// Private Data.\r
+// This structure abstracts the whole memory usage in FAT PEIM.\r
+// The entry point routine will get a chunk of memory (by whatever\r
+// means) whose size is sizeof(PEI_FAT_PRIVATE_DATA), which is clean\r
+// in both 32 and 64 bit environment. The boundary of the memory chunk\r
+// should be 64bit aligned.\r
+//\r
+#define PEI_FAT_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('p', 'f', 'a', 't')\r
+\r
+typedef struct {\r
+\r
+ UINTN Signature;\r
+ EFI_PEI_DEVICE_RECOVERY_MODULE_PPI DeviceRecoveryPpi;\r
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;\r
+ EFI_PEI_NOTIFY_DESCRIPTOR NotifyDescriptor;\r
+\r
+ UINT8 UnicodeCaseMap[0x300];\r
+ CHAR8 *EngUpperMap;\r
+ CHAR8 *EngLowerMap;\r
+ CHAR8 *EngInfoMap;\r
+\r
+ UINT64 BlockData[PEI_FAT_MAX_BLOCK_SIZE / 8];\r
+ UINTN BlockDeviceCount;\r
+ PEI_FAT_BLOCK_DEVICE BlockDevice[PEI_FAT_MAX_BLOCK_DEVICE];\r
+ UINTN VolumeCount;\r
+ PEI_FAT_VOLUME Volume[PEI_FAT_MAX_VOLUME];\r
+ PEI_FAT_FILE File;\r
+ PEI_FAT_CACHE_BUFFER CacheBuffer[PEI_FAT_CACHE_SIZE];\r
+\r
+} PEI_FAT_PRIVATE_DATA;\r
+\r
+#define PEI_FAT_PRIVATE_DATA_FROM_THIS(a) \\r
+ CR (a, PEI_FAT_PRIVATE_DATA, DeviceRecoveryPpi, PEI_FAT_PRIVATE_DATA_SIGNATURE)\r
+\r
+//\r
+// Extract INT32 from char array\r
+//\r
+#define UNPACK_INT32(a) \\r
+ (INT32) ((((UINT8 *) a)[0] << 0) | (((UINT8 *) a)[1] << 8) | (((UINT8 *) a)[2] << 16) | (((UINT8 *) a)[3] << 24))\r
+\r
+//\r
+// Extract UINT32 from char array\r
+//\r
+#define UNPACK_UINT32(a) \\r
+ (UINT32) ((((UINT8 *) a)[0] << 0) | (((UINT8 *) a)[1] << 8) | (((UINT8 *) a)[2] << 16) | (((UINT8 *) a)[3] << 24))\r
+\r
+\r
+//\r
+// API functions\r
+//\r
+\r
+/**\r
+ Finds the recovery file on a FAT volume.\r
+ This function finds the the recovery file named FileName on a specified FAT volume and returns\r
+ its FileHandle pointer.\r
+\r
+ @param PrivateData Global memory map for accessing global \r
+ variables. \r
+ @param VolumeIndex The index of the volume. \r
+ @param FileName The recovery file name to find. \r
+ @param Handle The output file handle. \r
+\r
+ @retval EFI_DEVICE_ERROR Some error occured when operating the FAT \r
+ volume. \r
+ @retval EFI_NOT_FOUND The recovery file was not found. \r
+ @retval EFI_SUCCESS The recovery file was successfully found on the \r
+ FAT volume.\r
+\r
+**/\r
+EFI_STATUS\r
+FindRecoveryFile (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN VolumeIndex,\r
+ IN CHAR16 *FileName,\r
+ OUT PEI_FILE_HANDLE *Handle\r
+ );\r
+\r
+\r
+/**\r
+ Returns the number of DXE capsules residing on the device.\r
+ This function, by whatever mechanism, searches for DXE capsules from the associated device and\r
+ returns the number and maximum size in bytes of the capsules discovered.Entry 1 is assumed to be\r
+ the highest load priority and entry N is assumed to be the lowest priority.\r
+\r
+ @param PeiServices General-purpose services that are available to \r
+ every PEIM. \r
+ @param This Indicates the \r
+ EFI_PEI_DEVICE_RECOVERY_MODULE_PPI instance. \r
+ @param NumberRecoveryCapsules Pointer to a caller-allocated UINTN.On output, \r
+ *NumberRecoveryCapsules contains the number of \r
+ recovery capsule images available for retrieval \r
+ from this PEIM instance. \r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetNumberRecoveryCapsules (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ OUT UINTN *NumberRecoveryCapsules\r
+ );\r
+\r
+\r
+/**\r
+ Returns the size and type of the requested recovery capsule.\r
+ This function returns the size and type of the capsule specified by CapsuleInstance.\r
+\r
+ @param PeiServices General-purpose services that are available to \r
+ every PEIM. \r
+ @param This Indicates the \r
+ EFI_PEI_DEVICE_RECOVERY_MODULE_PPI instance. \r
+ @param CapsuleInstance Specifies for which capsule instance to \r
+ retrieve the information.T his parameter must \r
+ be between one and the value returned by \r
+ GetNumberRecoveryCapsules() in \r
+ NumberRecoveryCapsules. \r
+ @param Size A pointer to a caller-allocated UINTN in which \r
+ the size of the requested recovery module is \r
+ returned. \r
+ @param CapsuleType A pointer to a caller-allocated EFI_GUID in \r
+ which the type of the requested recovery \r
+ capsule is returned.T he semantic meaning of \r
+ the value returned is defined by the \r
+ implementation. \r
+\r
+ @retval EFI_SUCCESS The capsule type and size were retrieved. \r
+ @retval EFI_INVALID_PARAMETER The input CapsuleInstance does not match any \r
+ discovered recovery capsule.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetRecoveryCapsuleInfo (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ IN UINTN CapsuleInstance,\r
+ OUT UINTN *Size,\r
+ OUT EFI_GUID *CapsuleType\r
+ );\r
+\r
+\r
+/**\r
+ Loads a DXE capsule from some media into memory.\r
+\r
+ This function, by whatever mechanism, retrieves a DXE capsule from some device\r
+ and loads it into memory. Note that the published interface is device neutral.\r
+\r
+ @param[in] PeiServices General-purpose services that are available \r
+ to every PEIM\r
+ @param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
+ instance.\r
+ @param[in] CapsuleInstance Specifies which capsule instance to retrieve.\r
+ @param[out] Buffer Specifies a caller-allocated buffer in which \r
+ the requested recovery capsule will be returned.\r
+\r
+ @retval EFI_SUCCESS The capsule was loaded correctly.\r
+ @retval EFI_DEVICE_ERROR A device error occurred.\r
+ @retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LoadRecoveryCapsule (\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,\r
+ IN UINTN CapsuleInstance,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+\r
+/**\r
+ This version is different from the version in Unicode collation\r
+ protocol in that this version strips off trailing blanks.\r
+ Converts an 8.3 FAT file name using an OEM character set\r
+ to a Null-terminated Unicode string.\r
+ Here does not expand DBCS FAT chars.\r
+\r
+ @param FatSize The size of the string Fat in bytes. \r
+ @param Fat A pointer to a Null-terminated string that contains \r
+ an 8.3 file name using an OEM character set. \r
+ @param Str A pointer to a Null-terminated Unicode string. The \r
+ string must be allocated in advance to hold FatSize \r
+ Unicode characters\r
+\r
+**/\r
+VOID\r
+EngFatToStr (\r
+ IN UINTN FatSize,\r
+ IN CHAR8 *Fat,\r
+ OUT CHAR16 *Str\r
+ );\r
+\r
+\r
+/**\r
+ Performs a case-insensitive comparison of two Null-terminated Unicode strings.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param Str1 First string to perform case insensitive comparison. \r
+ @param Str2 Second string to perform case insensitive comparison.\r
+\r
+**/\r
+BOOLEAN\r
+EngStriColl (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN CHAR16 *Str1,\r
+ IN CHAR16 *Str2\r
+ );\r
+\r
+\r
+/**\r
+ Reads a block of data from the block device by calling\r
+ underlying Block I/O service.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param BlockDeviceNo The index for the block device number. \r
+ @param Lba The logic block address to read data from. \r
+ @param BufferSize The size of data in byte to read. \r
+ @param Buffer The buffer of the \r
+\r
+ @retval EFI_DEVICE_ERROR The specified block device number exceeds the maximum \r
+ device number. \r
+ @retval EFI_DEVICE_ERROR The maximum address has exceeded the maximum address \r
+ of the block device.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadBlock (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN BlockDeviceNo,\r
+ IN EFI_PEI_LBA Lba,\r
+ IN UINTN BufferSize,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+\r
+/**\r
+ Check if there is a valid FAT in the corresponding Block device\r
+ of the volume and if yes, fill in the relevant fields for the\r
+ volume structure. Note there should be a valid Block device number\r
+ already set.\r
+\r
+ @param PrivateData Global memory map for accessing global \r
+ variables. \r
+ @param Volume On input, the BlockDeviceNumber field of the \r
+ Volume should be a valid value. On successful \r
+ output, all fields except the VolumeNumber \r
+ field is initialized. \r
+\r
+ @retval EFI_SUCCESS A FAT is found and the volume structure is \r
+ initialized. \r
+ @retval EFI_NOT_FOUND There is no FAT on the corresponding device. \r
+ @retval EFI_DEVICE_ERROR There is something error while accessing device.\r
+\r
+**/\r
+EFI_STATUS\r
+FatGetBpbInfo (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN OUT PEI_FAT_VOLUME *Volume\r
+ );\r
+\r
+\r
+/**\r
+ Gets the next cluster in the cluster chain.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param Volume The volume \r
+ @param Cluster The cluster \r
+ @param NextCluster The cluster number of the next cluster \r
+\r
+ @retval EFI_SUCCESS The address is got \r
+ @retval EFI_INVALID_PARAMETER ClusterNo exceeds the MaxCluster of the volume. \r
+ @retval EFI_DEVICE_ERROR Read disk error\r
+\r
+**/\r
+EFI_STATUS\r
+FatGetNextCluster (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN PEI_FAT_VOLUME *Volume,\r
+ IN UINT32 Cluster,\r
+ OUT UINT32 *NextCluster\r
+ );\r
+\r
+\r
+/**\r
+ Disk reading.\r
+\r
+ @param PrivateData the global memory map; \r
+ @param BlockDeviceNo the block device to read; \r
+ @param StartingAddress the starting address. \r
+ @param Size the amount of data to read. \r
+ @param Buffer the buffer holding the data \r
+\r
+ @retval EFI_SUCCESS The function completed successfully.\r
+ @retval EFI_DEVICE_ERROR Something error.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadDisk (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN BlockDeviceNo,\r
+ IN UINT64 StartingAddress,\r
+ IN UINTN Size,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+\r
+/**\r
+ Set a file's CurrentPos and CurrentCluster, then compute StraightReadAmount.\r
+\r
+ @param PrivateData the global memory map \r
+ @param File the file \r
+ @param Pos the Position which is offset from the file's \r
+ CurrentPos \r
+\r
+ @retval EFI_SUCCESS Success. \r
+ @retval EFI_INVALID_PARAMETER Pos is beyond file's size. \r
+ @retval EFI_DEVICE_ERROR Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatSetFilePos (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN PEI_FAT_FILE *File,\r
+ IN UINT32 Pos\r
+ );\r
+\r
+\r
+/**\r
+ Reads file data. Updates the file's CurrentPos.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param File The file. \r
+ @param Size The amount of data to read. \r
+ @param Buffer The buffer storing the data. \r
+\r
+ @retval EFI_SUCCESS The data is read. \r
+ @retval EFI_INVALID_PARAMETER File is invalid. \r
+ @retval EFI_DEVICE_ERROR Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadFile (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN PEI_FAT_FILE *File,\r
+ IN UINTN Size,\r
+ OUT VOID *Buffer\r
+ );\r
+\r
+\r
+/**\r
+ This function reads the next item in the parent directory and\r
+ initializes the output parameter SubFile (CurrentPos is initialized to 0).\r
+ The function updates the CurrentPos of the parent dir to after the item read.\r
+ If no more items were found, the function returns EFI_NOT_FOUND.\r
+\r
+ @param PrivateData Global memory map for accessing global variables \r
+ @param ParentDir The parent directory. \r
+ @param SubFile The File structure containing the sub file that \r
+ is caught. \r
+\r
+ @retval EFI_SUCCESS The next sub file is obtained. \r
+ @retval EFI_INVALID_PARAMETER The ParentDir is not a directory. \r
+ @retval EFI_NOT_FOUND No more sub file exists. \r
+ @retval EFI_DEVICE_ERROR Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadNextDirectoryEntry (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN PEI_FAT_FILE *ParentDir,\r
+ OUT PEI_FAT_FILE *SubFile\r
+ );\r
+\r
+\r
+/**\r
+ This function finds partitions (logical devices) in physical block devices.\r
+\r
+ @param PrivateData Global memory map for accessing global variables.\r
+\r
+**/\r
+VOID\r
+FatFindPartitions (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData\r
+ );\r
+\r
+#endif // _FAT_PEIM_H_\r
--- /dev/null
+## @file\r
+# Lite Fat driver only used in Pei Phase.\r
+#\r
+# Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+#\r
+# This program and the accompanying materials are licensed and made available\r
+# under the terms and conditions of the BSD License which accompanies this\r
+# distribution. The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+ INF_VERSION = 0x00010005\r
+ BASE_NAME = FatPei\r
+ FILE_GUID = 5B60CCFD-1011-4BCF-B7D1-BB99CA96A603\r
+ MODULE_TYPE = PEIM\r
+ VERSION_STRING = 1.0\r
+\r
+ ENTRY_POINT = FatPeimEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+ Part.c\r
+ FatLiteApi.c\r
+ FatLiteLib.c\r
+ FatLiteAccess.c\r
+ FatLiteApi.h\r
+ FatLitePeim.h\r
+ FatLiteFmt.h\r
+\r
+\r
+[Packages]\r
+ MdePkg/MdePkg.dec\r
+ MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+ PcdLib\r
+ BaseMemoryLib\r
+ PeimEntryPoint\r
+ BaseLib\r
+ DebugLib\r
+ PeiServicesTablePointerLib\r
+ PeiServicesLib\r
+\r
+\r
+[Guids]\r
+ gRecoveryOnFatUsbDiskGuid # ALWAYS_CONSUMED\r
+ gRecoveryOnFatIdeDiskGuid # ALWAYS_CONSUMED\r
+ gRecoveryOnFatFloppyDiskGuid # ALWAYS_CONSUMED\r
+\r
+\r
+[Ppis]\r
+ gEfiPeiVirtualBlockIoPpiGuid # PPI_NOTIFY SOMETIMES_CONSUMED\r
+ gEfiPeiDeviceRecoveryModulePpiGuid # SOMETIMES_PRODUCED\r
+\r
+\r
+[FeaturePcd]\r
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES\r
+ \r
+\r
+[Depex]\r
+ gEfiPeiMemoryDiscoveredPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid\r
+\r
+\r
--- /dev/null
+/** @file\r
+ Routines supporting partition discovery and \r
+ logical device reading\r
+\r
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <IndustryStandard/Mbr.h>\r
+#include <IndustryStandard/ElTorito.h>\r
+#include "FatLitePeim.h"\r
+\r
+/**\r
+ This function finds Eltorito partitions. Main algorithm\r
+ is ported from DXE partition driver.\r
+\r
+ @param PrivateData The global memory map \r
+ @param ParentBlockDevNo The parent block device \r
+\r
+ @retval TRUE New partitions are detected and logical block devices \r
+ are added to block device array \r
+ @retval FALSE No New partitions are added;\r
+\r
+**/\r
+BOOLEAN\r
+FatFindEltoritoPartitions (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN ParentBlockDevNo\r
+ );\r
+\r
+/**\r
+ This function finds Mbr partitions. Main algorithm\r
+ is ported from DXE partition driver.\r
+\r
+ @param PrivateData The global memory map \r
+ @param ParentBlockDevNo The parent block device \r
+\r
+ @retval TRUE New partitions are detected and logical block devices \r
+ are added to block device array \r
+ @retval FALSE No New partitions are added;\r
+\r
+**/\r
+BOOLEAN\r
+FatFindMbrPartitions (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN ParentBlockDevNo\r
+ );\r
+\r
+\r
+/**\r
+ This function finds partitions (logical devices) in physical block devices.\r
+\r
+ @param PrivateData Global memory map for accessing global variables.\r
+\r
+**/\r
+VOID\r
+FatFindPartitions (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData\r
+ )\r
+{\r
+ BOOLEAN Found;\r
+ UINTN Index;\r
+\r
+ do {\r
+ Found = FALSE;\r
+\r
+ for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) {\r
+ if (!PrivateData->BlockDevice[Index].PartitionChecked) {\r
+ Found = FatFindMbrPartitions (PrivateData, Index);\r
+ if (!Found) {\r
+ Found = FatFindEltoritoPartitions (PrivateData, Index);\r
+ }\r
+ }\r
+ }\r
+ } while (Found && PrivateData->BlockDeviceCount <= PEI_FAT_MAX_BLOCK_DEVICE);\r
+}\r
+\r
+\r
+/**\r
+ This function finds Eltorito partitions. Main algorithm\r
+ is ported from DXE partition driver.\r
+\r
+ @param PrivateData The global memory map \r
+ @param ParentBlockDevNo The parent block device \r
+\r
+ @retval TRUE New partitions are detected and logical block devices \r
+ are added to block device array \r
+ @retval FALSE No New partitions are added;\r
+\r
+**/\r
+BOOLEAN\r
+FatFindEltoritoPartitions (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN ParentBlockDevNo\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ BOOLEAN Found;\r
+ PEI_FAT_BLOCK_DEVICE *BlockDev;\r
+ PEI_FAT_BLOCK_DEVICE *ParentBlockDev;\r
+ UINT32 VolDescriptorLba;\r
+ UINT32 Lba;\r
+ CDROM_VOLUME_DESCRIPTOR *VolDescriptor;\r
+ ELTORITO_CATALOG *Catalog;\r
+ UINTN Check;\r
+ UINTN Index;\r
+ UINTN MaxIndex;\r
+ UINT16 *CheckBuffer;\r
+ UINT32 SubBlockSize;\r
+ UINT32 SectorCount;\r
+ UINT32 VolSpaceSize;\r
+\r
+ if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {\r
+ return FALSE;\r
+ }\r
+\r
+ Found = FALSE;\r
+ ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);\r
+ VolSpaceSize = 0;\r
+\r
+ //\r
+ // CD_ROM has the fixed block size as 2048 bytes\r
+ //\r
+ if (ParentBlockDev->BlockSize != 2048) {\r
+ return FALSE;\r
+ }\r
+\r
+ VolDescriptor = (CDROM_VOLUME_DESCRIPTOR *) PrivateData->BlockData;\r
+ Catalog = (ELTORITO_CATALOG *) VolDescriptor;\r
+\r
+ //\r
+ // the ISO-9660 volume descriptor starts at 32k on the media\r
+ // and CD_ROM has the fixed block size as 2048 bytes, so...\r
+ //\r
+ VolDescriptorLba = 15;\r
+ //\r
+ // ((16*2048) / Media->BlockSize) - 1;\r
+ //\r
+ // Loop: handle one volume descriptor per time\r
+ //\r
+ while (TRUE) {\r
+\r
+ VolDescriptorLba += 1;\r
+ if (VolDescriptorLba > ParentBlockDev->LastBlock) {\r
+ //\r
+ // We are pointing past the end of the device so exit\r
+ //\r
+ break;\r
+ }\r
+\r
+ Status = FatReadBlock (\r
+ PrivateData,\r
+ ParentBlockDevNo,\r
+ VolDescriptorLba,\r
+ ParentBlockDev->BlockSize,\r
+ VolDescriptor\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ //\r
+ // Check for valid volume descriptor signature\r
+ //\r
+ if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END ||\r
+ CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0\r
+ ) {\r
+ //\r
+ // end of Volume descriptor list\r
+ //\r
+ break;\r
+ }\r
+ //\r
+ // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte\r
+ //\r
+ if (VolDescriptor->Unknown.Type == CDVOL_TYPE_CODED) {\r
+ VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[1];\r
+ }\r
+ //\r
+ // Is it an El Torito volume descriptor?\r
+ //\r
+ if (CompareMem (\r
+ VolDescriptor->BootRecordVolume.SystemId,\r
+ CDVOL_ELTORITO_ID,\r
+ sizeof (CDVOL_ELTORITO_ID) - 1\r
+ ) != 0) {\r
+ continue;\r
+ }\r
+ //\r
+ // Read in the boot El Torito boot catalog\r
+ //\r
+ Lba = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);\r
+ if (Lba > ParentBlockDev->LastBlock) {\r
+ continue;\r
+ }\r
+\r
+ Status = FatReadBlock (\r
+ PrivateData,\r
+ ParentBlockDevNo,\r
+ Lba,\r
+ ParentBlockDev->BlockSize,\r
+ Catalog\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+ //\r
+ // We don't care too much about the Catalog header's contents, but we do want\r
+ // to make sure it looks like a Catalog header\r
+ //\r
+ if (Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG || Catalog->Catalog.Id55AA != 0xAA55) {\r
+ continue;\r
+ }\r
+\r
+ Check = 0;\r
+ CheckBuffer = (UINT16 *) Catalog;\r
+ for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {\r
+ Check += CheckBuffer[Index];\r
+ }\r
+\r
+ if ((Check & 0xFFFF) != 0) {\r
+ continue;\r
+ }\r
+\r
+ MaxIndex = ParentBlockDev->BlockSize / sizeof (ELTORITO_CATALOG);\r
+ for (Index = 1; Index < MaxIndex; Index += 1) {\r
+ //\r
+ // Next entry\r
+ //\r
+ Catalog += 1;\r
+\r
+ //\r
+ // Check this entry\r
+ //\r
+ if (Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE || Catalog->Boot.Lba == 0) {\r
+ continue;\r
+ }\r
+\r
+ SubBlockSize = 512;\r
+ SectorCount = Catalog->Boot.SectorCount;\r
+\r
+ switch (Catalog->Boot.MediaType) {\r
+\r
+ case ELTORITO_NO_EMULATION:\r
+ SubBlockSize = ParentBlockDev->BlockSize;\r
+ SectorCount = Catalog->Boot.SectorCount;\r
+ break;\r
+\r
+ case ELTORITO_HARD_DISK:\r
+ break;\r
+\r
+ case ELTORITO_12_DISKETTE:\r
+ SectorCount = 0x50 * 0x02 * 0x0F;\r
+ break;\r
+\r
+ case ELTORITO_14_DISKETTE:\r
+ SectorCount = 0x50 * 0x02 * 0x12;\r
+ break;\r
+\r
+ case ELTORITO_28_DISKETTE:\r
+ SectorCount = 0x50 * 0x02 * 0x24;\r
+ break;\r
+\r
+ default:\r
+ SectorCount = 0;\r
+ SubBlockSize = ParentBlockDev->BlockSize;\r
+ break;\r
+ }\r
+\r
+ if (SectorCount < 2) {\r
+ SectorCount = (VolSpaceSize > ParentBlockDev->LastBlock + 1) ? (UINT32) (ParentBlockDev->LastBlock - Catalog->Boot.Lba + 1) : (UINT32) (VolSpaceSize - Catalog->Boot.Lba);\r
+ }\r
+ //\r
+ // Register this partition\r
+ //\r
+ if (PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE) {\r
+\r
+ Found = TRUE;\r
+\r
+ BlockDev = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]);\r
+\r
+ BlockDev->BlockSize = SubBlockSize;\r
+ BlockDev->LastBlock = SectorCount - 1;\r
+ BlockDev->IoAlign = ParentBlockDev->IoAlign;\r
+ BlockDev->Logical = TRUE;\r
+ BlockDev->PartitionChecked = FALSE;\r
+ BlockDev->StartingPos = MultU64x32 (Catalog->Boot.Lba, ParentBlockDev->BlockSize);\r
+ BlockDev->ParentDevNo = ParentBlockDevNo;\r
+\r
+ PrivateData->BlockDeviceCount++;\r
+ }\r
+ }\r
+ }\r
+\r
+ ParentBlockDev->PartitionChecked = TRUE;\r
+\r
+ return Found;\r
+\r
+}\r
+\r
+\r
+/**\r
+ Test to see if the Mbr buffer is a valid MBR\r
+\r
+ @param Mbr Parent Handle \r
+ @param LastLba Last Lba address on the device. \r
+\r
+ @retval TRUE Mbr is a Valid MBR \r
+ @retval FALSE Mbr is not a Valid MBR\r
+\r
+**/\r
+BOOLEAN\r
+PartitionValidMbr (\r
+ IN MASTER_BOOT_RECORD *Mbr,\r
+ IN EFI_PEI_LBA LastLba\r
+ )\r
+{\r
+ UINT32 StartingLBA;\r
+ UINT32 EndingLBA;\r
+ UINT32 NewEndingLBA;\r
+ INTN Index1;\r
+ INTN Index2;\r
+ BOOLEAN MbrValid;\r
+\r
+ if (Mbr->Signature != MBR_SIGNATURE) {\r
+ return FALSE;\r
+ }\r
+ //\r
+ // The BPB also has this signature, so it can not be used alone.\r
+ //\r
+ MbrValid = FALSE;\r
+ for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) {\r
+ if (Mbr->Partition[Index1].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0) {\r
+ continue;\r
+ }\r
+\r
+ MbrValid = TRUE;\r
+ StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA);\r
+ EndingLBA = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1;\r
+ if (EndingLBA > LastLba) {\r
+ //\r
+ // Compatability Errata:\r
+ // Some systems try to hide drive space with thier INT 13h driver\r
+ // This does not hide space from the OS driver. This means the MBR\r
+ // that gets created from DOS is smaller than the MBR created from\r
+ // a real OS (NT & Win98). This leads to BlockIo->LastBlock being\r
+ // wrong on some systems FDISKed by the OS.\r
+ //\r
+ // return FALSE Because no block devices on a system are implemented\r
+ // with INT 13h\r
+ //\r
+ return FALSE;\r
+ }\r
+\r
+ for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) {\r
+ if (Mbr->Partition[Index2].OSIndicator == 0x00 || UNPACK_INT32 (Mbr->Partition[Index2].SizeInLBA) == 0) {\r
+ continue;\r
+ }\r
+\r
+ NewEndingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) + UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) - 1;\r
+ if (NewEndingLBA >= StartingLBA && UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) <= EndingLBA) {\r
+ //\r
+ // This region overlaps with the Index1'th region\r
+ //\r
+ return FALSE;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Non of the regions overlapped so MBR is O.K.\r
+ //\r
+ return MbrValid;\r
+}\r
+\r
+\r
+/**\r
+ This function finds Mbr partitions. Main algorithm\r
+ is ported from DXE partition driver.\r
+\r
+ @param PrivateData The global memory map \r
+ @param ParentBlockDevNo The parent block device \r
+\r
+ @retval TRUE New partitions are detected and logical block devices \r
+ are added to block device array \r
+ @retval FALSE No New partitions are added;\r
+\r
+**/\r
+BOOLEAN\r
+FatFindMbrPartitions (\r
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
+ IN UINTN ParentBlockDevNo\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ MASTER_BOOT_RECORD *Mbr;\r
+ UINTN Index;\r
+ BOOLEAN Found;\r
+ PEI_FAT_BLOCK_DEVICE *ParentBlockDev;\r
+ PEI_FAT_BLOCK_DEVICE *BlockDev;\r
+\r
+ if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {\r
+ return FALSE;\r
+ }\r
+\r
+ ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);\r
+\r
+ Found = FALSE;\r
+ Mbr = (MASTER_BOOT_RECORD *) PrivateData->BlockData;\r
+\r
+ Status = FatReadBlock (\r
+ PrivateData,\r
+ ParentBlockDevNo,\r
+ 0,\r
+ ParentBlockDev->BlockSize,\r
+ Mbr\r
+ );\r
+\r
+ if (EFI_ERROR (Status) || !PartitionValidMbr (Mbr, ParentBlockDev->LastBlock)) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // We have a valid mbr - add each partition\r
+ //\r
+ for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {\r
+ if (Mbr->Partition[Index].OSIndicator == 0x00 || UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) == 0) {\r
+ //\r
+ // Don't use null MBR entries\r
+ //\r
+ continue;\r
+ }\r
+ //\r
+ // Register this partition\r
+ //\r
+ if (PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE) {\r
+\r
+ Found = TRUE;\r
+\r
+ BlockDev = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]);\r
+\r
+ BlockDev->BlockSize = MBR_SIZE;\r
+ BlockDev->LastBlock = UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) - 1;\r
+ BlockDev->IoAlign = ParentBlockDev->IoAlign;\r
+ BlockDev->Logical = TRUE;\r
+ BlockDev->PartitionChecked = FALSE;\r
+ BlockDev->StartingPos = MultU64x32 (\r
+ UNPACK_INT32 (Mbr->Partition[Index].StartingLBA),\r
+ ParentBlockDev->BlockSize\r
+ );\r
+ BlockDev->ParentDevNo = ParentBlockDevNo;\r
+\r
+ PrivateData->BlockDeviceCount++;\r
+ }\r
+ }\r
+\r
+Done:\r
+\r
+ ParentBlockDev->PartitionChecked = TRUE;\r
+ return Found;\r
+}\r
BUILD_TARGETS = DEBUG|RELEASE\r
SKUID_IDENTIFIER = DEFAULT\r
\r
+[BuildOptions]\r
+ GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG\r
+ INTEL:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG\r
+ MSFT:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG\r
+\r
[LibraryClasses]\r
#\r
# Entry Point Libraries\r
DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf \r
DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf\r
\r
+[LibraryClasses.common.PEIM]\r
+ PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf\r
+ PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf\r
+ PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf\r
+ HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf\r
+ MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf\r
+ PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf\r
+\r
###################################################################################################\r
#\r
# Components Section - list of the modules and components that will be processed by compilation\r
###################################################################################################\r
\r
[Components]\r
+ FatPkg/FatPei/FatPei.inf\r
FatPkg/EnhancedFatDxe/Fat.inf\r