X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=FatPkg%2FFatPei%2FFatLiteAccess.c;fp=FatPkg%2FFatPei%2FFatLiteAccess.c;h=0a688a3185e6971779cd9b5dfd2269ea84978f90;hp=0000000000000000000000000000000000000000;hb=2f4dfa84ac56d84935e086e91f292134b8074984;hpb=43ba7907426032e0ed6033d95545f8f7c28c44bd diff --git a/FatPkg/FatPei/FatLiteAccess.c b/FatPkg/FatPei/FatLiteAccess.c new file mode 100644 index 0000000000..0a688a3185 --- /dev/null +++ b/FatPkg/FatPei/FatLiteAccess.c @@ -0,0 +1,527 @@ +/** @file + FAT file system access routines for FAT recovery PEIM + +Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.
+ +This program and the accompanying materials are licensed and made available +under the terms and conditions of the BSD License which accompanies this +distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#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; + + 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 : (UINTN) (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) || (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; + + if (SubFile->StartingCluster != 0) { + Status = FatSetFilePos (PrivateData, SubFile, 0); + } + // + // in Pei phase, time parameters do not need to be filled for minimum use. + // + return Status; +}