2 Initialization routines.
4 Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
13 Allocates volume structure, detects FAT file system, installs protocol,
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 devicel
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.
29 IN EFI_DISK_IO_PROTOCOL
*DiskIo
,
30 IN EFI_DISK_IO2_PROTOCOL
*DiskIo2
,
31 IN EFI_BLOCK_IO_PROTOCOL
*BlockIo
38 // Allocate a volume structure
40 Volume
= AllocateZeroPool (sizeof (FAT_VOLUME
));
42 return EFI_OUT_OF_RESOURCES
;
46 // Initialize the structure
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
);
60 // Initialize Root Directory entry
62 Volume
->RootDirEnt
.FileString
= Volume
->RootFileString
;
63 Volume
->RootDirEnt
.Entry
.Attributes
= FAT_ATTRIBUTE_DIRECTORY
;
65 // Check to see if there's a file system on the volume
67 Status
= FatOpenDevice (Volume
);
68 if (EFI_ERROR (Status
)) {
74 Status
= FatInitializeDiskCache (Volume
);
75 if (EFI_ERROR (Status
)) {
79 // Install our protocol interfaces on the device's handle
81 Status
= gBS
->InstallMultipleProtocolInterfaces (
83 &gEfiSimpleFileSystemProtocolGuid
,
84 &Volume
->VolumeInterface
,
87 if (EFI_ERROR (Status
)) {
93 DEBUG ((EFI_D_INIT
, "Installed Fat filesystem on %p\n", Handle
));
97 if (EFI_ERROR (Status
)) {
98 FatFreeVolume (Volume
);
106 Called by FatDriverBindingStop(), Abandon the volume.
108 @param Volume - The volume to be abandoned.
110 @retval EFI_SUCCESS - Abandoned the volume successfully.
111 @return Others - Can not uninstall the protocol interfaces.
116 IN FAT_VOLUME
*Volume
123 // Uninstall the protocol interface.
125 if (Volume
->Handle
!= NULL
) {
126 Status
= gBS
->UninstallMultipleProtocolInterfaces (
128 &gEfiSimpleFileSystemProtocolGuid
,
129 &Volume
->VolumeInterface
,
132 if (EFI_ERROR (Status
)) {
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.
145 Status
= FatAcquireLockOrFail ();
146 if (!EFI_ERROR (Status
)) {
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
154 if (Volume
->Root
!= NULL
) {
157 Volume
->BlockIo
->Media
->MediaPresent
? EFI_MEDIA_CHANGED
: EFI_NO_MEDIA
161 Volume
->Valid
= FALSE
;
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.
173 FatCleanupVolume (Volume
, NULL
, EFI_SUCCESS
, NULL
);
182 Detects FAT file system on Disk and set relevant fields of Volume.
184 @param Volume - The volume structure.
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.
193 IN OUT FAT_VOLUME
*Volume
199 EFI_DISK_IO_PROTOCOL
*DiskIo
;
200 FAT_BOOT_SECTOR FatBs
;
201 FAT_VOLUME_TYPE FatType
;
202 UINTN RootDirSectors
;
205 UINTN FirstClusterLba
;
208 UINT8 SectorsPerClusterAlignment
;
209 UINT8 BlockAlignment
;
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.
216 DiskIo
= Volume
->DiskIo
;
217 Status
= DiskIo
->ReadDisk (DiskIo
, Volume
->MediaId
, 0, sizeof (FatBs
), &FatBs
);
219 if (EFI_ERROR (Status
)) {
220 DEBUG ((EFI_D_INIT
, "FatOpenDevice: read of part_lba failed %r\n", Status
));
224 FatType
= FatUndefined
;
227 // Use LargeSectors if Sectors is 0
229 Sectors
= FatBs
.FatBsb
.Sectors
;
231 Sectors
= FatBs
.FatBsb
.LargeSectors
;
234 SectorsPerFat
= FatBs
.FatBsb
.SectorsPerFat
;
235 if (SectorsPerFat
== 0) {
236 SectorsPerFat
= FatBs
.FatBse
.Fat32Bse
.LargeSectorsPerFat
;
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
245 if (FatBs
.FatBsb
.ReservedSectors
== 0 || FatBs
.FatBsb
.NumFats
== 0 || Sectors
== 0) {
246 return EFI_UNSUPPORTED
;
249 if ((FatBs
.FatBsb
.SectorSize
& (FatBs
.FatBsb
.SectorSize
- 1)) != 0) {
250 return EFI_UNSUPPORTED
;
253 BlockAlignment
= (UINT8
) HighBitSet32 (FatBs
.FatBsb
.SectorSize
);
254 if (BlockAlignment
> MAX_BLOCK_ALIGNMENT
|| BlockAlignment
< MIN_BLOCK_ALIGNMENT
) {
255 return EFI_UNSUPPORTED
;
258 if ((FatBs
.FatBsb
.SectorsPerCluster
& (FatBs
.FatBsb
.SectorsPerCluster
- 1)) != 0) {
259 return EFI_UNSUPPORTED
;
262 SectorsPerClusterAlignment
= (UINT8
) HighBitSet32 (FatBs
.FatBsb
.SectorsPerCluster
);
263 if (SectorsPerClusterAlignment
> MAX_SECTORS_PER_CLUSTER_ALIGNMENT
) {
264 return EFI_UNSUPPORTED
;
267 if (FatBs
.FatBsb
.Media
<= 0xf7 &&
268 FatBs
.FatBsb
.Media
!= 0xf0 &&
269 FatBs
.FatBsb
.Media
!= 0x00 &&
270 FatBs
.FatBsb
.Media
!= 0x01
272 return EFI_UNSUPPORTED
;
275 // Initialize fields the volume information for this FatType
277 if (FatType
!= Fat32
) {
278 if (FatBs
.FatBsb
.RootEntries
== 0) {
279 return EFI_UNSUPPORTED
;
282 // Unpack fat12, fat16 info
284 Volume
->RootEntries
= FatBs
.FatBsb
.RootEntries
;
287 // If this is fat32, refuse to mount mirror-disabled volumes
289 if ((SectorsPerFat
== 0 || FatBs
.FatBse
.Fat32Bse
.FsVersion
!= 0) || (FatBs
.FatBse
.Fat32Bse
.ExtendedFlags
& 0x80)) {
290 return EFI_UNSUPPORTED
;
295 Volume
->RootCluster
= FatBs
.FatBse
.Fat32Bse
.RootDirFirstCluster
;
298 Volume
->NumFats
= FatBs
.FatBsb
.NumFats
;
300 // Compute some fat locations
302 BlockSize
= FatBs
.FatBsb
.SectorSize
;
303 RootDirSectors
= ((Volume
->RootEntries
* sizeof (FAT_DIRECTORY_ENTRY
)) + (BlockSize
- 1)) / BlockSize
;
305 FatLba
= FatBs
.FatBsb
.ReservedSectors
;
306 RootLba
= FatBs
.FatBsb
.NumFats
* SectorsPerFat
+ FatLba
;
307 FirstClusterLba
= RootLba
+ RootDirSectors
;
309 Volume
->FatPos
= FatLba
* BlockSize
;
310 Volume
->FatSize
= SectorsPerFat
* BlockSize
;
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
);
320 // If this is not a fat32, determine if it's a fat16 or fat12
322 if (FatType
!= Fat32
) {
323 if (Volume
->MaxCluster
>= FAT_MAX_FAT16_CLUSTER
) {
324 return EFI_VOLUME_CORRUPTED
;
327 FatType
= Volume
->MaxCluster
< FAT_MAX_FAT12_CLUSTER
? Fat12
: Fat16
;
329 // fat12 & fat16 fat-entries are 2 bytes
331 Volume
->FatEntrySize
= sizeof (UINT16
);
332 DirtyMask
= FAT16_DIRTY_MASK
;
334 if (Volume
->MaxCluster
< FAT_MAX_FAT16_CLUSTER
) {
335 return EFI_VOLUME_CORRUPTED
;
338 // fat32 fat-entries are 4 bytes
340 Volume
->FatEntrySize
= sizeof (UINT32
);
341 DirtyMask
= FAT32_DIRTY_MASK
;
344 // Get the DirtyValue and NotDirtyValue
345 // We should keep the initial value as the NotDirtyValue
346 // in case the volume is dirty already
348 if (FatType
!= Fat12
) {
349 Status
= FatAccessVolumeDirty (Volume
, ReadDisk
, &Volume
->NotDirtyValue
);
350 if (EFI_ERROR (Status
)) {
354 Volume
->DirtyValue
= Volume
->NotDirtyValue
& DirtyMask
;
357 // If present, read the fat hint info
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
368 Volume
->FreeInfoValid
= TRUE
;
373 // Just make up a FreeInfo.NextCluster for use by allocate cluster
375 if (FAT_MIN_CLUSTER
> Volume
->FatInfoSector
.FreeInfo
.NextCluster
||
376 Volume
->FatInfoSector
.FreeInfo
.NextCluster
> Volume
->MaxCluster
+ 1
378 Volume
->FatInfoSector
.FreeInfo
.NextCluster
= FAT_MIN_CLUSTER
;
381 // We are now defining FAT Type
383 Volume
->FatType
= FatType
;
384 ASSERT (FatType
!= FatUndefined
);