diff options
author | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
---|---|---|
committer | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/edk2/FatPkg/FatPei | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/edk2/FatPkg/FatPei')
-rw-r--r-- | roms/edk2/FatPkg/FatPei/Eltorito.c | 233 | ||||
-rw-r--r-- | roms/edk2/FatPkg/FatPei/FatLiteAccess.c | 521 | ||||
-rw-r--r-- | roms/edk2/FatPkg/FatPei/FatLiteApi.c | 675 | ||||
-rw-r--r-- | roms/edk2/FatPkg/FatPei/FatLiteApi.h | 25 | ||||
-rw-r--r-- | roms/edk2/FatPkg/FatPei/FatLiteFmt.h | 138 | ||||
-rw-r--r-- | roms/edk2/FatPkg/FatPei/FatLiteLib.c | 370 | ||||
-rw-r--r-- | roms/edk2/FatPkg/FatPei/FatLitePeim.h | 522 | ||||
-rw-r--r-- | roms/edk2/FatPkg/FatPei/FatPei.inf | 75 | ||||
-rw-r--r-- | roms/edk2/FatPkg/FatPei/FatPei.uni | 16 | ||||
-rw-r--r-- | roms/edk2/FatPkg/FatPei/FatPeiExtra.uni | 14 | ||||
-rw-r--r-- | roms/edk2/FatPkg/FatPei/Gpt.c | 545 | ||||
-rw-r--r-- | roms/edk2/FatPkg/FatPei/Mbr.c | 175 | ||||
-rw-r--r-- | roms/edk2/FatPkg/FatPei/Part.c | 104 |
13 files changed, 3413 insertions, 0 deletions
diff --git a/roms/edk2/FatPkg/FatPei/Eltorito.c b/roms/edk2/FatPkg/FatPei/Eltorito.c new file mode 100644 index 000000000..5fe0cb454 --- /dev/null +++ b/roms/edk2/FatPkg/FatPei/Eltorito.c @@ -0,0 +1,233 @@ +/** @file
+ Routines supporting partition discovery and
+ logical device reading
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <IndustryStandard/ElTorito.h>
+#include "FatLitePeim.h"
+
+/**
+ This function finds Eltorito partitions. Main algorithm
+ is ported from DXE partition driver.
+
+ @param[in] PrivateData The global memory map
+ @param[in] 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;
+
+}
diff --git a/roms/edk2/FatPkg/FatPei/FatLiteAccess.c b/roms/edk2/FatPkg/FatPei/FatLiteAccess.c new file mode 100644 index 000000000..a3f846dda --- /dev/null +++ b/roms/edk2/FatPkg/FatPei/FatLiteAccess.c @@ -0,0 +1,521 @@ +/** @file
+ FAT file system access routines for FAT recovery PEIM
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FatLitePeim.h"
+
+
+/**
+ Check if there is a valid FAT in the corresponding Block device
+ of the volume and if yes, fill in the relevant fields for the
+ volume structure. Note there should be a valid Block device number
+ already set.
+
+ @param PrivateData Global memory map for accessing global
+ variables.
+ @param Volume On input, the BlockDeviceNumber field of the
+ Volume should be a valid value. On successful
+ output, all fields except the VolumeNumber
+ field is initialized.
+
+ @retval EFI_SUCCESS A FAT is found and the volume structure is
+ initialized.
+ @retval EFI_NOT_FOUND There is no FAT on the corresponding device.
+ @retval EFI_DEVICE_ERROR There is something error while accessing device.
+
+**/
+EFI_STATUS
+FatGetBpbInfo (
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,
+ IN OUT PEI_FAT_VOLUME *Volume
+ )
+{
+ EFI_STATUS Status;
+ PEI_FAT_BOOT_SECTOR Bpb;
+ PEI_FAT_BOOT_SECTOR_EX BpbEx;
+ UINT32 Sectors;
+ UINT32 SectorsPerFat;
+ UINT32 RootDirSectors;
+ UINT64 FatLba;
+ UINT64 RootLba;
+ UINT64 FirstClusterLba;
+
+ //
+ // Read in the BPB
+ //
+ Status = FatReadDisk (
+ PrivateData,
+ Volume->BlockDeviceNo,
+ 0,
+ sizeof (PEI_FAT_BOOT_SECTOR_EX),
+ &BpbEx
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (
+ (UINT8 *) (&Bpb),
+ (UINT8 *) (&BpbEx),
+ sizeof (PEI_FAT_BOOT_SECTOR)
+ );
+
+ Volume->FatType = FatUnknown;
+
+ Sectors = Bpb.Sectors;
+ if (Sectors == 0) {
+ Sectors = Bpb.LargeSectors;
+ }
+
+ SectorsPerFat = Bpb.SectorsPerFat;
+ if (SectorsPerFat == 0) {
+ SectorsPerFat = BpbEx.LargeSectorsPerFat;
+ Volume->FatType = Fat32;
+ }
+ //
+ // Filter out those not a FAT
+ //
+ if (Bpb.Ia32Jump[0] != 0xe9 && Bpb.Ia32Jump[0] != 0xeb && Bpb.Ia32Jump[0] != 0x49) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Bpb.ReservedSectors == 0 || Bpb.NoFats == 0 || Sectors == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Bpb.SectorsPerCluster != 1 &&
+ Bpb.SectorsPerCluster != 2 &&
+ Bpb.SectorsPerCluster != 4 &&
+ Bpb.SectorsPerCluster != 8 &&
+ Bpb.SectorsPerCluster != 16 &&
+ Bpb.SectorsPerCluster != 32 &&
+ Bpb.SectorsPerCluster != 64 &&
+ Bpb.SectorsPerCluster != 128
+ ) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Volume->FatType == Fat32 && (SectorsPerFat == 0 || BpbEx.FsVersion != 0)) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Bpb.Media != 0xf0 &&
+ Bpb.Media != 0xf8 &&
+ Bpb.Media != 0xf9 &&
+ Bpb.Media != 0xfb &&
+ Bpb.Media != 0xfc &&
+ Bpb.Media != 0xfd &&
+ Bpb.Media != 0xfe &&
+ Bpb.Media != 0xff &&
+ //
+ // FujitsuFMR
+ //
+ Bpb.Media != 0x00 &&
+ Bpb.Media != 0x01 &&
+ Bpb.Media != 0xfa
+ ) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Volume->FatType != Fat32 && Bpb.RootEntries == 0) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // If this is fat32, refuse to mount mirror-disabled volumes
+ //
+ if (Volume->FatType == Fat32 && ((BpbEx.ExtendedFlags & 0x80) != 0)) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Fill in the volume structure fields
+ // (Sectors & SectorsPerFat is computed earlier already)
+ //
+ Volume->ClusterSize = Bpb.SectorSize * Bpb.SectorsPerCluster;
+ Volume->RootEntries = Bpb.RootEntries;
+ Volume->SectorSize = Bpb.SectorSize;
+
+ RootDirSectors = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (Volume->SectorSize - 1)) / Volume->SectorSize;
+
+ FatLba = Bpb.ReservedSectors;
+ RootLba = Bpb.NoFats * SectorsPerFat + FatLba;
+ FirstClusterLba = RootLba + RootDirSectors;
+
+ Volume->VolumeSize = MultU64x32 (Sectors, Volume->SectorSize);
+ Volume->FatPos = MultU64x32 (FatLba, Volume->SectorSize);
+ Volume->RootDirPos = MultU64x32 (RootLba, Volume->SectorSize);
+ Volume->FirstClusterPos = MultU64x32 (FirstClusterLba, Volume->SectorSize);
+ Volume->MaxCluster = (UINT32) (Sectors - FirstClusterLba) / Bpb.SectorsPerCluster;
+ Volume->RootDirCluster = BpbEx.RootDirFirstCluster;
+
+ //
+ // If this is not a fat32, determine if it's a fat16 or fat12
+ //
+ if (Volume->FatType != Fat32) {
+
+ if (Volume->MaxCluster >= 65525) {
+ return EFI_NOT_FOUND;
+ }
+
+ Volume->FatType = Volume->MaxCluster < 4085 ? Fat12 : Fat16;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Gets the next cluster in the cluster chain
+
+ @param PrivateData Global memory map for accessing global variables
+ @param Volume The volume
+ @param Cluster The cluster
+ @param NextCluster The cluster number of the next cluster
+
+ @retval EFI_SUCCESS The address is got
+ @retval EFI_INVALID_PARAMETER ClusterNo exceeds the MaxCluster of the volume.
+ @retval EFI_DEVICE_ERROR Read disk error
+
+**/
+EFI_STATUS
+FatGetNextCluster (
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,
+ IN PEI_FAT_VOLUME *Volume,
+ IN UINT32 Cluster,
+ OUT UINT32 *NextCluster
+ )
+{
+ EFI_STATUS Status;
+ UINT64 FatEntryPos;
+ UINT32 Dummy;
+
+ *NextCluster = 0;
+
+ if (Volume->FatType == Fat32) {
+ FatEntryPos = Volume->FatPos + MultU64x32 (4, Cluster);
+
+ Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 4, NextCluster);
+ *NextCluster &= 0x0fffffff;
+
+ //
+ // Pad high bits for our FAT_CLUSTER_... macro definitions to work
+ //
+ if ((*NextCluster) >= 0x0ffffff7) {
+ *NextCluster |= (-1 &~0xf);
+ }
+
+ } else if (Volume->FatType == Fat16) {
+ FatEntryPos = Volume->FatPos + MultU64x32 (2, Cluster);
+
+ Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);
+
+ //
+ // Pad high bits for our FAT_CLUSTER_... macro definitions to work
+ //
+ if ((*NextCluster) >= 0xfff7) {
+ *NextCluster |= (-1 &~0xf);
+ }
+
+ } else {
+ FatEntryPos = Volume->FatPos + DivU64x32Remainder (MultU64x32 (3, Cluster), 2, &Dummy);
+
+ Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);
+
+ if ((Cluster & 0x01) != 0) {
+ *NextCluster = (*NextCluster) >> 4;
+ } else {
+ *NextCluster = (*NextCluster) & 0x0fff;
+ }
+ //
+ // Pad high bits for our FAT_CLUSTER_... macro definitions to work
+ //
+ if ((*NextCluster) >= 0x0ff7) {
+ *NextCluster |= (-1 &~0xf);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ Set a file's CurrentPos and CurrentCluster, then compute StraightReadAmount.
+
+ @param PrivateData the global memory map
+ @param File the file
+ @param Pos the Position which is offset from the file's
+ CurrentPos
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Pos is beyond file's size.
+ @retval EFI_DEVICE_ERROR Something error while accessing media.
+
+**/
+EFI_STATUS
+FatSetFilePos (
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,
+ IN PEI_FAT_FILE *File,
+ IN UINT32 Pos
+ )
+{
+ EFI_STATUS Status;
+ UINT32 AlignedPos;
+ UINT32 Offset;
+ UINT32 Cluster;
+ UINT32 PrevCluster;
+
+ if (File->IsFixedRootDir) {
+
+ if (Pos >= MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ File->CurrentPos += Pos;
+ File->StraightReadAmount = (UINT32) (MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos);
+
+ } else {
+
+ DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);
+ AlignedPos = (UINT32) File->CurrentPos - (UINT32) Offset;
+
+ while
+ (
+ !FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster) &&
+ AlignedPos + File->Volume->ClusterSize <= File->CurrentPos + Pos
+ ) {
+ AlignedPos += File->Volume->ClusterSize;
+ Status = FatGetNextCluster (
+ PrivateData,
+ File->Volume,
+ File->CurrentCluster,
+ &File->CurrentCluster
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ if (FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ File->CurrentPos += Pos;
+ //
+ // Calculate the amount of consecutive cluster occupied by the file.
+ // FatReadFile() will use it to read these blocks once.
+ //
+ File->StraightReadAmount = 0;
+ Cluster = File->CurrentCluster;
+ while (!FAT_CLUSTER_FUNCTIONAL (Cluster)) {
+ File->StraightReadAmount += File->Volume->ClusterSize;
+ PrevCluster = Cluster;
+ Status = FatGetNextCluster (PrivateData, File->Volume, Cluster, &Cluster);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Cluster != PrevCluster + 1) {
+ break;
+ }
+ }
+
+ DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);
+ File->StraightReadAmount -= (UINT32) Offset;
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Reads file data. Updates the file's CurrentPos.
+
+ @param PrivateData Global memory map for accessing global variables
+ @param File The file.
+ @param Size The amount of data to read.
+ @param Buffer The buffer storing the data.
+
+ @retval EFI_SUCCESS The data is read.
+ @retval EFI_INVALID_PARAMETER File is invalid.
+ @retval EFI_DEVICE_ERROR Something error while accessing media.
+
+**/
+EFI_STATUS
+FatReadFile (
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,
+ IN PEI_FAT_FILE *File,
+ IN UINTN Size,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *BufferPtr;
+ UINT32 Offset;
+ UINT64 PhysicalAddr;
+ UINTN Amount;
+
+ BufferPtr = Buffer;
+
+ if (File->IsFixedRootDir) {
+ //
+ // This is the fixed root dir in FAT12 and FAT16
+ //
+ if (File->CurrentPos + Size > File->Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = FatReadDisk (
+ PrivateData,
+ File->Volume->BlockDeviceNo,
+ File->Volume->RootDirPos + File->CurrentPos,
+ Size,
+ Buffer
+ );
+ File->CurrentPos += (UINT32) Size;
+ return Status;
+
+ } else {
+
+ if ((File->Attributes & FAT_ATTR_DIRECTORY) == 0) {
+ Size = Size < (File->FileSize - File->CurrentPos) ? Size : (File->FileSize - File->CurrentPos);
+ }
+ //
+ // This is a normal cluster based file
+ //
+ while (Size != 0) {
+ DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);
+ PhysicalAddr = File->Volume->FirstClusterPos + MultU64x32 (File->Volume->ClusterSize, File->CurrentCluster - 2);
+
+ Amount = File->StraightReadAmount;
+ Amount = Size > Amount ? Amount : Size;
+ Status = FatReadDisk (
+ PrivateData,
+ File->Volume->BlockDeviceNo,
+ PhysicalAddr + Offset,
+ Amount,
+ BufferPtr
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Advance the file's current pos and current cluster
+ //
+ FatSetFilePos (PrivateData, File, (UINT32) Amount);
+
+ BufferPtr += Amount;
+ Size -= Amount;
+ }
+
+ return EFI_SUCCESS;
+ }
+}
+
+
+/**
+ This function reads the next item in the parent directory and
+ initializes the output parameter SubFile (CurrentPos is initialized to 0).
+ The function updates the CurrentPos of the parent dir to after the item read.
+ If no more items were found, the function returns EFI_NOT_FOUND.
+
+ @param PrivateData Global memory map for accessing global variables
+ @param ParentDir The parent directory.
+ @param SubFile The File structure containing the sub file that
+ is caught.
+
+ @retval EFI_SUCCESS The next sub file is obtained.
+ @retval EFI_INVALID_PARAMETER The ParentDir is not a directory.
+ @retval EFI_NOT_FOUND No more sub file exists.
+ @retval EFI_DEVICE_ERROR Something error while accessing media.
+
+**/
+EFI_STATUS
+FatReadNextDirectoryEntry (
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,
+ IN PEI_FAT_FILE *ParentDir,
+ OUT PEI_FAT_FILE *SubFile
+ )
+{
+ EFI_STATUS Status;
+ FAT_DIRECTORY_ENTRY DirEntry;
+ CHAR16 *Pos;
+ CHAR16 BaseName[9];
+ CHAR16 Ext[4];
+
+ ZeroMem ((UINT8 *) SubFile, sizeof (PEI_FAT_FILE));
+
+ //
+ // Pick a valid directory entry
+ //
+ while (1) {
+ //
+ // Read one entry
+ //
+ Status = FatReadFile (PrivateData, ParentDir, 32, &DirEntry);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // We only search for *FILE* in root directory
+ // Long file name entry is *NOT* supported
+ //
+ if (((DirEntry.Attributes & FAT_ATTR_DIRECTORY) == FAT_ATTR_DIRECTORY) || (DirEntry.Attributes == FAT_ATTR_LFN)) {
+ continue;
+ }
+ //
+ // if this is a terminator dir entry, just return EFI_NOT_FOUND
+ //
+ if (DirEntry.FileName[0] == EMPTY_ENTRY_MARK) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // If this not an invalid entry neither an empty entry, this is what we want.
+ // otherwise we will start a new loop to continue to find something meaningful
+ //
+ if ((UINT8) DirEntry.FileName[0] != DELETE_ENTRY_MARK) {
+ break;
+ }
+ }
+ //
+ // fill in the output parameter
+ //
+ EngFatToStr (8, DirEntry.FileName, BaseName);
+ EngFatToStr (3, DirEntry.FileName + 8, Ext);
+
+ Pos = (UINT16 *) SubFile->FileName;
+ SetMem ((UINT8 *) Pos, FAT_MAX_FILE_NAME_LENGTH, 0);
+ CopyMem ((UINT8 *) Pos, (UINT8 *) BaseName, 2 * (StrLen (BaseName) + 1));
+
+ if (Ext[0] != 0) {
+ Pos += StrLen (BaseName);
+ *Pos = '.';
+ Pos++;
+ CopyMem ((UINT8 *) Pos, (UINT8 *) Ext, 2 * (StrLen (Ext) + 1));
+ }
+
+ SubFile->Attributes = DirEntry.Attributes;
+ SubFile->CurrentCluster = DirEntry.FileCluster;
+ if (ParentDir->Volume->FatType == Fat32) {
+ SubFile->CurrentCluster |= DirEntry.FileClusterHigh << 16;
+ }
+
+ SubFile->CurrentPos = 0;
+ SubFile->FileSize = DirEntry.FileSize;
+ SubFile->StartingCluster = SubFile->CurrentCluster;
+ SubFile->Volume = ParentDir->Volume;
+
+ //
+ // in Pei phase, time parameters do not need to be filled for minimum use.
+ //
+ return Status;
+}
diff --git a/roms/edk2/FatPkg/FatPei/FatLiteApi.c b/roms/edk2/FatPkg/FatPei/FatLiteApi.c new file mode 100644 index 000000000..d07422ba9 --- /dev/null +++ b/roms/edk2/FatPkg/FatPei/FatLiteApi.c @@ -0,0 +1,675 @@ +/** @file
+ FAT recovery PEIM entry point, Ppi Functions and FAT Api functions.
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FatLitePeim.h"
+
+PEI_FAT_PRIVATE_DATA *mPrivateData = NULL;
+
+/**
+ 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
+ );
+
+
+/**
+ Discover all the block I/O devices to find the FAT volume.
+
+ @param PrivateData Global memory map for accessing global
+ variables.
+ @param BlockIo2 Boolean to show whether using BlockIo2 or BlockIo
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+UpdateBlocksAndVolumes (
+ IN OUT PEI_FAT_PRIVATE_DATA *PrivateData,
+ IN BOOLEAN BlockIo2
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_PPI_DESCRIPTOR *TempPpiDescriptor;
+ UINTN BlockIoPpiInstance;
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2Ppi;
+ UINTN NumberBlockDevices;
+ UINTN Index;
+ EFI_PEI_BLOCK_IO_MEDIA Media;
+ EFI_PEI_BLOCK_IO2_MEDIA Media2;
+ PEI_FAT_VOLUME Volume;
+ EFI_PEI_SERVICES **PeiServices;
+
+ PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer ();
+ BlockIo2Ppi = NULL;
+ BlockIoPpi = NULL;
+ //
+ // 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++) {
+ if (BlockIo2) {
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiVirtualBlockIo2PpiGuid,
+ BlockIoPpiInstance,
+ &TempPpiDescriptor,
+ (VOID **) &BlockIo2Ppi
+ );
+ } else {
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiVirtualBlockIoPpiGuid,
+ BlockIoPpiInstance,
+ &TempPpiDescriptor,
+ (VOID **) &BlockIoPpi
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ //
+ // Done with all Block Io Ppis
+ //
+ break;
+ }
+
+ if (BlockIo2) {
+ Status = BlockIo2Ppi->GetNumberOfBlockDevices (
+ PeiServices,
+ BlockIo2Ppi,
+ &NumberBlockDevices
+ );
+ } else {
+ Status = BlockIoPpi->GetNumberOfBlockDevices (
+ PeiServices,
+ BlockIoPpi,
+ &NumberBlockDevices
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ for (Index = 1; Index <= NumberBlockDevices && PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE; Index++) {
+
+ if (BlockIo2) {
+ Status = BlockIo2Ppi->GetBlockDeviceMediaInfo (
+ PeiServices,
+ BlockIo2Ppi,
+ Index,
+ &Media2
+ );
+ if (EFI_ERROR (Status) || !Media2.MediaPresent) {
+ continue;
+ }
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo2 = BlockIo2Ppi;
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].InterfaceType = Media2.InterfaceType;
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock = Media2.LastBlock;
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize = Media2.BlockSize;
+ } else {
+ Status = BlockIoPpi->GetBlockDeviceMediaInfo (
+ PeiServices,
+ BlockIoPpi,
+ Index,
+ &Media
+ );
+ if (EFI_ERROR (Status) || !Media.MediaPresent) {
+ continue;
+ }
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo = BlockIoPpi;
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].DevType = Media.DeviceType;
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock = Media.LastBlock;
+ PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize = (UINT32) Media.BlockSize;
+ }
+
+ 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].PhysicalDevNo = (UINT8) Index;
+ 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
+ )
+{
+ if (CompareGuid (NotifyDescriptor->Guid, &gEfiPeiVirtualBlockIo2PpiGuid)) {
+ UpdateBlocksAndVolumes (mPrivateData, TRUE);
+ } else {
+ UpdateBlocksAndVolumes (mPrivateData, FALSE);
+ }
+ 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_MEMORY_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, TRUE);
+ UpdateBlocksAndVolumes (PrivateData, FALSE);
+
+ //
+ // PrivateData is allocated now, set it to the module variable
+ //
+ mPrivateData = PrivateData;
+
+ //
+ // Installs Block Io Ppi notification function
+ //
+ PrivateData->NotifyDescriptor[0].Flags =
+ (
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK
+ );
+ PrivateData->NotifyDescriptor[0].Guid = &gEfiPeiVirtualBlockIoPpiGuid;
+ PrivateData->NotifyDescriptor[0].Notify = BlockIoNotifyEntry;
+ PrivateData->NotifyDescriptor[1].Flags =
+ (
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |
+ EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
+ );
+ PrivateData->NotifyDescriptor[1].Guid = &gEfiPeiVirtualBlockIo2PpiGuid;
+ PrivateData->NotifyDescriptor[1].Notify = BlockIoNotifyEntry;
+ return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor[0]);
+}
+
+
+/**
+ 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, (CHAR16 *)PcdGetPtr(PcdRecoveryFileName), &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 ((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, (CHAR16 *)PcdGetPtr(PcdRecoveryFileName), &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) {
+ if (PrivateData->BlockDevice[BlockDeviceNo].BlockIo2 != NULL) {
+ switch (PrivateData->BlockDevice[BlockDeviceNo].InterfaceType) {
+ case MSG_ATAPI_DP:
+ CopyGuid (CapsuleType, &gRecoveryOnFatIdeDiskGuid);
+ break;
+
+ case MSG_USB_DP:
+ CopyGuid (CapsuleType, &gRecoveryOnFatUsbDiskGuid);
+ break;
+
+ case MSG_NVME_NAMESPACE_DP:
+ CopyGuid (CapsuleType, &gRecoveryOnFatNvmeDiskGuid);
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (PrivateData->BlockDevice[BlockDeviceNo].BlockIo != NULL) {
+ 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 ((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, (CHAR16 *)PcdGetPtr(PcdRecoveryFileName), &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 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 occurred 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
+ //
+ ZeroMem (&Parent, sizeof (PEI_FAT_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) {
+ //
+ // Compare whether the file name is recovery file name.
+ //
+ if (EngStriColl (PrivateData, FileName, File->FileName)) {
+ break;
+ }
+
+ Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get the recovery file, set its file position to 0.
+ //
+ if (File->StartingCluster != 0) {
+ Status = FatSetFilePos (PrivateData, File, 0);
+ }
+
+ *Handle = File;
+
+ return EFI_SUCCESS;
+
+}
diff --git a/roms/edk2/FatPkg/FatPei/FatLiteApi.h b/roms/edk2/FatPkg/FatPei/FatLiteApi.h new file mode 100644 index 000000000..2d03fe17e --- /dev/null +++ b/roms/edk2/FatPkg/FatPei/FatLiteApi.h @@ -0,0 +1,25 @@ +/** @file
+ Definitions for FAT recovery PEIM API functions
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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/roms/edk2/FatPkg/FatPei/FatLiteFmt.h b/roms/edk2/FatPkg/FatPei/FatLiteFmt.h new file mode 100644 index 000000000..876874d6b --- /dev/null +++ b/roms/edk2/FatPkg/FatPei/FatLiteFmt.h @@ -0,0 +1,138 @@ +/** @file
+ FAT format data structures
+
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#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 ((MAX_UINT32 &~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/roms/edk2/FatPkg/FatPei/FatLiteLib.c b/roms/edk2/FatPkg/FatPei/FatLiteLib.c new file mode 100644 index 000000000..3d43e0b87 --- /dev/null +++ b/roms/edk2/FatPkg/FatPei/FatLiteLib.c @@ -0,0 +1,370 @@ +/** @file
+ General purpose supporting routines for FAT recovery PEIM
+
+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FatLitePeim.h"
+
+
+#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);
+ //
+ if (BlockDev->BlockIo2 != NULL) {
+ Status = BlockDev->BlockIo2->ReadBlocks (
+ (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
+ BlockDev->BlockIo2,
+ BlockDev->PhysicalDevNo,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+ } else {
+ 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) {
+ if (*Fat == ' ') {
+ break;
+ }
+ *String = *Fat;
+ String += 1;
+ Fat += 1;
+ FatSize -= 1;
+ }
+
+ *String = 0;
+}
+
+
+/**
+ 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/roms/edk2/FatPkg/FatPei/FatLitePeim.h b/roms/edk2/FatPkg/FatPei/FatLitePeim.h new file mode 100644 index 000000000..0c3c69853 --- /dev/null +++ b/roms/edk2/FatPkg/FatPei/FatLitePeim.h @@ -0,0 +1,522 @@ +/** @file
+ Data structures for FAT recovery PEIM
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FAT_PEIM_H_
+#define _FAT_PEIM_H_
+
+#include <PiPei.h>
+
+#include <Guid/RecoveryDevice.h>
+#include <Ppi/BlockIo.h>
+#include <Ppi/BlockIo2.h>
+#include <Ppi/DeviceRecoveryModule.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/PeiServicesLib.h>
+
+#include "FatLiteApi.h"
+#include "FatLiteFmt.h"
+
+//
+// Definitions
+//
+
+#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_MEMORY_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;
+ UINT8 InterfaceType;
+ //
+ // EFI_PEI_READ_BLOCKS ReadFunc;
+ //
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIo;
+ EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2;
+ 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[2];
+
+ 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 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 occurred 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/roms/edk2/FatPkg/FatPei/FatPei.inf b/roms/edk2/FatPkg/FatPei/FatPei.inf new file mode 100644 index 000000000..3de7e7ec7 --- /dev/null +++ b/roms/edk2/FatPkg/FatPei/FatPei.inf @@ -0,0 +1,75 @@ +## @file
+# Lite Fat driver only used in Pei Phase.
+#
+# Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FatPei
+ MODULE_UNI_FILE = FatPei.uni
+ 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 EBC
+#
+
+[Sources]
+ Mbr.c
+ Gpt.c
+ Eltorito.c
+ Part.c
+ FatLiteApi.c
+ FatLiteLib.c
+ FatLiteAccess.c
+ FatLiteApi.h
+ FatLitePeim.h
+ FatLiteFmt.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ PcdLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ PeimEntryPoint
+ BaseLib
+ DebugLib
+ PeiServicesTablePointerLib
+ PeiServicesLib
+
+
+[Guids]
+ gRecoveryOnFatUsbDiskGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gRecoveryOnFatIdeDiskGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gRecoveryOnFatFloppyDiskGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gRecoveryOnFatNvmeDiskGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiPartTypeUnusedGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+
+
+[Ppis]
+ gEfiPeiVirtualBlockIoPpiGuid ## SOMETIMES_CONSUMES PPI_NOTIFY
+ gEfiPeiVirtualBlockIo2PpiGuid ## SOMETIMES_CONSUMES PPI_NOTIFY
+ gEfiPeiDeviceRecoveryModulePpiGuid ## SOMETIMES_PRODUCES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdRecoveryFileName ## CONSUMES
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ FatPeiExtra.uni
diff --git a/roms/edk2/FatPkg/FatPei/FatPei.uni b/roms/edk2/FatPkg/FatPei/FatPei.uni new file mode 100644 index 000000000..8d8fc3d97 --- /dev/null +++ b/roms/edk2/FatPkg/FatPei/FatPei.uni @@ -0,0 +1,16 @@ +// /** @file
+// Lite Fat driver only used in Pei Phase.
+//
+// Lite Fat driver only used in Pei Phase.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Lite Fat driver only used in Pei Phase."
+
+#string STR_MODULE_DESCRIPTION #language en-US "Lite Fat driver only used in Pei Phase."
+
diff --git a/roms/edk2/FatPkg/FatPei/FatPeiExtra.uni b/roms/edk2/FatPkg/FatPei/FatPeiExtra.uni new file mode 100644 index 000000000..b3a735e4b --- /dev/null +++ b/roms/edk2/FatPkg/FatPei/FatPeiExtra.uni @@ -0,0 +1,14 @@ +// /** @file
+// FatPei Localized Strings and Content
+//
+// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"FAT File System Lite PEI Module"
+
+
diff --git a/roms/edk2/FatPkg/FatPei/Gpt.c b/roms/edk2/FatPkg/FatPei/Gpt.c new file mode 100644 index 000000000..4028c535f --- /dev/null +++ b/roms/edk2/FatPkg/FatPei/Gpt.c @@ -0,0 +1,545 @@ +/** @file
+ Routines supporting partition discovery and
+ logical device reading
+
+Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <IndustryStandard/Mbr.h>
+#include <Uefi/UefiGpt.h>
+#include <Library/BaseLib.h>
+#include "FatLitePeim.h"
+
+//
+// Assumption: 'a' and 'blocksize' are all UINT32 or UINT64.
+// If 'a' and 'blocksize' are not the same type, should use DivU64xU32 to calculate.
+//
+#define EFI_SIZE_TO_BLOCKS(a, blocksize) (((a) / (blocksize)) + (((a) % (blocksize)) ? 1 : 0))
+
+//
+// GPT Partition Entry Status
+//
+typedef struct {
+ BOOLEAN OutOfRange;
+ BOOLEAN Overlap;
+ BOOLEAN OsSpecific;
+} EFI_PARTITION_ENTRY_STATUS;
+
+/**
+ Check if the CRC field in the Partition table header is valid.
+
+ @param[in] PartHeader Partition table header structure
+
+ @retval TRUE the CRC is valid
+ @retval FALSE the CRC is invalid
+
+**/
+BOOLEAN
+PartitionCheckGptHeaderCRC (
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader
+ )
+{
+ UINT32 GptHdrCrc;
+ UINT32 Crc;
+
+ GptHdrCrc = PartHeader->Header.CRC32;
+
+ //
+ // Set CRC field to zero when doing calculation
+ //
+ PartHeader->Header.CRC32 = 0;
+
+ Crc = CalculateCrc32 (PartHeader, PartHeader->Header.HeaderSize);
+
+ //
+ // Restore Header CRC
+ //
+ PartHeader->Header.CRC32 = GptHdrCrc;
+
+ return (GptHdrCrc == Crc);
+}
+
+
+/**
+ Check if the CRC field in the Partition table header is valid
+ for Partition entry array.
+
+ @param[in] PartHeader Partition table header structure
+ @param[in] PartEntry The partition entry array
+
+ @retval TRUE the CRC is valid
+ @retval FALSE the CRC is invalid
+
+**/
+BOOLEAN
+PartitionCheckGptEntryArrayCRC (
+ IN EFI_PARTITION_TABLE_HEADER *PartHeader,
+ IN EFI_PARTITION_ENTRY *PartEntry
+ )
+{
+ UINT32 Crc;
+ UINTN Size;
+
+ Size = (UINTN)MultU64x32(PartHeader->NumberOfPartitionEntries, PartHeader->SizeOfPartitionEntry);
+ Crc = CalculateCrc32 (PartEntry, Size);
+
+ return (BOOLEAN) (PartHeader->PartitionEntryArrayCRC32 == Crc);
+}
+
+/**
+ The function is used for valid GPT table. Both for Primary and Backup GPT header.
+
+ @param[in] PrivateData The global memory map
+ @param[in] ParentBlockDevNo The parent block device
+ @param[in] IsPrimaryHeader Indicate to which header will be checked.
+ @param[in] PartHdr Stores the partition table that is read
+
+ @retval TRUE The partition table is valid
+ @retval FALSE The partition table is not valid
+
+**/
+BOOLEAN
+PartitionCheckGptHeader (
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,
+ IN UINTN ParentBlockDevNo,
+ IN BOOLEAN IsPrimaryHeader,
+ IN EFI_PARTITION_TABLE_HEADER *PartHdr
+ )
+{
+ PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
+ EFI_PEI_LBA Lba;
+ EFI_PEI_LBA AlternateLba;
+ EFI_PEI_LBA EntryArrayLastLba;
+
+ UINT64 PartitionEntryArraySize;
+ UINT64 PartitionEntryBlockNumb;
+ UINT32 EntryArraySizeRemainder;
+
+ ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
+
+ if (IsPrimaryHeader) {
+ Lba = PRIMARY_PART_HEADER_LBA;
+ AlternateLba = ParentBlockDev->LastBlock;
+ } else {
+ Lba = ParentBlockDev->LastBlock;
+ AlternateLba = PRIMARY_PART_HEADER_LBA;
+ }
+
+ if ( (PartHdr->Header.Signature != EFI_PTAB_HEADER_ID) ||
+ (PartHdr->Header.Revision != 0x00010000) ||
+ (PartHdr->Header.HeaderSize < 92) ||
+ (PartHdr->Header.HeaderSize > ParentBlockDev->BlockSize) ||
+ (!PartitionCheckGptHeaderCRC (PartHdr)) ||
+ (PartHdr->Header.Reserved != 0)
+ ) {
+ DEBUG ((DEBUG_ERROR, "Invalid efi partition table header\n"));
+ return FALSE;
+ }
+
+ //
+ // | Block0 | Block1 |Block2 ~ FirstUsableLBA - 1|FirstUsableLBA, ... ,LastUsableLBA|LastUsableLBA+1 ~ LastBlock-1| LastBlock |
+ // |Protective MBR|Primary Header|Entry Array(At Least 16384)| Partition | Entry Array(At Least 16384) |BackUp Header|
+ //
+ // 1. Protective MBR is fixed at Block 0.
+ // 2. Primary Header is fixed at Block 1.
+ // 3. Backup Header is fixed at LastBlock.
+ // 4. Must be remain 128*128 bytes for primary entry array.
+ // 5. Must be remain 128*128 bytes for backup entry array.
+ // 6. SizeOfPartitionEntry must be equals to 128 * 2^n.
+ //
+ if ( (PartHdr->MyLBA != Lba) ||
+ (PartHdr->AlternateLBA != AlternateLba) ||
+ (PartHdr->FirstUsableLBA < 2 + EFI_SIZE_TO_BLOCKS (EFI_GPT_PART_ENTRY_MIN_SIZE, ParentBlockDev->BlockSize)) ||
+ (PartHdr->LastUsableLBA > ParentBlockDev->LastBlock - 1 - EFI_SIZE_TO_BLOCKS (EFI_GPT_PART_ENTRY_MIN_SIZE, ParentBlockDev->BlockSize)) ||
+ (PartHdr->FirstUsableLBA > PartHdr->LastUsableLBA) ||
+ (PartHdr->PartitionEntryLBA < 2) ||
+ (PartHdr->PartitionEntryLBA > ParentBlockDev->LastBlock - 1) ||
+ (PartHdr->PartitionEntryLBA >= PartHdr->FirstUsableLBA && PartHdr->PartitionEntryLBA <= PartHdr->LastUsableLBA) ||
+ (PartHdr->SizeOfPartitionEntry%128 != 0) ||
+ (PartHdr->SizeOfPartitionEntry != sizeof (EFI_PARTITION_ENTRY))
+ ) {
+ DEBUG ((DEBUG_ERROR, "Invalid efi partition table header\n"));
+ return FALSE;
+ }
+
+ //
+ // Ensure the NumberOfPartitionEntries * SizeOfPartitionEntry doesn't overflow.
+ //
+ if (PartHdr->NumberOfPartitionEntries > DivU64x32 (MAX_UINTN, PartHdr->SizeOfPartitionEntry)) {
+ DEBUG ((DEBUG_ERROR, "Memory overflow in GPT Entry Array\n"));
+ return FALSE;
+ }
+
+ PartitionEntryArraySize = MultU64x32 (PartHdr->NumberOfPartitionEntries, PartHdr->SizeOfPartitionEntry);
+ EntryArraySizeRemainder = 0;
+ PartitionEntryBlockNumb = DivU64x32Remainder (PartitionEntryArraySize, ParentBlockDev->BlockSize, &EntryArraySizeRemainder);
+ if (EntryArraySizeRemainder != 0) {
+ PartitionEntryBlockNumb++;
+ }
+
+ if (IsPrimaryHeader) {
+ EntryArrayLastLba = PartHdr->FirstUsableLBA;
+ } else {
+ EntryArrayLastLba = ParentBlockDev->LastBlock;
+ }
+
+ //
+ // Make sure partition entry array not overlaps with partition area or the LastBlock.
+ //
+ if (PartHdr->PartitionEntryLBA + PartitionEntryBlockNumb > EntryArrayLastLba) {
+ DEBUG ((DEBUG_ERROR, "GPT Partition Entry Array Error!\n"));
+ DEBUG ((DEBUG_ERROR, "PartitionEntryArraySize = %lu.\n", PartitionEntryArraySize));
+ DEBUG ((DEBUG_ERROR, "PartitionEntryLBA = %lu.\n", PartHdr->PartitionEntryLBA));
+ DEBUG ((DEBUG_ERROR, "PartitionEntryBlockNumb = %lu.\n", PartitionEntryBlockNumb));
+ DEBUG ((DEBUG_ERROR, "EntryArrayLastLba = %lu.\n", EntryArrayLastLba));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ This function is used to verify each partition in block device.
+
+ @param[in] PrivateData The global memory map
+ @param[in] ParentBlockDevNo The parent block device
+ @param[in] PartHdr Stores the partition table that is read
+
+ @retval TRUE The partition is valid
+ @retval FALSE The partition is not valid
+
+**/
+BOOLEAN
+PartitionCheckGptEntryArray (
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,
+ IN UINTN ParentBlockDevNo,
+ IN EFI_PARTITION_TABLE_HEADER *PartHdr
+ )
+{
+ EFI_STATUS Status;
+ PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
+ PEI_FAT_BLOCK_DEVICE *BlockDevPtr;
+
+ UINT64 PartitionEntryArraySize;
+ UINT64 PartitionEntryBlockNumb;
+ UINT32 EntryArraySizeRemainder;
+
+ EFI_PARTITION_ENTRY *PartitionEntryBuffer;
+ EFI_PARTITION_ENTRY_STATUS *PartitionEntryStatus;
+
+ BOOLEAN Found;
+ EFI_LBA StartingLBA;
+ EFI_LBA EndingLBA;
+ UINTN Index;
+ UINTN Index1;
+ UINTN Index2;
+ EFI_PARTITION_ENTRY *Entry;
+
+ PartitionEntryBuffer = NULL;
+ PartitionEntryStatus = NULL;
+
+ ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
+ Found = FALSE;
+
+ PartitionEntryArraySize = MultU64x32 (PartHdr->NumberOfPartitionEntries, PartHdr->SizeOfPartitionEntry);
+ EntryArraySizeRemainder = 0;
+ PartitionEntryBlockNumb = DivU64x32Remainder (PartitionEntryArraySize, ParentBlockDev->BlockSize, &EntryArraySizeRemainder);
+ if (EntryArraySizeRemainder != 0) {
+ PartitionEntryBlockNumb++;
+ }
+ PartitionEntryArraySize = MultU64x32 (PartitionEntryBlockNumb, ParentBlockDev->BlockSize);
+
+ PartitionEntryBuffer = (EFI_PARTITION_ENTRY *) AllocatePages (EFI_SIZE_TO_PAGES ((UINTN)PartitionEntryArraySize));
+ if (PartitionEntryBuffer == NULL) {
+ DEBUG ((DEBUG_ERROR, "Allocate memory error!\n"));
+ goto EXIT;
+ }
+
+ PartitionEntryStatus = (EFI_PARTITION_ENTRY_STATUS *) AllocatePages (EFI_SIZE_TO_PAGES (PartHdr->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS)));
+ if (PartitionEntryStatus == NULL) {
+ DEBUG ((DEBUG_ERROR, "Allocate memory error!\n"));
+ goto EXIT;
+ }
+ ZeroMem (PartitionEntryStatus, PartHdr->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS));
+
+ Status = FatReadBlock (
+ PrivateData,
+ ParentBlockDevNo,
+ PartHdr->PartitionEntryLBA,
+ (UINTN)PartitionEntryArraySize,
+ PartitionEntryBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Read partition entry array error!\n"));
+ goto EXIT;
+ }
+
+ if (!PartitionCheckGptEntryArrayCRC (PartHdr, PartitionEntryBuffer)) {
+ DEBUG ((DEBUG_ERROR, "Partition entries CRC check fail\n"));
+ goto EXIT;
+ }
+
+ for (Index1 = 0; Index1 < PartHdr->NumberOfPartitionEntries; Index1++) {
+ Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartitionEntryBuffer + Index1 * PartHdr->SizeOfPartitionEntry);
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
+ continue;
+ }
+
+ StartingLBA = Entry->StartingLBA;
+ EndingLBA = Entry->EndingLBA;
+ if (StartingLBA > EndingLBA ||
+ StartingLBA < PartHdr->FirstUsableLBA ||
+ StartingLBA > PartHdr->LastUsableLBA ||
+ EndingLBA < PartHdr->FirstUsableLBA ||
+ EndingLBA > PartHdr->LastUsableLBA
+ ) {
+ PartitionEntryStatus[Index1].OutOfRange = TRUE;
+ continue;
+ }
+
+ if ((Entry->Attributes & BIT1) != 0) {
+ //
+ // If Bit 1 is set, this indicate that this is an OS specific GUID partition.
+ //
+ PartitionEntryStatus[Index1].OsSpecific = TRUE;
+ }
+
+ for (Index2 = Index1 + 1; Index2 < PartHdr->NumberOfPartitionEntries; Index2++) {
+ Entry = (EFI_PARTITION_ENTRY *) ((UINT8 *) PartitionEntryBuffer + Index2 * PartHdr->SizeOfPartitionEntry);
+ if (CompareGuid (&Entry->PartitionTypeGUID, &gEfiPartTypeUnusedGuid)) {
+ continue;
+ }
+
+ if (Entry->EndingLBA >= StartingLBA && Entry->StartingLBA <= EndingLBA) {
+ //
+ // This region overlaps with the Index1'th region
+ //
+ PartitionEntryStatus[Index1].Overlap = TRUE;
+ PartitionEntryStatus[Index2].Overlap = TRUE;
+ continue;
+ }
+ }
+ }
+
+ for (Index = 0; Index < PartHdr->NumberOfPartitionEntries; Index++) {
+ if (CompareGuid (&PartitionEntryBuffer[Index].PartitionTypeGUID, &gEfiPartTypeUnusedGuid)||
+ PartitionEntryStatus[Index].OutOfRange ||
+ PartitionEntryStatus[Index].Overlap ||
+ PartitionEntryStatus[Index].OsSpecific) {
+ //
+ // Don't use null EFI Partition Entries, Invalid Partition Entries or OS specific
+ // partition Entries
+ //
+ continue;
+ }
+
+ if (PrivateData->BlockDeviceCount >= PEI_FAT_MAX_BLOCK_DEVICE) {
+ break;
+ }
+
+ Found = TRUE;
+ BlockDevPtr = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]);
+
+ BlockDevPtr->BlockSize = ParentBlockDev->BlockSize;
+ BlockDevPtr->LastBlock = PartitionEntryBuffer[Index].EndingLBA;
+ BlockDevPtr->IoAlign = ParentBlockDev->IoAlign;
+ BlockDevPtr->Logical = TRUE;
+ BlockDevPtr->PartitionChecked = FALSE;
+ BlockDevPtr->StartingPos = MultU64x32 (
+ PartitionEntryBuffer[Index].StartingLBA,
+ ParentBlockDev->BlockSize
+ );
+ BlockDevPtr->ParentDevNo = ParentBlockDevNo;
+
+ PrivateData->BlockDeviceCount++;
+
+ DEBUG ((DEBUG_INFO, "Find GPT Partition [0x%lx", PartitionEntryBuffer[Index].StartingLBA, BlockDevPtr->LastBlock));
+ DEBUG ((DEBUG_INFO, ", 0x%lx]\n", BlockDevPtr->LastBlock));
+ DEBUG ((DEBUG_INFO, " BlockSize %x\n", BlockDevPtr->BlockSize));
+ }
+
+EXIT:
+ if (PartitionEntryBuffer != NULL) {
+ FreePages (PartitionEntryBuffer, EFI_SIZE_TO_PAGES ((UINTN)PartitionEntryArraySize));
+ }
+
+ if (PartitionEntryStatus != NULL) {
+ FreePages (PartitionEntryStatus, EFI_SIZE_TO_PAGES (PartHdr->NumberOfPartitionEntries * sizeof (EFI_PARTITION_ENTRY_STATUS)));
+ }
+
+ return Found;
+}
+
+/**
+ The function is used to check GPT structure, include GPT header and GPT entry array.
+
+ 1. Check GPT header.
+ 2. Check partition entry array.
+ 3. Check each partitions.
+
+ @param[in] PrivateData The global memory map
+ @param[in] ParentBlockDevNo The parent block device
+ @param[in] IsPrimary Indicate primary or backup to be check
+
+ @retval TRUE Primary or backup GPT structure is valid.
+ @retval FALSE Both primary and backup are invalid.
+
+**/
+BOOLEAN
+PartitionCheckGptStructure (
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,
+ IN UINTN ParentBlockDevNo,
+ IN BOOLEAN IsPrimary
+ )
+{
+ EFI_STATUS Status;
+ PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
+ EFI_PARTITION_TABLE_HEADER *PartHdr;
+ EFI_PEI_LBA GptHeaderLBA;
+
+ ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
+ PartHdr = (EFI_PARTITION_TABLE_HEADER *) PrivateData->BlockData;
+
+ if (IsPrimary) {
+ GptHeaderLBA = PRIMARY_PART_HEADER_LBA;
+ } else {
+ GptHeaderLBA = ParentBlockDev->LastBlock;
+ }
+
+ Status = FatReadBlock (
+ PrivateData,
+ ParentBlockDevNo,
+ GptHeaderLBA,
+ ParentBlockDev->BlockSize,
+ PartHdr
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if (!PartitionCheckGptHeader (PrivateData, ParentBlockDevNo, IsPrimary, PartHdr)) {
+ return FALSE;
+ }
+
+ if (!PartitionCheckGptEntryArray (PrivateData, ParentBlockDevNo, PartHdr)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ This function is used to check protective MBR structure before checking GPT.
+
+ @param[in] PrivateData The global memory map
+ @param[in] ParentBlockDevNo The parent block device
+
+ @retval TRUE Valid protective MBR
+ @retval FALSE Invalid MBR
+**/
+BOOLEAN
+PartitionCheckProtectiveMbr (
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,
+ IN UINTN ParentBlockDevNo
+ )
+{
+ EFI_STATUS Status;
+ MASTER_BOOT_RECORD *ProtectiveMbr;
+ MBR_PARTITION_RECORD *MbrPartition;
+ PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
+ UINTN Index;
+
+ ProtectiveMbr = (MASTER_BOOT_RECORD *) PrivateData->BlockData;
+ ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
+
+ //
+ // Read Protective MBR
+ //
+ Status = FatReadBlock (
+ PrivateData,
+ ParentBlockDevNo,
+ 0,
+ ParentBlockDev->BlockSize,
+ ProtectiveMbr
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "GPT Error When Read Protective Mbr From Partition!\n"));
+ return FALSE;
+ }
+
+ if (ProtectiveMbr->Signature != MBR_SIGNATURE) {
+ DEBUG ((DEBUG_ERROR, "Protective Mbr Signature is invalid!\n"));
+ return FALSE;
+ }
+
+ //
+ // The partition define in UEFI Spec Table 17.
+ // Boot Code, Unique MBR Disk Signature, Unknown.
+ // These parts will not be used by UEFI, so we skip to check them.
+ //
+ for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
+ MbrPartition = (MBR_PARTITION_RECORD *)&ProtectiveMbr->Partition[Index];
+ if (MbrPartition->BootIndicator == 0x00 &&
+ MbrPartition->StartSector == 0x02 &&
+ MbrPartition->OSIndicator == PMBR_GPT_PARTITION &&
+ UNPACK_UINT32 (MbrPartition->StartingLBA) == 1
+ ) {
+ return TRUE;
+ }
+ }
+
+ DEBUG ((DEBUG_ERROR, "Protective Mbr, All Partition Entry Are Empty!\n"));
+ return FALSE;
+}
+
+/**
+ This function is used for finding GPT partition on block device.
+ As follow UEFI spec we should check protective MBR first and then
+ try to check both primary/backup GPT structures.
+
+ @param[in] PrivateData The global memory map
+ @param[in] 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
+FatFindGptPartitions (
+ IN PEI_FAT_PRIVATE_DATA *PrivateData,
+ IN UINTN ParentBlockDevNo
+ )
+{
+ BOOLEAN Found;
+ PEI_FAT_BLOCK_DEVICE *ParentBlockDev;
+
+ if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {
+ return FALSE;
+ }
+
+ ParentBlockDev = &(PrivateData->BlockDevice[ParentBlockDevNo]);
+ if (ParentBlockDev->BlockSize > PEI_FAT_MAX_BLOCK_SIZE) {
+ DEBUG ((DEBUG_ERROR, "Device BlockSize %x exceed FAT_MAX_BLOCK_SIZE\n", ParentBlockDev->BlockSize));
+ return FALSE;
+ }
+
+ if (!PartitionCheckProtectiveMbr (PrivateData, ParentBlockDevNo)) {
+ return FALSE;
+ }
+
+ Found = PartitionCheckGptStructure (PrivateData, ParentBlockDevNo, TRUE);
+ if (!Found) {
+ DEBUG ((DEBUG_ERROR, "Primary GPT Header Error, Try to Check Backup GPT Header!\n"));
+ Found = PartitionCheckGptStructure (PrivateData, ParentBlockDevNo, FALSE);
+ }
+
+ if (Found) {
+ ParentBlockDev->PartitionChecked = TRUE;
+ }
+
+ return Found;
+}
diff --git a/roms/edk2/FatPkg/FatPei/Mbr.c b/roms/edk2/FatPkg/FatPei/Mbr.c new file mode 100644 index 000000000..78e73fb81 --- /dev/null +++ b/roms/edk2/FatPkg/FatPei/Mbr.c @@ -0,0 +1,175 @@ +/** @file
+ Routines supporting partition discovery and
+ logical device reading
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <IndustryStandard/Mbr.h>
+#include "FatLitePeim.h"
+
+/**
+ Test to see if the Mbr buffer is a valid MBR
+
+ @param[in] Mbr Parent Handle
+ @param[in] 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) {
+ //
+ // Compatibility Errata:
+ // Some systems try to hide drive space with their 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[in] PrivateData The global memory map
+ @param[in] 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]);
+
+ if (ParentBlockDev->BlockSize > PEI_FAT_MAX_BLOCK_SIZE) {
+ DEBUG((DEBUG_ERROR, "Device BlockSize %x exceeds FAT_MAX_BLOCK_SIZE\n", ParentBlockDev->BlockSize));
+ return FALSE;
+ }
+
+ 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/roms/edk2/FatPkg/FatPei/Part.c b/roms/edk2/FatPkg/FatPei/Part.c new file mode 100644 index 000000000..3e2ded31c --- /dev/null +++ b/roms/edk2/FatPkg/FatPei/Part.c @@ -0,0 +1,104 @@ +/** @file
+ Routines supporting partition discovery and
+ logical device reading
+
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "FatLitePeim.h"
+
+/**
+ This function finds Eltorito partitions. Main algorithm
+ is ported from DXE partition driver.
+
+ @param[in] PrivateData The global memory map
+ @param[in] 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[in] PrivateData The global memory map
+ @param[in] 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 is used for finding GPT partition on block device.
+ As follow UEFI spec we should check protective MBR first and then
+ try to check both primary/backup GPT structures.
+
+ @param[in] PrivateData The global memory map
+ @param[in] 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
+FatFindGptPartitions (
+ 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) {
+ if (FatFindGptPartitions (PrivateData, Index)) {
+ Found = TRUE;
+ continue;
+ }
+
+ if (FatFindMbrPartitions (PrivateData, Index)) {
+ Found = TRUE;
+ continue;
+ }
+
+ if (FatFindEltoritoPartitions (PrivateData, Index)) {
+ Found = TRUE;
+ continue;
+ }
+ }
+ }
+ } while (Found && PrivateData->BlockDeviceCount <= PEI_FAT_MAX_BLOCK_DEVICE);
+}
|