2 Initialization routines.
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
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.
19 Allocates volume structure, detects FAT file system, installs protocol,
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
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.
35 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
36 IN EFI_DISK_IO2_PROTOCOL
*DiskIo2
,
37 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
44 // Allocate a volume structure
46 Volume
= AllocateZeroPool (sizeof (FAT_VOLUME
));
48 return EFI_OUT_OF_RESOURCES
;
52 // Initialize the structure
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
);
66 // Initialize Root Directory entry
68 Volume
->RootDirEnt
.FileString
= Volume
->RootFileString
;
69 Volume
->RootDirEnt
.Entry
.Attributes
= FAT_ATTRIBUTE_DIRECTORY
;
71 // Check to see if there's a file system on the volume
73 Status
= FatOpenDevice (Volume
);
74 if (EFI_ERROR (Status
)) {
80 Status
= FatInitializeDiskCache (Volume
);
81 if (EFI_ERROR (Status
)) {
85 // Install our protocol interfaces on the device's handle
87 Status
= gBS
->InstallMultipleProtocolInterfaces (
89 &gEfiSimpleFileSystemProtocolGuid
,
90 &Volume
->VolumeInterface
,
93 if (EFI_ERROR (Status
)) {
99 DEBUG ((EFI_D_INIT
, "Installed Fat filesystem on %p\n", Handle
));
100 Volume
->Valid
= TRUE
;
103 if (EFI_ERROR (Status
)) {
104 FatFreeVolume (Volume
);
112 Called by FatDriverBindingStop(), Abandon the volume.
114 @param Volume - The volume to be abandoned.
116 @retval EFI_SUCCESS - Abandoned the volume successfully.
117 @return Others - Can not uninstall the protocol interfaces.
122 IN FAT_VOLUME
*Volume
129 // Uninstall the protocol interface.
131 if (Volume
->Handle
!= NULL
) {
132 Status
= gBS
->UninstallMultipleProtocolInterfaces (
134 &gEfiSimpleFileSystemProtocolGuid
,
135 &Volume
->VolumeInterface
,
138 if (EFI_ERROR (Status
)) {
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.
151 Status
= FatAcquireLockOrFail ();
152 if (!EFI_ERROR (Status
)) {
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
160 if (Volume
->Root
!= NULL
) {
163 Volume
->BlockIo
->Media
->MediaPresent
? EFI_MEDIA_CHANGED
: EFI_NO_MEDIA
167 Volume
->Valid
= FALSE
;
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.
179 FatCleanupVolume (Volume
, NULL
, EFI_SUCCESS
, NULL
);
188 Detects FAT file system on Disk and set relevant fields of Volume.
190 @param Volume - The volume structure.
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.
199 IN OUT FAT_VOLUME
*Volume
205 EFI_DISK_IO_PROTOCOL
*DiskIo
;
206 FAT_BOOT_SECTOR FatBs
;
207 FAT_VOLUME_TYPE FatType
;
208 UINTN RootDirSectors
;
211 UINTN FirstClusterLba
;
214 UINT8 SectorsPerClusterAlignment
;
215 UINT8 BlockAlignment
;
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.
222 DiskIo
= Volume
->DiskIo
;
223 Status
= DiskIo
->ReadDisk (DiskIo
, Volume
->MediaId
, 0, sizeof (FatBs
), &FatBs
);
225 if (EFI_ERROR (Status
)) {
226 DEBUG ((EFI_D_INIT
, "FatOpenDevice: read of part_lba failed %r\n", Status
));
230 FatType
= FatUndefined
;
233 // Use LargeSectors if Sectors is 0
235 Sectors
= FatBs
.FatBsb
.Sectors
;
237 Sectors
= FatBs
.FatBsb
.LargeSectors
;
240 SectorsPerFat
= FatBs
.FatBsb
.SectorsPerFat
;
241 if (SectorsPerFat
== 0) {
242 SectorsPerFat
= FatBs
.FatBse
.Fat32Bse
.LargeSectorsPerFat
;
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
251 if (FatBs
.FatBsb
.ReservedSectors
== 0 || FatBs
.FatBsb
.NumFats
== 0 || Sectors
== 0) {
252 return EFI_UNSUPPORTED
;
255 if ((FatBs
.FatBsb
.SectorSize
& (FatBs
.FatBsb
.SectorSize
- 1)) != 0) {
256 return EFI_UNSUPPORTED
;
259 BlockAlignment
= (UINT8
) HighBitSet32 (FatBs
.FatBsb
.SectorSize
);
260 if (BlockAlignment
> MAX_BLOCK_ALIGNMENT
|| BlockAlignment
< MIN_BLOCK_ALIGNMENT
) {
261 return EFI_UNSUPPORTED
;
264 if ((FatBs
.FatBsb
.SectorsPerCluster
& (FatBs
.FatBsb
.SectorsPerCluster
- 1)) != 0) {
265 return EFI_UNSUPPORTED
;
268 SectorsPerClusterAlignment
= (UINT8
) HighBitSet32 (FatBs
.FatBsb
.SectorsPerCluster
);
269 if (SectorsPerClusterAlignment
> MAX_SECTORS_PER_CLUSTER_ALIGNMENT
) {
270 return EFI_UNSUPPORTED
;
273 if (FatBs
.FatBsb
.Media
<= 0xf7 &&
274 FatBs
.FatBsb
.Media
!= 0xf0 &&
275 FatBs
.FatBsb
.Media
!= 0x00 &&
276 FatBs
.FatBsb
.Media
!= 0x01
278 return EFI_UNSUPPORTED
;
281 // Initialize fields the volume information for this FatType
283 if (FatType
!= Fat32
) {
284 if (FatBs
.FatBsb
.RootEntries
== 0) {
285 return EFI_UNSUPPORTED
;
288 // Unpack fat12, fat16 info
290 Volume
->RootEntries
= FatBs
.FatBsb
.RootEntries
;
293 // If this is fat32, refuse to mount mirror-disabled volumes
295 if ((SectorsPerFat
== 0 || FatBs
.FatBse
.Fat32Bse
.FsVersion
!= 0) || (FatBs
.FatBse
.Fat32Bse
.ExtendedFlags
& 0x80)) {
296 return EFI_UNSUPPORTED
;
301 Volume
->RootCluster
= FatBs
.FatBse
.Fat32Bse
.RootDirFirstCluster
;
304 Volume
->NumFats
= FatBs
.FatBsb
.NumFats
;
306 // Compute some fat locations
308 BlockSize
= FatBs
.FatBsb
.SectorSize
;
309 RootDirSectors
= ((Volume
->RootEntries
* sizeof (FAT_DIRECTORY_ENTRY
)) + (BlockSize
- 1)) / BlockSize
;
311 FatLba
= FatBs
.FatBsb
.ReservedSectors
;
312 RootLba
= FatBs
.FatBsb
.NumFats
* SectorsPerFat
+ FatLba
;
313 FirstClusterLba
= RootLba
+ RootDirSectors
;
315 Volume
->FatPos
= FatLba
* BlockSize
;
316 Volume
->FatSize
= SectorsPerFat
* BlockSize
;
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
);
326 // If this is not a fat32, determine if it's a fat16 or fat12
328 if (FatType
!= Fat32
) {
329 if (Volume
->MaxCluster
>= FAT_MAX_FAT16_CLUSTER
) {
330 return EFI_VOLUME_CORRUPTED
;
333 FatType
= Volume
->MaxCluster
< FAT_MAX_FAT12_CLUSTER
? Fat12
: Fat16
;
335 // fat12 & fat16 fat-entries are 2 bytes
337 Volume
->FatEntrySize
= sizeof (UINT16
);
338 DirtyMask
= FAT16_DIRTY_MASK
;
340 if (Volume
->MaxCluster
< FAT_MAX_FAT16_CLUSTER
) {
341 return EFI_VOLUME_CORRUPTED
;
344 // fat32 fat-entries are 4 bytes
346 Volume
->FatEntrySize
= sizeof (UINT32
);
347 DirtyMask
= FAT32_DIRTY_MASK
;
350 // Get the DirtyValue and NotDirtyValue
351 // We should keep the initial value as the NotDirtyValue
352 // in case the volume is dirty already
354 if (FatType
!= Fat12
) {
355 Status
= FatAccessVolumeDirty (Volume
, ReadDisk
, &Volume
->NotDirtyValue
);
356 if (EFI_ERROR (Status
)) {
360 Volume
->DirtyValue
= Volume
->NotDirtyValue
& DirtyMask
;
363 // If present, read the fat hint info
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
374 Volume
->FreeInfoValid
= TRUE
;
379 // Just make up a FreeInfo.NextCluster for use by allocate cluster
381 if (FAT_MIN_CLUSTER
> Volume
->FatInfoSector
.FreeInfo
.NextCluster
||
382 Volume
->FatInfoSector
.FreeInfo
.NextCluster
> Volume
->MaxCluster
+ 1
384 Volume
->FatInfoSector
.FreeInfo
.NextCluster
= FAT_MIN_CLUSTER
;
387 // We are now defining FAT Type
389 Volume
->FatType
= FatType
;
390 ASSERT (FatType
!= FatUndefined
);