3 Copyright (c) 2005 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials are licensed and made available
5 under the terms and conditions of the BSD License which accompanies this
6 distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 Initialization routines
28 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
29 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
35 Allocates volume structure, detects FAT file system, installs protocol,
40 Handle - The handle of parent device.
41 DiskIo - The DiskIo of parent device.
42 BlockIo - The BlockIo of parent devicel
46 EFI_SUCCESS - Allocate a new volume successfully.
47 EFI_OUT_OF_RESOURCES - Can not allocate the memory.
48 Others - Allocating a new volume failed.
57 // Allocate a volume structure
59 Volume
= AllocateZeroPool (sizeof (FAT_VOLUME
));
61 return EFI_OUT_OF_RESOURCES
;
65 // If caller has already acquired the lock, cannot lock it again.
67 if (!FatIsLocked ()) {
72 // Initialize the structure
74 Volume
->Signature
= FAT_VOLUME_SIGNATURE
;
75 Volume
->Handle
= Handle
;
76 Volume
->DiskIo
= DiskIo
;
77 Volume
->BlockIo
= BlockIo
;
78 Volume
->MediaId
= BlockIo
->Media
->MediaId
;
79 Volume
->ReadOnly
= BlockIo
->Media
->ReadOnly
;
80 Volume
->VolumeInterface
.Revision
= EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
;
81 Volume
->VolumeInterface
.OpenVolume
= FatOpenVolume
;
82 InitializeListHead (&Volume
->CheckRef
);
83 InitializeListHead (&Volume
->DirCacheList
);
85 // Initialize Root Directory entry
87 Volume
->RootDirEnt
.FileString
= Volume
->RootFileString
;
88 Volume
->RootDirEnt
.Entry
.Attributes
= FAT_ATTRIBUTE_DIRECTORY
;
90 // Check to see if there's a file system on the volume
92 Status
= FatOpenDevice (Volume
);
93 if (EFI_ERROR (Status
)) {
99 Status
= FatInitializeDiskCache (Volume
);
100 if (EFI_ERROR (Status
)) {
104 // Install our protocol interfaces on the device's handle
106 Status
= gBS
->InstallMultipleProtocolInterfaces (
108 &gEfiSimpleFileSystemProtocolGuid
,
109 &Volume
->VolumeInterface
,
112 if (EFI_ERROR (Status
)) {
118 DEBUG ((EFI_D_INIT
, "Installed Fat filesystem on %p\n", Handle
));
119 Volume
->Valid
= TRUE
;
123 // Unlock if locked by myself.
129 if (EFI_ERROR (Status
)) {
130 FatFreeVolume (Volume
);
138 IN FAT_VOLUME
*Volume
144 Called by FatDriverBindingStop(), Abandon the volume.
148 Volume - The volume to be abandoned.
152 EFI_SUCCESS - Abandoned the volume successfully.
153 Others - Can not uninstall the protocol interfaces.
161 // Uninstall the protocol interface.
163 if (Volume
->Handle
!= NULL
) {
164 Status
= gBS
->UninstallMultipleProtocolInterfaces (
166 &gEfiSimpleFileSystemProtocolGuid
,
167 &Volume
->VolumeInterface
,
170 if (EFI_ERROR (Status
)) {
179 // If the caller has already acquired the lock (which
180 // means we are in the process of some Fat operation),
181 // we can not acquire again.
183 if (!FatIsLocked ()) {
188 // The volume is still being used. Hence, set error flag for all OFiles still in
189 // use. In two cases, we could get here. One is EFI_MEDIA_CHANGED, the other is
192 if (Volume
->Root
!= NULL
) {
195 Volume
->BlockIo
->Media
->MediaPresent
? EFI_MEDIA_CHANGED
: EFI_NO_MEDIA
199 Volume
->Valid
= FALSE
;
203 // If locked by me, this means DriverBindingStop is NOT
204 // called within an on-going Fat operation, so we should
205 // take responsibility to cleanup and free the volume.
206 // Otherwise, the DriverBindingStop is called within an on-going
207 // Fat operation, we shouldn't check reference, so just let outer
208 // FatCleanupVolume do the task.
211 FatCleanupVolume (Volume
, NULL
, EFI_SUCCESS
);
220 IN OUT FAT_VOLUME
*Volume
226 Detects FAT file system on Disk and set relevant fields of Volume
230 Volume - The volume structure.
234 EFI_SUCCESS - The Fat File System is detected successfully
235 EFI_UNSUPPORTED - The volume is not FAT file system.
236 EFI_VOLUME_CORRUPTED - The volume is corrupted.
243 EFI_DISK_IO_PROTOCOL
*DiskIo
;
244 FAT_BOOT_SECTOR FatBs
;
245 FAT_VOLUME_TYPE FatType
;
246 UINTN RootDirSectors
;
249 UINTN FirstClusterLba
;
252 UINT8 SectorsPerClusterAlignment
;
253 UINT8 BlockAlignment
;
256 // Read the FAT_BOOT_SECTOR BPB info
257 // This is the only part of FAT code that uses parent DiskIo,
258 // Others use FatDiskIo which utilizes a Cache.
260 DiskIo
= Volume
->DiskIo
;
261 Status
= DiskIo
->ReadDisk (DiskIo
, Volume
->MediaId
, 0, sizeof (FatBs
), &FatBs
);
263 if (EFI_ERROR (Status
)) {
264 DEBUG ((EFI_D_INIT
, "FatOpenDevice: read of part_lba failed %r\n", Status
));
268 FatType
= FatUndefined
;
271 // Use LargeSectors if Sectors is 0
273 Sectors
= FatBs
.FatBsb
.Sectors
;
275 Sectors
= FatBs
.FatBsb
.LargeSectors
;
278 SectorsPerFat
= FatBs
.FatBsb
.SectorsPerFat
;
279 if (SectorsPerFat
== 0) {
280 SectorsPerFat
= FatBs
.FatBse
.Fat32Bse
.LargeSectorsPerFat
;
284 // Is boot sector a fat sector?
285 // (Note that so far we only know if the sector is FAT32 or not, we don't
286 // know if the sector is Fat16 or Fat12 until later when we can compute
289 if (FatBs
.FatBsb
.ReservedSectors
== 0 || FatBs
.FatBsb
.NumFats
== 0 || Sectors
== 0) {
290 return EFI_UNSUPPORTED
;
293 if ((FatBs
.FatBsb
.SectorSize
& (FatBs
.FatBsb
.SectorSize
- 1)) != 0) {
294 return EFI_UNSUPPORTED
;
297 BlockAlignment
= (UINT8
) HighBitSet32 (FatBs
.FatBsb
.SectorSize
);
298 if (BlockAlignment
> MAX_BLOCK_ALIGNMENT
|| BlockAlignment
< MIN_BLOCK_ALIGNMENT
) {
299 return EFI_UNSUPPORTED
;
302 if ((FatBs
.FatBsb
.SectorsPerCluster
& (FatBs
.FatBsb
.SectorsPerCluster
- 1)) != 0) {
303 return EFI_UNSUPPORTED
;
306 SectorsPerClusterAlignment
= (UINT8
) HighBitSet32 (FatBs
.FatBsb
.SectorsPerCluster
);
307 if (SectorsPerClusterAlignment
> MAX_SECTORS_PER_CLUSTER_ALIGNMENT
) {
308 return EFI_UNSUPPORTED
;
311 if (FatBs
.FatBsb
.Media
<= 0xf7 &&
312 FatBs
.FatBsb
.Media
!= 0xf0 &&
313 FatBs
.FatBsb
.Media
!= 0x00 &&
314 FatBs
.FatBsb
.Media
!= 0x01
316 return EFI_UNSUPPORTED
;
319 // Initialize fields the volume information for this FatType
321 if (FatType
!= FAT32
) {
322 if (FatBs
.FatBsb
.RootEntries
== 0) {
323 return EFI_UNSUPPORTED
;
326 // Unpack fat12, fat16 info
328 Volume
->RootEntries
= FatBs
.FatBsb
.RootEntries
;
331 // If this is fat32, refuse to mount mirror-disabled volumes
333 if ((SectorsPerFat
== 0 || FatBs
.FatBse
.Fat32Bse
.FsVersion
!= 0) || (FatBs
.FatBse
.Fat32Bse
.ExtendedFlags
& 0x80)) {
334 return EFI_UNSUPPORTED
;
339 Volume
->RootCluster
= FatBs
.FatBse
.Fat32Bse
.RootDirFirstCluster
;
342 Volume
->NumFats
= FatBs
.FatBsb
.NumFats
;
344 // Compute some fat locations
346 BlockSize
= FatBs
.FatBsb
.SectorSize
;
347 RootDirSectors
= ((Volume
->RootEntries
* sizeof (FAT_DIRECTORY_ENTRY
)) + (BlockSize
- 1)) / BlockSize
;
349 FatLba
= FatBs
.FatBsb
.ReservedSectors
;
350 RootLba
= FatBs
.FatBsb
.NumFats
* SectorsPerFat
+ FatLba
;
351 FirstClusterLba
= RootLba
+ RootDirSectors
;
353 Volume
->FatPos
= FatLba
* BlockSize
;
354 Volume
->FatSize
= SectorsPerFat
* BlockSize
;
356 Volume
->VolumeSize
= LShiftU64 (Sectors
, BlockAlignment
);
357 Volume
->RootPos
= LShiftU64 (RootLba
, BlockAlignment
);
358 Volume
->FirstClusterPos
= LShiftU64 (FirstClusterLba
, BlockAlignment
);
359 Volume
->MaxCluster
= (Sectors
- FirstClusterLba
) >> SectorsPerClusterAlignment
;
360 Volume
->ClusterAlignment
= (UINT8
)(BlockAlignment
+ SectorsPerClusterAlignment
);
361 Volume
->ClusterSize
= (UINTN
)1 << (Volume
->ClusterAlignment
);
364 // If this is not a fat32, determine if it's a fat16 or fat12
366 if (FatType
!= FAT32
) {
367 if (Volume
->MaxCluster
>= FAT_MAX_FAT16_CLUSTER
) {
368 return EFI_VOLUME_CORRUPTED
;
371 FatType
= Volume
->MaxCluster
< FAT_MAX_FAT12_CLUSTER
? FAT12
: FAT16
;
373 // fat12 & fat16 fat-entries are 2 bytes
375 Volume
->FatEntrySize
= sizeof (UINT16
);
376 DirtyMask
= FAT16_DIRTY_MASK
;
378 if (Volume
->MaxCluster
< FAT_MAX_FAT16_CLUSTER
) {
379 return EFI_VOLUME_CORRUPTED
;
382 // fat32 fat-entries are 4 bytes
384 Volume
->FatEntrySize
= sizeof (UINT32
);
385 DirtyMask
= FAT32_DIRTY_MASK
;
388 // Get the DirtyValue and NotDirtyValue
389 // We should keep the initial value as the NotDirtyValue
390 // in case the volume is dirty already
392 if (FatType
!= FAT12
) {
393 Status
= FatAccessVolumeDirty (Volume
, READ_DISK
, &Volume
->NotDirtyValue
);
394 if (EFI_ERROR (Status
)) {
398 Volume
->DirtyValue
= Volume
->NotDirtyValue
& DirtyMask
;
401 // If present, read the fat hint info
403 if (FatType
== FAT32
) {
404 Volume
->FreeInfoPos
= FatBs
.FatBse
.Fat32Bse
.FsInfoSector
* BlockSize
;
405 if (FatBs
.FatBse
.Fat32Bse
.FsInfoSector
!= 0) {
406 FatDiskIo (Volume
, READ_DISK
, Volume
->FreeInfoPos
, sizeof (FAT_INFO_SECTOR
), &Volume
->FatInfoSector
);
407 if (Volume
->FatInfoSector
.Signature
== FAT_INFO_SIGNATURE
&&
408 Volume
->FatInfoSector
.InfoBeginSignature
== FAT_INFO_BEGIN_SIGNATURE
&&
409 Volume
->FatInfoSector
.InfoEndSignature
== FAT_INFO_END_SIGNATURE
&&
410 Volume
->FatInfoSector
.FreeInfo
.ClusterCount
<= Volume
->MaxCluster
412 Volume
->FreeInfoValid
= TRUE
;
417 // Just make up a FreeInfo.NextCluster for use by allocate cluster
419 if (FAT_MIN_CLUSTER
> Volume
->FatInfoSector
.FreeInfo
.NextCluster
||
420 Volume
->FatInfoSector
.FreeInfo
.NextCluster
> Volume
->MaxCluster
+ 1
422 Volume
->FatInfoSector
.FreeInfo
.NextCluster
= FAT_MIN_CLUSTER
;
425 // We are now defining FAT Type
427 Volume
->FatType
= FatType
;
428 ASSERT (FatType
!= FatUndefined
);