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