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