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