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