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:
Jordan Justen 2011-07-01 00:37:55 +00:00
parent 43ba790742
commit 2f4dfa84ac
9 changed files with 2757 additions and 0 deletions

View 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;
}

611
FatPkg/FatPei/FatLiteApi.c Normal file
View File

@ -0,0 +1,611 @@
/** @file
FAT recovery PEIM entry point, Ppi Functions and FAT Api functions.
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"
PEI_FAT_PRIVATE_DATA *mPrivateData = NULL;
/**
BlockIo installation nofication function. Find out all the current BlockIO
PPIs in the system and add them into private data. Assume there is
@param PeiServices General purpose services available to every
PEIM.
@param NotifyDescriptor The typedef structure of the notification
descriptor. Not used in this function.
@param Ppi The typedef structure of the PPI descriptor.
Not used in this function.
@retval EFI_SUCCESS The function completed successfully.
**/
EFI_STATUS
EFIAPI
BlockIoNotifyEntry (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
IN VOID *Ppi
);
/**
Discover all the block I/O devices to find the FAT volume.
@param PrivateData Global memory map for accessing global
variables.
@retval EFI_SUCCESS The function completed successfully.
**/
EFI_STATUS
UpdateBlocksAndVolumes (
IN OUT PEI_FAT_PRIVATE_DATA *PrivateData
)
{
EFI_STATUS Status;
EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor;
UINTN BlockIoPpiInstance;
EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
UINTN NumberBlockDevices;
UINTN Index;
EFI_PEI_BLOCK_IO_MEDIA Media;
PEI_FAT_VOLUME Volume;
EFI_PEI_SERVICES **PeiServices;
PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer ();
//
// Clean up caches
//
for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {
PrivateData->CacheBuffer[Index].Valid = FALSE;
}
PrivateData->BlockDeviceCount = 0;
//
// Find out all Block Io Ppi instances within the system
// Assuming all device Block Io Peims are dispatched already
//
for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_FAT_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {
Status = PeiServicesLocatePpi (
&gEfiPeiVirtualBlockIoPpiGuid,
BlockIoPpiInstance,
&TempPpiDescriptor,
(VOID **) &BlockIoPpi
);
if (EFI_ERROR (Status)) {
//
// Done with all Block Io Ppis
//
break;
}
Status = BlockIoPpi->GetNumberOfBlockDevices (
PeiServices,
BlockIoPpi,
&NumberBlockDevices
);
if (EFI_ERROR (Status)) {
continue;
}
for (Index = 1; Index <= NumberBlockDevices && PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE; Index++) {
Status = BlockIoPpi->GetBlockDeviceMediaInfo (
PeiServices,
BlockIoPpi,
Index,
&Media
);
if (EFI_ERROR (Status) || !Media.MediaPresent) {
continue;
}
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize = (UINT32) Media.BlockSize;
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock = Media.LastBlock;
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].IoAlign = 0;
//
// Not used here
//
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].Logical = FALSE;
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PartitionChecked = FALSE;
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo = BlockIoPpi;
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PhysicalDevNo = (UINT8) Index;
PrivateData->BlockDevice[PrivateData->BlockDeviceCount].DevType = Media.DeviceType;
PrivateData->BlockDeviceCount++;
}
}
//
// Find out all logical devices
//
FatFindPartitions (PrivateData);
//
// Build up file system volume array
//
PrivateData->VolumeCount = 0;
for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) {
Volume.BlockDeviceNo = Index;
Status = FatGetBpbInfo (PrivateData, &Volume);
if (Status == EFI_SUCCESS) {
//
// Add the detected volume to the volume array
//
CopyMem (
(UINT8 *) &(PrivateData->Volume[PrivateData->VolumeCount]),
(UINT8 *) &Volume,
sizeof (PEI_FAT_VOLUME)
);
PrivateData->VolumeCount += 1;
if (PrivateData->VolumeCount >= PEI_FAT_MAX_VOLUME) {
break;
}
}
}
return EFI_SUCCESS;
}
/**
BlockIo installation notification function. Find out all the current BlockIO
PPIs in the system and add them into private data. Assume there is
@param PeiServices General purpose services available to every
PEIM.
@param NotifyDescriptor The typedef structure of the notification
descriptor. Not used in this function.
@param Ppi The typedef structure of the PPI descriptor.
Not used in this function.
@retval EFI_SUCCESS The function completed successfully.
**/
EFI_STATUS
EFIAPI
BlockIoNotifyEntry (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
IN VOID *Ppi
)
{
UpdateBlocksAndVolumes (mPrivateData);
return EFI_SUCCESS;
}
/**
Installs the Device Recovery Module PPI, Initialize BlockIo Ppi
installation notification
@param FileHandle Handle of the file being invoked. Type
EFI_PEI_FILE_HANDLE is defined in
FfsFindNextFile().
@param PeiServices Describes the list of possible PEI Services.
@retval EFI_SUCCESS The entry point was executed successfully.
@retval EFI_OUT_OF_RESOURCES There is no enough memory to complete the
operations.
**/
EFI_STATUS
EFIAPI
FatPeimEntry (
IN EFI_PEI_FILE_HANDLE FileHandle,
IN CONST EFI_PEI_SERVICES **PeiServices
)
{
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS Address;
PEI_FAT_PRIVATE_DATA *PrivateData;
Status = PeiServicesRegisterForShadow (FileHandle);
if (!EFI_ERROR (Status)) {
return Status;
}
Status = PeiServicesAllocatePages (
EfiBootServicesCode,
(sizeof (PEI_FAT_PRIVATE_DATA) - 1) / PEI_FAT_MEMMORY_PAGE_SIZE + 1,
&Address
);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
PrivateData = (PEI_FAT_PRIVATE_DATA *) (UINTN) Address;
//
// Initialize Private Data (to zero, as is required by subsequent operations)
//
ZeroMem ((UINT8 *) PrivateData, sizeof (PEI_FAT_PRIVATE_DATA));
PrivateData->Signature = PEI_FAT_PRIVATE_DATA_SIGNATURE;
//
// Installs Ppi
//
PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules = GetNumberRecoveryCapsules;
PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo = GetRecoveryCapsuleInfo;
PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule = LoadRecoveryCapsule;
PrivateData->PpiDescriptor.Flags = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);
PrivateData->PpiDescriptor.Guid = &gEfiPeiDeviceRecoveryModulePpiGuid;
PrivateData->PpiDescriptor.Ppi = &PrivateData->DeviceRecoveryPpi;
Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor);
if (EFI_ERROR (Status)) {
return EFI_OUT_OF_RESOURCES;
}
//
// Other initializations
//
PrivateData->BlockDeviceCount = 0;
UpdateBlocksAndVolumes (PrivateData);
//
// PrivateData is allocated now, set it to the module variable
//
mPrivateData = PrivateData;
//
// Installs Block Io Ppi notification function
//
PrivateData->NotifyDescriptor.Flags =
(
EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
);
PrivateData->NotifyDescriptor.Guid = &gEfiPeiVirtualBlockIoPpiGuid;
PrivateData->NotifyDescriptor.Notify = BlockIoNotifyEntry;
return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor);
}
/**
Returns the number of DXE capsules residing on the device.
This function searches for DXE capsules from the associated device and returns
the number and maximum size in bytes of the capsules discovered. Entry 1 is
assumed to be the highest load priority and entry N is assumed to be the lowest
priority.
@param[in] PeiServices General-purpose services that are available
to every PEIM
@param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
instance.
@param[out] NumberRecoveryCapsules Pointer to a caller-allocated UINTN. On
output, *NumberRecoveryCapsules contains
the number of recovery capsule images
available for retrieval from this PEIM
instance.
@retval EFI_SUCCESS One or more capsules were discovered.
@retval EFI_DEVICE_ERROR A device error occurred.
@retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
**/
EFI_STATUS
EFIAPI
GetNumberRecoveryCapsules (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
OUT UINTN *NumberRecoveryCapsules
)
{
EFI_STATUS Status;
PEI_FAT_PRIVATE_DATA *PrivateData;
UINTN Index;
UINTN RecoveryCapsuleCount;
PEI_FILE_HANDLE Handle;
PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);
//
// Search each volume in the root directory for the Recovery capsule
//
RecoveryCapsuleCount = 0;
for (Index = 0; Index < PrivateData->VolumeCount; Index++) {
Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle);
if (EFI_ERROR (Status)) {
continue;
}
RecoveryCapsuleCount++;
}
*NumberRecoveryCapsules = RecoveryCapsuleCount;
if (*NumberRecoveryCapsules == 0) {
return EFI_NOT_FOUND;
}
return EFI_SUCCESS;
}
/**
Returns the size and type of the requested recovery capsule.
This function gets the size and type of the capsule specified by CapsuleInstance.
@param[in] PeiServices General-purpose services that are available to every PEIM
@param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
instance.
@param[in] CapsuleInstance Specifies for which capsule instance to retrieve
the information. This parameter must be between
one and the value returned by GetNumberRecoveryCapsules()
in NumberRecoveryCapsules.
@param[out] Size A pointer to a caller-allocated UINTN in which
the size of the requested recovery module is
returned.
@param[out] CapsuleType A pointer to a caller-allocated EFI_GUID in which
the type of the requested recovery capsule is
returned. The semantic meaning of the value
returned is defined by the implementation.
@retval EFI_SUCCESS One or more capsules were discovered.
@retval EFI_DEVICE_ERROR A device error occurred.
@retval EFI_NOT_FOUND A recovery DXE capsule cannot be found.
**/
EFI_STATUS
EFIAPI
GetRecoveryCapsuleInfo (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
IN UINTN CapsuleInstance,
OUT UINTN *Size,
OUT EFI_GUID *CapsuleType
)
{
EFI_STATUS Status;
PEI_FAT_PRIVATE_DATA *PrivateData;
UINTN Index;
UINTN BlockDeviceNo;
UINTN RecoveryCapsuleCount;
PEI_FILE_HANDLE Handle;
UINTN NumberRecoveryCapsules;
Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
if (EFI_ERROR (Status)) {
return Status;
}
if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
CapsuleInstance = CapsuleInstance + 1;
}
if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
return EFI_NOT_FOUND;
}
PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);
//
// Search each volume in the root directory for the Recovery capsule
//
RecoveryCapsuleCount = 0;
for (Index = 0; Index < PrivateData->VolumeCount; Index++) {
Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle);
if (EFI_ERROR (Status)) {
continue;
}
if (CapsuleInstance - 1 == RecoveryCapsuleCount) {
//
// Get file size
//
*Size = (UINTN) (((PEI_FAT_FILE *) Handle)->FileSize);
//
// Find corresponding physical block device
//
BlockDeviceNo = PrivateData->Volume[Index].BlockDeviceNo;
while (PrivateData->BlockDevice[BlockDeviceNo].Logical && BlockDeviceNo < PrivateData->BlockDeviceCount) {
BlockDeviceNo = PrivateData->BlockDevice[BlockDeviceNo].ParentDevNo;
}
//
// Fill in the Capsule Type GUID according to the block device type
//
if (BlockDeviceNo < PrivateData->BlockDeviceCount) {
switch (PrivateData->BlockDevice[BlockDeviceNo].DevType) {
case LegacyFloppy:
CopyGuid (CapsuleType, &gRecoveryOnFatFloppyDiskGuid);
break;
case IdeCDROM:
case IdeLS120:
CopyGuid (CapsuleType, &gRecoveryOnFatIdeDiskGuid);
break;
case UsbMassStorage:
CopyGuid (CapsuleType, &gRecoveryOnFatUsbDiskGuid);
break;
default:
break;
}
}
return EFI_SUCCESS;
}
RecoveryCapsuleCount++;
}
return EFI_NOT_FOUND;
}
/**
Loads a DXE capsule from some media into memory.
This function, by whatever mechanism, retrieves a DXE capsule from some device
and loads it into memory. Note that the published interface is device neutral.
@param[in] PeiServices General-purpose services that are available
to every PEIM
@param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
instance.
@param[in] CapsuleInstance Specifies which capsule instance to retrieve.
@param[out] Buffer Specifies a caller-allocated buffer in which
the requested recovery capsule will be returned.
@retval EFI_SUCCESS The capsule was loaded correctly.
@retval EFI_DEVICE_ERROR A device error occurred.
@retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
**/
EFI_STATUS
EFIAPI
LoadRecoveryCapsule (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
IN UINTN CapsuleInstance,
OUT VOID *Buffer
)
{
EFI_STATUS Status;
PEI_FAT_PRIVATE_DATA *PrivateData;
UINTN Index;
UINTN RecoveryCapsuleCount;
PEI_FILE_HANDLE Handle;
UINTN NumberRecoveryCapsules;
Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);
if (EFI_ERROR (Status)) {
return Status;
}
if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
CapsuleInstance = CapsuleInstance + 1;
}
if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {
return EFI_NOT_FOUND;
}
PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);
//
// Search each volume in the root directory for the Recovery capsule
//
RecoveryCapsuleCount = 0;
for (Index = 0; Index < PrivateData->VolumeCount; Index++) {
Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle);
if (EFI_ERROR (Status)) {
continue;
}
if (CapsuleInstance - 1 == RecoveryCapsuleCount) {
Status = FatReadFile (
PrivateData,
Handle,
(UINTN) (((PEI_FAT_FILE *) Handle)->FileSize),
Buffer
);
return Status;
}
RecoveryCapsuleCount++;
}
return EFI_NOT_FOUND;
}
/**
Finds the recovery file on a FAT volume.
This function finds the the recovery file named FileName on a specified FAT volume and returns
its FileHandle pointer.
@param PrivateData Global memory map for accessing global
variables.
@param VolumeIndex The index of the volume.
@param FileName The recovery file name to find.
@param Handle The output file handle.
@retval EFI_DEVICE_ERROR Some error occured when operating the FAT
volume.
@retval EFI_NOT_FOUND The recovery file was not found.
@retval EFI_SUCCESS The recovery file was successfully found on the
FAT volume.
**/
EFI_STATUS
FindRecoveryFile (
IN PEI_FAT_PRIVATE_DATA *PrivateData,
IN UINTN VolumeIndex,
IN CHAR16 *FileName,
OUT PEI_FILE_HANDLE *Handle
)
{
EFI_STATUS Status;
PEI_FAT_FILE Parent;
PEI_FAT_FILE *File;
File = &PrivateData->File;
//
// VolumeIndex must be less than PEI_FAT_MAX_VOLUME because PrivateData->VolumeCount
// cannot be larger than PEI_FAT_MAX_VOLUME when detecting recovery volume.
//
ASSERT (VolumeIndex < PEI_FAT_MAX_VOLUME);
//
// Construct root directory file
//
Parent.IsFixedRootDir = (BOOLEAN) ((PrivateData->Volume[VolumeIndex].FatType == Fat32) ? FALSE : TRUE);
Parent.Attributes = FAT_ATTR_DIRECTORY;
Parent.CurrentPos = 0;
Parent.CurrentCluster = Parent.IsFixedRootDir ? 0 : PrivateData->Volume[VolumeIndex].RootDirCluster;
Parent.StartingCluster = Parent.CurrentCluster;
Parent.Volume = &PrivateData->Volume[VolumeIndex];
Status = FatSetFilePos (PrivateData, &Parent, 0);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
//
// Search for recovery capsule in root directory
//
Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);
while (Status == EFI_SUCCESS) {
if (EngStriColl (PrivateData, FileName, File->FileName)) {
break;
}
Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);
}
if (EFI_ERROR (Status)) {
return EFI_NOT_FOUND;
}
*Handle = File;
return EFI_SUCCESS;
}

View File

@ -0,0 +1,31 @@
/** @file
Definitions for FAT recovery PEIM API functions
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.
**/
#ifndef _FAT_API_H_
#define _FAT_API_H_
//
// API data structures
//
typedef VOID *PEI_FILE_HANDLE;
typedef enum {
Fat12,
Fat16,
Fat32,
FatUnknown
} PEI_FAT_TYPE;
#endif

144
FatPkg/FatPei/FatLiteFmt.h Normal file
View File

@ -0,0 +1,144 @@
/** @file
FAT format data structures
Copyright (c) 2006 - 2008, 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.
**/
#ifndef _FAT_FMT_H_
#define _FAT_FMT_H_
//
// Definitions
//
#define FAT_ATTR_READ_ONLY 0x01
#define FAT_ATTR_HIDDEN 0x02
#define FAT_ATTR_SYSTEM 0x04
#define FAT_ATTR_VOLUME_ID 0x08
#define FAT_ATTR_DIRECTORY 0x10
#define FAT_ATTR_ARCHIVE 0x20
#define FAT_ATTR_LFN (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)
#define FAT_CLUSTER_SPECIAL ((-1 &~0xF) | 0x7)
#define FAT_CLUSTER_FREE 0
#define FAT_CLUSTER_RESERVED (FAT_CLUSTER_SPECIAL)
#define FAT_CLUSTER_BAD (FAT_CLUSTER_SPECIAL)
#define FAT_CLUSTER_LAST (-1)
#define DELETE_ENTRY_MARK 0xE5
#define EMPTY_ENTRY_MARK 0x00
#define FAT_CLUSTER_FUNCTIONAL(Cluster) (((Cluster) == 0) || ((Cluster) >= FAT_CLUSTER_SPECIAL))
#define FAT_CLUSTER_END_OF_CHAIN(Cluster) ((Cluster) > (FAT_CLUSTER_SPECIAL))
//
// Directory Entry
//
#pragma pack(1)
typedef struct {
UINT16 Day : 5;
UINT16 Month : 4;
UINT16 Year : 7; // From 1980
} FAT_DATE;
typedef struct {
UINT16 DoubleSecond : 5;
UINT16 Minute : 6;
UINT16 Hour : 5;
} FAT_TIME;
typedef struct {
FAT_TIME Time;
FAT_DATE Date;
} FAT_DATE_TIME;
typedef struct {
CHAR8 FileName[11]; // 8.3 filename
UINT8 Attributes;
UINT8 CaseFlag;
UINT8 CreateMillisecond; // (creation milliseconds - ignored)
FAT_DATE_TIME FileCreateTime;
FAT_DATE FileLastAccess;
UINT16 FileClusterHigh; // >= FAT32
FAT_DATE_TIME FileModificationTime;
UINT16 FileCluster;
UINT32 FileSize;
} FAT_DIRECTORY_ENTRY;
#pragma pack()
//
// Boot Sector
//
#pragma pack(1)
typedef struct {
UINT8 Ia32Jump[3];
CHAR8 OemId[8];
UINT16 SectorSize;
UINT8 SectorsPerCluster;
UINT16 ReservedSectors;
UINT8 NoFats;
UINT16 RootEntries; // < FAT32, root dir is fixed size
UINT16 Sectors;
UINT8 Media; // (ignored)
UINT16 SectorsPerFat; // < FAT32
UINT16 SectorsPerTrack; // (ignored)
UINT16 Heads; // (ignored)
UINT32 HiddenSectors; // (ignored)
UINT32 LargeSectors; // => FAT32
UINT8 PhysicalDriveNumber; // (ignored)
UINT8 CurrentHead; // holds boot_sector_dirty bit
UINT8 Signature; // (ignored)
CHAR8 Id[4];
CHAR8 FatLabel[11];
CHAR8 SystemId[8];
} PEI_FAT_BOOT_SECTOR;
typedef struct {
UINT8 Ia32Jump[3];
CHAR8 OemId[8];
UINT16 SectorSize;
UINT8 SectorsPerCluster;
UINT16 ReservedSectors;
UINT8 NoFats;
UINT16 RootEntries; // < FAT32, root dir is fixed size
UINT16 Sectors;
UINT8 Media; // (ignored)
UINT16 SectorsPerFat; // < FAT32
UINT16 SectorsPerTrack; // (ignored)
UINT16 Heads; // (ignored)
UINT32 HiddenSectors; // (ignored)
UINT32 LargeSectors; // Used if Sectors==0
UINT32 LargeSectorsPerFat; // FAT32
UINT16 ExtendedFlags; // FAT32 (ignored)
UINT16 FsVersion; // FAT32 (ignored)
UINT32 RootDirFirstCluster; // FAT32
UINT16 FsInfoSector; // FAT32
UINT16 BackupBootSector; // FAT32
UINT8 Reserved[12]; // FAT32 (ignored)
UINT8 PhysicalDriveNumber; // (ignored)
UINT8 CurrentHead; // holds boot_sector_dirty bit
UINT8 Signature; // (ignored)
CHAR8 Id[4];
CHAR8 FatLabel[11];
CHAR8 SystemId[8];
} PEI_FAT_BOOT_SECTOR_EX;
#pragma pack()
#endif

364
FatPkg/FatPei/FatLiteLib.c Normal file
View File

@ -0,0 +1,364 @@
/** @file
General purpose supporting 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"
#define CHAR_FAT_VALID 0x01
/**
Converts a union code character to upper case.
This functions converts a unicode character to upper case.
If the input Letter is not a lower-cased letter,
the original value is returned.
@param Letter The input unicode character.
@return The upper cased letter.
**/
CHAR16
ToUpper (
IN CHAR16 Letter
)
{
if ('a' <= Letter && Letter <= 'z') {
Letter = (CHAR16) (Letter - 0x20);
}
return Letter;
}
/**
Reads a block of data from the block device by calling
underlying Block I/O service.
@param PrivateData Global memory map for accessing global variables
@param BlockDeviceNo The index for the block device number.
@param Lba The logic block address to read data from.
@param BufferSize The size of data in byte to read.
@param Buffer The buffer of the
@retval EFI_DEVICE_ERROR The specified block device number exceeds the maximum
device number.
@retval EFI_DEVICE_ERROR The maximum address has exceeded the maximum address
of the block device.
**/
EFI_STATUS
FatReadBlock (
IN PEI_FAT_PRIVATE_DATA *PrivateData,
IN UINTN BlockDeviceNo,
IN EFI_PEI_LBA Lba,
IN UINTN BufferSize,
OUT VOID *Buffer
)
{
EFI_STATUS Status;
PEI_FAT_BLOCK_DEVICE *BlockDev;
if (BlockDeviceNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {
return EFI_DEVICE_ERROR;
}
Status = EFI_SUCCESS;
BlockDev = &(PrivateData->BlockDevice[BlockDeviceNo]);
if (BufferSize > MultU64x32 (BlockDev->LastBlock - Lba + 1, BlockDev->BlockSize)) {
return EFI_DEVICE_ERROR;
}
if (!BlockDev->Logical) {
//
// Status = BlockDev->ReadFunc
// (PrivateData->PeiServices, BlockDev->PhysicalDevNo, Lba, BufferSize, Buffer);
//
Status = BlockDev->BlockIo->ReadBlocks (
(EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
BlockDev->BlockIo,
BlockDev->PhysicalDevNo,
Lba,
BufferSize,
Buffer
);
} else {
Status = FatReadDisk (
PrivateData,
BlockDev->ParentDevNo,
BlockDev->StartingPos + MultU64x32 (Lba, BlockDev->BlockSize),
BufferSize,
Buffer
);
}
return Status;
}
/**
Find a cache block designated to specific Block device and Lba.
If not found, invalidate an oldest one and use it. (LRU cache)
@param PrivateData the global memory map.
@param BlockDeviceNo the Block device.
@param Lba the Logical Block Address
@param CachePtr Ptr to the starting address of the memory holding the
data;
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_DEVICE_ERROR Something error while accessing media.
**/
EFI_STATUS
FatGetCacheBlock (
IN PEI_FAT_PRIVATE_DATA *PrivateData,
IN UINTN BlockDeviceNo,
IN UINT64 Lba,
OUT CHAR8 **CachePtr
)
{
EFI_STATUS Status;
PEI_FAT_CACHE_BUFFER *CacheBuffer;
INTN Index;
STATIC UINT8 Seed;
Status = EFI_SUCCESS;
CacheBuffer = NULL;
//
// go through existing cache buffers
//
for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {
CacheBuffer = &(PrivateData->CacheBuffer[Index]);
if (CacheBuffer->Valid && CacheBuffer->BlockDeviceNo == BlockDeviceNo && CacheBuffer->Lba == Lba) {
break;
}
}
if (Index < PEI_FAT_CACHE_SIZE) {
*CachePtr = (CHAR8 *) CacheBuffer->Buffer;
return EFI_SUCCESS;
}
//
// We have to find an invalid cache buffer
//
for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {
if (!PrivateData->CacheBuffer[Index].Valid) {
break;
}
}
//
// Use the cache buffer
//
if (Index == PEI_FAT_CACHE_SIZE) {
Index = (Seed++) % PEI_FAT_CACHE_SIZE;
}
//
// Current device ID should be less than maximum device ID.
//
if (BlockDeviceNo >= PEI_FAT_MAX_BLOCK_DEVICE) {
return EFI_DEVICE_ERROR;
}
CacheBuffer = &(PrivateData->CacheBuffer[Index]);
CacheBuffer->BlockDeviceNo = BlockDeviceNo;
CacheBuffer->Lba = Lba;
CacheBuffer->Size = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;
//
// Read in the data
//
Status = FatReadBlock (
PrivateData,
BlockDeviceNo,
Lba,
CacheBuffer->Size,
CacheBuffer->Buffer
);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
CacheBuffer->Valid = TRUE;
*CachePtr = (CHAR8 *) CacheBuffer->Buffer;
return Status;
}
/**
Disk reading.
@param PrivateData the global memory map;
@param BlockDeviceNo the block device to read;
@param StartingAddress the starting address.
@param Size the amount of data to read.
@param Buffer the buffer holding the data
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_DEVICE_ERROR Something error.
**/
EFI_STATUS
FatReadDisk (
IN PEI_FAT_PRIVATE_DATA *PrivateData,
IN UINTN BlockDeviceNo,
IN UINT64 StartingAddress,
IN UINTN Size,
OUT VOID *Buffer
)
{
EFI_STATUS Status;
UINT32 BlockSize;
CHAR8 *BufferPtr;
CHAR8 *CachePtr;
UINT32 Offset;
UINT64 Lba;
UINT64 OverRunLba;
UINTN Amount;
Status = EFI_SUCCESS;
BufferPtr = Buffer;
BlockSize = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;
//
// Read underrun
//
Lba = DivU64x32Remainder (StartingAddress, BlockSize, &Offset);
Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, Lba, &CachePtr);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
Amount = Size < (BlockSize - Offset) ? Size : (BlockSize - Offset);
CopyMem (BufferPtr, CachePtr + Offset, Amount);
if (Size == Amount) {
return EFI_SUCCESS;
}
Size -= Amount;
BufferPtr += Amount;
StartingAddress += Amount;
Lba += 1;
//
// Read aligned parts
//
OverRunLba = Lba + DivU64x32Remainder (Size, BlockSize, &Offset);
Size -= Offset;
Status = FatReadBlock (PrivateData, BlockDeviceNo, Lba, Size, BufferPtr);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
BufferPtr += Size;
//
// Read overrun
//
if (Offset != 0) {
Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, OverRunLba, &CachePtr);
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
CopyMem (BufferPtr, CachePtr, Offset);
}
return Status;
}
/**
This version is different from the version in Unicode collation
protocol in that this version strips off trailing blanks.
Converts an 8.3 FAT file name using an OEM character set
to a Null-terminated Unicode string.
Here does not expand DBCS FAT chars.
@param FatSize The size of the string Fat in bytes.
@param Fat A pointer to a Null-terminated string that contains
an 8.3 file name using an OEM character set.
@param Str A pointer to a Null-terminated Unicode string. The
string must be allocated in advance to hold FatSize
Unicode characters
**/
VOID
EngFatToStr (
IN UINTN FatSize,
IN CHAR8 *Fat,
OUT CHAR16 *Str
)
{
CHAR16 *String;
String = Str;
//
// No DBCS issues, just expand and add null terminate to end of string
//
while (*Fat != 0 && FatSize != 0) {
*String = *Fat;
String += 1;
Fat += 1;
FatSize -= 1;
if (*Fat == ' ') {
*String = 0;
return ;
}
}
}
/**
Performs a case-insensitive comparison of two Null-terminated Unicode strings.
@param PrivateData Global memory map for accessing global variables
@param Str1 First string to perform case insensitive comparison.
@param Str2 Second string to perform case insensitive comparison.
**/
BOOLEAN
EngStriColl (
IN PEI_FAT_PRIVATE_DATA *PrivateData,
IN CHAR16 *Str1,
IN CHAR16 *Str2
)
{
CHAR16 UpperS1;
CHAR16 UpperS2;
UpperS1 = ToUpper (*Str1);
UpperS2 = ToUpper (*Str2);
while (*Str1 != 0) {
if (UpperS1 != UpperS2) {
return FALSE;
}
Str1++;
Str2++;
UpperS1 = ToUpper (*Str1);
UpperS2 = ToUpper (*Str2);
}
return (BOOLEAN) ((*Str2 != 0) ? FALSE : TRUE);
}

526
FatPkg/FatPei/FatLitePeim.h Normal file
View File

@ -0,0 +1,526 @@
/** @file
Data structures 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.
**/
#ifndef _FAT_PEIM_H_
#define _FAT_PEIM_H_
#include <PiPei.h>
#include <Guid/RecoveryDevice.h>
#include <Ppi/BlockIo.h>
#include <Ppi/DeviceRecoveryModule.h>
#include <Library/DebugLib.h>
#include <Library/BaseLib.h>
#include <Library/PeimEntryPoint.h>
#include <Library/BaseMemoryLib.h>
#include <Library/PcdLib.h>
#include <Library/PeiServicesTablePointerLib.h>
#include <Library/PeiServicesLib.h>
#include "FatLiteApi.h"
#include "FatLiteFmt.h"
//
// Definitions
//
#define PEI_FAT_RECOVERY_CAPSULE_WITH_NT_EMULATOR L"fv0001.fv"
#define PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR L"fvmain.fv"
#define PEI_FAT_CACHE_SIZE 4
#define PEI_FAT_MAX_BLOCK_SIZE 8192
#define FAT_MAX_FILE_NAME_LENGTH 128
#define PEI_FAT_MAX_BLOCK_DEVICE 64
#define PEI_FAT_MAX_BLOCK_IO_PPI 32
#define PEI_FAT_MAX_VOLUME 64
#define PEI_FAT_MEMMORY_PAGE_SIZE 0x1000
//
// Data Structures
//
//
// The block device
//
typedef struct {
UINT32 BlockSize;
UINT64 LastBlock;
UINT32 IoAlign;
BOOLEAN Logical;
BOOLEAN PartitionChecked;
//
// Following fields only valid for logical device
//
CHAR8 PartitionFlag[8];
UINT64 StartingPos;
UINTN ParentDevNo;
//
// Following fields only valid for physical device
//
EFI_PEI_BLOCK_DEVICE_TYPE DevType;
//
// EFI_PEI_READ_BLOCKS ReadFunc;
//
EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIo;
UINT8 PhysicalDevNo;
} PEI_FAT_BLOCK_DEVICE;
//
// the Volume structure
//
typedef struct {
UINTN BlockDeviceNo;
UINTN VolumeNo;
UINT64 VolumeSize;
UINTN MaxCluster;
CHAR16 VolumeLabel[FAT_MAX_FILE_NAME_LENGTH];
PEI_FAT_TYPE FatType;
UINT64 FatPos;
UINT32 SectorSize;
UINT32 ClusterSize;
UINT64 FirstClusterPos;
UINT64 RootDirPos;
UINT32 RootEntries;
UINT32 RootDirCluster;
} PEI_FAT_VOLUME;
//
// File instance
//
typedef struct {
PEI_FAT_VOLUME *Volume;
CHAR16 FileName[FAT_MAX_FILE_NAME_LENGTH];
BOOLEAN IsFixedRootDir;
UINT32 StartingCluster;
UINT32 CurrentPos;
UINT32 StraightReadAmount;
UINT32 CurrentCluster;
UINT8 Attributes;
UINT32 FileSize;
} PEI_FAT_FILE;
//
// Cache Buffer
//
typedef struct {
BOOLEAN Valid;
UINTN BlockDeviceNo;
UINT64 Lba;
UINT32 Lru;
UINT64 Buffer[PEI_FAT_MAX_BLOCK_SIZE / 8];
UINTN Size;
} PEI_FAT_CACHE_BUFFER;
//
// Private Data.
// This structure abstracts the whole memory usage in FAT PEIM.
// The entry point routine will get a chunk of memory (by whatever
// means) whose size is sizeof(PEI_FAT_PRIVATE_DATA), which is clean
// in both 32 and 64 bit environment. The boundary of the memory chunk
// should be 64bit aligned.
//
#define PEI_FAT_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('p', 'f', 'a', 't')
typedef struct {
UINTN Signature;
EFI_PEI_DEVICE_RECOVERY_MODULE_PPI DeviceRecoveryPpi;
EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;
EFI_PEI_NOTIFY_DESCRIPTOR NotifyDescriptor;
UINT8 UnicodeCaseMap[0x300];
CHAR8 *EngUpperMap;
CHAR8 *EngLowerMap;
CHAR8 *EngInfoMap;
UINT64 BlockData[PEI_FAT_MAX_BLOCK_SIZE / 8];
UINTN BlockDeviceCount;
PEI_FAT_BLOCK_DEVICE BlockDevice[PEI_FAT_MAX_BLOCK_DEVICE];
UINTN VolumeCount;
PEI_FAT_VOLUME Volume[PEI_FAT_MAX_VOLUME];
PEI_FAT_FILE File;
PEI_FAT_CACHE_BUFFER CacheBuffer[PEI_FAT_CACHE_SIZE];
} PEI_FAT_PRIVATE_DATA;
#define PEI_FAT_PRIVATE_DATA_FROM_THIS(a) \
CR (a, PEI_FAT_PRIVATE_DATA, DeviceRecoveryPpi, PEI_FAT_PRIVATE_DATA_SIGNATURE)
//
// Extract INT32 from char array
//
#define UNPACK_INT32(a) \
(INT32) ((((UINT8 *) a)[0] << 0) | (((UINT8 *) a)[1] << 8) | (((UINT8 *) a)[2] << 16) | (((UINT8 *) a)[3] << 24))
//
// Extract UINT32 from char array
//
#define UNPACK_UINT32(a) \
(UINT32) ((((UINT8 *) a)[0] << 0) | (((UINT8 *) a)[1] << 8) | (((UINT8 *) a)[2] << 16) | (((UINT8 *) a)[3] << 24))
//
// API functions
//
/**
Finds the recovery file on a FAT volume.
This function finds the the recovery file named FileName on a specified FAT volume and returns
its FileHandle pointer.
@param PrivateData Global memory map for accessing global
variables.
@param VolumeIndex The index of the volume.
@param FileName The recovery file name to find.
@param Handle The output file handle.
@retval EFI_DEVICE_ERROR Some error occured when operating the FAT
volume.
@retval EFI_NOT_FOUND The recovery file was not found.
@retval EFI_SUCCESS The recovery file was successfully found on the
FAT volume.
**/
EFI_STATUS
FindRecoveryFile (
IN PEI_FAT_PRIVATE_DATA *PrivateData,
IN UINTN VolumeIndex,
IN CHAR16 *FileName,
OUT PEI_FILE_HANDLE *Handle
);
/**
Returns the number of DXE capsules residing on the device.
This function, by whatever mechanism, searches for DXE capsules from the associated device and
returns the number and maximum size in bytes of the capsules discovered.Entry 1 is assumed to be
the highest load priority and entry N is assumed to be the lowest priority.
@param PeiServices General-purpose services that are available to
every PEIM.
@param This Indicates the
EFI_PEI_DEVICE_RECOVERY_MODULE_PPI instance.
@param NumberRecoveryCapsules Pointer to a caller-allocated UINTN.On output,
*NumberRecoveryCapsules contains the number of
recovery capsule images available for retrieval
from this PEIM instance.
@retval EFI_SUCCESS The function completed successfully.
**/
EFI_STATUS
EFIAPI
GetNumberRecoveryCapsules (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
OUT UINTN *NumberRecoveryCapsules
);
/**
Returns the size and type of the requested recovery capsule.
This function returns the size and type of the capsule specified by CapsuleInstance.
@param PeiServices General-purpose services that are available to
every PEIM.
@param This Indicates the
EFI_PEI_DEVICE_RECOVERY_MODULE_PPI instance.
@param CapsuleInstance Specifies for which capsule instance to
retrieve the information.T his parameter must
be between one and the value returned by
GetNumberRecoveryCapsules() in
NumberRecoveryCapsules.
@param Size A pointer to a caller-allocated UINTN in which
the size of the requested recovery module is
returned.
@param CapsuleType A pointer to a caller-allocated EFI_GUID in
which the type of the requested recovery
capsule is returned.T he semantic meaning of
the value returned is defined by the
implementation.
@retval EFI_SUCCESS The capsule type and size were retrieved.
@retval EFI_INVALID_PARAMETER The input CapsuleInstance does not match any
discovered recovery capsule.
**/
EFI_STATUS
EFIAPI
GetRecoveryCapsuleInfo (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
IN UINTN CapsuleInstance,
OUT UINTN *Size,
OUT EFI_GUID *CapsuleType
);
/**
Loads a DXE capsule from some media into memory.
This function, by whatever mechanism, retrieves a DXE capsule from some device
and loads it into memory. Note that the published interface is device neutral.
@param[in] PeiServices General-purpose services that are available
to every PEIM
@param[in] This Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
instance.
@param[in] CapsuleInstance Specifies which capsule instance to retrieve.
@param[out] Buffer Specifies a caller-allocated buffer in which
the requested recovery capsule will be returned.
@retval EFI_SUCCESS The capsule was loaded correctly.
@retval EFI_DEVICE_ERROR A device error occurred.
@retval EFI_NOT_FOUND A requested recovery DXE capsule cannot be found.
**/
EFI_STATUS
EFIAPI
LoadRecoveryCapsule (
IN EFI_PEI_SERVICES **PeiServices,
IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI *This,
IN UINTN CapsuleInstance,
OUT VOID *Buffer
);
/**
This version is different from the version in Unicode collation
protocol in that this version strips off trailing blanks.
Converts an 8.3 FAT file name using an OEM character set
to a Null-terminated Unicode string.
Here does not expand DBCS FAT chars.
@param FatSize The size of the string Fat in bytes.
@param Fat A pointer to a Null-terminated string that contains
an 8.3 file name using an OEM character set.
@param Str A pointer to a Null-terminated Unicode string. The
string must be allocated in advance to hold FatSize
Unicode characters
**/
VOID
EngFatToStr (
IN UINTN FatSize,
IN CHAR8 *Fat,
OUT CHAR16 *Str
);
/**
Performs a case-insensitive comparison of two Null-terminated Unicode strings.
@param PrivateData Global memory map for accessing global variables
@param Str1 First string to perform case insensitive comparison.
@param Str2 Second string to perform case insensitive comparison.
**/
BOOLEAN
EngStriColl (
IN PEI_FAT_PRIVATE_DATA *PrivateData,
IN CHAR16 *Str1,
IN CHAR16 *Str2
);
/**
Reads a block of data from the block device by calling
underlying Block I/O service.
@param PrivateData Global memory map for accessing global variables
@param BlockDeviceNo The index for the block device number.
@param Lba The logic block address to read data from.
@param BufferSize The size of data in byte to read.
@param Buffer The buffer of the
@retval EFI_DEVICE_ERROR The specified block device number exceeds the maximum
device number.
@retval EFI_DEVICE_ERROR The maximum address has exceeded the maximum address
of the block device.
**/
EFI_STATUS
FatReadBlock (
IN PEI_FAT_PRIVATE_DATA *PrivateData,
IN UINTN BlockDeviceNo,
IN EFI_PEI_LBA Lba,
IN UINTN BufferSize,
OUT VOID *Buffer
);
/**
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
);
/**
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
);
/**
Disk reading.
@param PrivateData the global memory map;
@param BlockDeviceNo the block device to read;
@param StartingAddress the starting address.
@param Size the amount of data to read.
@param Buffer the buffer holding the data
@retval EFI_SUCCESS The function completed successfully.
@retval EFI_DEVICE_ERROR Something error.
**/
EFI_STATUS
FatReadDisk (
IN PEI_FAT_PRIVATE_DATA *PrivateData,
IN UINTN BlockDeviceNo,
IN UINT64 StartingAddress,
IN UINTN Size,
OUT VOID *Buffer
);
/**
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
);
/**
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
);
/**
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
);
/**
This function finds partitions (logical devices) in physical block devices.
@param PrivateData Global memory map for accessing global variables.
**/
VOID
FatFindPartitions (
IN PEI_FAT_PRIVATE_DATA *PrivateData
);
#endif // _FAT_PEIM_H_

74
FatPkg/FatPei/FatPei.inf Normal file
View File

@ -0,0 +1,74 @@
## @file
# Lite Fat driver only used in Pei Phase.
#
# 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.
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = FatPei
FILE_GUID = 5B60CCFD-1011-4BCF-B7D1-BB99CA96A603
MODULE_TYPE = PEIM
VERSION_STRING = 1.0
ENTRY_POINT = FatPeimEntry
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources]
Part.c
FatLiteApi.c
FatLiteLib.c
FatLiteAccess.c
FatLiteApi.h
FatLitePeim.h
FatLiteFmt.h
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
PcdLib
BaseMemoryLib
PeimEntryPoint
BaseLib
DebugLib
PeiServicesTablePointerLib
PeiServicesLib
[Guids]
gRecoveryOnFatUsbDiskGuid # ALWAYS_CONSUMED
gRecoveryOnFatIdeDiskGuid # ALWAYS_CONSUMED
gRecoveryOnFatFloppyDiskGuid # ALWAYS_CONSUMED
[Ppis]
gEfiPeiVirtualBlockIoPpiGuid # PPI_NOTIFY SOMETIMES_CONSUMED
gEfiPeiDeviceRecoveryModulePpiGuid # SOMETIMES_PRODUCED
[FeaturePcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES
[Depex]
gEfiPeiMemoryDiscoveredPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid

466
FatPkg/FatPei/Part.c Normal file
View File

@ -0,0 +1,466 @@
/** @file
Routines supporting partition discovery and
logical device reading
Copyright (c) 2006 - 2008, 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 <IndustryStandard/Mbr.h>
#include <IndustryStandard/ElTorito.h>
#include "FatLitePeim.h"
/**
This function finds Eltorito partitions. Main algorithm
is ported from DXE partition driver.
@param PrivateData The global memory map
@param ParentBlockDevNo The parent block device
@retval TRUE New partitions are detected and logical block devices
are added to block device array
@retval FALSE No New partitions are added;
**/
BOOLEAN
FatFindEltoritoPartitions (
IN PEI_FAT_PRIVATE_DATA *PrivateData,
IN UINTN ParentBlockDevNo
);
/**
This function finds Mbr partitions. Main algorithm
is ported from DXE partition driver.
@param PrivateData The global memory map
@param ParentBlockDevNo The parent block device
@retval TRUE New partitions are detected and logical block devices
are added to block device array
@retval FALSE No New partitions are added;
**/
BOOLEAN
FatFindMbrPartitions (
IN PEI_FAT_PRIVATE_DATA *PrivateData,
IN UINTN ParentBlockDevNo
);
/**
This function finds partitions (logical devices) in physical block devices.
@param PrivateData Global memory map for accessing global variables.
**/
VOID
FatFindPartitions (
IN PEI_FAT_PRIVATE_DATA *PrivateData
)
{
BOOLEAN Found;
UINTN Index;
do {
Found = FALSE;
for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) {
if (!PrivateData->BlockDevice[Index].PartitionChecked) {
Found = FatFindMbrPartitions (PrivateData, Index);
if (!Found) {
Found = FatFindEltoritoPartitions (PrivateData, Index);
}
}
}
} while (Found && PrivateData->BlockDeviceCount <= PEI_FAT_MAX_BLOCK_DEVICE);
}
/**
This function finds Eltorito partitions. Main algorithm
is ported from DXE partition driver.
@param PrivateData The global memory map
@param ParentBlockDevNo The parent block device
@retval TRUE New partitions are detected and logical block devices
are added to block device array
@retval FALSE No New partitions are added;
**/
BOOLEAN
FatFindEltoritoPartitions (
IN PEI_FAT_PRIVATE_DATA *PrivateData,
IN UINTN ParentBlockDevNo
)
{
EFI_STATUS Status;
BOOLEAN Found;
PEI_FAT_BLOCK_DEVICE *BlockDev;
PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
UINT32 VolDescriptorLba;
UINT32 Lba;
CDROM_VOLUME_DESCRIPTOR *VolDescriptor;
ELTORITO_CATALOG *Catalog;
UINTN Check;
UINTN Index;
UINTN MaxIndex;
UINT16 *CheckBuffer;
UINT32 SubBlockSize;
UINT32 SectorCount;
UINT32 VolSpaceSize;
if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {
return FALSE;
}
Found = FALSE;
ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
VolSpaceSize = 0;
//
// CD_ROM has the fixed block size as 2048 bytes
//
if (ParentBlockDev->BlockSize != 2048) {
return FALSE;
}
VolDescriptor = (CDROM_VOLUME_DESCRIPTOR *) PrivateData->BlockData;
Catalog = (ELTORITO_CATALOG *) VolDescriptor;
//
// the ISO-9660 volume descriptor starts at 32k on the media
// and CD_ROM has the fixed block size as 2048 bytes, so...
//
VolDescriptorLba = 15;
//
// ((16*2048) / Media->BlockSize) - 1;
//
// Loop: handle one volume descriptor per time
//
while (TRUE) {
VolDescriptorLba += 1;
if (VolDescriptorLba > ParentBlockDev->LastBlock) {
//
// We are pointing past the end of the device so exit
//
break;
}
Status = FatReadBlock (
PrivateData,
ParentBlockDevNo,
VolDescriptorLba,
ParentBlockDev->BlockSize,
VolDescriptor
);
if (EFI_ERROR (Status)) {
break;
}
//
// Check for valid volume descriptor signature
//
if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END ||
CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0
) {
//
// end of Volume descriptor list
//
break;
}
//
// Read the Volume Space Size from Primary Volume Descriptor 81-88 byte
//
if (VolDescriptor->Unknown.Type == CDVOL_TYPE_CODED) {
VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[1];
}
//
// Is it an El Torito volume descriptor?
//
if (CompareMem (
VolDescriptor->BootRecordVolume.SystemId,
CDVOL_ELTORITO_ID,
sizeof (CDVOL_ELTORITO_ID) - 1
) != 0) {
continue;
}
//
// Read in the boot El Torito boot catalog
//
Lba = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);
if (Lba > ParentBlockDev->LastBlock) {
continue;
}
Status = FatReadBlock (
PrivateData,
ParentBlockDevNo,
Lba,
ParentBlockDev->BlockSize,
Catalog
);
if (EFI_ERROR (Status)) {
continue;
}
//
// We don't care too much about the Catalog header's contents, but we do want
// to make sure it looks like a Catalog header
//
if (Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG || Catalog->Catalog.Id55AA != 0xAA55) {
continue;
}
Check = 0;
CheckBuffer = (UINT16 *) Catalog;
for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {
Check += CheckBuffer[Index];
}
if ((Check & 0xFFFF) != 0) {
continue;
}
MaxIndex = ParentBlockDev->BlockSize / sizeof (ELTORITO_CATALOG);
for (Index = 1; Index < MaxIndex; Index += 1) {
//
// Next entry
//
Catalog += 1;
//
// Check this entry
//
if (Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE || Catalog->Boot.Lba == 0) {
continue;
}
SubBlockSize = 512;
SectorCount = Catalog->Boot.SectorCount;
switch (Catalog->Boot.MediaType) {
case ELTORITO_NO_EMULATION:
SubBlockSize = ParentBlockDev->BlockSize;
SectorCount = Catalog->Boot.SectorCount;
break;
case ELTORITO_HARD_DISK:
break;
case ELTORITO_12_DISKETTE:
SectorCount = 0x50 * 0x02 * 0x0F;
break;
case ELTORITO_14_DISKETTE:
SectorCount = 0x50 * 0x02 * 0x12;
break;
case ELTORITO_28_DISKETTE:
SectorCount = 0x50 * 0x02 * 0x24;
break;
default:
SectorCount = 0;
SubBlockSize = ParentBlockDev->BlockSize;
break;
}
if (SectorCount < 2) {
SectorCount = (VolSpaceSize > ParentBlockDev->LastBlock + 1) ? (UINT32) (ParentBlockDev->LastBlock - Catalog->Boot.Lba + 1) : (UINT32) (VolSpaceSize - Catalog->Boot.Lba);
}
//
// Register this partition
//
if (PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE) {
Found = TRUE;
BlockDev = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]);
BlockDev->BlockSize = SubBlockSize;
BlockDev->LastBlock = SectorCount - 1;
BlockDev->IoAlign = ParentBlockDev->IoAlign;
BlockDev->Logical = TRUE;
BlockDev->PartitionChecked = FALSE;
BlockDev->StartingPos = MultU64x32 (Catalog->Boot.Lba, ParentBlockDev->BlockSize);
BlockDev->ParentDevNo = ParentBlockDevNo;
PrivateData->BlockDeviceCount++;
}
}
}
ParentBlockDev->PartitionChecked = TRUE;
return Found;
}
/**
Test to see if the Mbr buffer is a valid MBR
@param Mbr Parent Handle
@param LastLba Last Lba address on the device.
@retval TRUE Mbr is a Valid MBR
@retval FALSE Mbr is not a Valid MBR
**/
BOOLEAN
PartitionValidMbr (
IN MASTER_BOOT_RECORD *Mbr,
IN EFI_PEI_LBA LastLba
)
{
UINT32 StartingLBA;
UINT32 EndingLBA;
UINT32 NewEndingLBA;
INTN Index1;
INTN Index2;
BOOLEAN MbrValid;
if (Mbr->Signature != MBR_SIGNATURE) {
return FALSE;
}
//
// The BPB also has this signature, so it can not be used alone.
//
MbrValid = FALSE;
for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) {
if (Mbr->Partition[Index1].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0) {
continue;
}
MbrValid = TRUE;
StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA);
EndingLBA = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1;
if (EndingLBA > LastLba) {
//
// Compatability Errata:
// Some systems try to hide drive space with thier INT 13h driver
// This does not hide space from the OS driver. This means the MBR
// that gets created from DOS is smaller than the MBR created from
// a real OS (NT & Win98). This leads to BlockIo->LastBlock being
// wrong on some systems FDISKed by the OS.
//
// return FALSE Because no block devices on a system are implemented
// with INT 13h
//
return FALSE;
}
for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) {
if (Mbr->Partition[Index2].OSIndicator == 0x00 || UNPACK_INT32 (Mbr->Partition[Index2].SizeInLBA) == 0) {
continue;
}
NewEndingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) + UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) - 1;
if (NewEndingLBA >= StartingLBA && UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) <= EndingLBA) {
//
// This region overlaps with the Index1'th region
//
return FALSE;
}
}
}
//
// Non of the regions overlapped so MBR is O.K.
//
return MbrValid;
}
/**
This function finds Mbr partitions. Main algorithm
is ported from DXE partition driver.
@param PrivateData The global memory map
@param ParentBlockDevNo The parent block device
@retval TRUE New partitions are detected and logical block devices
are added to block device array
@retval FALSE No New partitions are added;
**/
BOOLEAN
FatFindMbrPartitions (
IN PEI_FAT_PRIVATE_DATA *PrivateData,
IN UINTN ParentBlockDevNo
)
{
EFI_STATUS Status;
MASTER_BOOT_RECORD *Mbr;
UINTN Index;
BOOLEAN Found;
PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
PEI_FAT_BLOCK_DEVICE *BlockDev;
if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {
return FALSE;
}
ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
Found = FALSE;
Mbr = (MASTER_BOOT_RECORD *) PrivateData->BlockData;
Status = FatReadBlock (
PrivateData,
ParentBlockDevNo,
0,
ParentBlockDev->BlockSize,
Mbr
);
if (EFI_ERROR (Status) || !PartitionValidMbr (Mbr, ParentBlockDev->LastBlock)) {
goto Done;
}
//
// We have a valid mbr - add each partition
//
for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
if (Mbr->Partition[Index].OSIndicator == 0x00 || UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) == 0) {
//
// Don't use null MBR entries
//
continue;
}
//
// Register this partition
//
if (PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE) {
Found = TRUE;
BlockDev = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]);
BlockDev->BlockSize = MBR_SIZE;
BlockDev->LastBlock = UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) - 1;
BlockDev->IoAlign = ParentBlockDev->IoAlign;
BlockDev->Logical = TRUE;
BlockDev->PartitionChecked = FALSE;
BlockDev->StartingPos = MultU64x32 (
UNPACK_INT32 (Mbr->Partition[Index].StartingLBA),
ParentBlockDev->BlockSize
);
BlockDev->ParentDevNo = ParentBlockDevNo;
PrivateData->BlockDeviceCount++;
}
}
Done:
ParentBlockDev->PartitionChecked = TRUE;
return Found;
}

View File

@ -26,6 +26,11 @@
BUILD_TARGETS = DEBUG|RELEASE
SKUID_IDENTIFIER = DEFAULT
[BuildOptions]
GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG
INTEL:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG
MSFT:RELEASE_*_*_CC_FLAGS = /D MDEPKG_NDEBUG
[LibraryClasses]
#
# Entry Point Libraries
@ -46,6 +51,14 @@
DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
[LibraryClasses.common.PEIM]
PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
###################################################################################################
#
# Components Section - list of the modules and components that will be processed by compilation
@ -66,4 +79,5 @@
###################################################################################################
[Components]
FatPkg/FatPei/FatPei.inf
FatPkg/EnhancedFatDxe/Fat.inf