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