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