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
FatAllocateVolume(IN EFI_HANDLE Handle,IN EFI_DISK_IO_PROTOCOL * DiskIo,IN EFI_DISK_IO2_PROTOCOL * DiskIo2,IN EFI_BLOCK_IO_PROTOCOL * BlockIo)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
FatAbandonVolume(IN FAT_VOLUME * Volume)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
FatOpenDevice(IN OUT FAT_VOLUME * Volume)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