/**
  Gets the next cluster in the cluster chain

  @param  PrivateData            Global memory map for accessing global variables
  @param  Volume                 The volume
  @param  Cluster                The cluster
  @param  NextCluster            The cluster number of the next cluster

  @retval EFI_SUCCESS            The address is got
  @retval EFI_INVALID_PARAMETER  ClusterNo exceeds the MaxCluster of the volume.
  @retval EFI_DEVICE_ERROR       Read disk error

**/
EFI_STATUS
FatGetNextCluster (
  IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
  IN  PEI_FAT_VOLUME        *Volume,
  IN  UINT32                Cluster,
  OUT UINT32                *NextCluster
  )
{
  EFI_STATUS  Status;
  UINT64      FatEntryPos;
  UINT32      Dummy;

  *NextCluster = 0;

  if (Volume->FatType == Fat32) {
    FatEntryPos = Volume->FatPos + MultU64x32 (4, Cluster);

    Status      = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 4, NextCluster);
    *NextCluster &= 0x0fffffff;

    //
    // Pad high bits for our FAT_CLUSTER_... macro definitions to work
    //
    if ((*NextCluster) >= 0x0ffffff7) {
      *NextCluster |= (-1 &~0xf);
    }

  } else if (Volume->FatType == Fat16) {
    FatEntryPos = Volume->FatPos + MultU64x32 (2, Cluster);

    Status      = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);

    //
    // Pad high bits for our FAT_CLUSTER_... macro definitions to work
    //
    if ((*NextCluster) >= 0xfff7) {
      *NextCluster |= (-1 &~0xf);
    }

  } else {
    FatEntryPos = Volume->FatPos + DivU64x32Remainder (MultU64x32 (3, Cluster), 2, &Dummy);

    Status      = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);

    if ((Cluster & 0x01) != 0) {
      *NextCluster = (*NextCluster) >> 4;
    } else {
Example #2
0
/**
  Reads a block of data from the block device by calling
  underlying Block I/O service.

  @param  PrivateData       Global memory map for accessing global variables 
  @param  BlockDeviceNo     The index for the block device number. 
  @param  Lba               The logic block address to read data from. 
  @param  BufferSize        The size of data in byte to read. 
  @param  Buffer            The buffer of the 

  @retval EFI_DEVICE_ERROR  The specified block device number exceeds the maximum 
                            device number. 
  @retval EFI_DEVICE_ERROR  The maximum address has exceeded the maximum address 
                            of the block device.

**/
EFI_STATUS
FatReadBlock (
  IN  PEI_FAT_PRIVATE_DATA   *PrivateData,
  IN  UINTN                  BlockDeviceNo,
  IN  EFI_PEI_LBA            Lba,
  IN  UINTN                  BufferSize,
  OUT VOID                   *Buffer
  )
{
  EFI_STATUS            Status;
  PEI_FAT_BLOCK_DEVICE  *BlockDev;

  if (BlockDeviceNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {
    return EFI_DEVICE_ERROR;
  }

  Status    = EFI_SUCCESS;
  BlockDev  = &(PrivateData->BlockDevice[BlockDeviceNo]);

  if (BufferSize > MultU64x32 (BlockDev->LastBlock - Lba + 1, BlockDev->BlockSize)) {
    return EFI_DEVICE_ERROR;
  }

  if (!BlockDev->Logical) {
    //
    // Status = BlockDev->ReadFunc
    //  (PrivateData->PeiServices, BlockDev->PhysicalDevNo, Lba, BufferSize, Buffer);
    //
    Status = BlockDev->BlockIo->ReadBlocks (
                                  (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
                                  BlockDev->BlockIo,
                                  BlockDev->PhysicalDevNo,
                                  Lba,
                                  BufferSize,
                                  Buffer
                                  );

  } else {
    Status = FatReadDisk (
              PrivateData,
              BlockDev->ParentDevNo,
              BlockDev->StartingPos + MultU64x32 (Lba, BlockDev->BlockSize),
              BufferSize,
              Buffer
              );
  }

  return Status;
}
/**
  Check if there is a valid FAT in the corresponding Block device
  of the volume and if yes, fill in the relevant fields for the
  volume structure. Note there should be a valid Block device number
  already set.

  @param  PrivateData            Global memory map for accessing global
                                 variables.
  @param  Volume                 On input, the BlockDeviceNumber field of the
                                 Volume  should be a valid value. On successful
                                 output, all  fields except the VolumeNumber
                                 field is initialized.

  @retval EFI_SUCCESS            A FAT is found and the volume structure is
                                 initialized.
  @retval EFI_NOT_FOUND          There is no FAT on the corresponding device.
  @retval EFI_DEVICE_ERROR       There is something error while accessing device.

**/
EFI_STATUS
FatGetBpbInfo (
  IN      PEI_FAT_PRIVATE_DATA  *PrivateData,
  IN OUT  PEI_FAT_VOLUME        *Volume
  )
{
  EFI_STATUS              Status;
  PEI_FAT_BOOT_SECTOR     Bpb;
  PEI_FAT_BOOT_SECTOR_EX  BpbEx;
  UINT32                  Sectors;
  UINT32                  SectorsPerFat;
  UINT32                  RootDirSectors;
  UINT64                  FatLba;
  UINT64                  RootLba;
  UINT64                  FirstClusterLba;

  //
  // Read in the BPB
  //
  Status = FatReadDisk (
            PrivateData,
            Volume->BlockDeviceNo,
            0,
            sizeof (PEI_FAT_BOOT_SECTOR_EX),
            &BpbEx
            );
  if (EFI_ERROR (Status)) {
    return Status;
  }

  CopyMem (
    (UINT8 *) (&Bpb),
    (UINT8 *) (&BpbEx),
    sizeof (PEI_FAT_BOOT_SECTOR)
    );

  Volume->FatType = FatUnknown;

  Sectors         = Bpb.Sectors;
  if (Sectors == 0) {
    Sectors = Bpb.LargeSectors;
  }

  SectorsPerFat = Bpb.SectorsPerFat;
  if (SectorsPerFat == 0) {
    SectorsPerFat   = BpbEx.LargeSectorsPerFat;
    Volume->FatType = Fat32;
  }
  //
  // Filter out those not a FAT
  //
  if (Bpb.Ia32Jump[0] != 0xe9 && Bpb.Ia32Jump[0] != 0xeb && Bpb.Ia32Jump[0] != 0x49) {
    return EFI_NOT_FOUND;
  }

  if (Bpb.ReservedSectors == 0 || Bpb.NoFats == 0 || Sectors == 0) {
    return EFI_NOT_FOUND;
  }

  if (Bpb.SectorsPerCluster != 1 &&
      Bpb.SectorsPerCluster != 2 &&
      Bpb.SectorsPerCluster != 4 &&
      Bpb.SectorsPerCluster != 8 &&
      Bpb.SectorsPerCluster != 16 &&
      Bpb.SectorsPerCluster != 32 &&
      Bpb.SectorsPerCluster != 64 &&
      Bpb.SectorsPerCluster != 128
      ) {
    return EFI_NOT_FOUND;
  }

  if (Volume->FatType == Fat32 && (SectorsPerFat == 0 || BpbEx.FsVersion != 0)) {
    return EFI_NOT_FOUND;
  }

  if (Bpb.Media != 0xf0 &&
      Bpb.Media != 0xf8 &&
      Bpb.Media != 0xf9 &&
      Bpb.Media != 0xfb &&
      Bpb.Media != 0xfc &&
      Bpb.Media != 0xfd &&
      Bpb.Media != 0xfe &&
      Bpb.Media != 0xff &&
      //
      // FujitsuFMR
      //
      Bpb.Media != 0x00 &&
      Bpb.Media != 0x01 &&
      Bpb.Media != 0xfa
      ) {
    return EFI_NOT_FOUND;
  }

  if (Volume->FatType != Fat32 && Bpb.RootEntries == 0) {
    return EFI_NOT_FOUND;
  }
  //
  // If this is fat32, refuse to mount mirror-disabled volumes
  //
  if (Volume->FatType == Fat32 && ((BpbEx.ExtendedFlags & 0x80) != 0)) {
    return EFI_NOT_FOUND;
  }
  //
  // Fill in the volume structure fields
  // (Sectors & SectorsPerFat is computed earlier already)
  //
  Volume->ClusterSize = Bpb.SectorSize * Bpb.SectorsPerCluster;
  Volume->RootEntries = Bpb.RootEntries;
  Volume->SectorSize  = Bpb.SectorSize;

  RootDirSectors = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (Volume->SectorSize - 1)) / Volume->SectorSize;

  FatLba                  = Bpb.ReservedSectors;
  RootLba                 = Bpb.NoFats * SectorsPerFat + FatLba;
  FirstClusterLba         = RootLba + RootDirSectors;

  Volume->VolumeSize      = MultU64x32 (Sectors, Volume->SectorSize);
  Volume->FatPos          = MultU64x32 (FatLba, Volume->SectorSize);
  Volume->RootDirPos      = MultU64x32 (RootLba, Volume->SectorSize);
  Volume->FirstClusterPos = MultU64x32 (FirstClusterLba, Volume->SectorSize);
  Volume->MaxCluster      = (UINT32) (Sectors - FirstClusterLba) / Bpb.SectorsPerCluster;
  Volume->RootDirCluster  = BpbEx.RootDirFirstCluster;

  //
  // If this is not a fat32, determine if it's a fat16 or fat12
  //
  if (Volume->FatType != Fat32) {

    if (Volume->MaxCluster >= 65525) {
      return EFI_NOT_FOUND;
    }

    Volume->FatType = Volume->MaxCluster < 4085 ? Fat12 : Fat16;
  }

  return EFI_SUCCESS;
}