123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519 |
- /** @file
- FAT file system access routines for FAT recovery PEIM
- Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include "FatLitePeim.h"
- /**
- Check if there is a valid FAT in the corresponding Block device
- of the volume and if yes, fill in the relevant fields for the
- volume structure. Note there should be a valid Block device number
- already set.
- @param PrivateData Global memory map for accessing global
- variables.
- @param Volume On input, the BlockDeviceNumber field of the
- Volume should be a valid value. On successful
- output, all fields except the VolumeNumber
- field is initialized.
- @retval EFI_SUCCESS A FAT is found and the volume structure is
- initialized.
- @retval EFI_NOT_FOUND There is no FAT on the corresponding device.
- @retval EFI_DEVICE_ERROR There is something error while accessing device.
- **/
- EFI_STATUS
- FatGetBpbInfo (
- IN PEI_FAT_PRIVATE_DATA *PrivateData,
- IN OUT PEI_FAT_VOLUME *Volume
- )
- {
- EFI_STATUS Status;
- PEI_FAT_BOOT_SECTOR Bpb;
- PEI_FAT_BOOT_SECTOR_EX BpbEx;
- UINT32 Sectors;
- UINT32 SectorsPerFat;
- UINT32 RootDirSectors;
- UINT64 FatLba;
- UINT64 RootLba;
- UINT64 FirstClusterLba;
- //
- // Read in the BPB
- //
- Status = FatReadDisk (
- PrivateData,
- Volume->BlockDeviceNo,
- 0,
- sizeof (PEI_FAT_BOOT_SECTOR_EX),
- &BpbEx
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
- CopyMem (
- (UINT8 *)(&Bpb),
- (UINT8 *)(&BpbEx),
- sizeof (PEI_FAT_BOOT_SECTOR)
- );
- Volume->FatType = FatUnknown;
- Sectors = Bpb.Sectors;
- if (Sectors == 0) {
- Sectors = Bpb.LargeSectors;
- }
- SectorsPerFat = Bpb.SectorsPerFat;
- if (SectorsPerFat == 0) {
- SectorsPerFat = BpbEx.LargeSectorsPerFat;
- Volume->FatType = Fat32;
- }
- //
- // Filter out those not a FAT
- //
- if ((Bpb.Ia32Jump[0] != 0xe9) && (Bpb.Ia32Jump[0] != 0xeb) && (Bpb.Ia32Jump[0] != 0x49)) {
- return EFI_NOT_FOUND;
- }
- if ((Bpb.ReservedSectors == 0) || (Bpb.NoFats == 0) || (Sectors == 0)) {
- return EFI_NOT_FOUND;
- }
- if ((Bpb.SectorsPerCluster != 1) &&
- (Bpb.SectorsPerCluster != 2) &&
- (Bpb.SectorsPerCluster != 4) &&
- (Bpb.SectorsPerCluster != 8) &&
- (Bpb.SectorsPerCluster != 16) &&
- (Bpb.SectorsPerCluster != 32) &&
- (Bpb.SectorsPerCluster != 64) &&
- (Bpb.SectorsPerCluster != 128)
- )
- {
- return EFI_NOT_FOUND;
- }
- if ((Volume->FatType == Fat32) && ((SectorsPerFat == 0) || (BpbEx.FsVersion != 0))) {
- return EFI_NOT_FOUND;
- }
- if ((Bpb.Media != 0xf0) &&
- (Bpb.Media != 0xf8) &&
- (Bpb.Media != 0xf9) &&
- (Bpb.Media != 0xfb) &&
- (Bpb.Media != 0xfc) &&
- (Bpb.Media != 0xfd) &&
- (Bpb.Media != 0xfe) &&
- (Bpb.Media != 0xff) &&
- //
- // FujitsuFMR
- //
- (Bpb.Media != 0x00) &&
- (Bpb.Media != 0x01) &&
- (Bpb.Media != 0xfa)
- )
- {
- return EFI_NOT_FOUND;
- }
- if ((Volume->FatType != Fat32) && (Bpb.RootEntries == 0)) {
- return EFI_NOT_FOUND;
- }
- //
- // If this is fat32, refuse to mount mirror-disabled volumes
- //
- if ((Volume->FatType == Fat32) && ((BpbEx.ExtendedFlags & 0x80) != 0)) {
- return EFI_NOT_FOUND;
- }
- //
- // Fill in the volume structure fields
- // (Sectors & SectorsPerFat is computed earlier already)
- //
- Volume->ClusterSize = Bpb.SectorSize * Bpb.SectorsPerCluster;
- Volume->RootEntries = Bpb.RootEntries;
- Volume->SectorSize = Bpb.SectorSize;
- RootDirSectors = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (Volume->SectorSize - 1)) / Volume->SectorSize;
- FatLba = Bpb.ReservedSectors;
- RootLba = Bpb.NoFats * SectorsPerFat + FatLba;
- FirstClusterLba = RootLba + RootDirSectors;
- Volume->VolumeSize = MultU64x32 (Sectors, Volume->SectorSize);
- Volume->FatPos = MultU64x32 (FatLba, Volume->SectorSize);
- Volume->RootDirPos = MultU64x32 (RootLba, Volume->SectorSize);
- Volume->FirstClusterPos = MultU64x32 (FirstClusterLba, Volume->SectorSize);
- Volume->MaxCluster = (UINT32)(Sectors - FirstClusterLba) / Bpb.SectorsPerCluster;
- Volume->RootDirCluster = BpbEx.RootDirFirstCluster;
- //
- // If this is not a fat32, determine if it's a fat16 or fat12
- //
- if (Volume->FatType != Fat32) {
- if (Volume->MaxCluster >= 65525) {
- return EFI_NOT_FOUND;
- }
- Volume->FatType = Volume->MaxCluster < 4085 ? Fat12 : Fat16;
- }
- return EFI_SUCCESS;
- }
- /**
- Gets the next cluster in the cluster chain
- @param PrivateData Global memory map for accessing global variables
- @param Volume The volume
- @param Cluster The cluster
- @param NextCluster The cluster number of the next cluster
- @retval EFI_SUCCESS The address is got
- @retval EFI_INVALID_PARAMETER ClusterNo exceeds the MaxCluster of the volume.
- @retval EFI_DEVICE_ERROR Read disk error
- **/
- EFI_STATUS
- FatGetNextCluster (
- IN PEI_FAT_PRIVATE_DATA *PrivateData,
- IN PEI_FAT_VOLUME *Volume,
- IN UINT32 Cluster,
- OUT UINT32 *NextCluster
- )
- {
- EFI_STATUS Status;
- UINT64 FatEntryPos;
- UINT32 Dummy;
- *NextCluster = 0;
- if (Volume->FatType == Fat32) {
- FatEntryPos = Volume->FatPos + MultU64x32 (4, Cluster);
- Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 4, NextCluster);
- *NextCluster &= 0x0fffffff;
- //
- // Pad high bits for our FAT_CLUSTER_... macro definitions to work
- //
- if ((*NextCluster) >= 0x0ffffff7) {
- *NextCluster |= (-1 &~0xf);
- }
- } else if (Volume->FatType == Fat16) {
- FatEntryPos = Volume->FatPos + MultU64x32 (2, Cluster);
- Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);
- //
- // Pad high bits for our FAT_CLUSTER_... macro definitions to work
- //
- if ((*NextCluster) >= 0xfff7) {
- *NextCluster |= (-1 &~0xf);
- }
- } else {
- FatEntryPos = Volume->FatPos + DivU64x32Remainder (MultU64x32 (3, Cluster), 2, &Dummy);
- Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);
- if ((Cluster & 0x01) != 0) {
- *NextCluster = (*NextCluster) >> 4;
- } else {
- *NextCluster = (*NextCluster) & 0x0fff;
- }
- //
- // Pad high bits for our FAT_CLUSTER_... macro definitions to work
- //
- if ((*NextCluster) >= 0x0ff7) {
- *NextCluster |= (-1 &~0xf);
- }
- }
- if (EFI_ERROR (Status)) {
- return EFI_DEVICE_ERROR;
- }
- return EFI_SUCCESS;
- }
- /**
- Set a file's CurrentPos and CurrentCluster, then compute StraightReadAmount.
- @param PrivateData the global memory map
- @param File the file
- @param Pos the Position which is offset from the file's
- CurrentPos
- @retval EFI_SUCCESS Success.
- @retval EFI_INVALID_PARAMETER Pos is beyond file's size.
- @retval EFI_DEVICE_ERROR Something error while accessing media.
- **/
- EFI_STATUS
- FatSetFilePos (
- IN PEI_FAT_PRIVATE_DATA *PrivateData,
- IN PEI_FAT_FILE *File,
- IN UINT32 Pos
- )
- {
- EFI_STATUS Status;
- UINT32 AlignedPos;
- UINT32 Offset;
- UINT32 Cluster;
- UINT32 PrevCluster;
- if (File->IsFixedRootDir) {
- if (Pos >= MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos) {
- return EFI_INVALID_PARAMETER;
- }
- File->CurrentPos += Pos;
- File->StraightReadAmount = (UINT32)(MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos);
- } else {
- DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);
- AlignedPos = (UINT32)File->CurrentPos - (UINT32)Offset;
- while
- (
- !FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster) &&
- AlignedPos + File->Volume->ClusterSize <= File->CurrentPos + Pos
- )
- {
- AlignedPos += File->Volume->ClusterSize;
- Status = FatGetNextCluster (
- PrivateData,
- File->Volume,
- File->CurrentCluster,
- &File->CurrentCluster
- );
- if (EFI_ERROR (Status)) {
- return EFI_DEVICE_ERROR;
- }
- }
- if (FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster)) {
- return EFI_INVALID_PARAMETER;
- }
- File->CurrentPos += Pos;
- //
- // Calculate the amount of consecutive cluster occupied by the file.
- // FatReadFile() will use it to read these blocks once.
- //
- File->StraightReadAmount = 0;
- Cluster = File->CurrentCluster;
- while (!FAT_CLUSTER_FUNCTIONAL (Cluster)) {
- File->StraightReadAmount += File->Volume->ClusterSize;
- PrevCluster = Cluster;
- Status = FatGetNextCluster (PrivateData, File->Volume, Cluster, &Cluster);
- if (EFI_ERROR (Status)) {
- return EFI_DEVICE_ERROR;
- }
- if (Cluster != PrevCluster + 1) {
- break;
- }
- }
- DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);
- File->StraightReadAmount -= (UINT32)Offset;
- }
- return EFI_SUCCESS;
- }
- /**
- Reads file data. Updates the file's CurrentPos.
- @param PrivateData Global memory map for accessing global variables
- @param File The file.
- @param Size The amount of data to read.
- @param Buffer The buffer storing the data.
- @retval EFI_SUCCESS The data is read.
- @retval EFI_INVALID_PARAMETER File is invalid.
- @retval EFI_DEVICE_ERROR Something error while accessing media.
- **/
- EFI_STATUS
- FatReadFile (
- IN PEI_FAT_PRIVATE_DATA *PrivateData,
- IN PEI_FAT_FILE *File,
- IN UINTN Size,
- OUT VOID *Buffer
- )
- {
- EFI_STATUS Status;
- CHAR8 *BufferPtr;
- UINT32 Offset;
- UINT64 PhysicalAddr;
- UINTN Amount;
- BufferPtr = Buffer;
- if (File->IsFixedRootDir) {
- //
- // This is the fixed root dir in FAT12 and FAT16
- //
- if (File->CurrentPos + Size > File->Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) {
- return EFI_INVALID_PARAMETER;
- }
- Status = FatReadDisk (
- PrivateData,
- File->Volume->BlockDeviceNo,
- File->Volume->RootDirPos + File->CurrentPos,
- Size,
- Buffer
- );
- File->CurrentPos += (UINT32)Size;
- return Status;
- } else {
- if ((File->Attributes & FAT_ATTR_DIRECTORY) == 0) {
- Size = Size < (File->FileSize - File->CurrentPos) ? Size : (File->FileSize - File->CurrentPos);
- }
- //
- // This is a normal cluster based file
- //
- while (Size != 0) {
- DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);
- PhysicalAddr = File->Volume->FirstClusterPos + MultU64x32 (File->Volume->ClusterSize, File->CurrentCluster - 2);
- Amount = File->StraightReadAmount;
- Amount = Size > Amount ? Amount : Size;
- Status = FatReadDisk (
- PrivateData,
- File->Volume->BlockDeviceNo,
- PhysicalAddr + Offset,
- Amount,
- BufferPtr
- );
- if (EFI_ERROR (Status)) {
- return EFI_DEVICE_ERROR;
- }
- //
- // Advance the file's current pos and current cluster
- //
- FatSetFilePos (PrivateData, File, (UINT32)Amount);
- BufferPtr += Amount;
- Size -= Amount;
- }
- return EFI_SUCCESS;
- }
- }
- /**
- This function reads the next item in the parent directory and
- initializes the output parameter SubFile (CurrentPos is initialized to 0).
- The function updates the CurrentPos of the parent dir to after the item read.
- If no more items were found, the function returns EFI_NOT_FOUND.
- @param PrivateData Global memory map for accessing global variables
- @param ParentDir The parent directory.
- @param SubFile The File structure containing the sub file that
- is caught.
- @retval EFI_SUCCESS The next sub file is obtained.
- @retval EFI_INVALID_PARAMETER The ParentDir is not a directory.
- @retval EFI_NOT_FOUND No more sub file exists.
- @retval EFI_DEVICE_ERROR Something error while accessing media.
- **/
- EFI_STATUS
- FatReadNextDirectoryEntry (
- IN PEI_FAT_PRIVATE_DATA *PrivateData,
- IN PEI_FAT_FILE *ParentDir,
- OUT PEI_FAT_FILE *SubFile
- )
- {
- EFI_STATUS Status;
- FAT_DIRECTORY_ENTRY DirEntry;
- CHAR16 *Pos;
- CHAR16 BaseName[9];
- CHAR16 Ext[4];
- ZeroMem ((UINT8 *)SubFile, sizeof (PEI_FAT_FILE));
- //
- // Pick a valid directory entry
- //
- while (1) {
- //
- // Read one entry
- //
- Status = FatReadFile (PrivateData, ParentDir, 32, &DirEntry);
- if (EFI_ERROR (Status)) {
- return EFI_DEVICE_ERROR;
- }
- //
- // We only search for *FILE* in root directory
- // Long file name entry is *NOT* supported
- //
- if (((DirEntry.Attributes & FAT_ATTR_DIRECTORY) == FAT_ATTR_DIRECTORY) || (DirEntry.Attributes == FAT_ATTR_LFN)) {
- continue;
- }
- //
- // if this is a terminator dir entry, just return EFI_NOT_FOUND
- //
- if (DirEntry.FileName[0] == EMPTY_ENTRY_MARK) {
- return EFI_NOT_FOUND;
- }
- //
- // If this not an invalid entry neither an empty entry, this is what we want.
- // otherwise we will start a new loop to continue to find something meaningful
- //
- if ((UINT8)DirEntry.FileName[0] != DELETE_ENTRY_MARK) {
- break;
- }
- }
- //
- // fill in the output parameter
- //
- EngFatToStr (8, DirEntry.FileName, BaseName);
- EngFatToStr (3, DirEntry.FileName + 8, Ext);
- Pos = (UINT16 *)SubFile->FileName;
- SetMem ((UINT8 *)Pos, FAT_MAX_FILE_NAME_LENGTH, 0);
- CopyMem ((UINT8 *)Pos, (UINT8 *)BaseName, 2 * (StrLen (BaseName) + 1));
- if (Ext[0] != 0) {
- Pos += StrLen (BaseName);
- *Pos = '.';
- Pos++;
- CopyMem ((UINT8 *)Pos, (UINT8 *)Ext, 2 * (StrLen (Ext) + 1));
- }
- SubFile->Attributes = DirEntry.Attributes;
- SubFile->CurrentCluster = DirEntry.FileCluster;
- if (ParentDir->Volume->FatType == Fat32) {
- SubFile->CurrentCluster |= DirEntry.FileClusterHigh << 16;
- }
- SubFile->CurrentPos = 0;
- SubFile->FileSize = DirEntry.FileSize;
- SubFile->StartingCluster = SubFile->CurrentCluster;
- SubFile->Volume = ParentDir->Volume;
- //
- // in Pei phase, time parameters do not need to be filled for minimum use.
- //
- return Status;
- }
|