]> git.proxmox.com Git - mirror_edk2.git/commitdiff
FatPkg: Add FAT PEIM
authorJordan Justen <jordan.l.justen@intel.com>
Fri, 1 Jul 2011 00:37:55 +0000 (00:37 +0000)
committerJordan Justen <jordan.l.justen@intel.com>
Thu, 7 Apr 2016 06:22:43 +0000 (23:22 -0700)
Signed-off-by: jljusten
Reviewed-by: mdkinney
(based on FatPkg commit bead7f219277e063ed28589de8ddd01cf180c1a8)

[jordan.l.justen@intel.com: Use script to relicense to 2-clause BSD]
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jordan Justen <jordan.l.justen@intel.com>
Acked-by: Mark Doran <mark.doran@intel.com>
Acked-by: Laszlo Ersek <lersek@redhat.com>
FatPkg/FatPei/FatLiteAccess.c [new file with mode: 0644]
FatPkg/FatPei/FatLiteApi.c [new file with mode: 0644]
FatPkg/FatPei/FatLiteApi.h [new file with mode: 0644]
FatPkg/FatPei/FatLiteFmt.h [new file with mode: 0644]
FatPkg/FatPei/FatLiteLib.c [new file with mode: 0644]
FatPkg/FatPei/FatLitePeim.h [new file with mode: 0644]
FatPkg/FatPei/FatPei.inf [new file with mode: 0644]
FatPkg/FatPei/Part.c [new file with mode: 0644]
FatPkg/FatPkg.dsc

diff --git a/FatPkg/FatPei/FatLiteAccess.c b/FatPkg/FatPei/FatLiteAccess.c
new file mode 100644 (file)
index 0000000..0a688a3
--- /dev/null
@@ -0,0 +1,527 @@
+/** @file\r
+  FAT file system access routines for FAT recovery PEIM\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FatLitePeim.h"\r
+\r
+\r
+/**\r
+  Check if there is a valid FAT in the corresponding Block device\r
+  of the volume and if yes, fill in the relevant fields for the\r
+  volume structure. Note there should be a valid Block device number\r
+  already set.\r
+\r
+  @param  PrivateData            Global memory map for accessing global \r
+                                 variables. \r
+  @param  Volume                 On input, the BlockDeviceNumber field of the \r
+                                 Volume  should be a valid value. On successful \r
+                                 output, all  fields except the VolumeNumber \r
+                                 field is initialized. \r
+\r
+  @retval EFI_SUCCESS            A FAT is found and the volume structure is \r
+                                 initialized. \r
+  @retval EFI_NOT_FOUND          There is no FAT on the corresponding device. \r
+  @retval EFI_DEVICE_ERROR       There is something error while accessing device.\r
+\r
+**/\r
+EFI_STATUS\r
+FatGetBpbInfo (\r
+  IN      PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN OUT  PEI_FAT_VOLUME        *Volume\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  PEI_FAT_BOOT_SECTOR     Bpb;\r
+  PEI_FAT_BOOT_SECTOR_EX  BpbEx;\r
+  UINT32                  Sectors;\r
+  UINT32                  SectorsPerFat;\r
+  UINT32                  RootDirSectors;\r
+  UINT64                  FatLba;\r
+  UINT64                  RootLba;\r
+  UINT64                  FirstClusterLba;\r
+\r
+  //\r
+  // Read in the BPB\r
+  //\r
+  Status = FatReadDisk (\r
+            PrivateData,\r
+            Volume->BlockDeviceNo,\r
+            0,\r
+            sizeof (PEI_FAT_BOOT_SECTOR_EX),\r
+            &BpbEx\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  CopyMem (\r
+    (UINT8 *) (&Bpb),\r
+    (UINT8 *) (&BpbEx),\r
+    sizeof (PEI_FAT_BOOT_SECTOR)\r
+    );\r
+\r
+  Volume->FatType = FatUnknown;\r
+\r
+  Sectors         = Bpb.Sectors;\r
+  if (Sectors == 0) {\r
+    Sectors = Bpb.LargeSectors;\r
+  }\r
+\r
+  SectorsPerFat = Bpb.SectorsPerFat;\r
+  if (SectorsPerFat == 0) {\r
+    SectorsPerFat   = BpbEx.LargeSectorsPerFat;\r
+    Volume->FatType = Fat32;\r
+  }\r
+  //\r
+  // Filter out those not a FAT\r
+  //\r
+  if (Bpb.Ia32Jump[0] != 0xe9 && Bpb.Ia32Jump[0] != 0xeb && Bpb.Ia32Jump[0] != 0x49) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (Bpb.ReservedSectors == 0 || Bpb.NoFats == 0 || Sectors == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (Bpb.SectorsPerCluster != 1 &&\r
+      Bpb.SectorsPerCluster != 2 &&\r
+      Bpb.SectorsPerCluster != 4 &&\r
+      Bpb.SectorsPerCluster != 8 &&\r
+      Bpb.SectorsPerCluster != 16 &&\r
+      Bpb.SectorsPerCluster != 32 &&\r
+      Bpb.SectorsPerCluster != 64 &&\r
+      Bpb.SectorsPerCluster != 128\r
+      ) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (Volume->FatType == Fat32 && (SectorsPerFat == 0 || BpbEx.FsVersion != 0)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (Bpb.Media != 0xf0 &&\r
+      Bpb.Media != 0xf8 &&\r
+      Bpb.Media != 0xf9 &&\r
+      Bpb.Media != 0xfb &&\r
+      Bpb.Media != 0xfc &&\r
+      Bpb.Media != 0xfd &&\r
+      Bpb.Media != 0xfe &&\r
+      Bpb.Media != 0xff &&\r
+      //\r
+      // FujitsuFMR\r
+      //\r
+      Bpb.Media != 0x00 &&\r
+      Bpb.Media != 0x01 &&\r
+      Bpb.Media != 0xfa\r
+      ) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  if (Volume->FatType != Fat32 && Bpb.RootEntries == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  //\r
+  // If this is fat32, refuse to mount mirror-disabled volumes\r
+  //\r
+  if (Volume->FatType == Fat32 && ((BpbEx.ExtendedFlags & 0x80) != 0)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  //\r
+  // Fill in the volume structure fields\r
+  // (Sectors & SectorsPerFat is computed earlier already)\r
+  //\r
+  Volume->ClusterSize = Bpb.SectorSize * Bpb.SectorsPerCluster;\r
+  Volume->RootEntries = Bpb.RootEntries;\r
+  Volume->SectorSize  = Bpb.SectorSize;\r
+\r
+  RootDirSectors = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (Volume->SectorSize - 1)) / Volume->SectorSize;\r
+\r
+  FatLba                  = Bpb.ReservedSectors;\r
+  RootLba                 = Bpb.NoFats * SectorsPerFat + FatLba;\r
+  FirstClusterLba         = RootLba + RootDirSectors;\r
+\r
+  Volume->VolumeSize      = MultU64x32 (Sectors, Volume->SectorSize);\r
+  Volume->FatPos          = MultU64x32 (FatLba, Volume->SectorSize);\r
+  Volume->RootDirPos      = MultU64x32 (RootLba, Volume->SectorSize);\r
+  Volume->FirstClusterPos = MultU64x32 (FirstClusterLba, Volume->SectorSize);\r
+  Volume->MaxCluster      = (UINT32) (Sectors - FirstClusterLba) / Bpb.SectorsPerCluster;\r
+  Volume->RootDirCluster  = BpbEx.RootDirFirstCluster;\r
+\r
+  //\r
+  // If this is not a fat32, determine if it's a fat16 or fat12\r
+  //\r
+  if (Volume->FatType != Fat32) {\r
+\r
+    if (Volume->MaxCluster >= 65525) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+\r
+    Volume->FatType = Volume->MaxCluster < 4085 ? Fat12 : Fat16;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Gets the next cluster in the cluster chain\r
+\r
+  @param  PrivateData            Global memory map for accessing global variables \r
+  @param  Volume                 The volume \r
+  @param  Cluster                The cluster \r
+  @param  NextCluster            The cluster number of the next cluster \r
+\r
+  @retval EFI_SUCCESS            The address is got \r
+  @retval EFI_INVALID_PARAMETER  ClusterNo exceeds the MaxCluster of the volume. \r
+  @retval EFI_DEVICE_ERROR       Read disk error\r
+\r
+**/\r
+EFI_STATUS\r
+FatGetNextCluster (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN  PEI_FAT_VOLUME        *Volume,\r
+  IN  UINT32                Cluster,\r
+  OUT UINT32                *NextCluster\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT64      FatEntryPos;\r
+  UINT32      Dummy;\r
+\r
+  *NextCluster = 0;\r
+\r
+  if (Volume->FatType == Fat32) {\r
+    FatEntryPos = Volume->FatPos + MultU64x32 (4, Cluster);\r
+\r
+    Status      = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 4, NextCluster);\r
+    *NextCluster &= 0x0fffffff;\r
+\r
+    //\r
+    // Pad high bits for our FAT_CLUSTER_... macro definitions to work\r
+    //\r
+    if ((*NextCluster) >= 0x0ffffff7) {\r
+      *NextCluster |= (-1 &~0xf);\r
+    }\r
+\r
+  } else if (Volume->FatType == Fat16) {\r
+    FatEntryPos = Volume->FatPos + MultU64x32 (2, Cluster);\r
+\r
+    Status      = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);\r
+\r
+    //\r
+    // Pad high bits for our FAT_CLUSTER_... macro definitions to work\r
+    //\r
+    if ((*NextCluster) >= 0xfff7) {\r
+      *NextCluster |= (-1 &~0xf);\r
+    }\r
+\r
+  } else {\r
+    FatEntryPos = Volume->FatPos + DivU64x32Remainder (MultU64x32 (3, Cluster), 2, &Dummy);\r
+\r
+    Status      = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);\r
+\r
+    if ((Cluster & 0x01) != 0) {\r
+      *NextCluster = (*NextCluster) >> 4;\r
+    } else {\r
+      *NextCluster = (*NextCluster) & 0x0fff;\r
+    }\r
+    //\r
+    // Pad high bits for our FAT_CLUSTER_... macro definitions to work\r
+    //\r
+    if ((*NextCluster) >= 0x0ff7) {\r
+      *NextCluster |= (-1 &~0xf);\r
+    }\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+/**\r
+  Set a file's CurrentPos and CurrentCluster, then compute StraightReadAmount.\r
+\r
+  @param  PrivateData            the global memory map \r
+  @param  File                   the file \r
+  @param  Pos                    the Position which is offset from the file's \r
+                                 CurrentPos \r
+\r
+  @retval EFI_SUCCESS            Success. \r
+  @retval EFI_INVALID_PARAMETER  Pos is beyond file's size. \r
+  @retval EFI_DEVICE_ERROR       Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatSetFilePos (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN  PEI_FAT_FILE          *File,\r
+  IN  UINT32                Pos\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT32      AlignedPos;\r
+  UINT32      Offset;\r
+  UINT32      Cluster;\r
+  UINT32      PrevCluster;\r
+\r
+  if (File->IsFixedRootDir) {\r
+\r
+    if (Pos >= MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    File->CurrentPos += Pos;\r
+    File->StraightReadAmount = (UINT32) (MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos);\r
+\r
+  } else {\r
+\r
+    DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);\r
+    AlignedPos = (UINT32) File->CurrentPos - (UINT32) Offset;\r
+\r
+    while\r
+    (\r
+      !FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster) &&\r
+      AlignedPos + File->Volume->ClusterSize <= File->CurrentPos + Pos\r
+    ) {\r
+      AlignedPos += File->Volume->ClusterSize;\r
+      Status = FatGetNextCluster (\r
+                PrivateData,\r
+                File->Volume,\r
+                File->CurrentCluster,\r
+                &File->CurrentCluster\r
+                );\r
+      if (EFI_ERROR (Status)) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+    }\r
+\r
+    if (FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    File->CurrentPos += Pos;\r
+\r
+    File->StraightReadAmount  = 0;\r
+    Cluster                   = File->CurrentCluster;\r
+    while (!FAT_CLUSTER_FUNCTIONAL (Cluster)) {\r
+      File->StraightReadAmount += File->Volume->ClusterSize;\r
+      PrevCluster = Cluster;\r
+      Status      = FatGetNextCluster (PrivateData, File->Volume, Cluster, &Cluster);\r
+      if (EFI_ERROR (Status)) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+\r
+      if (Cluster != PrevCluster + 1) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);\r
+    File->StraightReadAmount -= (UINT32) Offset;\r
+\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Reads file data. Updates the file's CurrentPos.\r
+\r
+  @param  PrivateData            Global memory map for accessing global variables \r
+  @param  File                   The file. \r
+  @param  Size                   The amount of data to read. \r
+  @param  Buffer                 The buffer storing the data. \r
+\r
+  @retval EFI_SUCCESS            The data is read. \r
+  @retval EFI_INVALID_PARAMETER  File is invalid. \r
+  @retval EFI_DEVICE_ERROR       Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadFile (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN  PEI_FAT_FILE          *File,\r
+  IN  UINTN                 Size,\r
+  OUT VOID                  *Buffer\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  CHAR8       *BufferPtr;\r
+  UINT32      Offset;\r
+  UINT64      PhysicalAddr;\r
+  UINTN       Amount;\r
+\r
+  BufferPtr = Buffer;\r
+\r
+  if (File->IsFixedRootDir) {\r
+    //\r
+    // This is the fixed root dir in FAT12 and FAT16\r
+    //\r
+    if (File->CurrentPos + Size > File->Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    Status = FatReadDisk (\r
+              PrivateData,\r
+              File->Volume->BlockDeviceNo,\r
+              File->Volume->RootDirPos + File->CurrentPos,\r
+              Size,\r
+              Buffer\r
+              );\r
+    File->CurrentPos += (UINT32) Size;\r
+    return Status;\r
+\r
+  } else {\r
+\r
+    if ((File->Attributes & FAT_ATTR_DIRECTORY) == 0) {\r
+      Size = Size < (File->FileSize - File->CurrentPos) ? Size : (UINTN) (File->FileSize - File->CurrentPos);\r
+    }\r
+    //\r
+    // This is a normal cluster based file\r
+    //\r
+    while (Size != 0) {\r
+      DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);\r
+      PhysicalAddr  = File->Volume->FirstClusterPos + MultU64x32 (File->Volume->ClusterSize, File->CurrentCluster - 2);\r
+\r
+      Amount        = File->StraightReadAmount;\r
+      Amount        = Size > Amount ? Amount : Size;\r
+      Status = FatReadDisk (\r
+                PrivateData,\r
+                File->Volume->BlockDeviceNo,\r
+                PhysicalAddr + Offset,\r
+                Amount,\r
+                BufferPtr\r
+                );\r
+      if (EFI_ERROR (Status)) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+      //\r
+      // Advance the file's current pos and current cluster\r
+      //\r
+      FatSetFilePos (PrivateData, File, (UINT32) Amount);\r
+\r
+      BufferPtr += Amount;\r
+      Size -= Amount;\r
+    }\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  This function reads the next item in the parent directory and\r
+  initializes the output parameter SubFile (CurrentPos is initialized to 0).\r
+  The function updates the CurrentPos of the parent dir to after the item read.\r
+  If no more items were found, the function returns EFI_NOT_FOUND.\r
+\r
+  @param  PrivateData            Global memory map for accessing global variables \r
+  @param  ParentDir              The parent directory. \r
+  @param  SubFile                The File structure containing the sub file that \r
+                                 is caught. \r
+\r
+  @retval EFI_SUCCESS            The next sub file is obtained. \r
+  @retval EFI_INVALID_PARAMETER  The ParentDir is not a directory. \r
+  @retval EFI_NOT_FOUND          No more sub file exists. \r
+  @retval EFI_DEVICE_ERROR       Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadNextDirectoryEntry (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN  PEI_FAT_FILE          *ParentDir,\r
+  OUT PEI_FAT_FILE          *SubFile\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  FAT_DIRECTORY_ENTRY DirEntry;\r
+  CHAR16              *Pos;\r
+  CHAR16              BaseName[9];\r
+  CHAR16              Ext[4];\r
+\r
+  ZeroMem ((UINT8 *) SubFile, sizeof (PEI_FAT_FILE));\r
+\r
+  //\r
+  // Pick a valid directory entry\r
+  //\r
+  while (1) {\r
+    //\r
+    // Read one entry\r
+    //\r
+    Status = FatReadFile (PrivateData, ParentDir, 32, &DirEntry);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+    //\r
+    // We only search for *FILE* in root directory\r
+    // Long file name entry is *NOT* supported\r
+    //\r
+    if ((DirEntry.Attributes == FAT_ATTR_DIRECTORY) || (DirEntry.Attributes == FAT_ATTR_LFN)) {\r
+      continue;\r
+    }\r
+    //\r
+    // if this is a terminator dir entry, just return EFI_NOT_FOUND\r
+    //\r
+    if (DirEntry.FileName[0] == EMPTY_ENTRY_MARK) {\r
+      return EFI_NOT_FOUND;\r
+    }\r
+    //\r
+    // If this not an invalid entry neither an empty entry, this is what we want.\r
+    // otherwise we will start a new loop to continue to find something meaningful\r
+    //\r
+    if ((UINT8) DirEntry.FileName[0] != DELETE_ENTRY_MARK) {\r
+      break;\r
+    }\r
+  }\r
+  //\r
+  // fill in the output parameter\r
+  //\r
+  EngFatToStr (8, DirEntry.FileName, BaseName);\r
+  EngFatToStr (3, DirEntry.FileName + 8, Ext);\r
+\r
+  Pos = (UINT16 *) SubFile->FileName;\r
+  SetMem ((UINT8 *) Pos, FAT_MAX_FILE_NAME_LENGTH, 0);\r
+  CopyMem ((UINT8 *) Pos, (UINT8 *) BaseName, 2 * (StrLen (BaseName) + 1));\r
+\r
+  if (Ext[0] != 0) {\r
+    Pos += StrLen (BaseName);\r
+    *Pos = '.';\r
+    Pos++;\r
+    CopyMem ((UINT8 *) Pos, (UINT8 *) Ext, 2 * (StrLen (Ext) + 1));\r
+  }\r
+\r
+  SubFile->Attributes     = DirEntry.Attributes;\r
+  SubFile->CurrentCluster = DirEntry.FileCluster;\r
+  if (ParentDir->Volume->FatType == Fat32) {\r
+    SubFile->CurrentCluster |= DirEntry.FileClusterHigh << 16;\r
+  }\r
+\r
+  SubFile->CurrentPos       = 0;\r
+  SubFile->FileSize         = DirEntry.FileSize;\r
+  SubFile->StartingCluster  = SubFile->CurrentCluster;\r
+  SubFile->Volume           = ParentDir->Volume;\r
+\r
+  if (SubFile->StartingCluster != 0) {\r
+    Status = FatSetFilePos (PrivateData, SubFile, 0);\r
+  }\r
+  //\r
+  // in Pei phase, time parameters do not need to be filled for minimum use.\r
+  //\r
+  return Status;\r
+}\r
diff --git a/FatPkg/FatPei/FatLiteApi.c b/FatPkg/FatPei/FatLiteApi.c
new file mode 100644 (file)
index 0000000..bf8158d
--- /dev/null
@@ -0,0 +1,611 @@
+/** @file\r
+  FAT recovery PEIM entry point, Ppi Functions and FAT Api functions.\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FatLitePeim.h"\r
+\r
+PEI_FAT_PRIVATE_DATA  *mPrivateData = NULL;\r
+\r
+/**\r
+  BlockIo installation nofication function. Find out all the current BlockIO\r
+  PPIs in the system and add them into private data. Assume there is\r
+\r
+  @param  PeiServices             General purpose services available to every \r
+                                  PEIM. \r
+  @param  NotifyDescriptor        The typedef structure of the notification \r
+                                  descriptor. Not used in this function. \r
+  @param  Ppi                     The typedef structure of the PPI descriptor. \r
+                                  Not used in this function. \r
+\r
+  @retval EFI_SUCCESS             The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BlockIoNotifyEntry (\r
+  IN EFI_PEI_SERVICES           **PeiServices,\r
+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,\r
+  IN VOID                       *Ppi\r
+  );\r
+\r
+\r
+/**\r
+  Discover all the block I/O devices to find the FAT volume.\r
+\r
+  @param  PrivateData             Global memory map for accessing global \r
+                                  variables. \r
+\r
+  @retval EFI_SUCCESS             The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdateBlocksAndVolumes (\r
+  IN OUT PEI_FAT_PRIVATE_DATA            *PrivateData\r
+  )\r
+{\r
+  EFI_STATUS                    Status;\r
+  EFI_PEI_PPI_DESCRIPTOR        *TempPpiDescriptor;\r
+  UINTN                         BlockIoPpiInstance;\r
+  EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIoPpi;\r
+  UINTN                         NumberBlockDevices;\r
+  UINTN                         Index;\r
+  EFI_PEI_BLOCK_IO_MEDIA        Media;\r
+  PEI_FAT_VOLUME                Volume;\r
+  EFI_PEI_SERVICES              **PeiServices;\r
+\r
+  PeiServices = (EFI_PEI_SERVICES **) GetPeiServicesTablePointer ();\r
+\r
+  //\r
+  // Clean up caches\r
+  //\r
+  for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {\r
+    PrivateData->CacheBuffer[Index].Valid = FALSE;\r
+  }\r
+\r
+  PrivateData->BlockDeviceCount = 0;\r
+\r
+  //\r
+  // Find out all Block Io Ppi instances within the system\r
+  // Assuming all device Block Io Peims are dispatched already\r
+  //\r
+  for (BlockIoPpiInstance = 0; BlockIoPpiInstance < PEI_FAT_MAX_BLOCK_IO_PPI; BlockIoPpiInstance++) {\r
+    Status = PeiServicesLocatePpi (\r
+              &gEfiPeiVirtualBlockIoPpiGuid,\r
+              BlockIoPpiInstance,\r
+              &TempPpiDescriptor,\r
+              (VOID **) &BlockIoPpi\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      //\r
+      // Done with all Block Io Ppis\r
+      //\r
+      break;\r
+    }\r
+\r
+    Status = BlockIoPpi->GetNumberOfBlockDevices (\r
+                          PeiServices,\r
+                          BlockIoPpi,\r
+                          &NumberBlockDevices\r
+                          );\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    for (Index = 1; Index <= NumberBlockDevices && PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE; Index++) {\r
+\r
+      Status = BlockIoPpi->GetBlockDeviceMediaInfo (\r
+                            PeiServices,\r
+                            BlockIoPpi,\r
+                            Index,\r
+                            &Media\r
+                            );\r
+      if (EFI_ERROR (Status) || !Media.MediaPresent) {\r
+        continue;\r
+      }\r
+\r
+      PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockSize = (UINT32) Media.BlockSize;\r
+      PrivateData->BlockDevice[PrivateData->BlockDeviceCount].LastBlock = Media.LastBlock;\r
+      PrivateData->BlockDevice[PrivateData->BlockDeviceCount].IoAlign   = 0;\r
+      //\r
+      // Not used here\r
+      //\r
+      PrivateData->BlockDevice[PrivateData->BlockDeviceCount].Logical           = FALSE;\r
+      PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PartitionChecked  = FALSE;\r
+\r
+      PrivateData->BlockDevice[PrivateData->BlockDeviceCount].BlockIo           = BlockIoPpi;\r
+      PrivateData->BlockDevice[PrivateData->BlockDeviceCount].PhysicalDevNo     = (UINT8) Index;\r
+      PrivateData->BlockDevice[PrivateData->BlockDeviceCount].DevType           = Media.DeviceType;\r
+\r
+      PrivateData->BlockDeviceCount++;\r
+    }\r
+  }\r
+  //\r
+  // Find out all logical devices\r
+  //\r
+  FatFindPartitions (PrivateData);\r
+\r
+  //\r
+  // Build up file system volume array\r
+  //\r
+  PrivateData->VolumeCount = 0;\r
+  for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) {\r
+    Volume.BlockDeviceNo  = Index;\r
+    Status                = FatGetBpbInfo (PrivateData, &Volume);\r
+    if (Status == EFI_SUCCESS) {\r
+      //\r
+      // Add the detected volume to the volume array\r
+      //\r
+      CopyMem (\r
+        (UINT8 *) &(PrivateData->Volume[PrivateData->VolumeCount]),\r
+        (UINT8 *) &Volume,\r
+        sizeof (PEI_FAT_VOLUME)\r
+        );\r
+      PrivateData->VolumeCount += 1;\r
+      if (PrivateData->VolumeCount >= PEI_FAT_MAX_VOLUME) {\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  BlockIo installation notification function. Find out all the current BlockIO\r
+  PPIs in the system and add them into private data. Assume there is\r
+\r
+  @param  PeiServices             General purpose services available to every \r
+                                  PEIM. \r
+  @param  NotifyDescriptor        The typedef structure of the notification \r
+                                  descriptor. Not used in this function. \r
+  @param  Ppi                     The typedef structure of the PPI descriptor. \r
+                                  Not used in this function. \r
+\r
+  @retval EFI_SUCCESS             The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+BlockIoNotifyEntry (\r
+  IN EFI_PEI_SERVICES           **PeiServices,\r
+  IN EFI_PEI_NOTIFY_DESCRIPTOR  *NotifyDescriptor,\r
+  IN VOID                       *Ppi\r
+  )\r
+{\r
+  UpdateBlocksAndVolumes (mPrivateData);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Installs the Device Recovery Module PPI, Initialize BlockIo Ppi\r
+  installation notification\r
+\r
+  @param  FileHandle              Handle of the file being invoked. Type \r
+                                  EFI_PEI_FILE_HANDLE is defined in  \r
+                                  FfsFindNextFile(). \r
+  @param  PeiServices             Describes the list of possible PEI Services. \r
+\r
+  @retval EFI_SUCCESS             The entry point was executed successfully. \r
+  @retval EFI_OUT_OF_RESOURCES    There is no enough memory to complete the \r
+                                  operations.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FatPeimEntry (\r
+  IN EFI_PEI_FILE_HANDLE       FileHandle,\r
+  IN CONST EFI_PEI_SERVICES    **PeiServices\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  EFI_PHYSICAL_ADDRESS  Address;\r
+  PEI_FAT_PRIVATE_DATA  *PrivateData;\r
+\r
+  Status = PeiServicesRegisterForShadow (FileHandle);\r
+  if (!EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Status = PeiServicesAllocatePages (\r
+            EfiBootServicesCode,\r
+            (sizeof (PEI_FAT_PRIVATE_DATA) - 1) / PEI_FAT_MEMMORY_PAGE_SIZE + 1,\r
+            &Address\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  PrivateData = (PEI_FAT_PRIVATE_DATA *) (UINTN) Address;\r
+\r
+  //\r
+  // Initialize Private Data (to zero, as is required by subsequent operations)\r
+  //\r
+  ZeroMem ((UINT8 *) PrivateData, sizeof (PEI_FAT_PRIVATE_DATA));\r
+\r
+  PrivateData->Signature = PEI_FAT_PRIVATE_DATA_SIGNATURE;\r
+\r
+  //\r
+  // Installs Ppi\r
+  //\r
+  PrivateData->DeviceRecoveryPpi.GetNumberRecoveryCapsules  = GetNumberRecoveryCapsules;\r
+  PrivateData->DeviceRecoveryPpi.GetRecoveryCapsuleInfo     = GetRecoveryCapsuleInfo;\r
+  PrivateData->DeviceRecoveryPpi.LoadRecoveryCapsule        = LoadRecoveryCapsule;\r
+\r
+  PrivateData->PpiDescriptor.Flags                          = (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST);\r
+  PrivateData->PpiDescriptor.Guid = &gEfiPeiDeviceRecoveryModulePpiGuid;\r
+  PrivateData->PpiDescriptor.Ppi = &PrivateData->DeviceRecoveryPpi;\r
+\r
+  Status = PeiServicesInstallPpi (&PrivateData->PpiDescriptor);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  //\r
+  // Other initializations\r
+  //\r
+  PrivateData->BlockDeviceCount = 0;\r
+\r
+  UpdateBlocksAndVolumes (PrivateData);\r
+\r
+  //\r
+  // PrivateData is allocated now, set it to the module variable\r
+  //\r
+  mPrivateData = PrivateData;\r
+\r
+  //\r
+  // Installs Block Io Ppi notification function\r
+  //\r
+  PrivateData->NotifyDescriptor.Flags =\r
+    (\r
+      EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK |\r
+      EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST\r
+    );\r
+  PrivateData->NotifyDescriptor.Guid    = &gEfiPeiVirtualBlockIoPpiGuid;\r
+  PrivateData->NotifyDescriptor.Notify  = BlockIoNotifyEntry;\r
+  return PeiServicesNotifyPpi (&PrivateData->NotifyDescriptor);\r
+}\r
+\r
+\r
+/**\r
+  Returns the number of DXE capsules residing on the device.\r
+\r
+  This function searches for DXE capsules from the associated device and returns\r
+  the number and maximum size in bytes of the capsules discovered. Entry 1 is \r
+  assumed to be the highest load priority and entry N is assumed to be the lowest \r
+  priority.\r
+\r
+  @param[in]  PeiServices              General-purpose services that are available \r
+                                       to every PEIM\r
+  @param[in]  This                     Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
+                                       instance.\r
+  @param[out] NumberRecoveryCapsules   Pointer to a caller-allocated UINTN. On \r
+                                       output, *NumberRecoveryCapsules contains \r
+                                       the number of recovery capsule images \r
+                                       available for retrieval from this PEIM \r
+                                       instance.\r
+\r
+  @retval EFI_SUCCESS        One or more capsules were discovered.\r
+  @retval EFI_DEVICE_ERROR   A device error occurred.\r
+  @retval EFI_NOT_FOUND      A recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetNumberRecoveryCapsules (\r
+  IN EFI_PEI_SERVICES                               **PeiServices,\r
+  IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI             *This,\r
+  OUT UINTN                                         *NumberRecoveryCapsules\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  PEI_FAT_PRIVATE_DATA  *PrivateData;\r
+  UINTN                 Index;\r
+  UINTN                 RecoveryCapsuleCount;\r
+  PEI_FILE_HANDLE       Handle;\r
+\r
+  PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Search each volume in the root directory for the Recovery capsule\r
+  //\r
+  RecoveryCapsuleCount = 0;\r
+  for (Index = 0; Index < PrivateData->VolumeCount; Index++) {\r
+    Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    RecoveryCapsuleCount++;\r
+  }\r
+\r
+  *NumberRecoveryCapsules = RecoveryCapsuleCount;\r
+\r
+  if (*NumberRecoveryCapsules == 0) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Returns the size and type of the requested recovery capsule.\r
+\r
+  This function gets the size and type of the capsule specified by CapsuleInstance.\r
+\r
+  @param[in]  PeiServices       General-purpose services that are available to every PEIM\r
+  @param[in]  This              Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI \r
+                                instance.\r
+  @param[in]  CapsuleInstance   Specifies for which capsule instance to retrieve \r
+                                the information.  This parameter must be between \r
+                                one and the value returned by GetNumberRecoveryCapsules() \r
+                                in NumberRecoveryCapsules.\r
+  @param[out] Size              A pointer to a caller-allocated UINTN in which \r
+                                the size of the requested recovery module is \r
+                                returned.\r
+  @param[out] CapsuleType       A pointer to a caller-allocated EFI_GUID in which \r
+                                the type of the requested recovery capsule is \r
+                                returned.  The semantic meaning of the value \r
+                                returned is defined by the implementation.\r
+\r
+  @retval EFI_SUCCESS        One or more capsules were discovered.\r
+  @retval EFI_DEVICE_ERROR   A device error occurred.\r
+  @retval EFI_NOT_FOUND      A recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetRecoveryCapsuleInfo (\r
+  IN  EFI_PEI_SERVICES                              **PeiServices,\r
+  IN  EFI_PEI_DEVICE_RECOVERY_MODULE_PPI            *This,\r
+  IN  UINTN                                         CapsuleInstance,\r
+  OUT UINTN                                         *Size,\r
+  OUT EFI_GUID                                      *CapsuleType\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  PEI_FAT_PRIVATE_DATA  *PrivateData;\r
+  UINTN                 Index;\r
+  UINTN                 BlockDeviceNo;\r
+  UINTN                 RecoveryCapsuleCount;\r
+  PEI_FILE_HANDLE       Handle;\r
+  UINTN                 NumberRecoveryCapsules;\r
+\r
+  Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
+    CapsuleInstance = CapsuleInstance + 1;\r
+  }\r
+\r
+  if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Search each volume in the root directory for the Recovery capsule\r
+  //\r
+  RecoveryCapsuleCount = 0;\r
+  for (Index = 0; Index < PrivateData->VolumeCount; Index++) {\r
+    Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    if (CapsuleInstance - 1 == RecoveryCapsuleCount) {\r
+      //\r
+      // Get file size\r
+      //\r
+      *Size = (UINTN) (((PEI_FAT_FILE *) Handle)->FileSize);\r
+\r
+      //\r
+      // Find corresponding physical block device\r
+      //\r
+      BlockDeviceNo = PrivateData->Volume[Index].BlockDeviceNo;\r
+      while (PrivateData->BlockDevice[BlockDeviceNo].Logical && BlockDeviceNo < PrivateData->BlockDeviceCount) {\r
+        BlockDeviceNo = PrivateData->BlockDevice[BlockDeviceNo].ParentDevNo;\r
+      }\r
+      //\r
+      // Fill in the Capsule Type GUID according to the block device type\r
+      //\r
+      if (BlockDeviceNo < PrivateData->BlockDeviceCount) {\r
+        switch (PrivateData->BlockDevice[BlockDeviceNo].DevType) {\r
+        case LegacyFloppy:\r
+          CopyGuid (CapsuleType, &gRecoveryOnFatFloppyDiskGuid);\r
+          break;\r
+\r
+        case IdeCDROM:\r
+        case IdeLS120:\r
+          CopyGuid (CapsuleType, &gRecoveryOnFatIdeDiskGuid);\r
+          break;\r
+\r
+        case UsbMassStorage:\r
+          CopyGuid (CapsuleType, &gRecoveryOnFatUsbDiskGuid);\r
+          break;\r
+\r
+        default:\r
+          break;\r
+        }\r
+      }\r
+\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    RecoveryCapsuleCount++;\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Loads a DXE capsule from some media into memory.\r
+\r
+  This function, by whatever mechanism, retrieves a DXE capsule from some device\r
+  and loads it into memory. Note that the published interface is device neutral.\r
+\r
+  @param[in]     PeiServices       General-purpose services that are available \r
+                                   to every PEIM\r
+  @param[in]     This              Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
+                                   instance.\r
+  @param[in]     CapsuleInstance   Specifies which capsule instance to retrieve.\r
+  @param[out]    Buffer            Specifies a caller-allocated buffer in which \r
+                                   the requested recovery capsule will be returned.\r
+\r
+  @retval EFI_SUCCESS        The capsule was loaded correctly.\r
+  @retval EFI_DEVICE_ERROR   A device error occurred.\r
+  @retval EFI_NOT_FOUND      A requested recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LoadRecoveryCapsule (\r
+  IN EFI_PEI_SERVICES                             **PeiServices,\r
+  IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI           *This,\r
+  IN UINTN                                        CapsuleInstance,\r
+  OUT VOID                                        *Buffer\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  PEI_FAT_PRIVATE_DATA  *PrivateData;\r
+  UINTN                 Index;\r
+  UINTN                 RecoveryCapsuleCount;\r
+  PEI_FILE_HANDLE       Handle;\r
+  UINTN                 NumberRecoveryCapsules;\r
+\r
+  Status = GetNumberRecoveryCapsules (PeiServices, This, &NumberRecoveryCapsules);\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {\r
+    CapsuleInstance = CapsuleInstance + 1;\r
+  }\r
+\r
+  if ((CapsuleInstance == 0) || (CapsuleInstance > NumberRecoveryCapsules)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  PrivateData = PEI_FAT_PRIVATE_DATA_FROM_THIS (This);\r
+\r
+  //\r
+  // Search each volume in the root directory for the Recovery capsule\r
+  //\r
+  RecoveryCapsuleCount = 0;\r
+  for (Index = 0; Index < PrivateData->VolumeCount; Index++) {\r
+    Status = FindRecoveryFile (PrivateData, Index, PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR, &Handle);\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+\r
+    if (CapsuleInstance - 1 == RecoveryCapsuleCount) {\r
+\r
+      Status = FatReadFile (\r
+                PrivateData,\r
+                Handle,\r
+                (UINTN) (((PEI_FAT_FILE *) Handle)->FileSize),\r
+                Buffer\r
+                );\r
+      return Status;\r
+    }\r
+\r
+    RecoveryCapsuleCount++;\r
+  }\r
+\r
+  return EFI_NOT_FOUND;\r
+}\r
+\r
+\r
+/**\r
+  Finds the recovery file on a FAT volume.\r
+  This function finds the the recovery file named FileName on a specified FAT volume and returns\r
+  its FileHandle pointer.\r
+\r
+  @param  PrivateData             Global memory map for accessing global \r
+                                  variables. \r
+  @param  VolumeIndex             The index of the volume. \r
+  @param  FileName                The recovery file name to find. \r
+  @param  Handle                  The output file handle. \r
+\r
+  @retval EFI_DEVICE_ERROR        Some error occured when operating the FAT \r
+                                  volume. \r
+  @retval EFI_NOT_FOUND           The recovery file was not found. \r
+  @retval EFI_SUCCESS             The recovery file was successfully found on the \r
+                                  FAT volume.\r
+\r
+**/\r
+EFI_STATUS\r
+FindRecoveryFile (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN  UINTN                 VolumeIndex,\r
+  IN  CHAR16                *FileName,\r
+  OUT PEI_FILE_HANDLE       *Handle\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+  PEI_FAT_FILE  Parent;\r
+  PEI_FAT_FILE  *File;\r
+\r
+  File = &PrivateData->File;\r
+\r
+  //\r
+  // VolumeIndex must be less than PEI_FAT_MAX_VOLUME because PrivateData->VolumeCount\r
+  // cannot be larger than PEI_FAT_MAX_VOLUME when detecting recovery volume.\r
+  //\r
+  ASSERT (VolumeIndex < PEI_FAT_MAX_VOLUME);\r
+\r
+  //\r
+  // Construct root directory file\r
+  //\r
+  Parent.IsFixedRootDir   = (BOOLEAN) ((PrivateData->Volume[VolumeIndex].FatType == Fat32) ? FALSE : TRUE);\r
+  Parent.Attributes       = FAT_ATTR_DIRECTORY;\r
+  Parent.CurrentPos       = 0;\r
+  Parent.CurrentCluster   = Parent.IsFixedRootDir ? 0 : PrivateData->Volume[VolumeIndex].RootDirCluster;\r
+  Parent.StartingCluster  = Parent.CurrentCluster;\r
+  Parent.Volume           = &PrivateData->Volume[VolumeIndex];\r
+\r
+  Status                  = FatSetFilePos (PrivateData, &Parent, 0);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+  //\r
+  // Search for recovery capsule in root directory\r
+  //\r
+  Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);\r
+  while (Status == EFI_SUCCESS) {\r
+    if (EngStriColl (PrivateData, FileName, File->FileName)) {\r
+      break;\r
+    }\r
+\r
+    Status = FatReadNextDirectoryEntry (PrivateData, &Parent, File);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  *Handle = File;\r
+\r
+  return EFI_SUCCESS;\r
+\r
+}\r
diff --git a/FatPkg/FatPei/FatLiteApi.h b/FatPkg/FatPei/FatLiteApi.h
new file mode 100644 (file)
index 0000000..d1ad277
--- /dev/null
@@ -0,0 +1,31 @@
+/** @file\r
+  Definitions for FAT recovery PEIM API functions\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _FAT_API_H_\r
+#define _FAT_API_H_\r
+\r
+//\r
+// API data structures\r
+//\r
+typedef VOID  *PEI_FILE_HANDLE;\r
+\r
+typedef enum {\r
+  Fat12,\r
+  Fat16,\r
+  Fat32,\r
+  FatUnknown\r
+} PEI_FAT_TYPE;\r
+\r
+#endif\r
diff --git a/FatPkg/FatPei/FatLiteFmt.h b/FatPkg/FatPei/FatLiteFmt.h
new file mode 100644 (file)
index 0000000..d4f26f3
--- /dev/null
@@ -0,0 +1,144 @@
+/** @file\r
+  FAT format data structures\r
+\r
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _FAT_FMT_H_\r
+#define _FAT_FMT_H_\r
+\r
+//\r
+// Definitions\r
+//\r
+#define FAT_ATTR_READ_ONLY                0x01\r
+#define FAT_ATTR_HIDDEN                   0x02\r
+#define FAT_ATTR_SYSTEM                   0x04\r
+#define FAT_ATTR_VOLUME_ID                0x08\r
+#define FAT_ATTR_DIRECTORY                0x10\r
+#define FAT_ATTR_ARCHIVE                  0x20\r
+#define FAT_ATTR_LFN                      (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID)\r
+\r
+#define FAT_CLUSTER_SPECIAL               ((-1 &~0xF) | 0x7)\r
+#define FAT_CLUSTER_FREE                  0\r
+#define FAT_CLUSTER_RESERVED              (FAT_CLUSTER_SPECIAL)\r
+#define FAT_CLUSTER_BAD                   (FAT_CLUSTER_SPECIAL)\r
+#define FAT_CLUSTER_LAST                  (-1)\r
+\r
+#define DELETE_ENTRY_MARK                 0xE5\r
+#define EMPTY_ENTRY_MARK                  0x00\r
+\r
+#define FAT_CLUSTER_FUNCTIONAL(Cluster)   (((Cluster) == 0) || ((Cluster) >= FAT_CLUSTER_SPECIAL))\r
+#define FAT_CLUSTER_END_OF_CHAIN(Cluster) ((Cluster) > (FAT_CLUSTER_SPECIAL))\r
+\r
+//\r
+// Directory Entry\r
+//\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+  UINT16  Day : 5;\r
+  UINT16  Month : 4;\r
+  UINT16  Year : 7;                 // From 1980\r
+} FAT_DATE;\r
+\r
+typedef struct {\r
+  UINT16  DoubleSecond : 5;\r
+  UINT16  Minute : 6;\r
+  UINT16  Hour : 5;\r
+} FAT_TIME;\r
+\r
+typedef struct {\r
+  FAT_TIME  Time;\r
+  FAT_DATE  Date;\r
+} FAT_DATE_TIME;\r
+\r
+typedef struct {\r
+  CHAR8         FileName[11];       // 8.3 filename\r
+  UINT8         Attributes;\r
+  UINT8         CaseFlag;\r
+  UINT8         CreateMillisecond;  // (creation milliseconds - ignored)\r
+  FAT_DATE_TIME FileCreateTime;\r
+  FAT_DATE      FileLastAccess;\r
+  UINT16        FileClusterHigh;    // >= FAT32\r
+  FAT_DATE_TIME FileModificationTime;\r
+  UINT16        FileCluster;\r
+  UINT32        FileSize;\r
+} FAT_DIRECTORY_ENTRY;\r
+\r
+#pragma pack()\r
+//\r
+// Boot Sector\r
+//\r
+#pragma pack(1)\r
+\r
+typedef struct {\r
+\r
+  UINT8   Ia32Jump[3];\r
+  CHAR8   OemId[8];\r
+\r
+  UINT16  SectorSize;\r
+  UINT8   SectorsPerCluster;\r
+  UINT16  ReservedSectors;\r
+  UINT8   NoFats;\r
+  UINT16  RootEntries;          // < FAT32, root dir is fixed size\r
+  UINT16  Sectors;\r
+  UINT8   Media;                // (ignored)\r
+  UINT16  SectorsPerFat;        // < FAT32\r
+  UINT16  SectorsPerTrack;      // (ignored)\r
+  UINT16  Heads;                // (ignored)\r
+  UINT32  HiddenSectors;        // (ignored)\r
+  UINT32  LargeSectors;         // => FAT32\r
+  UINT8   PhysicalDriveNumber;  // (ignored)\r
+  UINT8   CurrentHead;          // holds boot_sector_dirty bit\r
+  UINT8   Signature;            // (ignored)\r
+  CHAR8   Id[4];\r
+  CHAR8   FatLabel[11];\r
+  CHAR8   SystemId[8];\r
+\r
+} PEI_FAT_BOOT_SECTOR;\r
+\r
+typedef struct {\r
+\r
+  UINT8   Ia32Jump[3];\r
+  CHAR8   OemId[8];\r
+\r
+  UINT16  SectorSize;\r
+  UINT8   SectorsPerCluster;\r
+  UINT16  ReservedSectors;\r
+  UINT8   NoFats;\r
+  UINT16  RootEntries;          // < FAT32, root dir is fixed size\r
+  UINT16  Sectors;\r
+  UINT8   Media;                // (ignored)\r
+  UINT16  SectorsPerFat;        // < FAT32\r
+  UINT16  SectorsPerTrack;      // (ignored)\r
+  UINT16  Heads;                // (ignored)\r
+  UINT32  HiddenSectors;        // (ignored)\r
+  UINT32  LargeSectors;         // Used if Sectors==0\r
+  UINT32  LargeSectorsPerFat;   // FAT32\r
+  UINT16  ExtendedFlags;        // FAT32 (ignored)\r
+  UINT16  FsVersion;            // FAT32 (ignored)\r
+  UINT32  RootDirFirstCluster;  // FAT32\r
+  UINT16  FsInfoSector;         // FAT32\r
+  UINT16  BackupBootSector;     // FAT32\r
+  UINT8   Reserved[12];         // FAT32 (ignored)\r
+  UINT8   PhysicalDriveNumber;  // (ignored)\r
+  UINT8   CurrentHead;          // holds boot_sector_dirty bit\r
+  UINT8   Signature;            // (ignored)\r
+  CHAR8   Id[4];\r
+  CHAR8   FatLabel[11];\r
+  CHAR8   SystemId[8];\r
+\r
+} PEI_FAT_BOOT_SECTOR_EX;\r
+\r
+#pragma pack()\r
+\r
+#endif\r
diff --git a/FatPkg/FatPei/FatLiteLib.c b/FatPkg/FatPei/FatLiteLib.c
new file mode 100644 (file)
index 0000000..b5191b6
--- /dev/null
@@ -0,0 +1,364 @@
+/** @file\r
+  General purpose supporting routines for FAT recovery PEIM\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "FatLitePeim.h"\r
+\r
+\r
+#define CHAR_FAT_VALID  0x01\r
+\r
+\r
+/**\r
+  Converts a union code character to upper case.\r
+  This functions converts a unicode character to upper case.\r
+  If the input Letter is not a lower-cased letter,\r
+  the original value is returned.\r
+\r
+  @param  Letter            The input unicode character. \r
+\r
+  @return The upper cased letter.\r
+\r
+**/\r
+CHAR16\r
+ToUpper (\r
+  IN CHAR16                    Letter\r
+  )\r
+{\r
+  if ('a' <= Letter && Letter <= 'z') {\r
+    Letter = (CHAR16) (Letter - 0x20);\r
+  }\r
+\r
+  return Letter;\r
+}\r
+\r
+\r
+/**\r
+  Reads a block of data from the block device by calling\r
+  underlying Block I/O service.\r
+\r
+  @param  PrivateData       Global memory map for accessing global variables \r
+  @param  BlockDeviceNo     The index for the block device number. \r
+  @param  Lba               The logic block address to read data from. \r
+  @param  BufferSize        The size of data in byte to read. \r
+  @param  Buffer            The buffer of the \r
+\r
+  @retval EFI_DEVICE_ERROR  The specified block device number exceeds the maximum \r
+                            device number. \r
+  @retval EFI_DEVICE_ERROR  The maximum address has exceeded the maximum address \r
+                            of the block device.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadBlock (\r
+  IN  PEI_FAT_PRIVATE_DATA   *PrivateData,\r
+  IN  UINTN                  BlockDeviceNo,\r
+  IN  EFI_PEI_LBA            Lba,\r
+  IN  UINTN                  BufferSize,\r
+  OUT VOID                   *Buffer\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  PEI_FAT_BLOCK_DEVICE  *BlockDev;\r
+\r
+  if (BlockDeviceNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Status    = EFI_SUCCESS;\r
+  BlockDev  = &(PrivateData->BlockDevice[BlockDeviceNo]);\r
+\r
+  if (BufferSize > MultU64x32 (BlockDev->LastBlock - Lba + 1, BlockDev->BlockSize)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  if (!BlockDev->Logical) {\r
+    //\r
+    // Status = BlockDev->ReadFunc\r
+    //  (PrivateData->PeiServices, BlockDev->PhysicalDevNo, Lba, BufferSize, Buffer);\r
+    //\r
+    Status = BlockDev->BlockIo->ReadBlocks (\r
+                                  (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),\r
+                                  BlockDev->BlockIo,\r
+                                  BlockDev->PhysicalDevNo,\r
+                                  Lba,\r
+                                  BufferSize,\r
+                                  Buffer\r
+                                  );\r
+\r
+  } else {\r
+    Status = FatReadDisk (\r
+              PrivateData,\r
+              BlockDev->ParentDevNo,\r
+              BlockDev->StartingPos + MultU64x32 (Lba, BlockDev->BlockSize),\r
+              BufferSize,\r
+              Buffer\r
+              );\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Find a cache block designated to specific Block device and Lba.\r
+  If not found, invalidate an oldest one and use it. (LRU cache)\r
+\r
+  @param  PrivateData       the global memory map. \r
+  @param  BlockDeviceNo     the Block device. \r
+  @param  Lba               the Logical Block Address \r
+  @param  CachePtr          Ptr to the starting address of the memory holding the \r
+                            data; \r
+\r
+  @retval EFI_SUCCESS       The function completed successfully.\r
+  @retval EFI_DEVICE_ERROR  Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatGetCacheBlock (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN  UINTN                 BlockDeviceNo,\r
+  IN  UINT64                Lba,\r
+  OUT CHAR8                 **CachePtr\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  PEI_FAT_CACHE_BUFFER  *CacheBuffer;\r
+  INTN                  Index;\r
+  STATIC UINT8          Seed;\r
+\r
+  Status      = EFI_SUCCESS;\r
+  CacheBuffer = NULL;\r
+\r
+  //\r
+  // go through existing cache buffers\r
+  //\r
+  for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {\r
+    CacheBuffer = &(PrivateData->CacheBuffer[Index]);\r
+    if (CacheBuffer->Valid && CacheBuffer->BlockDeviceNo == BlockDeviceNo && CacheBuffer->Lba == Lba) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (Index < PEI_FAT_CACHE_SIZE) {\r
+    *CachePtr = (CHAR8 *) CacheBuffer->Buffer;\r
+    return EFI_SUCCESS;\r
+  }\r
+  //\r
+  // We have to find an invalid cache buffer\r
+  //\r
+  for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {\r
+    if (!PrivateData->CacheBuffer[Index].Valid) {\r
+      break;\r
+    }\r
+  }\r
+  //\r
+  // Use the cache buffer\r
+  //\r
+  if (Index == PEI_FAT_CACHE_SIZE) {\r
+    Index = (Seed++) % PEI_FAT_CACHE_SIZE;\r
+  }\r
+  \r
+  //\r
+  // Current device ID should be less than maximum device ID. \r
+  //\r
+  if (BlockDeviceNo >= PEI_FAT_MAX_BLOCK_DEVICE) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  CacheBuffer                 = &(PrivateData->CacheBuffer[Index]);\r
+\r
+  CacheBuffer->BlockDeviceNo  = BlockDeviceNo;\r
+  CacheBuffer->Lba            = Lba;\r
+  CacheBuffer->Size           = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;\r
+\r
+  //\r
+  // Read in the data\r
+  //\r
+  Status = FatReadBlock (\r
+            PrivateData,\r
+            BlockDeviceNo,\r
+            Lba,\r
+            CacheBuffer->Size,\r
+            CacheBuffer->Buffer\r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  CacheBuffer->Valid  = TRUE;\r
+  *CachePtr           = (CHAR8 *) CacheBuffer->Buffer;\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Disk reading.\r
+\r
+  @param  PrivateData       the global memory map; \r
+  @param  BlockDeviceNo     the block device to read; \r
+  @param  StartingAddress   the starting address. \r
+  @param  Size              the amount of data to read. \r
+  @param  Buffer            the buffer holding the data \r
+\r
+  @retval EFI_SUCCESS       The function completed successfully.\r
+  @retval EFI_DEVICE_ERROR  Something error.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadDisk (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN  UINTN                 BlockDeviceNo,\r
+  IN  UINT64                StartingAddress,\r
+  IN  UINTN                 Size,\r
+  OUT VOID                  *Buffer\r
+  )\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT32      BlockSize;\r
+  CHAR8       *BufferPtr;\r
+  CHAR8       *CachePtr;\r
+  UINT32      Offset;\r
+  UINT64      Lba;\r
+  UINT64      OverRunLba;\r
+  UINTN       Amount;\r
+\r
+  Status    = EFI_SUCCESS;\r
+  BufferPtr = Buffer;\r
+  BlockSize = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;\r
+\r
+  //\r
+  // Read underrun\r
+  //\r
+  Lba     = DivU64x32Remainder (StartingAddress, BlockSize, &Offset);\r
+  Status  = FatGetCacheBlock (PrivateData, BlockDeviceNo, Lba, &CachePtr);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  Amount = Size < (BlockSize - Offset) ? Size : (BlockSize - Offset);\r
+  CopyMem (BufferPtr, CachePtr + Offset, Amount);\r
+\r
+  if (Size == Amount) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  Size -= Amount;\r
+  BufferPtr += Amount;\r
+  StartingAddress += Amount;\r
+  Lba += 1;\r
+\r
+  //\r
+  // Read aligned parts\r
+  //\r
+  OverRunLba = Lba + DivU64x32Remainder (Size, BlockSize, &Offset);\r
+\r
+  Size -= Offset;\r
+  Status = FatReadBlock (PrivateData, BlockDeviceNo, Lba, Size, BufferPtr);\r
+  if (EFI_ERROR (Status)) {\r
+    return EFI_DEVICE_ERROR;\r
+  }\r
+\r
+  BufferPtr += Size;\r
+\r
+  //\r
+  // Read overrun\r
+  //\r
+  if (Offset != 0) {\r
+    Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, OverRunLba, &CachePtr);\r
+    if (EFI_ERROR (Status)) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+    CopyMem (BufferPtr, CachePtr, Offset);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  This version is different from the version in Unicode collation\r
+  protocol in that this version strips off trailing blanks.\r
+  Converts an 8.3 FAT file name using an OEM character set\r
+  to a Null-terminated Unicode string.\r
+  Here does not expand DBCS FAT chars.\r
+\r
+  @param  FatSize           The size of the string Fat in bytes. \r
+  @param  Fat               A pointer to a Null-terminated string that contains \r
+                            an 8.3 file name using an OEM character set. \r
+  @param  Str               A pointer to a Null-terminated Unicode string. The \r
+                            string must be allocated in advance to hold FatSize \r
+                            Unicode characters\r
+\r
+**/\r
+VOID\r
+EngFatToStr (\r
+  IN UINTN                            FatSize,\r
+  IN CHAR8                            *Fat,\r
+  OUT CHAR16                          *Str\r
+  )\r
+{\r
+  CHAR16  *String;\r
+\r
+  String = Str;\r
+  //\r
+  // No DBCS issues, just expand and add null terminate to end of string\r
+  //\r
+  while (*Fat != 0 && FatSize != 0) {\r
+    *String = *Fat;\r
+    String += 1;\r
+    Fat += 1;\r
+    FatSize -= 1;\r
+    if (*Fat == ' ') {\r
+      *String = 0;\r
+      return ;\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Performs a case-insensitive comparison of two Null-terminated Unicode strings.\r
+\r
+  @param  PrivateData       Global memory map for accessing global variables \r
+  @param  Str1              First string to perform case insensitive comparison. \r
+  @param  Str2              Second string to perform case insensitive comparison.\r
+\r
+**/\r
+BOOLEAN\r
+EngStriColl (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN CHAR16                 *Str1,\r
+  IN CHAR16                 *Str2\r
+  )\r
+{\r
+  CHAR16  UpperS1;\r
+  CHAR16  UpperS2;\r
+\r
+  UpperS1 = ToUpper (*Str1);\r
+  UpperS2 = ToUpper (*Str2);\r
+  while (*Str1 != 0) {\r
+    if (UpperS1 != UpperS2) {\r
+      return FALSE;\r
+    }\r
+\r
+    Str1++;\r
+    Str2++;\r
+    UpperS1 = ToUpper (*Str1);\r
+    UpperS2 = ToUpper (*Str2);\r
+  }\r
+\r
+  return (BOOLEAN) ((*Str2 != 0) ? FALSE : TRUE);\r
+}\r
diff --git a/FatPkg/FatPei/FatLitePeim.h b/FatPkg/FatPei/FatLitePeim.h
new file mode 100644 (file)
index 0000000..69429fe
--- /dev/null
@@ -0,0 +1,526 @@
+/** @file\r
+  Data structures for FAT recovery PEIM\r
+\r
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#ifndef _FAT_PEIM_H_\r
+#define _FAT_PEIM_H_\r
+\r
+#include <PiPei.h>\r
+\r
+#include <Guid/RecoveryDevice.h>\r
+#include <Ppi/BlockIo.h>\r
+#include <Ppi/DeviceRecoveryModule.h>\r
+\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/PeimEntryPoint.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/PeiServicesTablePointerLib.h>\r
+#include <Library/PeiServicesLib.h>\r
+\r
+#include "FatLiteApi.h"\r
+#include "FatLiteFmt.h"\r
+\r
+//\r
+// Definitions\r
+//\r
+#define PEI_FAT_RECOVERY_CAPSULE_WITH_NT_EMULATOR     L"fv0001.fv"\r
+#define PEI_FAT_RECOVERY_CAPSULE_WITHOUT_NT_EMULATOR  L"fvmain.fv"\r
+\r
+#define PEI_FAT_CACHE_SIZE                            4\r
+#define PEI_FAT_MAX_BLOCK_SIZE                        8192\r
+#define FAT_MAX_FILE_NAME_LENGTH                      128\r
+#define PEI_FAT_MAX_BLOCK_DEVICE                      64\r
+#define PEI_FAT_MAX_BLOCK_IO_PPI                      32\r
+#define PEI_FAT_MAX_VOLUME                            64\r
+\r
+#define PEI_FAT_MEMMORY_PAGE_SIZE                     0x1000\r
+\r
+//\r
+// Data Structures\r
+//\r
+//\r
+// The block device\r
+//\r
+typedef struct {\r
+\r
+  UINT32                        BlockSize;\r
+  UINT64                        LastBlock;\r
+  UINT32                        IoAlign;\r
+  BOOLEAN                       Logical;\r
+  BOOLEAN                       PartitionChecked;\r
+\r
+  //\r
+  // Following fields only valid for logical device\r
+  //\r
+  CHAR8                         PartitionFlag[8];\r
+  UINT64                        StartingPos;\r
+  UINTN                         ParentDevNo;\r
+\r
+  //\r
+  // Following fields only valid for physical device\r
+  //\r
+  EFI_PEI_BLOCK_DEVICE_TYPE     DevType;\r
+  //\r
+  // EFI_PEI_READ_BLOCKS         ReadFunc;\r
+  //\r
+  EFI_PEI_RECOVERY_BLOCK_IO_PPI *BlockIo;\r
+  UINT8                         PhysicalDevNo;\r
+} PEI_FAT_BLOCK_DEVICE;\r
+\r
+//\r
+// the Volume structure\r
+//\r
+typedef struct {\r
+\r
+  UINTN         BlockDeviceNo;\r
+  UINTN         VolumeNo;\r
+  UINT64        VolumeSize;\r
+  UINTN         MaxCluster;\r
+  CHAR16        VolumeLabel[FAT_MAX_FILE_NAME_LENGTH];\r
+  PEI_FAT_TYPE  FatType;\r
+  UINT64        FatPos;\r
+  UINT32        SectorSize;\r
+  UINT32        ClusterSize;\r
+  UINT64        FirstClusterPos;\r
+  UINT64        RootDirPos;\r
+  UINT32        RootEntries;\r
+  UINT32        RootDirCluster;\r
+\r
+} PEI_FAT_VOLUME;\r
+\r
+//\r
+// File instance\r
+//\r
+typedef struct {\r
+\r
+  PEI_FAT_VOLUME  *Volume;\r
+  CHAR16          FileName[FAT_MAX_FILE_NAME_LENGTH];\r
+\r
+  BOOLEAN         IsFixedRootDir;\r
+\r
+  UINT32          StartingCluster;\r
+  UINT32          CurrentPos;\r
+  UINT32          StraightReadAmount;\r
+  UINT32          CurrentCluster;\r
+\r
+  UINT8           Attributes;\r
+  UINT32          FileSize;\r
+\r
+} PEI_FAT_FILE;\r
+\r
+//\r
+// Cache Buffer\r
+//\r
+typedef struct {\r
+\r
+  BOOLEAN Valid;\r
+  UINTN   BlockDeviceNo;\r
+  UINT64  Lba;\r
+  UINT32  Lru;\r
+  UINT64  Buffer[PEI_FAT_MAX_BLOCK_SIZE / 8];\r
+  UINTN   Size;\r
+\r
+} PEI_FAT_CACHE_BUFFER;\r
+\r
+//\r
+// Private Data.\r
+// This structure abstracts the whole memory usage in FAT PEIM.\r
+// The entry point routine will get a chunk of memory (by whatever\r
+// means) whose size is sizeof(PEI_FAT_PRIVATE_DATA), which is clean\r
+// in both 32 and 64 bit environment. The boundary of the memory chunk\r
+// should be 64bit aligned.\r
+//\r
+#define PEI_FAT_PRIVATE_DATA_SIGNATURE  SIGNATURE_32 ('p', 'f', 'a', 't')\r
+\r
+typedef struct {\r
+\r
+  UINTN                               Signature;\r
+  EFI_PEI_DEVICE_RECOVERY_MODULE_PPI  DeviceRecoveryPpi;\r
+  EFI_PEI_PPI_DESCRIPTOR              PpiDescriptor;\r
+  EFI_PEI_NOTIFY_DESCRIPTOR           NotifyDescriptor;\r
+\r
+  UINT8                               UnicodeCaseMap[0x300];\r
+  CHAR8                               *EngUpperMap;\r
+  CHAR8                               *EngLowerMap;\r
+  CHAR8                               *EngInfoMap;\r
+\r
+  UINT64                              BlockData[PEI_FAT_MAX_BLOCK_SIZE / 8];\r
+  UINTN                               BlockDeviceCount;\r
+  PEI_FAT_BLOCK_DEVICE                BlockDevice[PEI_FAT_MAX_BLOCK_DEVICE];\r
+  UINTN                               VolumeCount;\r
+  PEI_FAT_VOLUME                      Volume[PEI_FAT_MAX_VOLUME];\r
+  PEI_FAT_FILE                        File;\r
+  PEI_FAT_CACHE_BUFFER                CacheBuffer[PEI_FAT_CACHE_SIZE];\r
+\r
+} PEI_FAT_PRIVATE_DATA;\r
+\r
+#define PEI_FAT_PRIVATE_DATA_FROM_THIS(a) \\r
+  CR (a,  PEI_FAT_PRIVATE_DATA, DeviceRecoveryPpi, PEI_FAT_PRIVATE_DATA_SIGNATURE)\r
+\r
+//\r
+// Extract INT32 from char array\r
+//\r
+#define UNPACK_INT32(a) \\r
+  (INT32) ((((UINT8 *) a)[0] << 0) | (((UINT8 *) a)[1] << 8) | (((UINT8 *) a)[2] << 16) | (((UINT8 *) a)[3] << 24))\r
+\r
+//\r
+// Extract UINT32 from char array\r
+//\r
+#define UNPACK_UINT32(a) \\r
+  (UINT32) ((((UINT8 *) a)[0] << 0) | (((UINT8 *) a)[1] << 8) | (((UINT8 *) a)[2] << 16) | (((UINT8 *) a)[3] << 24))\r
+\r
+\r
+//\r
+// API functions\r
+//\r
+\r
+/**\r
+  Finds the recovery file on a FAT volume.\r
+  This function finds the the recovery file named FileName on a specified FAT volume and returns\r
+  its FileHandle pointer.\r
+\r
+  @param  PrivateData             Global memory map for accessing global \r
+                                  variables. \r
+  @param  VolumeIndex             The index of the volume. \r
+  @param  FileName                The recovery file name to find. \r
+  @param  Handle                  The output file handle. \r
+\r
+  @retval EFI_DEVICE_ERROR        Some error occured when operating the FAT \r
+                                  volume. \r
+  @retval EFI_NOT_FOUND           The recovery file was not found. \r
+  @retval EFI_SUCCESS             The recovery file was successfully found on the \r
+                                  FAT volume.\r
+\r
+**/\r
+EFI_STATUS\r
+FindRecoveryFile (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN  UINTN                 VolumeIndex,\r
+  IN  CHAR16                *FileName,\r
+  OUT PEI_FILE_HANDLE       *Handle\r
+  );\r
+\r
+\r
+/**\r
+  Returns the number of DXE capsules residing on the device.\r
+  This function, by whatever mechanism, searches for DXE capsules from the associated device and\r
+  returns the number and maximum size in bytes of the capsules discovered.Entry 1 is assumed to be\r
+  the highest load priority and entry N is assumed to be the lowest priority.\r
+\r
+  @param  PeiServices             General-purpose services that are available to \r
+                                  every PEIM. \r
+  @param  This                    Indicates the \r
+                                  EFI_PEI_DEVICE_RECOVERY_MODULE_PPI instance. \r
+  @param  NumberRecoveryCapsules  Pointer to a caller-allocated UINTN.On output, \r
+                                  *NumberRecoveryCapsules contains the number of \r
+                                  recovery capsule images available for retrieval \r
+                                  from this PEIM instance. \r
+\r
+  @retval EFI_SUCCESS             The function completed successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetNumberRecoveryCapsules (\r
+  IN EFI_PEI_SERVICES                               **PeiServices,\r
+  IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI             *This,\r
+  OUT UINTN                                         *NumberRecoveryCapsules\r
+  );\r
+\r
+\r
+/**\r
+  Returns the size and type of the requested recovery capsule.\r
+  This function returns the size and type of the capsule specified by CapsuleInstance.\r
+\r
+  @param  PeiServices             General-purpose services that are available to \r
+                                  every PEIM. \r
+  @param  This                    Indicates the \r
+                                  EFI_PEI_DEVICE_RECOVERY_MODULE_PPI instance. \r
+  @param  CapsuleInstance         Specifies for which capsule instance to \r
+                                  retrieve the information.T his parameter must \r
+                                  be between one and the value returned by \r
+                                  GetNumberRecoveryCapsules() in \r
+                                  NumberRecoveryCapsules. \r
+  @param  Size                    A pointer to a caller-allocated UINTN in which \r
+                                  the size of the requested recovery module is \r
+                                  returned. \r
+  @param  CapsuleType             A pointer to a caller-allocated EFI_GUID in \r
+                                  which the type of the requested recovery \r
+                                  capsule is returned.T he semantic meaning of \r
+                                  the value returned is defined by the \r
+                                  implementation. \r
+\r
+  @retval EFI_SUCCESS             The capsule type and size were retrieved. \r
+  @retval EFI_INVALID_PARAMETER   The input CapsuleInstance does not match any \r
+                                  discovered recovery capsule.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetRecoveryCapsuleInfo (\r
+  IN  EFI_PEI_SERVICES                              **PeiServices,\r
+  IN  EFI_PEI_DEVICE_RECOVERY_MODULE_PPI            *This,\r
+  IN  UINTN                                         CapsuleInstance,\r
+  OUT UINTN                                         *Size,\r
+  OUT EFI_GUID                                      *CapsuleType\r
+  );\r
+\r
+\r
+/**\r
+  Loads a DXE capsule from some media into memory.\r
+\r
+  This function, by whatever mechanism, retrieves a DXE capsule from some device\r
+  and loads it into memory. Note that the published interface is device neutral.\r
+\r
+  @param[in]     PeiServices       General-purpose services that are available \r
+                                   to every PEIM\r
+  @param[in]     This              Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI\r
+                                   instance.\r
+  @param[in]     CapsuleInstance   Specifies which capsule instance to retrieve.\r
+  @param[out]    Buffer            Specifies a caller-allocated buffer in which \r
+                                   the requested recovery capsule will be returned.\r
+\r
+  @retval EFI_SUCCESS        The capsule was loaded correctly.\r
+  @retval EFI_DEVICE_ERROR   A device error occurred.\r
+  @retval EFI_NOT_FOUND      A requested recovery DXE capsule cannot be found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LoadRecoveryCapsule (\r
+  IN EFI_PEI_SERVICES                             **PeiServices,\r
+  IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI           *This,\r
+  IN UINTN                                        CapsuleInstance,\r
+  OUT VOID                                        *Buffer\r
+  );\r
+\r
+\r
+/**\r
+  This version is different from the version in Unicode collation\r
+  protocol in that this version strips off trailing blanks.\r
+  Converts an 8.3 FAT file name using an OEM character set\r
+  to a Null-terminated Unicode string.\r
+  Here does not expand DBCS FAT chars.\r
+\r
+  @param  FatSize           The size of the string Fat in bytes. \r
+  @param  Fat               A pointer to a Null-terminated string that contains \r
+                            an 8.3 file name using an OEM character set. \r
+  @param  Str               A pointer to a Null-terminated Unicode string. The \r
+                            string must be allocated in advance to hold FatSize \r
+                            Unicode characters\r
+\r
+**/\r
+VOID\r
+EngFatToStr (\r
+  IN UINTN                            FatSize,\r
+  IN CHAR8                            *Fat,\r
+  OUT CHAR16                          *Str\r
+  );\r
+\r
+\r
+/**\r
+  Performs a case-insensitive comparison of two Null-terminated Unicode strings.\r
+\r
+  @param  PrivateData       Global memory map for accessing global variables \r
+  @param  Str1              First string to perform case insensitive comparison. \r
+  @param  Str2              Second string to perform case insensitive comparison.\r
+\r
+**/\r
+BOOLEAN\r
+EngStriColl (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN CHAR16                 *Str1,\r
+  IN CHAR16                 *Str2\r
+  );\r
+\r
+\r
+/**\r
+  Reads a block of data from the block device by calling\r
+  underlying Block I/O service.\r
+\r
+  @param  PrivateData       Global memory map for accessing global variables \r
+  @param  BlockDeviceNo     The index for the block device number. \r
+  @param  Lba               The logic block address to read data from. \r
+  @param  BufferSize        The size of data in byte to read. \r
+  @param  Buffer            The buffer of the \r
+\r
+  @retval EFI_DEVICE_ERROR  The specified block device number exceeds the maximum \r
+                            device number. \r
+  @retval EFI_DEVICE_ERROR  The maximum address has exceeded the maximum address \r
+                            of the block device.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadBlock (\r
+  IN  PEI_FAT_PRIVATE_DATA   *PrivateData,\r
+  IN  UINTN                  BlockDeviceNo,\r
+  IN  EFI_PEI_LBA            Lba,\r
+  IN  UINTN                  BufferSize,\r
+  OUT VOID                   *Buffer\r
+  );\r
+\r
+\r
+/**\r
+  Check if there is a valid FAT in the corresponding Block device\r
+  of the volume and if yes, fill in the relevant fields for the\r
+  volume structure. Note there should be a valid Block device number\r
+  already set.\r
+\r
+  @param  PrivateData            Global memory map for accessing global \r
+                                 variables. \r
+  @param  Volume                 On input, the BlockDeviceNumber field of the \r
+                                 Volume  should be a valid value. On successful \r
+                                 output, all  fields except the VolumeNumber \r
+                                 field is initialized. \r
+\r
+  @retval EFI_SUCCESS            A FAT is found and the volume structure is \r
+                                 initialized. \r
+  @retval EFI_NOT_FOUND          There is no FAT on the corresponding device. \r
+  @retval EFI_DEVICE_ERROR       There is something error while accessing device.\r
+\r
+**/\r
+EFI_STATUS\r
+FatGetBpbInfo (\r
+  IN      PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN OUT  PEI_FAT_VOLUME        *Volume\r
+  );\r
+\r
+\r
+/**\r
+  Gets the next cluster in the cluster chain.\r
+\r
+  @param  PrivateData            Global memory map for accessing global variables \r
+  @param  Volume                 The volume \r
+  @param  Cluster                The cluster \r
+  @param  NextCluster            The cluster number of the next cluster \r
+\r
+  @retval EFI_SUCCESS            The address is got \r
+  @retval EFI_INVALID_PARAMETER  ClusterNo exceeds the MaxCluster of the volume. \r
+  @retval EFI_DEVICE_ERROR       Read disk error\r
+\r
+**/\r
+EFI_STATUS\r
+FatGetNextCluster (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN  PEI_FAT_VOLUME        *Volume,\r
+  IN  UINT32                Cluster,\r
+  OUT UINT32                *NextCluster\r
+  );\r
+\r
+\r
+/**\r
+  Disk reading.\r
+\r
+  @param  PrivateData       the global memory map; \r
+  @param  BlockDeviceNo     the block device to read; \r
+  @param  StartingAddress   the starting address. \r
+  @param  Size              the amount of data to read. \r
+  @param  Buffer            the buffer holding the data \r
+\r
+  @retval EFI_SUCCESS       The function completed successfully.\r
+  @retval EFI_DEVICE_ERROR  Something error.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadDisk (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN  UINTN                 BlockDeviceNo,\r
+  IN  UINT64                StartingAddress,\r
+  IN  UINTN                 Size,\r
+  OUT VOID                  *Buffer\r
+  );\r
+\r
+\r
+/**\r
+  Set a file's CurrentPos and CurrentCluster, then compute StraightReadAmount.\r
+\r
+  @param  PrivateData            the global memory map \r
+  @param  File                   the file \r
+  @param  Pos                    the Position which is offset from the file's \r
+                                 CurrentPos \r
+\r
+  @retval EFI_SUCCESS            Success. \r
+  @retval EFI_INVALID_PARAMETER  Pos is beyond file's size. \r
+  @retval EFI_DEVICE_ERROR       Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatSetFilePos (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN  PEI_FAT_FILE          *File,\r
+  IN  UINT32                Pos\r
+  );\r
+\r
+\r
+/**\r
+  Reads file data. Updates the file's CurrentPos.\r
+\r
+  @param  PrivateData            Global memory map for accessing global variables \r
+  @param  File                   The file. \r
+  @param  Size                   The amount of data to read. \r
+  @param  Buffer                 The buffer storing the data. \r
+\r
+  @retval EFI_SUCCESS            The data is read. \r
+  @retval EFI_INVALID_PARAMETER  File is invalid. \r
+  @retval EFI_DEVICE_ERROR       Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadFile (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN  PEI_FAT_FILE          *File,\r
+  IN  UINTN                 Size,\r
+  OUT VOID                  *Buffer\r
+  );\r
+\r
+\r
+/**\r
+  This function reads the next item in the parent directory and\r
+  initializes the output parameter SubFile (CurrentPos is initialized to 0).\r
+  The function updates the CurrentPos of the parent dir to after the item read.\r
+  If no more items were found, the function returns EFI_NOT_FOUND.\r
+\r
+  @param  PrivateData            Global memory map for accessing global variables \r
+  @param  ParentDir              The parent directory. \r
+  @param  SubFile                The File structure containing the sub file that \r
+                                 is caught. \r
+\r
+  @retval EFI_SUCCESS            The next sub file is obtained. \r
+  @retval EFI_INVALID_PARAMETER  The ParentDir is not a directory. \r
+  @retval EFI_NOT_FOUND          No more sub file exists. \r
+  @retval EFI_DEVICE_ERROR       Something error while accessing media.\r
+\r
+**/\r
+EFI_STATUS\r
+FatReadNextDirectoryEntry (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,\r
+  IN  PEI_FAT_FILE          *ParentDir,\r
+  OUT PEI_FAT_FILE          *SubFile\r
+  );\r
+\r
+\r
+/**\r
+  This function finds partitions (logical devices) in physical block devices.\r
+\r
+  @param  PrivateData       Global memory map for accessing global variables.\r
+\r
+**/\r
+VOID\r
+FatFindPartitions (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData\r
+  );\r
+\r
+#endif // _FAT_PEIM_H_\r
diff --git a/FatPkg/FatPei/FatPei.inf b/FatPkg/FatPei/FatPei.inf
new file mode 100644 (file)
index 0000000..a81d265
--- /dev/null
@@ -0,0 +1,74 @@
+## @file\r
+#    Lite Fat driver only used in Pei Phase.\r
+#\r
+#  Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  This program and the accompanying materials are licensed and made available\r
+#  under the terms and conditions of the BSD License which accompanies this\r
+#  distribution. The full text of the license may be found at\r
+#  http://opensource.org/licenses/bsd-license.php\r
+#\r
+#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = FatPei\r
+  FILE_GUID                      = 5B60CCFD-1011-4BCF-B7D1-BB99CA96A603\r
+  MODULE_TYPE                    = PEIM\r
+  VERSION_STRING                 = 1.0\r
+\r
+  ENTRY_POINT                    = FatPeimEntry\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  Part.c\r
+  FatLiteApi.c\r
+  FatLiteLib.c\r
+  FatLiteAccess.c\r
+  FatLiteApi.h\r
+  FatLitePeim.h\r
+  FatLiteFmt.h\r
+\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+  PcdLib\r
+  BaseMemoryLib\r
+  PeimEntryPoint\r
+  BaseLib\r
+  DebugLib\r
+  PeiServicesTablePointerLib\r
+  PeiServicesLib\r
+\r
+\r
+[Guids]\r
+  gRecoveryOnFatUsbDiskGuid                   # ALWAYS_CONSUMED\r
+  gRecoveryOnFatIdeDiskGuid                   # ALWAYS_CONSUMED\r
+  gRecoveryOnFatFloppyDiskGuid                # ALWAYS_CONSUMED\r
+\r
+\r
+[Ppis]\r
+  gEfiPeiVirtualBlockIoPpiGuid                  # PPI_NOTIFY SOMETIMES_CONSUMED\r
+  gEfiPeiDeviceRecoveryModulePpiGuid            # SOMETIMES_PRODUCED\r
+\r
+\r
+[FeaturePcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport               ## CONSUMES\r
+  \r
+\r
+[Depex]\r
+  gEfiPeiMemoryDiscoveredPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid\r
+\r
+\r
diff --git a/FatPkg/FatPei/Part.c b/FatPkg/FatPei/Part.c
new file mode 100644 (file)
index 0000000..1c1b289
--- /dev/null
@@ -0,0 +1,466 @@
+/** @file\r
+  Routines supporting partition discovery and \r
+  logical device reading\r
+\r
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>\r
+\r
+This program and the accompanying materials are licensed and made available\r
+under the terms and conditions of the BSD License which accompanies this\r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <IndustryStandard/Mbr.h>\r
+#include <IndustryStandard/ElTorito.h>\r
+#include "FatLitePeim.h"\r
+\r
+/**\r
+  This function finds Eltorito partitions. Main algorithm\r
+  is ported from DXE partition driver.\r
+\r
+  @param  PrivateData       The global memory map \r
+  @param  ParentBlockDevNo  The parent block device \r
+\r
+  @retval TRUE              New partitions are detected and logical block devices \r
+                            are  added to block device array \r
+  @retval FALSE             No New partitions are added;\r
+\r
+**/\r
+BOOLEAN\r
+FatFindEltoritoPartitions (\r
+  IN  PEI_FAT_PRIVATE_DATA *PrivateData,\r
+  IN  UINTN                ParentBlockDevNo\r
+  );\r
+\r
+/**\r
+  This function finds Mbr partitions. Main algorithm\r
+  is ported from DXE partition driver.\r
+\r
+  @param  PrivateData       The global memory map \r
+  @param  ParentBlockDevNo  The parent block device \r
+\r
+  @retval TRUE              New partitions are detected and logical block devices \r
+                            are  added to block device array \r
+  @retval FALSE             No New partitions are added;\r
+\r
+**/\r
+BOOLEAN\r
+FatFindMbrPartitions (\r
+  IN  PEI_FAT_PRIVATE_DATA *PrivateData,\r
+  IN  UINTN                ParentBlockDevNo\r
+  );\r
+\r
+\r
+/**\r
+  This function finds partitions (logical devices) in physical block devices.\r
+\r
+  @param  PrivateData       Global memory map for accessing global variables.\r
+\r
+**/\r
+VOID\r
+FatFindPartitions (\r
+  IN  PEI_FAT_PRIVATE_DATA  *PrivateData\r
+  )\r
+{\r
+  BOOLEAN Found;\r
+  UINTN   Index;\r
+\r
+  do {\r
+    Found = FALSE;\r
+\r
+    for (Index = 0; Index < PrivateData->BlockDeviceCount; Index++) {\r
+      if (!PrivateData->BlockDevice[Index].PartitionChecked) {\r
+        Found = FatFindMbrPartitions (PrivateData, Index);\r
+        if (!Found) {\r
+          Found = FatFindEltoritoPartitions (PrivateData, Index);\r
+        }\r
+      }\r
+    }\r
+  } while (Found && PrivateData->BlockDeviceCount <= PEI_FAT_MAX_BLOCK_DEVICE);\r
+}\r
+\r
+\r
+/**\r
+  This function finds Eltorito partitions. Main algorithm\r
+  is ported from DXE partition driver.\r
+\r
+  @param  PrivateData       The global memory map \r
+  @param  ParentBlockDevNo  The parent block device \r
+\r
+  @retval TRUE              New partitions are detected and logical block devices \r
+                            are  added to block device array \r
+  @retval FALSE             No New partitions are added;\r
+\r
+**/\r
+BOOLEAN\r
+FatFindEltoritoPartitions (\r
+  IN  PEI_FAT_PRIVATE_DATA *PrivateData,\r
+  IN  UINTN                ParentBlockDevNo\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  BOOLEAN                 Found;\r
+  PEI_FAT_BLOCK_DEVICE    *BlockDev;\r
+  PEI_FAT_BLOCK_DEVICE    *ParentBlockDev;\r
+  UINT32                  VolDescriptorLba;\r
+  UINT32                  Lba;\r
+  CDROM_VOLUME_DESCRIPTOR *VolDescriptor;\r
+  ELTORITO_CATALOG        *Catalog;\r
+  UINTN                   Check;\r
+  UINTN                   Index;\r
+  UINTN                   MaxIndex;\r
+  UINT16                  *CheckBuffer;\r
+  UINT32                  SubBlockSize;\r
+  UINT32                  SectorCount;\r
+  UINT32                  VolSpaceSize;\r
+\r
+  if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {\r
+    return FALSE;\r
+  }\r
+\r
+  Found           = FALSE;\r
+  ParentBlockDev  = &(PrivateData->BlockDevice[ParentBlockDevNo]);\r
+  VolSpaceSize    = 0;\r
+\r
+  //\r
+  // CD_ROM has the fixed block size as 2048 bytes\r
+  //\r
+  if (ParentBlockDev->BlockSize != 2048) {\r
+    return FALSE;\r
+  }\r
+\r
+  VolDescriptor = (CDROM_VOLUME_DESCRIPTOR *) PrivateData->BlockData;\r
+  Catalog       = (ELTORITO_CATALOG *) VolDescriptor;\r
+\r
+  //\r
+  // the ISO-9660 volume descriptor starts at 32k on the media\r
+  // and CD_ROM has the fixed block size as 2048 bytes, so...\r
+  //\r
+  VolDescriptorLba = 15;\r
+  //\r
+  // ((16*2048) / Media->BlockSize) - 1;\r
+  //\r
+  // Loop: handle one volume descriptor per time\r
+  //\r
+  while (TRUE) {\r
+\r
+    VolDescriptorLba += 1;\r
+    if (VolDescriptorLba > ParentBlockDev->LastBlock) {\r
+      //\r
+      // We are pointing past the end of the device so exit\r
+      //\r
+      break;\r
+    }\r
+\r
+    Status = FatReadBlock (\r
+              PrivateData,\r
+              ParentBlockDevNo,\r
+              VolDescriptorLba,\r
+              ParentBlockDev->BlockSize,\r
+              VolDescriptor\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      break;\r
+    }\r
+    //\r
+    // Check for valid volume descriptor signature\r
+    //\r
+    if (VolDescriptor->Unknown.Type == CDVOL_TYPE_END ||\r
+        CompareMem (VolDescriptor->Unknown.Id, CDVOL_ID, sizeof (VolDescriptor->Unknown.Id)) != 0\r
+        ) {\r
+      //\r
+      // end of Volume descriptor list\r
+      //\r
+      break;\r
+    }\r
+    //\r
+    // Read the Volume Space Size from Primary Volume Descriptor 81-88 byte\r
+    //\r
+    if (VolDescriptor->Unknown.Type == CDVOL_TYPE_CODED) {\r
+      VolSpaceSize = VolDescriptor->PrimaryVolume.VolSpaceSize[1];\r
+    }\r
+    //\r
+    // Is it an El Torito volume descriptor?\r
+    //\r
+    if (CompareMem (\r
+          VolDescriptor->BootRecordVolume.SystemId,\r
+          CDVOL_ELTORITO_ID,\r
+          sizeof (CDVOL_ELTORITO_ID) - 1\r
+          ) != 0) {\r
+      continue;\r
+    }\r
+    //\r
+    // Read in the boot El Torito boot catalog\r
+    //\r
+    Lba = UNPACK_INT32 (VolDescriptor->BootRecordVolume.EltCatalog);\r
+    if (Lba > ParentBlockDev->LastBlock) {\r
+      continue;\r
+    }\r
+\r
+    Status = FatReadBlock (\r
+              PrivateData,\r
+              ParentBlockDevNo,\r
+              Lba,\r
+              ParentBlockDev->BlockSize,\r
+              Catalog\r
+              );\r
+    if (EFI_ERROR (Status)) {\r
+      continue;\r
+    }\r
+    //\r
+    // We don't care too much about the Catalog header's contents, but we do want\r
+    // to make sure it looks like a Catalog header\r
+    //\r
+    if (Catalog->Catalog.Indicator != ELTORITO_ID_CATALOG || Catalog->Catalog.Id55AA != 0xAA55) {\r
+      continue;\r
+    }\r
+\r
+    Check       = 0;\r
+    CheckBuffer = (UINT16 *) Catalog;\r
+    for (Index = 0; Index < sizeof (ELTORITO_CATALOG) / sizeof (UINT16); Index += 1) {\r
+      Check += CheckBuffer[Index];\r
+    }\r
+\r
+    if ((Check & 0xFFFF) != 0) {\r
+      continue;\r
+    }\r
+\r
+    MaxIndex = ParentBlockDev->BlockSize / sizeof (ELTORITO_CATALOG);\r
+    for (Index = 1; Index < MaxIndex; Index += 1) {\r
+      //\r
+      // Next entry\r
+      //\r
+      Catalog += 1;\r
+\r
+      //\r
+      // Check this entry\r
+      //\r
+      if (Catalog->Boot.Indicator != ELTORITO_ID_SECTION_BOOTABLE || Catalog->Boot.Lba == 0) {\r
+        continue;\r
+      }\r
+\r
+      SubBlockSize  = 512;\r
+      SectorCount   = Catalog->Boot.SectorCount;\r
+\r
+      switch (Catalog->Boot.MediaType) {\r
+\r
+      case ELTORITO_NO_EMULATION:\r
+        SubBlockSize  = ParentBlockDev->BlockSize;\r
+        SectorCount   = Catalog->Boot.SectorCount;\r
+        break;\r
+\r
+      case ELTORITO_HARD_DISK:\r
+        break;\r
+\r
+      case ELTORITO_12_DISKETTE:\r
+        SectorCount = 0x50 * 0x02 * 0x0F;\r
+        break;\r
+\r
+      case ELTORITO_14_DISKETTE:\r
+        SectorCount = 0x50 * 0x02 * 0x12;\r
+        break;\r
+\r
+      case ELTORITO_28_DISKETTE:\r
+        SectorCount = 0x50 * 0x02 * 0x24;\r
+        break;\r
+\r
+      default:\r
+        SectorCount   = 0;\r
+        SubBlockSize  = ParentBlockDev->BlockSize;\r
+        break;\r
+      }\r
+\r
+      if (SectorCount < 2) {\r
+        SectorCount = (VolSpaceSize > ParentBlockDev->LastBlock + 1) ? (UINT32) (ParentBlockDev->LastBlock - Catalog->Boot.Lba + 1) : (UINT32) (VolSpaceSize - Catalog->Boot.Lba);\r
+      }\r
+      //\r
+      // Register this partition\r
+      //\r
+      if (PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE) {\r
+\r
+        Found                       = TRUE;\r
+\r
+        BlockDev                    = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]);\r
+\r
+        BlockDev->BlockSize         = SubBlockSize;\r
+        BlockDev->LastBlock         = SectorCount - 1;\r
+        BlockDev->IoAlign           = ParentBlockDev->IoAlign;\r
+        BlockDev->Logical           = TRUE;\r
+        BlockDev->PartitionChecked  = FALSE;\r
+        BlockDev->StartingPos       = MultU64x32 (Catalog->Boot.Lba, ParentBlockDev->BlockSize);\r
+        BlockDev->ParentDevNo       = ParentBlockDevNo;\r
+\r
+        PrivateData->BlockDeviceCount++;\r
+      }\r
+    }\r
+  }\r
+\r
+  ParentBlockDev->PartitionChecked = TRUE;\r
+\r
+  return Found;\r
+\r
+}\r
+\r
+\r
+/**\r
+  Test to see if the Mbr buffer is a valid MBR\r
+\r
+  @param  Mbr               Parent Handle \r
+  @param  LastLba           Last Lba address on the device. \r
+\r
+  @retval TRUE              Mbr is a Valid MBR \r
+  @retval FALSE             Mbr is not a Valid MBR\r
+\r
+**/\r
+BOOLEAN\r
+PartitionValidMbr (\r
+  IN  MASTER_BOOT_RECORD      *Mbr,\r
+  IN  EFI_PEI_LBA             LastLba\r
+  )\r
+{\r
+  UINT32  StartingLBA;\r
+  UINT32  EndingLBA;\r
+  UINT32  NewEndingLBA;\r
+  INTN    Index1;\r
+  INTN    Index2;\r
+  BOOLEAN MbrValid;\r
+\r
+  if (Mbr->Signature != MBR_SIGNATURE) {\r
+    return FALSE;\r
+  }\r
+  //\r
+  // The BPB also has this signature, so it can not be used alone.\r
+  //\r
+  MbrValid = FALSE;\r
+  for (Index1 = 0; Index1 < MAX_MBR_PARTITIONS; Index1++) {\r
+    if (Mbr->Partition[Index1].OSIndicator == 0x00 || UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) == 0) {\r
+      continue;\r
+    }\r
+\r
+    MbrValid    = TRUE;\r
+    StartingLBA = UNPACK_UINT32 (Mbr->Partition[Index1].StartingLBA);\r
+    EndingLBA   = StartingLBA + UNPACK_UINT32 (Mbr->Partition[Index1].SizeInLBA) - 1;\r
+    if (EndingLBA > LastLba) {\r
+      //\r
+      // Compatability Errata:\r
+      //  Some systems try to hide drive space with thier INT 13h driver\r
+      //  This does not hide space from the OS driver. This means the MBR\r
+      //  that gets created from DOS is smaller than the MBR created from\r
+      //  a real OS (NT & Win98). This leads to BlockIo->LastBlock being\r
+      //  wrong on some systems FDISKed by the OS.\r
+      //\r
+      //  return FALSE Because no block devices on a system are implemented\r
+      //  with INT 13h\r
+      //\r
+      return FALSE;\r
+    }\r
+\r
+    for (Index2 = Index1 + 1; Index2 < MAX_MBR_PARTITIONS; Index2++) {\r
+      if (Mbr->Partition[Index2].OSIndicator == 0x00 || UNPACK_INT32 (Mbr->Partition[Index2].SizeInLBA) == 0) {\r
+        continue;\r
+      }\r
+\r
+      NewEndingLBA = UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) + UNPACK_UINT32 (Mbr->Partition[Index2].SizeInLBA) - 1;\r
+      if (NewEndingLBA >= StartingLBA && UNPACK_UINT32 (Mbr->Partition[Index2].StartingLBA) <= EndingLBA) {\r
+        //\r
+        // This region overlaps with the Index1'th region\r
+        //\r
+        return FALSE;\r
+      }\r
+    }\r
+  }\r
+  //\r
+  // Non of the regions overlapped so MBR is O.K.\r
+  //\r
+  return MbrValid;\r
+}\r
+\r
+\r
+/**\r
+  This function finds Mbr partitions. Main algorithm\r
+  is ported from DXE partition driver.\r
+\r
+  @param  PrivateData       The global memory map \r
+  @param  ParentBlockDevNo  The parent block device \r
+\r
+  @retval TRUE              New partitions are detected and logical block devices \r
+                            are  added to block device array \r
+  @retval FALSE             No New partitions are added;\r
+\r
+**/\r
+BOOLEAN\r
+FatFindMbrPartitions (\r
+  IN  PEI_FAT_PRIVATE_DATA *PrivateData,\r
+  IN  UINTN                ParentBlockDevNo\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  MASTER_BOOT_RECORD    *Mbr;\r
+  UINTN                 Index;\r
+  BOOLEAN               Found;\r
+  PEI_FAT_BLOCK_DEVICE  *ParentBlockDev;\r
+  PEI_FAT_BLOCK_DEVICE  *BlockDev;\r
+\r
+  if (ParentBlockDevNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {\r
+    return FALSE;\r
+  }\r
+\r
+  ParentBlockDev  = &(PrivateData->BlockDevice[ParentBlockDevNo]);\r
+\r
+  Found           = FALSE;\r
+  Mbr             = (MASTER_BOOT_RECORD *) PrivateData->BlockData;\r
+\r
+  Status = FatReadBlock (\r
+            PrivateData,\r
+            ParentBlockDevNo,\r
+            0,\r
+            ParentBlockDev->BlockSize,\r
+            Mbr\r
+            );\r
+\r
+  if (EFI_ERROR (Status) || !PartitionValidMbr (Mbr, ParentBlockDev->LastBlock)) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // We have a valid mbr - add each partition\r
+  //\r
+  for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {\r
+    if (Mbr->Partition[Index].OSIndicator == 0x00 || UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) == 0) {\r
+      //\r
+      // Don't use null MBR entries\r
+      //\r
+      continue;\r
+    }\r
+    //\r
+    // Register this partition\r
+    //\r
+    if (PrivateData->BlockDeviceCount < PEI_FAT_MAX_BLOCK_DEVICE) {\r
+\r
+      Found                       = TRUE;\r
+\r
+      BlockDev                    = &(PrivateData->BlockDevice[PrivateData->BlockDeviceCount]);\r
+\r
+      BlockDev->BlockSize         = MBR_SIZE;\r
+      BlockDev->LastBlock         = UNPACK_INT32 (Mbr->Partition[Index].SizeInLBA) - 1;\r
+      BlockDev->IoAlign           = ParentBlockDev->IoAlign;\r
+      BlockDev->Logical           = TRUE;\r
+      BlockDev->PartitionChecked  = FALSE;\r
+      BlockDev->StartingPos = MultU64x32 (\r
+                                UNPACK_INT32 (Mbr->Partition[Index].StartingLBA),\r
+                                ParentBlockDev->BlockSize\r
+                                );\r
+      BlockDev->ParentDevNo = ParentBlockDevNo;\r
+\r
+      PrivateData->BlockDeviceCount++;\r
+    }\r
+  }\r
+\r
+Done:\r
+\r
+  ParentBlockDev->PartitionChecked = TRUE;\r
+  return Found;\r
+}\r
index cfb73f27f2b5afd301859b08a98475454d944af2..f8309717a6a48decf32beeb741762141f63cb23b 100644 (file)
   BUILD_TARGETS                  = DEBUG|RELEASE\r
   SKUID_IDENTIFIER               = DEFAULT\r
 \r
+[BuildOptions]\r
+  GCC:RELEASE_*_*_CC_FLAGS             = -DMDEPKG_NDEBUG\r
+  INTEL:RELEASE_*_*_CC_FLAGS           = /D MDEPKG_NDEBUG\r
+  MSFT:RELEASE_*_*_CC_FLAGS            = /D MDEPKG_NDEBUG\r
+\r
 [LibraryClasses]\r
   #\r
   # Entry Point Libraries\r
   DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf  \r
   DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf\r
 \r
+[LibraryClasses.common.PEIM]\r
+  PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf\r
+  PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf\r
+  PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf\r
+  HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf\r
+  MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf\r
+  PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf\r
+\r
 ###################################################################################################\r
 #\r
 # Components Section - list of the modules and components that will be processed by compilation\r
@@ -66,4 +79,5 @@
 ###################################################################################################\r
 \r
 [Components]\r
+  FatPkg/FatPei/FatPei.inf\r
   FatPkg/EnhancedFatDxe/Fat.inf\r