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