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