]> git.proxmox.com Git - mirror_edk2.git/blame - FatPkg/EnhancedFatDxe/Init.c
BaseTools: Library hashing fix and optimization for --hash feature
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / Init.c
CommitLineData
cae7420b
DB
1/** @file\r
2 Initialization routines.\r
b9ec9330 3\r
149d6335 4Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
eb6cb4ce 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
b9ec9330 6\r
cae7420b 7**/\r
b9ec9330 8\r
cae7420b 9#include "Fat.h"\r
b9ec9330 10\r
cae7420b 11/**\r
b9ec9330 12\r
cae7420b
DB
13 Allocates volume structure, detects FAT file system, installs protocol,\r
14 and initialize cache.\r
b9ec9330 15\r
cae7420b
DB
16 @param Handle - The handle of parent device.\r
17 @param DiskIo - The DiskIo of parent device.\r
18 @param DiskIo2 - The DiskIo2 of parent device.\r
19 @param BlockIo - The BlockIo of parent devicel\r
b9ec9330 20\r
cae7420b
DB
21 @retval EFI_SUCCESS - Allocate a new volume successfully.\r
22 @retval EFI_OUT_OF_RESOURCES - Can not allocate the memory.\r
23 @return Others - Allocating a new volume failed.\r
b9ec9330 24\r
cae7420b 25**/\r
b9ec9330
QH
26EFI_STATUS\r
27FatAllocateVolume (\r
28 IN EFI_HANDLE Handle,\r
29 IN EFI_DISK_IO_PROTOCOL *DiskIo,\r
149d6335 30 IN EFI_DISK_IO2_PROTOCOL *DiskIo2,\r
b9ec9330
QH
31 IN EFI_BLOCK_IO_PROTOCOL *BlockIo\r
32 )\r
b9ec9330
QH
33{\r
34 EFI_STATUS Status;\r
35 FAT_VOLUME *Volume;\r
5251cb9d 36\r
b9ec9330
QH
37 //\r
38 // Allocate a volume structure\r
39 //\r
40 Volume = AllocateZeroPool (sizeof (FAT_VOLUME));\r
41 if (Volume == NULL) {\r
42 return EFI_OUT_OF_RESOURCES;\r
43 }\r
5251cb9d 44\r
b9ec9330
QH
45 //\r
46 // Initialize the structure\r
47 //\r
48 Volume->Signature = FAT_VOLUME_SIGNATURE;\r
49 Volume->Handle = Handle;\r
50 Volume->DiskIo = DiskIo;\r
149d6335 51 Volume->DiskIo2 = DiskIo2;\r
b9ec9330
QH
52 Volume->BlockIo = BlockIo;\r
53 Volume->MediaId = BlockIo->Media->MediaId;\r
54 Volume->ReadOnly = BlockIo->Media->ReadOnly;\r
55 Volume->VolumeInterface.Revision = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION;\r
56 Volume->VolumeInterface.OpenVolume = FatOpenVolume;\r
57 InitializeListHead (&Volume->CheckRef);\r
58 InitializeListHead (&Volume->DirCacheList);\r
59 //\r
60 // Initialize Root Directory entry\r
61 //\r
62 Volume->RootDirEnt.FileString = Volume->RootFileString;\r
63 Volume->RootDirEnt.Entry.Attributes = FAT_ATTRIBUTE_DIRECTORY;\r
64 //\r
65 // Check to see if there's a file system on the volume\r
66 //\r
67 Status = FatOpenDevice (Volume);\r
68 if (EFI_ERROR (Status)) {\r
69 goto Done;\r
70 }\r
71 //\r
72 // Initialize cache\r
73 //\r
74 Status = FatInitializeDiskCache (Volume);\r
75 if (EFI_ERROR (Status)) {\r
76 goto Done;\r
77 }\r
78 //\r
79 // Install our protocol interfaces on the device's handle\r
80 //\r
81 Status = gBS->InstallMultipleProtocolInterfaces (\r
82 &Volume->Handle,\r
83 &gEfiSimpleFileSystemProtocolGuid,\r
84 &Volume->VolumeInterface,\r
85 NULL\r
86 );\r
87 if (EFI_ERROR (Status)) {\r
88 goto Done;\r
89 }\r
90 //\r
91 // Volume installed\r
92 //\r
c22c8322 93 DEBUG ((EFI_D_INIT, "Installed Fat filesystem on %p\n", Handle));\r
b9ec9330
QH
94 Volume->Valid = TRUE;\r
95\r
96Done:\r
b9ec9330
QH
97 if (EFI_ERROR (Status)) {\r
98 FatFreeVolume (Volume);\r
99 }\r
100\r
101 return Status;\r
102}\r
103\r
cae7420b 104/**\r
b9ec9330
QH
105\r
106 Called by FatDriverBindingStop(), Abandon the volume.\r
107\r
cae7420b 108 @param Volume - The volume to be abandoned.\r
b9ec9330 109\r
cae7420b
DB
110 @retval EFI_SUCCESS - Abandoned the volume successfully.\r
111 @return Others - Can not uninstall the protocol interfaces.\r
b9ec9330 112\r
cae7420b
DB
113**/\r
114EFI_STATUS\r
115FatAbandonVolume (\r
116 IN FAT_VOLUME *Volume\r
117 )\r
b9ec9330
QH
118{\r
119 EFI_STATUS Status;\r
120 BOOLEAN LockedByMe;\r
121\r
122 //\r
123 // Uninstall the protocol interface.\r
124 //\r
125 if (Volume->Handle != NULL) {\r
126 Status = gBS->UninstallMultipleProtocolInterfaces (\r
127 Volume->Handle,\r
128 &gEfiSimpleFileSystemProtocolGuid,\r
129 &Volume->VolumeInterface,\r
130 NULL\r
131 );\r
132 if (EFI_ERROR (Status)) {\r
133 return Status;\r
134 }\r
135 }\r
136\r
137 LockedByMe = FALSE;\r
138\r
139 //\r
140 // Acquire the lock.\r
141 // If the caller has already acquired the lock (which\r
142 // means we are in the process of some Fat operation),\r
143 // we can not acquire again.\r
144 //\r
25ce9b1f
QH
145 Status = FatAcquireLockOrFail ();\r
146 if (!EFI_ERROR (Status)) {\r
b9ec9330 147 LockedByMe = TRUE;\r
b9ec9330
QH
148 }\r
149 //\r
150 // The volume is still being used. Hence, set error flag for all OFiles still in\r
151 // use. In two cases, we could get here. One is EFI_MEDIA_CHANGED, the other is\r
152 // EFI_NO_MEDIA.\r
153 //\r
154 if (Volume->Root != NULL) {\r
155 FatSetVolumeError (\r
156 Volume->Root,\r
157 Volume->BlockIo->Media->MediaPresent ? EFI_MEDIA_CHANGED : EFI_NO_MEDIA\r
158 );\r
159 }\r
160\r
161 Volume->Valid = FALSE;\r
162\r
163 //\r
164 // Release the lock.\r
165 // If locked by me, this means DriverBindingStop is NOT\r
166 // called within an on-going Fat operation, so we should\r
167 // take responsibility to cleanup and free the volume.\r
168 // Otherwise, the DriverBindingStop is called within an on-going\r
169 // Fat operation, we shouldn't check reference, so just let outer\r
170 // FatCleanupVolume do the task.\r
171 //\r
172 if (LockedByMe) {\r
149d6335 173 FatCleanupVolume (Volume, NULL, EFI_SUCCESS, NULL);\r
b9ec9330
QH
174 FatReleaseLock ();\r
175 }\r
176\r
177 return EFI_SUCCESS;\r
178}\r
179\r
cae7420b 180/**\r
b9ec9330 181\r
cae7420b 182 Detects FAT file system on Disk and set relevant fields of Volume.\r
b9ec9330 183\r
cae7420b 184 @param Volume - The volume structure.\r
b9ec9330 185\r
cae7420b
DB
186 @retval EFI_SUCCESS - The Fat File System is detected successfully\r
187 @retval EFI_UNSUPPORTED - The volume is not FAT file system.\r
188 @retval EFI_VOLUME_CORRUPTED - The volume is corrupted.\r
b9ec9330 189\r
cae7420b
DB
190**/\r
191EFI_STATUS\r
192FatOpenDevice (\r
193 IN OUT FAT_VOLUME *Volume\r
194 )\r
b9ec9330
QH
195{\r
196 EFI_STATUS Status;\r
197 UINT32 BlockSize;\r
198 UINT32 DirtyMask;\r
199 EFI_DISK_IO_PROTOCOL *DiskIo;\r
200 FAT_BOOT_SECTOR FatBs;\r
201 FAT_VOLUME_TYPE FatType;\r
202 UINTN RootDirSectors;\r
203 UINTN FatLba;\r
204 UINTN RootLba;\r
205 UINTN FirstClusterLba;\r
206 UINTN Sectors;\r
207 UINTN SectorsPerFat;\r
208 UINT8 SectorsPerClusterAlignment;\r
209 UINT8 BlockAlignment;\r
210\r
211 //\r
212 // Read the FAT_BOOT_SECTOR BPB info\r
213 // This is the only part of FAT code that uses parent DiskIo,\r
214 // Others use FatDiskIo which utilizes a Cache.\r
215 //\r
216 DiskIo = Volume->DiskIo;\r
217 Status = DiskIo->ReadDisk (DiskIo, Volume->MediaId, 0, sizeof (FatBs), &FatBs);\r
218\r
219 if (EFI_ERROR (Status)) {\r
220 DEBUG ((EFI_D_INIT, "FatOpenDevice: read of part_lba failed %r\n", Status));\r
221 return Status;\r
222 }\r
223\r
224 FatType = FatUndefined;\r
225\r
226 //\r
227 // Use LargeSectors if Sectors is 0\r
228 //\r
229 Sectors = FatBs.FatBsb.Sectors;\r
230 if (Sectors == 0) {\r
231 Sectors = FatBs.FatBsb.LargeSectors;\r
232 }\r
233\r
234 SectorsPerFat = FatBs.FatBsb.SectorsPerFat;\r
235 if (SectorsPerFat == 0) {\r
236 SectorsPerFat = FatBs.FatBse.Fat32Bse.LargeSectorsPerFat;\r
c1680e88 237 FatType = Fat32;\r
b9ec9330
QH
238 }\r
239 //\r
240 // Is boot sector a fat sector?\r
241 // (Note that so far we only know if the sector is FAT32 or not, we don't\r
242 // know if the sector is Fat16 or Fat12 until later when we can compute\r
243 // the volume size)\r
244 //\r
245 if (FatBs.FatBsb.ReservedSectors == 0 || FatBs.FatBsb.NumFats == 0 || Sectors == 0) {\r
246 return EFI_UNSUPPORTED;\r
247 }\r
248\r
249 if ((FatBs.FatBsb.SectorSize & (FatBs.FatBsb.SectorSize - 1)) != 0) {\r
250 return EFI_UNSUPPORTED;\r
251 }\r
252\r
253 BlockAlignment = (UINT8) HighBitSet32 (FatBs.FatBsb.SectorSize);\r
254 if (BlockAlignment > MAX_BLOCK_ALIGNMENT || BlockAlignment < MIN_BLOCK_ALIGNMENT) {\r
255 return EFI_UNSUPPORTED;\r
256 }\r
257\r
258 if ((FatBs.FatBsb.SectorsPerCluster & (FatBs.FatBsb.SectorsPerCluster - 1)) != 0) {\r
259 return EFI_UNSUPPORTED;\r
260 }\r
261\r
262 SectorsPerClusterAlignment = (UINT8) HighBitSet32 (FatBs.FatBsb.SectorsPerCluster);\r
263 if (SectorsPerClusterAlignment > MAX_SECTORS_PER_CLUSTER_ALIGNMENT) {\r
264 return EFI_UNSUPPORTED;\r
265 }\r
266\r
267 if (FatBs.FatBsb.Media <= 0xf7 &&\r
268 FatBs.FatBsb.Media != 0xf0 &&\r
269 FatBs.FatBsb.Media != 0x00 &&\r
270 FatBs.FatBsb.Media != 0x01\r
271 ) {\r
272 return EFI_UNSUPPORTED;\r
273 }\r
274 //\r
275 // Initialize fields the volume information for this FatType\r
276 //\r
c1680e88 277 if (FatType != Fat32) {\r
b9ec9330
QH
278 if (FatBs.FatBsb.RootEntries == 0) {\r
279 return EFI_UNSUPPORTED;\r
280 }\r
281 //\r
282 // Unpack fat12, fat16 info\r
283 //\r
284 Volume->RootEntries = FatBs.FatBsb.RootEntries;\r
285 } else {\r
286 //\r
287 // If this is fat32, refuse to mount mirror-disabled volumes\r
288 //\r
289 if ((SectorsPerFat == 0 || FatBs.FatBse.Fat32Bse.FsVersion != 0) || (FatBs.FatBse.Fat32Bse.ExtendedFlags & 0x80)) {\r
290 return EFI_UNSUPPORTED;\r
291 }\r
292 //\r
293 // Unpack fat32 info\r
294 //\r
295 Volume->RootCluster = FatBs.FatBse.Fat32Bse.RootDirFirstCluster;\r
296 }\r
297\r
298 Volume->NumFats = FatBs.FatBsb.NumFats;\r
299 //\r
300 // Compute some fat locations\r
301 //\r
302 BlockSize = FatBs.FatBsb.SectorSize;\r
303 RootDirSectors = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (BlockSize - 1)) / BlockSize;\r
304\r
305 FatLba = FatBs.FatBsb.ReservedSectors;\r
306 RootLba = FatBs.FatBsb.NumFats * SectorsPerFat + FatLba;\r
307 FirstClusterLba = RootLba + RootDirSectors;\r
308\r
309 Volume->FatPos = FatLba * BlockSize;\r
310 Volume->FatSize = SectorsPerFat * BlockSize;\r
311\r
312 Volume->VolumeSize = LShiftU64 (Sectors, BlockAlignment);\r
313 Volume->RootPos = LShiftU64 (RootLba, BlockAlignment);\r
314 Volume->FirstClusterPos = LShiftU64 (FirstClusterLba, BlockAlignment);\r
315 Volume->MaxCluster = (Sectors - FirstClusterLba) >> SectorsPerClusterAlignment;\r
316 Volume->ClusterAlignment = (UINT8)(BlockAlignment + SectorsPerClusterAlignment);\r
317 Volume->ClusterSize = (UINTN)1 << (Volume->ClusterAlignment);\r
318\r
319 //\r
320 // If this is not a fat32, determine if it's a fat16 or fat12\r
321 //\r
c1680e88 322 if (FatType != Fat32) {\r
b9ec9330
QH
323 if (Volume->MaxCluster >= FAT_MAX_FAT16_CLUSTER) {\r
324 return EFI_VOLUME_CORRUPTED;\r
325 }\r
326\r
c1680e88 327 FatType = Volume->MaxCluster < FAT_MAX_FAT12_CLUSTER ? Fat12 : Fat16;\r
b9ec9330
QH
328 //\r
329 // fat12 & fat16 fat-entries are 2 bytes\r
330 //\r
331 Volume->FatEntrySize = sizeof (UINT16);\r
332 DirtyMask = FAT16_DIRTY_MASK;\r
333 } else {\r
334 if (Volume->MaxCluster < FAT_MAX_FAT16_CLUSTER) {\r
335 return EFI_VOLUME_CORRUPTED;\r
336 }\r
337 //\r
338 // fat32 fat-entries are 4 bytes\r
339 //\r
340 Volume->FatEntrySize = sizeof (UINT32);\r
341 DirtyMask = FAT32_DIRTY_MASK;\r
342 }\r
343 //\r
344 // Get the DirtyValue and NotDirtyValue\r
345 // We should keep the initial value as the NotDirtyValue\r
346 // in case the volume is dirty already\r
347 //\r
c1680e88
DB
348 if (FatType != Fat12) {\r
349 Status = FatAccessVolumeDirty (Volume, ReadDisk, &Volume->NotDirtyValue);\r
b9ec9330
QH
350 if (EFI_ERROR (Status)) {\r
351 return Status;\r
352 }\r
353\r
354 Volume->DirtyValue = Volume->NotDirtyValue & DirtyMask;\r
355 }\r
356 //\r
357 // If present, read the fat hint info\r
358 //\r
c1680e88 359 if (FatType == Fat32) {\r
b9ec9330
QH
360 Volume->FreeInfoPos = FatBs.FatBse.Fat32Bse.FsInfoSector * BlockSize;\r
361 if (FatBs.FatBse.Fat32Bse.FsInfoSector != 0) {\r
c1680e88 362 FatDiskIo (Volume, ReadDisk, Volume->FreeInfoPos, sizeof (FAT_INFO_SECTOR), &Volume->FatInfoSector, NULL);\r
b9ec9330
QH
363 if (Volume->FatInfoSector.Signature == FAT_INFO_SIGNATURE &&\r
364 Volume->FatInfoSector.InfoBeginSignature == FAT_INFO_BEGIN_SIGNATURE &&\r
365 Volume->FatInfoSector.InfoEndSignature == FAT_INFO_END_SIGNATURE &&\r
366 Volume->FatInfoSector.FreeInfo.ClusterCount <= Volume->MaxCluster\r
367 ) {\r
368 Volume->FreeInfoValid = TRUE;\r
369 }\r
370 }\r
371 }\r
372 //\r
373 // Just make up a FreeInfo.NextCluster for use by allocate cluster\r
374 //\r
375 if (FAT_MIN_CLUSTER > Volume->FatInfoSector.FreeInfo.NextCluster ||\r
376 Volume->FatInfoSector.FreeInfo.NextCluster > Volume->MaxCluster + 1\r
377 ) {\r
378 Volume->FatInfoSector.FreeInfo.NextCluster = FAT_MIN_CLUSTER;\r
379 }\r
380 //\r
381 // We are now defining FAT Type\r
382 //\r
383 Volume->FatType = FatType;\r
384 ASSERT (FatType != FatUndefined);\r
385\r
386 return EFI_SUCCESS;\r
387}\r