1 /** @file 2 Initialization routines. 3 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 9 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. 12 13 **/ 14 15 #include "Fat.h" 16 17 /** 18 19 Allocates volume structure, detects FAT file system, installs protocol, 20 and initialize cache. 21 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 26 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. 30 31 **/ 32 EFI_STATUS 33 FatAllocateVolume ( 34 IN EFI_HANDLE Handle, 35 IN EFI_DISK_IO_PROTOCOL *DiskIo, 36 IN EFI_DISK_IO2_PROTOCOL *DiskIo2, 37 IN EFI_BLOCK_IO_PROTOCOL *BlockIo 38 ) 39 { 40 EFI_STATUS Status; 41 FAT_VOLUME *Volume; 42 43 // 44 // Allocate a volume structure 45 // 46 Volume = AllocateZeroPool (sizeof (FAT_VOLUME)); 47 if (Volume == NULL) { 48 return EFI_OUT_OF_RESOURCES; 49 } 50 51 // 52 // Initialize the structure 53 // 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); 65 // 66 // Initialize Root Directory entry 67 // 68 Volume->RootDirEnt.FileString = Volume->RootFileString; 69 Volume->RootDirEnt.Entry.Attributes = FAT_ATTRIBUTE_DIRECTORY; 70 // 71 // Check to see if there's a file system on the volume 72 // 73 Status = FatOpenDevice (Volume); 74 if (EFI_ERROR (Status)) { 75 goto Done; 76 } 77 // 78 // Initialize cache 79 // 80 Status = FatInitializeDiskCache (Volume); 81 if (EFI_ERROR (Status)) { 82 goto Done; 83 } 84 // 85 // Install our protocol interfaces on the device's handle 86 // 87 Status = gBS->InstallMultipleProtocolInterfaces ( 88 &Volume->Handle, 89 &gEfiSimpleFileSystemProtocolGuid, 90 &Volume->VolumeInterface, 91 NULL 92 ); 93 if (EFI_ERROR (Status)) { 94 goto Done; 95 } 96 // 97 // Volume installed 98 // 99 DEBUG ((EFI_D_INIT, "Installed Fat filesystem on %p\n", Handle)); 100 Volume->Valid = TRUE; 101 102 Done: 103 if (EFI_ERROR (Status)) { 104 FatFreeVolume (Volume); 105 } 106 107 return Status; 108 } 109 110 /** 111 112 Called by FatDriverBindingStop(), Abandon the volume. 113 114 @param Volume - The volume to be abandoned. 115 116 @retval EFI_SUCCESS - Abandoned the volume successfully. 117 @return Others - Can not uninstall the protocol interfaces. 118 119 **/ 120 EFI_STATUS 121 FatAbandonVolume ( 122 IN FAT_VOLUME *Volume 123 ) 124 { 125 EFI_STATUS Status; 126 BOOLEAN LockedByMe; 127 128 // 129 // Uninstall the protocol interface. 130 // 131 if (Volume->Handle != NULL) { 132 Status = gBS->UninstallMultipleProtocolInterfaces ( 133 Volume->Handle, 134 &gEfiSimpleFileSystemProtocolGuid, 135 &Volume->VolumeInterface, 136 NULL 137 ); 138 if (EFI_ERROR (Status)) { 139 return Status; 140 } 141 } 142 143 LockedByMe = FALSE; 144 145 // 146 // Acquire the lock. 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. 150 // 151 Status = FatAcquireLockOrFail (); 152 if (!EFI_ERROR (Status)) { 153 LockedByMe = TRUE; 154 } 155 // 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 158 // EFI_NO_MEDIA. 159 // 160 if (Volume->Root != NULL) { 161 FatSetVolumeError ( 162 Volume->Root, 163 Volume->BlockIo->Media->MediaPresent ? EFI_MEDIA_CHANGED : EFI_NO_MEDIA 164 ); 165 } 166 167 Volume->Valid = FALSE; 168 169 // 170 // Release the lock. 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. 177 // 178 if (LockedByMe) { 179 FatCleanupVolume (Volume, NULL, EFI_SUCCESS, NULL); 180 FatReleaseLock (); 181 } 182 183 return EFI_SUCCESS; 184 } 185 186 /** 187 188 Detects FAT file system on Disk and set relevant fields of Volume. 189 190 @param Volume - The volume structure. 191 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. 195 196 **/ 197 EFI_STATUS 198 FatOpenDevice ( 199 IN OUT FAT_VOLUME *Volume 200 ) 201 { 202 EFI_STATUS Status; 203 UINT32 BlockSize; 204 UINT32 DirtyMask; 205 EFI_DISK_IO_PROTOCOL *DiskIo; 206 FAT_BOOT_SECTOR FatBs; 207 FAT_VOLUME_TYPE FatType; 208 UINTN RootDirSectors; 209 UINTN FatLba; 210 UINTN RootLba; 211 UINTN FirstClusterLba; 212 UINTN Sectors; 213 UINTN SectorsPerFat; 214 UINT8 SectorsPerClusterAlignment; 215 UINT8 BlockAlignment; 216 217 // 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. 221 // 222 DiskIo = Volume->DiskIo; 223 Status = DiskIo->ReadDisk (DiskIo, Volume->MediaId, 0, sizeof (FatBs), &FatBs); 224 225 if (EFI_ERROR (Status)) { 226 DEBUG ((EFI_D_INIT, "FatOpenDevice: read of part_lba failed %r\n", Status)); 227 return Status; 228 } 229 230 FatType = FatUndefined; 231 232 // 233 // Use LargeSectors if Sectors is 0 234 // 235 Sectors = FatBs.FatBsb.Sectors; 236 if (Sectors == 0) { 237 Sectors = FatBs.FatBsb.LargeSectors; 238 } 239 240 SectorsPerFat = FatBs.FatBsb.SectorsPerFat; 241 if (SectorsPerFat == 0) { 242 SectorsPerFat = FatBs.FatBse.Fat32Bse.LargeSectorsPerFat; 243 FatType = Fat32; 244 } 245 // 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 249 // the volume size) 250 // 251 if (FatBs.FatBsb.ReservedSectors == 0 || FatBs.FatBsb.NumFats == 0 || Sectors == 0) { 252 return EFI_UNSUPPORTED; 253 } 254 255 if ((FatBs.FatBsb.SectorSize & (FatBs.FatBsb.SectorSize - 1)) != 0) { 256 return EFI_UNSUPPORTED; 257 } 258 259 BlockAlignment = (UINT8) HighBitSet32 (FatBs.FatBsb.SectorSize); 260 if (BlockAlignment > MAX_BLOCK_ALIGNMENT || BlockAlignment < MIN_BLOCK_ALIGNMENT) { 261 return EFI_UNSUPPORTED; 262 } 263 264 if ((FatBs.FatBsb.SectorsPerCluster & (FatBs.FatBsb.SectorsPerCluster - 1)) != 0) { 265 return EFI_UNSUPPORTED; 266 } 267 268 SectorsPerClusterAlignment = (UINT8) HighBitSet32 (FatBs.FatBsb.SectorsPerCluster); 269 if (SectorsPerClusterAlignment > MAX_SECTORS_PER_CLUSTER_ALIGNMENT) { 270 return EFI_UNSUPPORTED; 271 } 272 273 if (FatBs.FatBsb.Media <= 0xf7 && 274 FatBs.FatBsb.Media != 0xf0 && 275 FatBs.FatBsb.Media != 0x00 && 276 FatBs.FatBsb.Media != 0x01 277 ) { 278 return EFI_UNSUPPORTED; 279 } 280 // 281 // Initialize fields the volume information for this FatType 282 // 283 if (FatType != Fat32) { 284 if (FatBs.FatBsb.RootEntries == 0) { 285 return EFI_UNSUPPORTED; 286 } 287 // 288 // Unpack fat12, fat16 info 289 // 290 Volume->RootEntries = FatBs.FatBsb.RootEntries; 291 } else { 292 // 293 // If this is fat32, refuse to mount mirror-disabled volumes 294 // 295 if ((SectorsPerFat == 0 || FatBs.FatBse.Fat32Bse.FsVersion != 0) || (FatBs.FatBse.Fat32Bse.ExtendedFlags & 0x80)) { 296 return EFI_UNSUPPORTED; 297 } 298 // 299 // Unpack fat32 info 300 // 301 Volume->RootCluster = FatBs.FatBse.Fat32Bse.RootDirFirstCluster; 302 } 303 304 Volume->NumFats = FatBs.FatBsb.NumFats; 305 // 306 // Compute some fat locations 307 // 308 BlockSize = FatBs.FatBsb.SectorSize; 309 RootDirSectors = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (BlockSize - 1)) / BlockSize; 310 311 FatLba = FatBs.FatBsb.ReservedSectors; 312 RootLba = FatBs.FatBsb.NumFats * SectorsPerFat + FatLba; 313 FirstClusterLba = RootLba + RootDirSectors; 314 315 Volume->FatPos = FatLba * BlockSize; 316 Volume->FatSize = SectorsPerFat * BlockSize; 317 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); 324 325 // 326 // If this is not a fat32, determine if it's a fat16 or fat12 327 // 328 if (FatType != Fat32) { 329 if (Volume->MaxCluster >= FAT_MAX_FAT16_CLUSTER) { 330 return EFI_VOLUME_CORRUPTED; 331 } 332 333 FatType = Volume->MaxCluster < FAT_MAX_FAT12_CLUSTER ? Fat12 : Fat16; 334 // 335 // fat12 & fat16 fat-entries are 2 bytes 336 // 337 Volume->FatEntrySize = sizeof (UINT16); 338 DirtyMask = FAT16_DIRTY_MASK; 339 } else { 340 if (Volume->MaxCluster < FAT_MAX_FAT16_CLUSTER) { 341 return EFI_VOLUME_CORRUPTED; 342 } 343 // 344 // fat32 fat-entries are 4 bytes 345 // 346 Volume->FatEntrySize = sizeof (UINT32); 347 DirtyMask = FAT32_DIRTY_MASK; 348 } 349 // 350 // Get the DirtyValue and NotDirtyValue 351 // We should keep the initial value as the NotDirtyValue 352 // in case the volume is dirty already 353 // 354 if (FatType != Fat12) { 355 Status = FatAccessVolumeDirty (Volume, ReadDisk, &Volume->NotDirtyValue); 356 if (EFI_ERROR (Status)) { 357 return Status; 358 } 359 360 Volume->DirtyValue = Volume->NotDirtyValue & DirtyMask; 361 } 362 // 363 // If present, read the fat hint info 364 // 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 373 ) { 374 Volume->FreeInfoValid = TRUE; 375 } 376 } 377 } 378 // 379 // Just make up a FreeInfo.NextCluster for use by allocate cluster 380 // 381 if (FAT_MIN_CLUSTER > Volume->FatInfoSector.FreeInfo.NextCluster || 382 Volume->FatInfoSector.FreeInfo.NextCluster > Volume->MaxCluster + 1 383 ) { 384 Volume->FatInfoSector.FreeInfo.NextCluster = FAT_MIN_CLUSTER; 385 } 386 // 387 // We are now defining FAT Type 388 // 389 Volume->FatType = FatType; 390 ASSERT (FatType != FatUndefined); 391 392 return EFI_SUCCESS; 393 } 394