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