From 2f4dfa84ac56d84935e086e91f292134b8074984 Mon Sep 17 00:00:00 2001 From: Jordan Justen Date: Fri, 1 Jul 2011 00:37:55 +0000 Subject: [PATCH] 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 Acked-by: Mark Doran Acked-by: Laszlo Ersek --- FatPkg/FatPei/FatLiteAccess.c | 527 +++++++++++++++++++++++++++++ FatPkg/FatPei/FatLiteApi.c | 611 ++++++++++++++++++++++++++++++++++ FatPkg/FatPei/FatLiteApi.h | 31 ++ FatPkg/FatPei/FatLiteFmt.h | 144 ++++++++ FatPkg/FatPei/FatLiteLib.c | 364 ++++++++++++++++++++ FatPkg/FatPei/FatLitePeim.h | 526 +++++++++++++++++++++++++++++ FatPkg/FatPei/FatPei.inf | 74 ++++ FatPkg/FatPei/Part.c | 466 ++++++++++++++++++++++++++ FatPkg/FatPkg.dsc | 14 + 9 files changed, 2757 insertions(+) create mode 100644 FatPkg/FatPei/FatLiteAccess.c create mode 100644 FatPkg/FatPei/FatLiteApi.c create mode 100644 FatPkg/FatPei/FatLiteApi.h create mode 100644 FatPkg/FatPei/FatLiteFmt.h create mode 100644 FatPkg/FatPei/FatLiteLib.c create mode 100644 FatPkg/FatPei/FatLitePeim.h create mode 100644 FatPkg/FatPei/FatPei.inf create mode 100644 FatPkg/FatPei/Part.c 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; +} diff --git a/FatPkg/FatPei/FatLiteApi.c b/FatPkg/FatPei/FatLiteApi.c new file mode 100644 index 0000000000..bf8158d94f --- /dev/null +++ b/FatPkg/FatPei/FatLiteApi.c @@ -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.
+ +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; + +} diff --git a/FatPkg/FatPei/FatLiteApi.h b/FatPkg/FatPei/FatLiteApi.h new file mode 100644 index 0000000000..d1ad277f98 --- /dev/null +++ b/FatPkg/FatPei/FatLiteApi.h @@ -0,0 +1,31 @@ +/** @file + Definitions for FAT recovery PEIM API functions + +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. + +**/ + +#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 diff --git a/FatPkg/FatPei/FatLiteFmt.h b/FatPkg/FatPei/FatLiteFmt.h new file mode 100644 index 0000000000..d4f26f3540 --- /dev/null +++ b/FatPkg/FatPei/FatLiteFmt.h @@ -0,0 +1,144 @@ +/** @file + FAT format data structures + +Copyright (c) 2006 - 2008, 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. + +**/ + +#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 diff --git a/FatPkg/FatPei/FatLiteLib.c b/FatPkg/FatPei/FatLiteLib.c new file mode 100644 index 0000000000..b5191b6706 --- /dev/null +++ b/FatPkg/FatPei/FatLiteLib.c @@ -0,0 +1,364 @@ +/** @file + General purpose supporting 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" + + +#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); +} diff --git a/FatPkg/FatPei/FatLitePeim.h b/FatPkg/FatPei/FatLitePeim.h new file mode 100644 index 0000000000..69429fe03a --- /dev/null +++ b/FatPkg/FatPei/FatLitePeim.h @@ -0,0 +1,526 @@ +/** @file + Data structures 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. + +**/ + +#ifndef _FAT_PEIM_H_ +#define _FAT_PEIM_H_ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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_ diff --git a/FatPkg/FatPei/FatPei.inf b/FatPkg/FatPei/FatPei.inf new file mode 100644 index 0000000000..a81d265f82 --- /dev/null +++ b/FatPkg/FatPei/FatPei.inf @@ -0,0 +1,74 @@ +## @file +# Lite Fat driver only used in Pei Phase. +# +# 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. +# +## + +[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 + + diff --git a/FatPkg/FatPei/Part.c b/FatPkg/FatPei/Part.c new file mode 100644 index 0000000000..1c1b2896bf --- /dev/null +++ b/FatPkg/FatPei/Part.c @@ -0,0 +1,466 @@ +/** @file + Routines supporting partition discovery and + logical device reading + +Copyright (c) 2006 - 2008, 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 +#include +#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; +} diff --git a/FatPkg/FatPkg.dsc b/FatPkg/FatPkg.dsc index cfb73f27f2..f8309717a6 100644 --- a/FatPkg/FatPkg.dsc +++ b/FatPkg/FatPkg.dsc @@ -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 -- 2.39.2