]> git.proxmox.com Git - mirror_edk2.git/blame - FatPkg/FatPei/FatLiteAccess.c
FatPkg: Apply uncrustify changes
[mirror_edk2.git] / FatPkg / FatPei / FatLiteAccess.c
CommitLineData
2f4dfa84
JJ
1/** @file\r
2 FAT file system access routines for FAT recovery PEIM\r
3\r
e38f26a2 4Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
2f4dfa84 5\r
eb6cb4ce 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
2f4dfa84
JJ
7\r
8**/\r
9\r
10#include "FatLitePeim.h"\r
11\r
2f4dfa84
JJ
12/**\r
13 Check if there is a valid FAT in the corresponding Block device\r
14 of the volume and if yes, fill in the relevant fields for the\r
15 volume structure. Note there should be a valid Block device number\r
16 already set.\r
17\r
e38f26a2
LG
18 @param PrivateData Global memory map for accessing global\r
19 variables.\r
20 @param Volume On input, the BlockDeviceNumber field of the\r
21 Volume should be a valid value. On successful\r
22 output, all fields except the VolumeNumber\r
23 field is initialized.\r
2f4dfa84 24\r
e38f26a2
LG
25 @retval EFI_SUCCESS A FAT is found and the volume structure is\r
26 initialized.\r
27 @retval EFI_NOT_FOUND There is no FAT on the corresponding device.\r
2f4dfa84
JJ
28 @retval EFI_DEVICE_ERROR There is something error while accessing device.\r
29\r
30**/\r
31EFI_STATUS\r
32FatGetBpbInfo (\r
33 IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
34 IN OUT PEI_FAT_VOLUME *Volume\r
35 )\r
36{\r
37 EFI_STATUS Status;\r
38 PEI_FAT_BOOT_SECTOR Bpb;\r
39 PEI_FAT_BOOT_SECTOR_EX BpbEx;\r
40 UINT32 Sectors;\r
41 UINT32 SectorsPerFat;\r
42 UINT32 RootDirSectors;\r
43 UINT64 FatLba;\r
44 UINT64 RootLba;\r
45 UINT64 FirstClusterLba;\r
46\r
47 //\r
48 // Read in the BPB\r
49 //\r
50 Status = FatReadDisk (\r
bcdcc416
MK
51 PrivateData,\r
52 Volume->BlockDeviceNo,\r
53 0,\r
54 sizeof (PEI_FAT_BOOT_SECTOR_EX),\r
55 &BpbEx\r
56 );\r
2f4dfa84
JJ
57 if (EFI_ERROR (Status)) {\r
58 return Status;\r
59 }\r
60\r
61 CopyMem (\r
bcdcc416
MK
62 (UINT8 *)(&Bpb),\r
63 (UINT8 *)(&BpbEx),\r
2f4dfa84
JJ
64 sizeof (PEI_FAT_BOOT_SECTOR)\r
65 );\r
66\r
67 Volume->FatType = FatUnknown;\r
68\r
bcdcc416 69 Sectors = Bpb.Sectors;\r
2f4dfa84
JJ
70 if (Sectors == 0) {\r
71 Sectors = Bpb.LargeSectors;\r
72 }\r
73\r
74 SectorsPerFat = Bpb.SectorsPerFat;\r
75 if (SectorsPerFat == 0) {\r
76 SectorsPerFat = BpbEx.LargeSectorsPerFat;\r
77 Volume->FatType = Fat32;\r
78 }\r
bcdcc416 79\r
2f4dfa84
JJ
80 //\r
81 // Filter out those not a FAT\r
82 //\r
bcdcc416 83 if ((Bpb.Ia32Jump[0] != 0xe9) && (Bpb.Ia32Jump[0] != 0xeb) && (Bpb.Ia32Jump[0] != 0x49)) {\r
2f4dfa84
JJ
84 return EFI_NOT_FOUND;\r
85 }\r
86\r
bcdcc416 87 if ((Bpb.ReservedSectors == 0) || (Bpb.NoFats == 0) || (Sectors == 0)) {\r
2f4dfa84
JJ
88 return EFI_NOT_FOUND;\r
89 }\r
90\r
bcdcc416
MK
91 if ((Bpb.SectorsPerCluster != 1) &&\r
92 (Bpb.SectorsPerCluster != 2) &&\r
93 (Bpb.SectorsPerCluster != 4) &&\r
94 (Bpb.SectorsPerCluster != 8) &&\r
95 (Bpb.SectorsPerCluster != 16) &&\r
96 (Bpb.SectorsPerCluster != 32) &&\r
97 (Bpb.SectorsPerCluster != 64) &&\r
98 (Bpb.SectorsPerCluster != 128)\r
99 )\r
100 {\r
2f4dfa84
JJ
101 return EFI_NOT_FOUND;\r
102 }\r
103\r
bcdcc416 104 if ((Volume->FatType == Fat32) && ((SectorsPerFat == 0) || (BpbEx.FsVersion != 0))) {\r
2f4dfa84
JJ
105 return EFI_NOT_FOUND;\r
106 }\r
107\r
bcdcc416
MK
108 if ((Bpb.Media != 0xf0) &&\r
109 (Bpb.Media != 0xf8) &&\r
110 (Bpb.Media != 0xf9) &&\r
111 (Bpb.Media != 0xfb) &&\r
112 (Bpb.Media != 0xfc) &&\r
113 (Bpb.Media != 0xfd) &&\r
114 (Bpb.Media != 0xfe) &&\r
115 (Bpb.Media != 0xff) &&\r
2f4dfa84
JJ
116 //\r
117 // FujitsuFMR\r
118 //\r
bcdcc416
MK
119 (Bpb.Media != 0x00) &&\r
120 (Bpb.Media != 0x01) &&\r
121 (Bpb.Media != 0xfa)\r
122 )\r
123 {\r
2f4dfa84
JJ
124 return EFI_NOT_FOUND;\r
125 }\r
126\r
bcdcc416 127 if ((Volume->FatType != Fat32) && (Bpb.RootEntries == 0)) {\r
2f4dfa84
JJ
128 return EFI_NOT_FOUND;\r
129 }\r
bcdcc416 130\r
2f4dfa84
JJ
131 //\r
132 // If this is fat32, refuse to mount mirror-disabled volumes\r
133 //\r
bcdcc416 134 if ((Volume->FatType == Fat32) && ((BpbEx.ExtendedFlags & 0x80) != 0)) {\r
2f4dfa84
JJ
135 return EFI_NOT_FOUND;\r
136 }\r
bcdcc416 137\r
2f4dfa84
JJ
138 //\r
139 // Fill in the volume structure fields\r
140 // (Sectors & SectorsPerFat is computed earlier already)\r
141 //\r
142 Volume->ClusterSize = Bpb.SectorSize * Bpb.SectorsPerCluster;\r
143 Volume->RootEntries = Bpb.RootEntries;\r
144 Volume->SectorSize = Bpb.SectorSize;\r
145\r
146 RootDirSectors = ((Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) + (Volume->SectorSize - 1)) / Volume->SectorSize;\r
147\r
bcdcc416
MK
148 FatLba = Bpb.ReservedSectors;\r
149 RootLba = Bpb.NoFats * SectorsPerFat + FatLba;\r
150 FirstClusterLba = RootLba + RootDirSectors;\r
2f4dfa84
JJ
151\r
152 Volume->VolumeSize = MultU64x32 (Sectors, Volume->SectorSize);\r
153 Volume->FatPos = MultU64x32 (FatLba, Volume->SectorSize);\r
154 Volume->RootDirPos = MultU64x32 (RootLba, Volume->SectorSize);\r
155 Volume->FirstClusterPos = MultU64x32 (FirstClusterLba, Volume->SectorSize);\r
bcdcc416 156 Volume->MaxCluster = (UINT32)(Sectors - FirstClusterLba) / Bpb.SectorsPerCluster;\r
2f4dfa84
JJ
157 Volume->RootDirCluster = BpbEx.RootDirFirstCluster;\r
158\r
159 //\r
160 // If this is not a fat32, determine if it's a fat16 or fat12\r
161 //\r
162 if (Volume->FatType != Fat32) {\r
2f4dfa84
JJ
163 if (Volume->MaxCluster >= 65525) {\r
164 return EFI_NOT_FOUND;\r
165 }\r
166\r
167 Volume->FatType = Volume->MaxCluster < 4085 ? Fat12 : Fat16;\r
168 }\r
169\r
170 return EFI_SUCCESS;\r
171}\r
172\r
2f4dfa84
JJ
173/**\r
174 Gets the next cluster in the cluster chain\r
175\r
e38f26a2
LG
176 @param PrivateData Global memory map for accessing global variables\r
177 @param Volume The volume\r
178 @param Cluster The cluster\r
179 @param NextCluster The cluster number of the next cluster\r
2f4dfa84 180\r
e38f26a2
LG
181 @retval EFI_SUCCESS The address is got\r
182 @retval EFI_INVALID_PARAMETER ClusterNo exceeds the MaxCluster of the volume.\r
2f4dfa84
JJ
183 @retval EFI_DEVICE_ERROR Read disk error\r
184\r
185**/\r
186EFI_STATUS\r
187FatGetNextCluster (\r
188 IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
189 IN PEI_FAT_VOLUME *Volume,\r
190 IN UINT32 Cluster,\r
191 OUT UINT32 *NextCluster\r
192 )\r
193{\r
194 EFI_STATUS Status;\r
195 UINT64 FatEntryPos;\r
196 UINT32 Dummy;\r
197\r
198 *NextCluster = 0;\r
199\r
200 if (Volume->FatType == Fat32) {\r
201 FatEntryPos = Volume->FatPos + MultU64x32 (4, Cluster);\r
202\r
bcdcc416 203 Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 4, NextCluster);\r
2f4dfa84
JJ
204 *NextCluster &= 0x0fffffff;\r
205\r
206 //\r
207 // Pad high bits for our FAT_CLUSTER_... macro definitions to work\r
208 //\r
209 if ((*NextCluster) >= 0x0ffffff7) {\r
210 *NextCluster |= (-1 &~0xf);\r
211 }\r
2f4dfa84
JJ
212 } else if (Volume->FatType == Fat16) {\r
213 FatEntryPos = Volume->FatPos + MultU64x32 (2, Cluster);\r
214\r
bcdcc416 215 Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);\r
2f4dfa84
JJ
216\r
217 //\r
218 // Pad high bits for our FAT_CLUSTER_... macro definitions to work\r
219 //\r
220 if ((*NextCluster) >= 0xfff7) {\r
221 *NextCluster |= (-1 &~0xf);\r
222 }\r
2f4dfa84
JJ
223 } else {\r
224 FatEntryPos = Volume->FatPos + DivU64x32Remainder (MultU64x32 (3, Cluster), 2, &Dummy);\r
225\r
bcdcc416 226 Status = FatReadDisk (PrivateData, Volume->BlockDeviceNo, FatEntryPos, 2, NextCluster);\r
2f4dfa84
JJ
227\r
228 if ((Cluster & 0x01) != 0) {\r
229 *NextCluster = (*NextCluster) >> 4;\r
230 } else {\r
231 *NextCluster = (*NextCluster) & 0x0fff;\r
232 }\r
bcdcc416 233\r
2f4dfa84
JJ
234 //\r
235 // Pad high bits for our FAT_CLUSTER_... macro definitions to work\r
236 //\r
237 if ((*NextCluster) >= 0x0ff7) {\r
238 *NextCluster |= (-1 &~0xf);\r
239 }\r
240 }\r
241\r
242 if (EFI_ERROR (Status)) {\r
243 return EFI_DEVICE_ERROR;\r
244 }\r
245\r
246 return EFI_SUCCESS;\r
2f4dfa84
JJ
247}\r
248\r
2f4dfa84
JJ
249/**\r
250 Set a file's CurrentPos and CurrentCluster, then compute StraightReadAmount.\r
251\r
e38f26a2
LG
252 @param PrivateData the global memory map\r
253 @param File the file\r
254 @param Pos the Position which is offset from the file's\r
255 CurrentPos\r
2f4dfa84 256\r
e38f26a2
LG
257 @retval EFI_SUCCESS Success.\r
258 @retval EFI_INVALID_PARAMETER Pos is beyond file's size.\r
2f4dfa84
JJ
259 @retval EFI_DEVICE_ERROR Something error while accessing media.\r
260\r
261**/\r
262EFI_STATUS\r
263FatSetFilePos (\r
264 IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
265 IN PEI_FAT_FILE *File,\r
266 IN UINT32 Pos\r
267 )\r
268{\r
269 EFI_STATUS Status;\r
270 UINT32 AlignedPos;\r
271 UINT32 Offset;\r
272 UINT32 Cluster;\r
273 UINT32 PrevCluster;\r
274\r
275 if (File->IsFixedRootDir) {\r
2f4dfa84
JJ
276 if (Pos >= MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos) {\r
277 return EFI_INVALID_PARAMETER;\r
278 }\r
279\r
bcdcc416
MK
280 File->CurrentPos += Pos;\r
281 File->StraightReadAmount = (UINT32)(MultU64x32 (File->Volume->RootEntries, 32) - File->CurrentPos);\r
2f4dfa84 282 } else {\r
2f4dfa84 283 DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);\r
bcdcc416 284 AlignedPos = (UINT32)File->CurrentPos - (UINT32)Offset;\r
2f4dfa84
JJ
285\r
286 while\r
287 (\r
bcdcc416
MK
288 !FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster) &&\r
289 AlignedPos + File->Volume->ClusterSize <= File->CurrentPos + Pos\r
290 )\r
291 {\r
2f4dfa84 292 AlignedPos += File->Volume->ClusterSize;\r
bcdcc416
MK
293 Status = FatGetNextCluster (\r
294 PrivateData,\r
295 File->Volume,\r
296 File->CurrentCluster,\r
297 &File->CurrentCluster\r
298 );\r
2f4dfa84
JJ
299 if (EFI_ERROR (Status)) {\r
300 return EFI_DEVICE_ERROR;\r
301 }\r
302 }\r
303\r
304 if (FAT_CLUSTER_FUNCTIONAL (File->CurrentCluster)) {\r
305 return EFI_INVALID_PARAMETER;\r
306 }\r
307\r
308 File->CurrentPos += Pos;\r
1d951a30
FT
309 //\r
310 // Calculate the amount of consecutive cluster occupied by the file.\r
311 // FatReadFile() will use it to read these blocks once.\r
312 //\r
bcdcc416
MK
313 File->StraightReadAmount = 0;\r
314 Cluster = File->CurrentCluster;\r
2f4dfa84
JJ
315 while (!FAT_CLUSTER_FUNCTIONAL (Cluster)) {\r
316 File->StraightReadAmount += File->Volume->ClusterSize;\r
bcdcc416
MK
317 PrevCluster = Cluster;\r
318 Status = FatGetNextCluster (PrivateData, File->Volume, Cluster, &Cluster);\r
2f4dfa84
JJ
319 if (EFI_ERROR (Status)) {\r
320 return EFI_DEVICE_ERROR;\r
321 }\r
322\r
323 if (Cluster != PrevCluster + 1) {\r
324 break;\r
325 }\r
326 }\r
327\r
328 DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);\r
bcdcc416 329 File->StraightReadAmount -= (UINT32)Offset;\r
2f4dfa84
JJ
330 }\r
331\r
332 return EFI_SUCCESS;\r
333}\r
334\r
2f4dfa84
JJ
335/**\r
336 Reads file data. Updates the file's CurrentPos.\r
337\r
e38f26a2
LG
338 @param PrivateData Global memory map for accessing global variables\r
339 @param File The file.\r
340 @param Size The amount of data to read.\r
341 @param Buffer The buffer storing the data.\r
2f4dfa84 342\r
e38f26a2
LG
343 @retval EFI_SUCCESS The data is read.\r
344 @retval EFI_INVALID_PARAMETER File is invalid.\r
2f4dfa84
JJ
345 @retval EFI_DEVICE_ERROR Something error while accessing media.\r
346\r
347**/\r
348EFI_STATUS\r
349FatReadFile (\r
350 IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
351 IN PEI_FAT_FILE *File,\r
352 IN UINTN Size,\r
353 OUT VOID *Buffer\r
354 )\r
355{\r
356 EFI_STATUS Status;\r
357 CHAR8 *BufferPtr;\r
358 UINT32 Offset;\r
359 UINT64 PhysicalAddr;\r
360 UINTN Amount;\r
361\r
362 BufferPtr = Buffer;\r
363\r
364 if (File->IsFixedRootDir) {\r
365 //\r
366 // This is the fixed root dir in FAT12 and FAT16\r
367 //\r
368 if (File->CurrentPos + Size > File->Volume->RootEntries * sizeof (FAT_DIRECTORY_ENTRY)) {\r
369 return EFI_INVALID_PARAMETER;\r
370 }\r
371\r
372 Status = FatReadDisk (\r
bcdcc416
MK
373 PrivateData,\r
374 File->Volume->BlockDeviceNo,\r
375 File->Volume->RootDirPos + File->CurrentPos,\r
376 Size,\r
377 Buffer\r
378 );\r
379 File->CurrentPos += (UINT32)Size;\r
2f4dfa84 380 return Status;\r
2f4dfa84 381 } else {\r
2f4dfa84 382 if ((File->Attributes & FAT_ATTR_DIRECTORY) == 0) {\r
64b25f5d 383 Size = Size < (File->FileSize - File->CurrentPos) ? Size : (File->FileSize - File->CurrentPos);\r
2f4dfa84 384 }\r
bcdcc416 385\r
2f4dfa84
JJ
386 //\r
387 // This is a normal cluster based file\r
388 //\r
389 while (Size != 0) {\r
390 DivU64x32Remainder (File->CurrentPos, File->Volume->ClusterSize, &Offset);\r
bcdcc416 391 PhysicalAddr = File->Volume->FirstClusterPos + MultU64x32 (File->Volume->ClusterSize, File->CurrentCluster - 2);\r
2f4dfa84 392\r
bcdcc416
MK
393 Amount = File->StraightReadAmount;\r
394 Amount = Size > Amount ? Amount : Size;\r
2f4dfa84 395 Status = FatReadDisk (\r
bcdcc416
MK
396 PrivateData,\r
397 File->Volume->BlockDeviceNo,\r
398 PhysicalAddr + Offset,\r
399 Amount,\r
400 BufferPtr\r
401 );\r
2f4dfa84
JJ
402 if (EFI_ERROR (Status)) {\r
403 return EFI_DEVICE_ERROR;\r
404 }\r
bcdcc416 405\r
2f4dfa84
JJ
406 //\r
407 // Advance the file's current pos and current cluster\r
408 //\r
bcdcc416 409 FatSetFilePos (PrivateData, File, (UINT32)Amount);\r
2f4dfa84
JJ
410\r
411 BufferPtr += Amount;\r
bcdcc416 412 Size -= Amount;\r
2f4dfa84
JJ
413 }\r
414\r
415 return EFI_SUCCESS;\r
416 }\r
417}\r
418\r
2f4dfa84
JJ
419/**\r
420 This function reads the next item in the parent directory and\r
421 initializes the output parameter SubFile (CurrentPos is initialized to 0).\r
422 The function updates the CurrentPos of the parent dir to after the item read.\r
423 If no more items were found, the function returns EFI_NOT_FOUND.\r
424\r
e38f26a2
LG
425 @param PrivateData Global memory map for accessing global variables\r
426 @param ParentDir The parent directory.\r
427 @param SubFile The File structure containing the sub file that\r
428 is caught.\r
2f4dfa84 429\r
e38f26a2
LG
430 @retval EFI_SUCCESS The next sub file is obtained.\r
431 @retval EFI_INVALID_PARAMETER The ParentDir is not a directory.\r
432 @retval EFI_NOT_FOUND No more sub file exists.\r
2f4dfa84
JJ
433 @retval EFI_DEVICE_ERROR Something error while accessing media.\r
434\r
435**/\r
436EFI_STATUS\r
437FatReadNextDirectoryEntry (\r
438 IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
439 IN PEI_FAT_FILE *ParentDir,\r
440 OUT PEI_FAT_FILE *SubFile\r
441 )\r
442{\r
bcdcc416
MK
443 EFI_STATUS Status;\r
444 FAT_DIRECTORY_ENTRY DirEntry;\r
445 CHAR16 *Pos;\r
446 CHAR16 BaseName[9];\r
447 CHAR16 Ext[4];\r
2f4dfa84 448\r
bcdcc416 449 ZeroMem ((UINT8 *)SubFile, sizeof (PEI_FAT_FILE));\r
2f4dfa84
JJ
450\r
451 //\r
452 // Pick a valid directory entry\r
453 //\r
454 while (1) {\r
455 //\r
456 // Read one entry\r
457 //\r
458 Status = FatReadFile (PrivateData, ParentDir, 32, &DirEntry);\r
459 if (EFI_ERROR (Status)) {\r
460 return EFI_DEVICE_ERROR;\r
461 }\r
bcdcc416 462\r
2f4dfa84
JJ
463 //\r
464 // We only search for *FILE* in root directory\r
465 // Long file name entry is *NOT* supported\r
466 //\r
3ba5368d 467 if (((DirEntry.Attributes & FAT_ATTR_DIRECTORY) == FAT_ATTR_DIRECTORY) || (DirEntry.Attributes == FAT_ATTR_LFN)) {\r
2f4dfa84
JJ
468 continue;\r
469 }\r
bcdcc416 470\r
2f4dfa84
JJ
471 //\r
472 // if this is a terminator dir entry, just return EFI_NOT_FOUND\r
473 //\r
474 if (DirEntry.FileName[0] == EMPTY_ENTRY_MARK) {\r
475 return EFI_NOT_FOUND;\r
476 }\r
bcdcc416 477\r
2f4dfa84
JJ
478 //\r
479 // If this not an invalid entry neither an empty entry, this is what we want.\r
480 // otherwise we will start a new loop to continue to find something meaningful\r
481 //\r
bcdcc416 482 if ((UINT8)DirEntry.FileName[0] != DELETE_ENTRY_MARK) {\r
2f4dfa84
JJ
483 break;\r
484 }\r
485 }\r
bcdcc416 486\r
2f4dfa84
JJ
487 //\r
488 // fill in the output parameter\r
489 //\r
490 EngFatToStr (8, DirEntry.FileName, BaseName);\r
491 EngFatToStr (3, DirEntry.FileName + 8, Ext);\r
492\r
bcdcc416
MK
493 Pos = (UINT16 *)SubFile->FileName;\r
494 SetMem ((UINT8 *)Pos, FAT_MAX_FILE_NAME_LENGTH, 0);\r
495 CopyMem ((UINT8 *)Pos, (UINT8 *)BaseName, 2 * (StrLen (BaseName) + 1));\r
2f4dfa84
JJ
496\r
497 if (Ext[0] != 0) {\r
498 Pos += StrLen (BaseName);\r
499 *Pos = '.';\r
500 Pos++;\r
bcdcc416 501 CopyMem ((UINT8 *)Pos, (UINT8 *)Ext, 2 * (StrLen (Ext) + 1));\r
2f4dfa84
JJ
502 }\r
503\r
504 SubFile->Attributes = DirEntry.Attributes;\r
505 SubFile->CurrentCluster = DirEntry.FileCluster;\r
506 if (ParentDir->Volume->FatType == Fat32) {\r
507 SubFile->CurrentCluster |= DirEntry.FileClusterHigh << 16;\r
508 }\r
509\r
bcdcc416
MK
510 SubFile->CurrentPos = 0;\r
511 SubFile->FileSize = DirEntry.FileSize;\r
512 SubFile->StartingCluster = SubFile->CurrentCluster;\r
513 SubFile->Volume = ParentDir->Volume;\r
2f4dfa84 514\r
2f4dfa84
JJ
515 //\r
516 // in Pei phase, time parameters do not need to be filled for minimum use.\r
517 //\r
518 return Status;\r
519}\r