Home | History | Annotate | Download | only in EnhancedFatDxe
      1 /** @file
      2   Initialization routines.
      3 
      4 Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials are licensed and made available
      6 under the terms and conditions of the BSD License which accompanies this
      7 distribution. The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "Fat.h"
     16 
     17 /**
     18 
     19   Allocates volume structure, detects FAT file system, installs protocol,
     20   and initialize cache.
     21 
     22   @param  Handle                - The handle of parent device.
     23   @param  DiskIo                - The DiskIo of parent device.
     24   @param  DiskIo2               - The DiskIo2 of parent device.
     25   @param  BlockIo               - The BlockIo of parent devicel
     26 
     27   @retval EFI_SUCCESS           - Allocate a new volume successfully.
     28   @retval EFI_OUT_OF_RESOURCES  - Can not allocate the memory.
     29   @return Others                - Allocating a new volume failed.
     30 
     31 **/
     32 EFI_STATUS
     33 FatAllocateVolume (
     34   IN  EFI_HANDLE                Handle,
     35   IN  EFI_DISK_IO_PROTOCOL      *DiskIo,
     36   IN  EFI_DISK_IO2_PROTOCOL     *DiskIo2,
     37   IN  EFI_BLOCK_IO_PROTOCOL     *BlockIo
     38   )
     39 {
     40   EFI_STATUS  Status;
     41   FAT_VOLUME  *Volume;
     42 
     43   //
     44   // Allocate a volume structure
     45   //
     46   Volume = AllocateZeroPool (sizeof (FAT_VOLUME));
     47   if (Volume == NULL) {
     48     return EFI_OUT_OF_RESOURCES;
     49   }
     50 
     51   //
     52   // Initialize the structure
     53   //
     54   Volume->Signature                   = FAT_VOLUME_SIGNATURE;
     55   Volume->Handle                      = Handle;
     56   Volume->DiskIo                      = DiskIo;
     57   Volume->DiskIo2                     = DiskIo2;
     58   Volume->BlockIo                     = BlockIo;
     59   Volume->MediaId                     = BlockIo->Media->MediaId;
     60   Volume->ReadOnly                    = BlockIo->Media->ReadOnly;
     61   Volume->VolumeInterface.Revision    = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;
     62   Volume->VolumeInterface.OpenVolume  = FatOpenVolume;
     63   InitializeListHead (&Volume->CheckRef);
     64   InitializeListHead (&Volume->DirCacheList);
     65   //
     66   // Initialize Root Directory entry
     67   //
     68   Volume->RootDirEnt.FileString       = Volume->RootFileString;
     69   Volume->RootDirEnt.Entry.Attributes = FAT_ATTRIBUTE_DIRECTORY;
     70   //
     71   // Check to see if there's a file system on the volume
     72   //
     73   Status = FatOpenDevice (Volume);
     74   if (EFI_ERROR (Status)) {
     75     goto Done;
     76   }
     77   //
     78   // Initialize cache
     79   //
     80   Status = FatInitializeDiskCache (Volume);
     81   if (EFI_ERROR (Status)) {
     82     goto Done;
     83   }
     84   //
     85   // Install our protocol interfaces on the device's handle
     86   //
     87   Status = gBS->InstallMultipleProtocolInterfaces (
     88                   &Volume->Handle,
     89                   &gEfiSimpleFileSystemProtocolGuid,
     90                   &Volume->VolumeInterface,
     91                   NULL
     92                   );
     93   if (EFI_ERROR (Status)) {
     94     goto Done;
     95   }
     96   //
     97   // Volume installed
     98   //
     99   DEBUG ((EFI_D_INIT, "Installed Fat filesystem on %p\n", Handle));
    100   Volume->Valid = TRUE;
    101 
    102 Done:
    103   if (EFI_ERROR (Status)) {
    104     FatFreeVolume (Volume);
    105   }
    106 
    107   return Status;
    108 }
    109 
    110 /**
    111 
    112   Called by FatDriverBindingStop(), Abandon the volume.
    113 
    114   @param  Volume                - The volume to be abandoned.
    115 
    116   @retval EFI_SUCCESS           - Abandoned the volume successfully.
    117   @return Others                - Can not uninstall the protocol interfaces.
    118 
    119 **/
    120 EFI_STATUS
    121 FatAbandonVolume (
    122   IN FAT_VOLUME *Volume
    123   )
    124 {
    125   EFI_STATUS  Status;
    126   BOOLEAN     LockedByMe;
    127 
    128   //
    129   // Uninstall the protocol interface.
    130   //
    131   if (Volume->Handle != NULL) {
    132     Status = gBS->UninstallMultipleProtocolInterfaces (
    133                     Volume->Handle,
    134                     &gEfiSimpleFileSystemProtocolGuid,
    135                     &Volume->VolumeInterface,
    136                     NULL
    137                     );
    138     if (EFI_ERROR (Status)) {
    139       return Status;
    140     }
    141   }
    142 
    143   LockedByMe = FALSE;
    144 
    145   //
    146   // Acquire the lock.
    147   // If the caller has already acquired the lock (which
    148   // means we are in the process of some Fat operation),
    149   // we can not acquire again.
    150   //
    151   Status = FatAcquireLockOrFail ();
    152   if (!EFI_ERROR (Status)) {
    153     LockedByMe = TRUE;
    154   }
    155   //
    156   // The volume is still being used. Hence, set error flag for all OFiles still in
    157   // use. In two cases, we could get here. One is EFI_MEDIA_CHANGED, the other is
    158   // EFI_NO_MEDIA.
    159   //
    160   if (Volume->Root != NULL) {
    161     FatSetVolumeError (
    162       Volume->Root,
    163       Volume->BlockIo->Media->MediaPresent ? EFI_MEDIA_CHANGED : EFI_NO_MEDIA
    164       );
    165   }
    166 
    167   Volume->Valid = FALSE;
    168 
    169   //
    170   // Release the lock.
    171   // If locked by me, this means DriverBindingStop is NOT
    172   // called within an on-going Fat operation, so we should
    173   // take responsibility to cleanup and free the volume.
    174   // Otherwise, the DriverBindingStop is called within an on-going
    175   // Fat operation, we shouldn't check reference, so just let outer
    176   // FatCleanupVolume do the task.
    177   //
    178   if (LockedByMe) {
    179     FatCleanupVolume (Volume, NULL, EFI_SUCCESS, NULL);
    180     FatReleaseLock ();
    181   }
    182 
    183   return EFI_SUCCESS;
    184 }
    185 
    186 /**
    187 
    188   Detects FAT file system on Disk and set relevant fields of Volume.
    189 
    190   @param Volume                - The volume structure.
    191 
    192   @retval EFI_SUCCESS           - The Fat File System is detected successfully
    193   @retval EFI_UNSUPPORTED       - The volume is not FAT file system.
    194   @retval EFI_VOLUME_CORRUPTED  - The volume is corrupted.
    195 
    196 **/
    197 EFI_STATUS
    198 FatOpenDevice (
    199   IN OUT FAT_VOLUME           *Volume
    200   )
    201 {
    202   EFI_STATUS            Status;
    203   UINT32                BlockSize;
    204   UINT32                DirtyMask;
    205   EFI_DISK_IO_PROTOCOL  *DiskIo;
    206   FAT_BOOT_SECTOR       FatBs;
    207   FAT_VOLUME_TYPE       FatType;
    208   UINTN                 RootDirSectors;
    209   UINTN                 FatLba;
    210   UINTN                 RootLba;
    211   UINTN                 FirstClusterLba;
    212   UINTN                 Sectors;
    213   UINTN                 SectorsPerFat;
    214   UINT8                 SectorsPerClusterAlignment;
    215   UINT8                 BlockAlignment;
    216 
    217   //
    218   // Read the FAT_BOOT_SECTOR BPB info
    219   // This is the only part of FAT code that uses parent DiskIo,
    220   // Others use FatDiskIo which utilizes a Cache.
    221   //
    222   DiskIo  = Volume->DiskIo;
    223   Status  = DiskIo->ReadDisk (DiskIo, Volume->MediaId, 0, sizeof (FatBs), &FatBs);
    224 
    225   if (EFI_ERROR (Status)) {
    226     DEBUG ((EFI_D_INIT, "FatOpenDevice: read of part_lba failed %r\n", Status));
    227     return Status;
    228   }
    229 
    230   FatType = FatUndefined;
    231 
    232   //
    233   // Use LargeSectors if Sectors is 0
    234   //
    235   Sectors = FatBs.FatBsb.Sectors;
    236   if (Sectors == 0) {
    237     Sectors = FatBs.FatBsb.LargeSectors;
    238   }
    239 
    240   SectorsPerFat = FatBs.FatBsb.SectorsPerFat;
    241   if (SectorsPerFat == 0) {
    242     SectorsPerFat = FatBs.FatBse.Fat32Bse.LargeSectorsPerFat;
    243     FatType       = Fat32;
    244   }
    245   //
    246   // Is boot sector a fat sector?
    247   // (Note that so far we only know if the sector is FAT32 or not, we don't
    248   // know if the sector is Fat16 or Fat12 until later when we can compute
    249   // the volume size)
    250   //
    251   if (FatBs.FatBsb.ReservedSectors == 0 || FatBs.FatBsb.NumFats == 0 || Sectors == 0) {
    252     return EFI_UNSUPPORTED;
    253   }
    254 
    255   if ((FatBs.FatBsb.SectorSize & (FatBs.FatBsb.SectorSize - 1)) != 0) {
    256     return EFI_UNSUPPORTED;
    257   }
    258 
    259   BlockAlignment = (UINT8) HighBitSet32 (FatBs.FatBsb.SectorSize);
    260   if (BlockAlignment > MAX_BLOCK_ALIGNMENT || BlockAlignment < MIN_BLOCK_ALIGNMENT) {
    261     return EFI_UNSUPPORTED;
    262   }
    263 
    264   if ((FatBs.FatBsb.SectorsPerCluster & (FatBs.FatBsb.SectorsPerCluster - 1)) != 0) {
    265     return EFI_UNSUPPORTED;
    266   }
    267 
    268   SectorsPerClusterAlignment = (UINT8) HighBitSet32 (FatBs.FatBsb.SectorsPerCluster);
    269   if (SectorsPerClusterAlignment > MAX_SECTORS_PER_CLUSTER_ALIGNMENT) {
    270     return EFI_UNSUPPORTED;
    271   }
    272 
    273   if (FatBs.FatBsb.Media <= 0xf7 &&
    274       FatBs.FatBsb.Media != 0xf0 &&
    275       FatBs.FatBsb.Media != 0x00 &&
    276       FatBs.FatBsb.Media != 0x01
    277       ) {
    278     return EFI_UNSUPPORTED;
    279   }
    280   //
    281   // Initialize fields the volume information for this FatType
    282   //
    283   if (FatType != Fat32) {
    284     if (FatBs.FatBsb.RootEntries == 0) {
    285       return EFI_UNSUPPORTED;
    286     }
    287     //
    288     // Unpack fat12, fat16 info
    289     //
    290     Volume->RootEntries = FatBs.FatBsb.RootEntries;
    291   } else {
    292     //
    293     // If this is fat32, refuse to mount mirror-disabled volumes
    294     //
    295     if ((SectorsPerFat == 0 || FatBs.FatBse.Fat32Bse.FsVersion != 0) || (FatBs.FatBse.Fat32Bse.ExtendedFlags & 0x80)) {
    296       return EFI_UNSUPPORTED;
    297     }
    298     //
    299     // Unpack fat32 info
    300     //
    301     Volume->RootCluster = FatBs.FatBse.Fat32Bse.RootDirFirstCluster;
    302   }
    303 
    304   Volume->NumFats           = FatBs.FatBsb.NumFats;
    305   //
    306   // Compute some fat locations
    307   //
    308   BlockSize                 = FatBs.FatBsb.SectorSize;
    309   RootDirSectors            = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (BlockSize - 1)) / BlockSize;
    310 
    311   FatLba                    = FatBs.FatBsb.ReservedSectors;
    312   RootLba                   = FatBs.FatBsb.NumFats * SectorsPerFat + FatLba;
    313   FirstClusterLba           = RootLba + RootDirSectors;
    314 
    315   Volume->FatPos            = FatLba * BlockSize;
    316   Volume->FatSize           = SectorsPerFat * BlockSize;
    317 
    318   Volume->VolumeSize        = LShiftU64 (Sectors, BlockAlignment);
    319   Volume->RootPos           = LShiftU64 (RootLba, BlockAlignment);
    320   Volume->FirstClusterPos   = LShiftU64 (FirstClusterLba, BlockAlignment);
    321   Volume->MaxCluster        = (Sectors - FirstClusterLba) >> SectorsPerClusterAlignment;
    322   Volume->ClusterAlignment  = (UINT8)(BlockAlignment + SectorsPerClusterAlignment);
    323   Volume->ClusterSize       = (UINTN)1 << (Volume->ClusterAlignment);
    324 
    325   //
    326   // If this is not a fat32, determine if it's a fat16 or fat12
    327   //
    328   if (FatType != Fat32) {
    329     if (Volume->MaxCluster >= FAT_MAX_FAT16_CLUSTER) {
    330       return EFI_VOLUME_CORRUPTED;
    331     }
    332 
    333     FatType = Volume->MaxCluster < FAT_MAX_FAT12_CLUSTER ? Fat12 : Fat16;
    334     //
    335     // fat12 & fat16 fat-entries are 2 bytes
    336     //
    337     Volume->FatEntrySize = sizeof (UINT16);
    338     DirtyMask            = FAT16_DIRTY_MASK;
    339   } else {
    340     if (Volume->MaxCluster < FAT_MAX_FAT16_CLUSTER) {
    341       return EFI_VOLUME_CORRUPTED;
    342     }
    343     //
    344     // fat32 fat-entries are 4 bytes
    345     //
    346     Volume->FatEntrySize = sizeof (UINT32);
    347     DirtyMask            = FAT32_DIRTY_MASK;
    348   }
    349   //
    350   // Get the DirtyValue and NotDirtyValue
    351   // We should keep the initial value as the NotDirtyValue
    352   // in case the volume is dirty already
    353   //
    354   if (FatType != Fat12) {
    355     Status = FatAccessVolumeDirty (Volume, ReadDisk, &Volume->NotDirtyValue);
    356     if (EFI_ERROR (Status)) {
    357       return Status;
    358     }
    359 
    360     Volume->DirtyValue = Volume->NotDirtyValue & DirtyMask;
    361   }
    362   //
    363   // If present, read the fat hint info
    364   //
    365   if (FatType == Fat32) {
    366     Volume->FreeInfoPos = FatBs.FatBse.Fat32Bse.FsInfoSector * BlockSize;
    367     if (FatBs.FatBse.Fat32Bse.FsInfoSector != 0) {
    368       FatDiskIo (Volume, ReadDisk, Volume->FreeInfoPos, sizeof (FAT_INFO_SECTOR), &Volume->FatInfoSector, NULL);
    369       if (Volume->FatInfoSector.Signature == FAT_INFO_SIGNATURE &&
    370           Volume->FatInfoSector.InfoBeginSignature == FAT_INFO_BEGIN_SIGNATURE &&
    371           Volume->FatInfoSector.InfoEndSignature == FAT_INFO_END_SIGNATURE &&
    372           Volume->FatInfoSector.FreeInfo.ClusterCount <= Volume->MaxCluster
    373           ) {
    374         Volume->FreeInfoValid = TRUE;
    375       }
    376     }
    377   }
    378   //
    379   // Just make up a FreeInfo.NextCluster for use by allocate cluster
    380   //
    381   if (FAT_MIN_CLUSTER > Volume->FatInfoSector.FreeInfo.NextCluster ||
    382      Volume->FatInfoSector.FreeInfo.NextCluster > Volume->MaxCluster + 1
    383      ) {
    384     Volume->FatInfoSector.FreeInfo.NextCluster = FAT_MIN_CLUSTER;
    385   }
    386   //
    387   // We are now defining FAT Type
    388   //
    389   Volume->FatType = FatType;
    390   ASSERT (FatType != FatUndefined);
    391 
    392   return EFI_SUCCESS;
    393 }
    394