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