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 device.
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
)) {
75 Status
= FatInitializeDiskCache (Volume
);
76 if (EFI_ERROR (Status
)) {
81 // Install our protocol interfaces on the device's handle
83 Status
= gBS
->InstallMultipleProtocolInterfaces (
85 &gEfiSimpleFileSystemProtocolGuid
,
86 &Volume
->VolumeInterface
,
89 if (EFI_ERROR (Status
)) {
96 DEBUG ((DEBUG_INIT
, "Installed Fat filesystem on %p\n", Handle
));
100 if (EFI_ERROR (Status
)) {
101 FatFreeVolume (Volume
);
109 Called by FatDriverBindingStop(), Abandon the volume.
111 @param Volume - The volume to be abandoned.
113 @retval EFI_SUCCESS - Abandoned the volume successfully.
114 @return Others - Can not uninstall the protocol interfaces.
119 IN FAT_VOLUME
*Volume
126 // Uninstall the protocol interface.
128 if (Volume
->Handle
!= NULL
) {
129 Status
= gBS
->UninstallMultipleProtocolInterfaces (
131 &gEfiSimpleFileSystemProtocolGuid
,
132 &Volume
->VolumeInterface
,
135 if (EFI_ERROR (Status
)) {
144 // If the caller has already acquired the lock (which
145 // means we are in the process of some Fat operation),
146 // we can not acquire again.
148 Status
= FatAcquireLockOrFail ();
149 if (!EFI_ERROR (Status
)) {
154 // The volume is still being used. Hence, set error flag for all OFiles still in
155 // use. In two cases, we could get here. One is EFI_MEDIA_CHANGED, the other is
158 if (Volume
->Root
!= NULL
) {
161 Volume
->BlockIo
->Media
->MediaPresent
? EFI_MEDIA_CHANGED
: EFI_NO_MEDIA
165 Volume
->Valid
= FALSE
;
169 // If locked by me, this means DriverBindingStop is NOT
170 // called within an on-going Fat operation, so we should
171 // take responsibility to cleanup and free the volume.
172 // Otherwise, the DriverBindingStop is called within an on-going
173 // Fat operation, we shouldn't check reference, so just let outer
174 // FatCleanupVolume do the task.
177 FatCleanupVolume (Volume
, NULL
, EFI_SUCCESS
, NULL
);
186 Detects FAT file system on Disk and set relevant fields of Volume.
188 @param Volume - The volume structure.
190 @retval EFI_SUCCESS - The Fat File System is detected successfully
191 @retval EFI_UNSUPPORTED - The volume is not FAT file system.
192 @retval EFI_VOLUME_CORRUPTED - The volume is corrupted.
197 IN OUT FAT_VOLUME
*Volume
203 EFI_DISK_IO_PROTOCOL
*DiskIo
;
204 FAT_BOOT_SECTOR FatBs
;
205 FAT_VOLUME_TYPE FatType
;
206 UINTN RootDirSectors
;
209 UINTN FirstClusterLba
;
212 UINT8 SectorsPerClusterAlignment
;
213 UINT8 BlockAlignment
;
216 // Read the FAT_BOOT_SECTOR BPB info
217 // This is the only part of FAT code that uses parent DiskIo,
218 // Others use FatDiskIo which utilizes a Cache.
220 DiskIo
= Volume
->DiskIo
;
221 Status
= DiskIo
->ReadDisk (DiskIo
, Volume
->MediaId
, 0, sizeof (FatBs
), &FatBs
);
223 if (EFI_ERROR (Status
)) {
224 DEBUG ((DEBUG_INIT
, "FatOpenDevice: read of part_lba failed %r\n", Status
));
228 FatType
= FatUndefined
;
231 // Use LargeSectors if Sectors is 0
233 Sectors
= FatBs
.FatBsb
.Sectors
;
235 Sectors
= FatBs
.FatBsb
.LargeSectors
;
238 SectorsPerFat
= FatBs
.FatBsb
.SectorsPerFat
;
239 if (SectorsPerFat
== 0) {
240 SectorsPerFat
= FatBs
.FatBse
.Fat32Bse
.LargeSectorsPerFat
;
245 // Is boot sector a fat sector?
246 // (Note that so far we only know if the sector is FAT32 or not, we don't
247 // know if the sector is Fat16 or Fat12 until later when we can compute
250 if ((FatBs
.FatBsb
.ReservedSectors
== 0) || (FatBs
.FatBsb
.NumFats
== 0) || (Sectors
== 0)) {
251 return EFI_UNSUPPORTED
;
254 if ((FatBs
.FatBsb
.SectorSize
& (FatBs
.FatBsb
.SectorSize
- 1)) != 0) {
255 return EFI_UNSUPPORTED
;
258 BlockAlignment
= (UINT8
)HighBitSet32 (FatBs
.FatBsb
.SectorSize
);
259 if ((BlockAlignment
> MAX_BLOCK_ALIGNMENT
) || (BlockAlignment
< MIN_BLOCK_ALIGNMENT
)) {
260 return EFI_UNSUPPORTED
;
263 if ((FatBs
.FatBsb
.SectorsPerCluster
& (FatBs
.FatBsb
.SectorsPerCluster
- 1)) != 0) {
264 return EFI_UNSUPPORTED
;
267 SectorsPerClusterAlignment
= (UINT8
)HighBitSet32 (FatBs
.FatBsb
.SectorsPerCluster
);
268 if (SectorsPerClusterAlignment
> MAX_SECTORS_PER_CLUSTER_ALIGNMENT
) {
269 return EFI_UNSUPPORTED
;
272 if ((FatBs
.FatBsb
.Media
<= 0xf7) &&
273 (FatBs
.FatBsb
.Media
!= 0xf0) &&
274 (FatBs
.FatBsb
.Media
!= 0x00) &&
275 (FatBs
.FatBsb
.Media
!= 0x01)
278 return EFI_UNSUPPORTED
;
282 // Initialize fields the volume information for this FatType
284 if (FatType
!= Fat32
) {
285 if (FatBs
.FatBsb
.RootEntries
== 0) {
286 return EFI_UNSUPPORTED
;
290 // Unpack fat12, fat16 info
292 Volume
->RootEntries
= FatBs
.FatBsb
.RootEntries
;
295 // If this is fat32, refuse to mount mirror-disabled volumes
297 if (((SectorsPerFat
== 0) || (FatBs
.FatBse
.Fat32Bse
.FsVersion
!= 0)) || (FatBs
.FatBse
.Fat32Bse
.ExtendedFlags
& 0x80)) {
298 return EFI_UNSUPPORTED
;
304 Volume
->RootCluster
= FatBs
.FatBse
.Fat32Bse
.RootDirFirstCluster
;
307 Volume
->NumFats
= FatBs
.FatBsb
.NumFats
;
309 // Compute some fat locations
311 BlockSize
= FatBs
.FatBsb
.SectorSize
;
312 RootDirSectors
= ((Volume
->RootEntries
* sizeof (FAT_DIRECTORY_ENTRY
)) + (BlockSize
- 1)) / BlockSize
;
314 FatLba
= FatBs
.FatBsb
.ReservedSectors
;
315 RootLba
= FatBs
.FatBsb
.NumFats
* SectorsPerFat
+ FatLba
;
316 FirstClusterLba
= RootLba
+ RootDirSectors
;
318 Volume
->FatPos
= FatLba
* BlockSize
;
319 Volume
->FatSize
= SectorsPerFat
* BlockSize
;
321 Volume
->VolumeSize
= LShiftU64 (Sectors
, BlockAlignment
);
322 Volume
->RootPos
= LShiftU64 (RootLba
, BlockAlignment
);
323 Volume
->FirstClusterPos
= LShiftU64 (FirstClusterLba
, BlockAlignment
);
324 Volume
->MaxCluster
= (Sectors
- FirstClusterLba
) >> SectorsPerClusterAlignment
;
325 Volume
->ClusterAlignment
= (UINT8
)(BlockAlignment
+ SectorsPerClusterAlignment
);
326 Volume
->ClusterSize
= (UINTN
)1 << (Volume
->ClusterAlignment
);
329 // If this is not a fat32, determine if it's a fat16 or fat12
331 if (FatType
!= Fat32
) {
332 if (Volume
->MaxCluster
>= FAT_MAX_FAT16_CLUSTER
) {
333 return EFI_VOLUME_CORRUPTED
;
336 FatType
= Volume
->MaxCluster
< FAT_MAX_FAT12_CLUSTER
? Fat12
: Fat16
;
338 // fat12 & fat16 fat-entries are 2 bytes
340 Volume
->FatEntrySize
= sizeof (UINT16
);
341 DirtyMask
= FAT16_DIRTY_MASK
;
343 if (Volume
->MaxCluster
< FAT_MAX_FAT16_CLUSTER
) {
344 return EFI_VOLUME_CORRUPTED
;
348 // fat32 fat-entries are 4 bytes
350 Volume
->FatEntrySize
= sizeof (UINT32
);
351 DirtyMask
= FAT32_DIRTY_MASK
;
355 // Get the DirtyValue and NotDirtyValue
356 // We should keep the initial value as the NotDirtyValue
357 // in case the volume is dirty already
359 if (FatType
!= Fat12
) {
360 Status
= FatAccessVolumeDirty (Volume
, ReadDisk
, &Volume
->NotDirtyValue
);
361 if (EFI_ERROR (Status
)) {
365 Volume
->DirtyValue
= Volume
->NotDirtyValue
& DirtyMask
;
369 // If present, read the fat hint info
371 if (FatType
== Fat32
) {
372 Volume
->FreeInfoPos
= FatBs
.FatBse
.Fat32Bse
.FsInfoSector
* BlockSize
;
373 if (FatBs
.FatBse
.Fat32Bse
.FsInfoSector
!= 0) {
374 FatDiskIo (Volume
, ReadDisk
, Volume
->FreeInfoPos
, sizeof (FAT_INFO_SECTOR
), &Volume
->FatInfoSector
, NULL
);
375 if ((Volume
->FatInfoSector
.Signature
== FAT_INFO_SIGNATURE
) &&
376 (Volume
->FatInfoSector
.InfoBeginSignature
== FAT_INFO_BEGIN_SIGNATURE
) &&
377 (Volume
->FatInfoSector
.InfoEndSignature
== FAT_INFO_END_SIGNATURE
) &&
378 (Volume
->FatInfoSector
.FreeInfo
.ClusterCount
<= Volume
->MaxCluster
)
381 Volume
->FreeInfoValid
= TRUE
;
387 // Just make up a FreeInfo.NextCluster for use by allocate cluster
389 if ((FAT_MIN_CLUSTER
> Volume
->FatInfoSector
.FreeInfo
.NextCluster
) ||
390 (Volume
->FatInfoSector
.FreeInfo
.NextCluster
> Volume
->MaxCluster
+ 1)
393 Volume
->FatInfoSector
.FreeInfo
.NextCluster
= FAT_MIN_CLUSTER
;
397 // We are now defining FAT Type
399 Volume
->FatType
= FatType
;
400 ASSERT (FatType
!= FatUndefined
);