3 Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>
4 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_DISK_IO2_PROTOCOL
*DiskIo2
,
30 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
36 Allocates volume structure, detects FAT file system, installs protocol,
41 Handle - The handle of parent device.
42 DiskIo - The DiskIo of parent device.
43 BlockIo - The BlockIo of parent devicel
47 EFI_SUCCESS - Allocate a new volume successfully.
48 EFI_OUT_OF_RESOURCES - Can not allocate the memory.
49 Others - Allocating a new volume failed.
57 // Allocate a volume structure
59 Volume
= AllocateZeroPool (sizeof (FAT_VOLUME
));
61 return EFI_OUT_OF_RESOURCES
;
65 // Initialize the structure
67 Volume
->Signature
= FAT_VOLUME_SIGNATURE
;
68 Volume
->Handle
= Handle
;
69 Volume
->DiskIo
= DiskIo
;
70 Volume
->DiskIo2
= DiskIo2
;
71 Volume
->BlockIo
= BlockIo
;
72 Volume
->MediaId
= BlockIo
->Media
->MediaId
;
73 Volume
->ReadOnly
= BlockIo
->Media
->ReadOnly
;
74 Volume
->VolumeInterface
.Revision
= EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION
;
75 Volume
->VolumeInterface
.OpenVolume
= FatOpenVolume
;
76 InitializeListHead (&Volume
->CheckRef
);
77 InitializeListHead (&Volume
->DirCacheList
);
79 // Initialize Root Directory entry
81 Volume
->RootDirEnt
.FileString
= Volume
->RootFileString
;
82 Volume
->RootDirEnt
.Entry
.Attributes
= FAT_ATTRIBUTE_DIRECTORY
;
84 // Check to see if there's a file system on the volume
86 Status
= FatOpenDevice (Volume
);
87 if (EFI_ERROR (Status
)) {
93 Status
= FatInitializeDiskCache (Volume
);
94 if (EFI_ERROR (Status
)) {
98 // Install our protocol interfaces on the device's handle
100 Status
= gBS
->InstallMultipleProtocolInterfaces (
102 &gEfiSimpleFileSystemProtocolGuid
,
103 &Volume
->VolumeInterface
,
106 if (EFI_ERROR (Status
)) {
112 DEBUG ((EFI_D_INIT
, "Installed Fat filesystem on %p\n", Handle
));
113 Volume
->Valid
= TRUE
;
116 if (EFI_ERROR (Status
)) {
117 FatFreeVolume (Volume
);
125 IN FAT_VOLUME
*Volume
131 Called by FatDriverBindingStop(), Abandon the volume.
135 Volume - The volume to be abandoned.
139 EFI_SUCCESS - Abandoned the volume successfully.
140 Others - Can not uninstall the protocol interfaces.
148 // Uninstall the protocol interface.
150 if (Volume
->Handle
!= NULL
) {
151 Status
= gBS
->UninstallMultipleProtocolInterfaces (
153 &gEfiSimpleFileSystemProtocolGuid
,
154 &Volume
->VolumeInterface
,
157 if (EFI_ERROR (Status
)) {
166 // If the caller has already acquired the lock (which
167 // means we are in the process of some Fat operation),
168 // we can not acquire again.
170 Status
= FatAcquireLockOrFail ();
171 if (!EFI_ERROR (Status
)) {
175 // The volume is still being used. Hence, set error flag for all OFiles still in
176 // use. In two cases, we could get here. One is EFI_MEDIA_CHANGED, the other is
179 if (Volume
->Root
!= NULL
) {
182 Volume
->BlockIo
->Media
->MediaPresent
? EFI_MEDIA_CHANGED
: EFI_NO_MEDIA
186 Volume
->Valid
= FALSE
;
190 // If locked by me, this means DriverBindingStop is NOT
191 // called within an on-going Fat operation, so we should
192 // take responsibility to cleanup and free the volume.
193 // Otherwise, the DriverBindingStop is called within an on-going
194 // Fat operation, we shouldn't check reference, so just let outer
195 // FatCleanupVolume do the task.
198 FatCleanupVolume (Volume
, NULL
, EFI_SUCCESS
, NULL
);
207 IN OUT FAT_VOLUME
*Volume
213 Detects FAT file system on Disk and set relevant fields of Volume
217 Volume - The volume structure.
221 EFI_SUCCESS - The Fat File System is detected successfully
222 EFI_UNSUPPORTED - The volume is not FAT file system.
223 EFI_VOLUME_CORRUPTED - The volume is corrupted.
230 EFI_DISK_IO_PROTOCOL
*DiskIo
;
231 FAT_BOOT_SECTOR FatBs
;
232 FAT_VOLUME_TYPE FatType
;
233 UINTN RootDirSectors
;
236 UINTN FirstClusterLba
;
239 UINT8 SectorsPerClusterAlignment
;
240 UINT8 BlockAlignment
;
243 // Read the FAT_BOOT_SECTOR BPB info
244 // This is the only part of FAT code that uses parent DiskIo,
245 // Others use FatDiskIo which utilizes a Cache.
247 DiskIo
= Volume
->DiskIo
;
248 Status
= DiskIo
->ReadDisk (DiskIo
, Volume
->MediaId
, 0, sizeof (FatBs
), &FatBs
);
250 if (EFI_ERROR (Status
)) {
251 DEBUG ((EFI_D_INIT
, "FatOpenDevice: read of part_lba failed %r\n", Status
));
255 FatType
= FatUndefined
;
258 // Use LargeSectors if Sectors is 0
260 Sectors
= FatBs
.FatBsb
.Sectors
;
262 Sectors
= FatBs
.FatBsb
.LargeSectors
;
265 SectorsPerFat
= FatBs
.FatBsb
.SectorsPerFat
;
266 if (SectorsPerFat
== 0) {
267 SectorsPerFat
= FatBs
.FatBse
.Fat32Bse
.LargeSectorsPerFat
;
271 // Is boot sector a fat sector?
272 // (Note that so far we only know if the sector is FAT32 or not, we don't
273 // know if the sector is Fat16 or Fat12 until later when we can compute
276 if (FatBs
.FatBsb
.ReservedSectors
== 0 || FatBs
.FatBsb
.NumFats
== 0 || Sectors
== 0) {
277 return EFI_UNSUPPORTED
;
280 if ((FatBs
.FatBsb
.SectorSize
& (FatBs
.FatBsb
.SectorSize
- 1)) != 0) {
281 return EFI_UNSUPPORTED
;
284 BlockAlignment
= (UINT8
) HighBitSet32 (FatBs
.FatBsb
.SectorSize
);
285 if (BlockAlignment
> MAX_BLOCK_ALIGNMENT
|| BlockAlignment
< MIN_BLOCK_ALIGNMENT
) {
286 return EFI_UNSUPPORTED
;
289 if ((FatBs
.FatBsb
.SectorsPerCluster
& (FatBs
.FatBsb
.SectorsPerCluster
- 1)) != 0) {
290 return EFI_UNSUPPORTED
;
293 SectorsPerClusterAlignment
= (UINT8
) HighBitSet32 (FatBs
.FatBsb
.SectorsPerCluster
);
294 if (SectorsPerClusterAlignment
> MAX_SECTORS_PER_CLUSTER_ALIGNMENT
) {
295 return EFI_UNSUPPORTED
;
298 if (FatBs
.FatBsb
.Media
<= 0xf7 &&
299 FatBs
.FatBsb
.Media
!= 0xf0 &&
300 FatBs
.FatBsb
.Media
!= 0x00 &&
301 FatBs
.FatBsb
.Media
!= 0x01
303 return EFI_UNSUPPORTED
;
306 // Initialize fields the volume information for this FatType
308 if (FatType
!= FAT32
) {
309 if (FatBs
.FatBsb
.RootEntries
== 0) {
310 return EFI_UNSUPPORTED
;
313 // Unpack fat12, fat16 info
315 Volume
->RootEntries
= FatBs
.FatBsb
.RootEntries
;
318 // If this is fat32, refuse to mount mirror-disabled volumes
320 if ((SectorsPerFat
== 0 || FatBs
.FatBse
.Fat32Bse
.FsVersion
!= 0) || (FatBs
.FatBse
.Fat32Bse
.ExtendedFlags
& 0x80)) {
321 return EFI_UNSUPPORTED
;
326 Volume
->RootCluster
= FatBs
.FatBse
.Fat32Bse
.RootDirFirstCluster
;
329 Volume
->NumFats
= FatBs
.FatBsb
.NumFats
;
331 // Compute some fat locations
333 BlockSize
= FatBs
.FatBsb
.SectorSize
;
334 RootDirSectors
= ((Volume
->RootEntries
* sizeof (FAT_DIRECTORY_ENTRY
)) + (BlockSize
- 1)) / BlockSize
;
336 FatLba
= FatBs
.FatBsb
.ReservedSectors
;
337 RootLba
= FatBs
.FatBsb
.NumFats
* SectorsPerFat
+ FatLba
;
338 FirstClusterLba
= RootLba
+ RootDirSectors
;
340 Volume
->FatPos
= FatLba
* BlockSize
;
341 Volume
->FatSize
= SectorsPerFat
* BlockSize
;
343 Volume
->VolumeSize
= LShiftU64 (Sectors
, BlockAlignment
);
344 Volume
->RootPos
= LShiftU64 (RootLba
, BlockAlignment
);
345 Volume
->FirstClusterPos
= LShiftU64 (FirstClusterLba
, BlockAlignment
);
346 Volume
->MaxCluster
= (Sectors
- FirstClusterLba
) >> SectorsPerClusterAlignment
;
347 Volume
->ClusterAlignment
= (UINT8
)(BlockAlignment
+ SectorsPerClusterAlignment
);
348 Volume
->ClusterSize
= (UINTN
)1 << (Volume
->ClusterAlignment
);
351 // If this is not a fat32, determine if it's a fat16 or fat12
353 if (FatType
!= FAT32
) {
354 if (Volume
->MaxCluster
>= FAT_MAX_FAT16_CLUSTER
) {
355 return EFI_VOLUME_CORRUPTED
;
358 FatType
= Volume
->MaxCluster
< FAT_MAX_FAT12_CLUSTER
? FAT12
: FAT16
;
360 // fat12 & fat16 fat-entries are 2 bytes
362 Volume
->FatEntrySize
= sizeof (UINT16
);
363 DirtyMask
= FAT16_DIRTY_MASK
;
365 if (Volume
->MaxCluster
< FAT_MAX_FAT16_CLUSTER
) {
366 return EFI_VOLUME_CORRUPTED
;
369 // fat32 fat-entries are 4 bytes
371 Volume
->FatEntrySize
= sizeof (UINT32
);
372 DirtyMask
= FAT32_DIRTY_MASK
;
375 // Get the DirtyValue and NotDirtyValue
376 // We should keep the initial value as the NotDirtyValue
377 // in case the volume is dirty already
379 if (FatType
!= FAT12
) {
380 Status
= FatAccessVolumeDirty (Volume
, READ_DISK
, &Volume
->NotDirtyValue
);
381 if (EFI_ERROR (Status
)) {
385 Volume
->DirtyValue
= Volume
->NotDirtyValue
& DirtyMask
;
388 // If present, read the fat hint info
390 if (FatType
== FAT32
) {
391 Volume
->FreeInfoPos
= FatBs
.FatBse
.Fat32Bse
.FsInfoSector
* BlockSize
;
392 if (FatBs
.FatBse
.Fat32Bse
.FsInfoSector
!= 0) {
393 FatDiskIo (Volume
, READ_DISK
, Volume
->FreeInfoPos
, sizeof (FAT_INFO_SECTOR
), &Volume
->FatInfoSector
, NULL
);
394 if (Volume
->FatInfoSector
.Signature
== FAT_INFO_SIGNATURE
&&
395 Volume
->FatInfoSector
.InfoBeginSignature
== FAT_INFO_BEGIN_SIGNATURE
&&
396 Volume
->FatInfoSector
.InfoEndSignature
== FAT_INFO_END_SIGNATURE
&&
397 Volume
->FatInfoSector
.FreeInfo
.ClusterCount
<= Volume
->MaxCluster
399 Volume
->FreeInfoValid
= TRUE
;
404 // Just make up a FreeInfo.NextCluster for use by allocate cluster
406 if (FAT_MIN_CLUSTER
> Volume
->FatInfoSector
.FreeInfo
.NextCluster
||
407 Volume
->FatInfoSector
.FreeInfo
.NextCluster
> Volume
->MaxCluster
+ 1
409 Volume
->FatInfoSector
.FreeInfo
.NextCluster
= FAT_MIN_CLUSTER
;
412 // We are now defining FAT Type
414 Volume
->FatType
= FatType
;
415 ASSERT (FatType
!= FatUndefined
);