FatPkg: Add FAT PEIM
Signed-off-by: jljusten Reviewed-by: mdkinney (based on FatPkg commit bead7f219277e063ed28589de8ddd01cf180c1a8) [jordan.l.justen@intel.com: Use script to relicense to 2-clause BSD] Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jordan Justen <jordan.l.justen@intel.com> Acked-by: Mark Doran <mark.doran@intel.com> Acked-by: Laszlo Ersek <lersek@redhat.com>
This commit is contained in:
527
FatPkg/FatPei/FatLiteAccess.c
Normal file
527
FatPkg/FatPei/FatLiteAccess.c
Normal file
@@ -0,0 +1,527 @@
|
||||
/** @file
|
||||
FAT file system access routines for FAT recovery PEIM
|
||||
|
||||
Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
|
||||
|
||||
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;
|
||||
}
|
Reference in New Issue
Block a user