1 /** @file
2   Data structures for FAT recovery PEIM
3 
4 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
5 
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #ifndef _FAT_PEIM_H_
11 #define _FAT_PEIM_H_
12 
13 #include <PiPei.h>
14 
15 #include <Guid/RecoveryDevice.h>
16 #include <Ppi/BlockIo.h>
17 #include <Ppi/BlockIo2.h>
18 #include <Ppi/DeviceRecoveryModule.h>
19 
20 #include <Library/DebugLib.h>
21 #include <Library/BaseLib.h>
22 #include <Library/PeimEntryPoint.h>
23 #include <Library/BaseMemoryLib.h>
24 #include <Library/MemoryAllocationLib.h>
25 #include <Library/PcdLib.h>
26 #include <Library/PeiServicesTablePointerLib.h>
27 #include <Library/PeiServicesLib.h>
28 
29 #include "FatLiteApi.h"
30 #include "FatLiteFmt.h"
31 
32 //
33 // Definitions
34 //
35 
36 #define PEI_FAT_CACHE_SIZE                            4
37 #define PEI_FAT_MAX_BLOCK_SIZE                        8192
38 #define FAT_MAX_FILE_NAME_LENGTH                      128
39 #define PEI_FAT_MAX_BLOCK_DEVICE                      64
40 #define PEI_FAT_MAX_BLOCK_IO_PPI                      32
41 #define PEI_FAT_MAX_VOLUME                            64
42 
43 #define PEI_FAT_MEMORY_PAGE_SIZE                      0x1000
44 
45 //
46 // Data Structures
47 //
48 //
49 // The block device
50 //
51 typedef struct {
52 
53   UINT32                        BlockSize;
54   UINT64                        LastBlock;
55   UINT32                        IoAlign;
56   BOOLEAN                       Logical;
57   BOOLEAN                       PartitionChecked;
58 
59   //
60   // Following fields only valid for logical device
61   //
62   CHAR8                         PartitionFlag[8];
63   UINT64                        StartingPos;
64   UINTN                         ParentDevNo;
65 
66   //
67   // Following fields only valid for physical device
68   //
69   EFI_PEI_BLOCK_DEVICE_TYPE     DevType;
70   UINT8                         InterfaceType;
71   //
72   // EFI_PEI_READ_BLOCKS         ReadFunc;
73   //
74   EFI_PEI_RECOVERY_BLOCK_IO_PPI  *BlockIo;
75   EFI_PEI_RECOVERY_BLOCK_IO2_PPI *BlockIo2;
76   UINT8                          PhysicalDevNo;
77 } PEI_FAT_BLOCK_DEVICE;
78 
79 //
80 // the Volume structure
81 //
82 typedef struct {
83 
84   UINTN         BlockDeviceNo;
85   UINTN         VolumeNo;
86   UINT64        VolumeSize;
87   UINTN         MaxCluster;
88   CHAR16        VolumeLabel[FAT_MAX_FILE_NAME_LENGTH];
89   PEI_FAT_TYPE  FatType;
90   UINT64        FatPos;
91   UINT32        SectorSize;
92   UINT32        ClusterSize;
93   UINT64        FirstClusterPos;
94   UINT64        RootDirPos;
95   UINT32        RootEntries;
96   UINT32        RootDirCluster;
97 
98 } PEI_FAT_VOLUME;
99 
100 //
101 // File instance
102 //
103 typedef struct {
104 
105   PEI_FAT_VOLUME  *Volume;
106   CHAR16          FileName[FAT_MAX_FILE_NAME_LENGTH];
107 
108   BOOLEAN         IsFixedRootDir;
109 
110   UINT32          StartingCluster;
111   UINT32          CurrentPos;
112   UINT32          StraightReadAmount;
113   UINT32          CurrentCluster;
114 
115   UINT8           Attributes;
116   UINT32          FileSize;
117 
118 } PEI_FAT_FILE;
119 
120 //
121 // Cache Buffer
122 //
123 typedef struct {
124 
125   BOOLEAN Valid;
126   UINTN   BlockDeviceNo;
127   UINT64  Lba;
128   UINT32  Lru;
129   UINT64  Buffer[PEI_FAT_MAX_BLOCK_SIZE / 8];
130   UINTN   Size;
131 
132 } PEI_FAT_CACHE_BUFFER;
133 
134 //
135 // Private Data.
136 // This structure abstracts the whole memory usage in FAT PEIM.
137 // The entry point routine will get a chunk of memory (by whatever
138 // means) whose size is sizeof(PEI_FAT_PRIVATE_DATA), which is clean
139 // in both 32 and 64 bit environment. The boundary of the memory chunk
140 // should be 64bit aligned.
141 //
142 #define PEI_FAT_PRIVATE_DATA_SIGNATURE  SIGNATURE_32 ('p', 'f', 'a', 't')
143 
144 typedef struct {
145 
146   UINTN                               Signature;
147   EFI_PEI_DEVICE_RECOVERY_MODULE_PPI  DeviceRecoveryPpi;
148   EFI_PEI_PPI_DESCRIPTOR              PpiDescriptor;
149   EFI_PEI_NOTIFY_DESCRIPTOR           NotifyDescriptor[2];
150 
151   UINT8                               UnicodeCaseMap[0x300];
152   CHAR8                               *EngUpperMap;
153   CHAR8                               *EngLowerMap;
154   CHAR8                               *EngInfoMap;
155 
156   UINT64                              BlockData[PEI_FAT_MAX_BLOCK_SIZE / 8];
157   UINTN                               BlockDeviceCount;
158   PEI_FAT_BLOCK_DEVICE                BlockDevice[PEI_FAT_MAX_BLOCK_DEVICE];
159   UINTN                               VolumeCount;
160   PEI_FAT_VOLUME                      Volume[PEI_FAT_MAX_VOLUME];
161   PEI_FAT_FILE                        File;
162   PEI_FAT_CACHE_BUFFER                CacheBuffer[PEI_FAT_CACHE_SIZE];
163 
164 } PEI_FAT_PRIVATE_DATA;
165 
166 #define PEI_FAT_PRIVATE_DATA_FROM_THIS(a) \
167   CR (a,  PEI_FAT_PRIVATE_DATA, DeviceRecoveryPpi, PEI_FAT_PRIVATE_DATA_SIGNATURE)
168 
169 //
170 // Extract INT32 from char array
171 //
172 #define UNPACK_INT32(a) \
173   (INT32) ((((UINT8 *) a)[0] << 0) | (((UINT8 *) a)[1] << 8) | (((UINT8 *) a)[2] << 16) | (((UINT8 *) a)[3] << 24))
174 
175 //
176 // Extract UINT32 from char array
177 //
178 #define UNPACK_UINT32(a) \
179   (UINT32) ((((UINT8 *) a)[0] << 0) | (((UINT8 *) a)[1] << 8) | (((UINT8 *) a)[2] << 16) | (((UINT8 *) a)[3] << 24))
180 
181 
182 //
183 // API functions
184 //
185 
186 /**
187   Finds the recovery file on a FAT volume.
188   This function finds the recovery file named FileName on a specified FAT volume and returns
189   its FileHandle pointer.
190 
191   @param  PrivateData             Global memory map for accessing global
192                                   variables.
193   @param  VolumeIndex             The index of the volume.
194   @param  FileName                The recovery file name to find.
195   @param  Handle                  The output file handle.
196 
197   @retval EFI_DEVICE_ERROR        Some error occurred when operating the FAT
198                                   volume.
199   @retval EFI_NOT_FOUND           The recovery file was not found.
200   @retval EFI_SUCCESS             The recovery file was successfully found on the
201                                   FAT volume.
202 
203 **/
204 EFI_STATUS
205 FindRecoveryFile (
206   IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
207   IN  UINTN                 VolumeIndex,
208   IN  CHAR16                *FileName,
209   OUT PEI_FILE_HANDLE       *Handle
210   );
211 
212 
213 /**
214   Returns the number of DXE capsules residing on the device.
215   This function, by whatever mechanism, searches for DXE capsules from the associated device and
216   returns the number and maximum size in bytes of the capsules discovered.Entry 1 is assumed to be
217   the highest load priority and entry N is assumed to be the lowest priority.
218 
219   @param  PeiServices             General-purpose services that are available to
220                                   every PEIM.
221   @param  This                    Indicates the
222                                   EFI_PEI_DEVICE_RECOVERY_MODULE_PPI instance.
223   @param  NumberRecoveryCapsules  Pointer to a caller-allocated UINTN.On output,
224                                   *NumberRecoveryCapsules contains the number of
225                                   recovery capsule images available for retrieval
226                                   from this PEIM instance.
227 
228   @retval EFI_SUCCESS             The function completed successfully.
229 
230 **/
231 EFI_STATUS
232 EFIAPI
233 GetNumberRecoveryCapsules (
234   IN EFI_PEI_SERVICES                               **PeiServices,
235   IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI             *This,
236   OUT UINTN                                         *NumberRecoveryCapsules
237   );
238 
239 
240 /**
241   Returns the size and type of the requested recovery capsule.
242   This function returns the size and type of the capsule specified by CapsuleInstance.
243 
244   @param  PeiServices             General-purpose services that are available to
245                                   every PEIM.
246   @param  This                    Indicates the
247                                   EFI_PEI_DEVICE_RECOVERY_MODULE_PPI instance.
248   @param  CapsuleInstance         Specifies for which capsule instance to
249                                   retrieve the information.T his parameter must
250                                   be between one and the value returned by
251                                   GetNumberRecoveryCapsules() in
252                                   NumberRecoveryCapsules.
253   @param  Size                    A pointer to a caller-allocated UINTN in which
254                                   the size of the requested recovery module is
255                                   returned.
256   @param  CapsuleType             A pointer to a caller-allocated EFI_GUID in
257                                   which the type of the requested recovery
258                                   capsule is returned.T he semantic meaning of
259                                   the value returned is defined by the
260                                   implementation.
261 
262   @retval EFI_SUCCESS             The capsule type and size were retrieved.
263   @retval EFI_INVALID_PARAMETER   The input CapsuleInstance does not match any
264                                   discovered recovery capsule.
265 
266 **/
267 EFI_STATUS
268 EFIAPI
269 GetRecoveryCapsuleInfo (
270   IN  EFI_PEI_SERVICES                              **PeiServices,
271   IN  EFI_PEI_DEVICE_RECOVERY_MODULE_PPI            *This,
272   IN  UINTN                                         CapsuleInstance,
273   OUT UINTN                                         *Size,
274   OUT EFI_GUID                                      *CapsuleType
275   );
276 
277 
278 /**
279   Loads a DXE capsule from some media into memory.
280 
281   This function, by whatever mechanism, retrieves a DXE capsule from some device
282   and loads it into memory. Note that the published interface is device neutral.
283 
284   @param[in]     PeiServices       General-purpose services that are available
285                                    to every PEIM
286   @param[in]     This              Indicates the EFI_PEI_DEVICE_RECOVERY_MODULE_PPI
287                                    instance.
288   @param[in]     CapsuleInstance   Specifies which capsule instance to retrieve.
289   @param[out]    Buffer            Specifies a caller-allocated buffer in which
290                                    the requested recovery capsule will be returned.
291 
292   @retval EFI_SUCCESS        The capsule was loaded correctly.
293   @retval EFI_DEVICE_ERROR   A device error occurred.
294   @retval EFI_NOT_FOUND      A requested recovery DXE capsule cannot be found.
295 
296 **/
297 EFI_STATUS
298 EFIAPI
299 LoadRecoveryCapsule (
300   IN EFI_PEI_SERVICES                             **PeiServices,
301   IN EFI_PEI_DEVICE_RECOVERY_MODULE_PPI           *This,
302   IN UINTN                                        CapsuleInstance,
303   OUT VOID                                        *Buffer
304   );
305 
306 
307 /**
308   This version is different from the version in Unicode collation
309   protocol in that this version strips off trailing blanks.
310   Converts an 8.3 FAT file name using an OEM character set
311   to a Null-terminated Unicode string.
312   Here does not expand DBCS FAT chars.
313 
314   @param  FatSize           The size of the string Fat in bytes.
315   @param  Fat               A pointer to a Null-terminated string that contains
316                             an 8.3 file name using an OEM character set.
317   @param  Str               A pointer to a Null-terminated Unicode string. The
318                             string must be allocated in advance to hold FatSize
319                             Unicode characters
320 
321 **/
322 VOID
323 EngFatToStr (
324   IN UINTN                            FatSize,
325   IN CHAR8                            *Fat,
326   OUT CHAR16                          *Str
327   );
328 
329 
330 /**
331   Performs a case-insensitive comparison of two Null-terminated Unicode strings.
332 
333   @param  PrivateData       Global memory map for accessing global variables
334   @param  Str1              First string to perform case insensitive comparison.
335   @param  Str2              Second string to perform case insensitive comparison.
336 
337 **/
338 BOOLEAN
339 EngStriColl (
340   IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
341   IN CHAR16                 *Str1,
342   IN CHAR16                 *Str2
343   );
344 
345 
346 /**
347   Reads a block of data from the block device by calling
348   underlying Block I/O service.
349 
350   @param  PrivateData       Global memory map for accessing global variables
351   @param  BlockDeviceNo     The index for the block device number.
352   @param  Lba               The logic block address to read data from.
353   @param  BufferSize        The size of data in byte to read.
354   @param  Buffer            The buffer of the
355 
356   @retval EFI_DEVICE_ERROR  The specified block device number exceeds the maximum
357                             device number.
358   @retval EFI_DEVICE_ERROR  The maximum address has exceeded the maximum address
359                             of the block device.
360 
361 **/
362 EFI_STATUS
363 FatReadBlock (
364   IN  PEI_FAT_PRIVATE_DATA   *PrivateData,
365   IN  UINTN                  BlockDeviceNo,
366   IN  EFI_PEI_LBA            Lba,
367   IN  UINTN                  BufferSize,
368   OUT VOID                   *Buffer
369   );
370 
371 
372 /**
373   Check if there is a valid FAT in the corresponding Block device
374   of the volume and if yes, fill in the relevant fields for the
375   volume structure. Note there should be a valid Block device number
376   already set.
377 
378   @param  PrivateData            Global memory map for accessing global
379                                  variables.
380   @param  Volume                 On input, the BlockDeviceNumber field of the
381                                  Volume  should be a valid value. On successful
382                                  output, all  fields except the VolumeNumber
383                                  field is initialized.
384 
385   @retval EFI_SUCCESS            A FAT is found and the volume structure is
386                                  initialized.
387   @retval EFI_NOT_FOUND          There is no FAT on the corresponding device.
388   @retval EFI_DEVICE_ERROR       There is something error while accessing device.
389 
390 **/
391 EFI_STATUS
392 FatGetBpbInfo (
393   IN      PEI_FAT_PRIVATE_DATA  *PrivateData,
394   IN OUT  PEI_FAT_VOLUME        *Volume
395   );
396 
397 
398 /**
399   Gets the next cluster in the cluster chain.
400 
401   @param  PrivateData            Global memory map for accessing global variables
402   @param  Volume                 The volume
403   @param  Cluster                The cluster
404   @param  NextCluster            The cluster number of the next cluster
405 
406   @retval EFI_SUCCESS            The address is got
407   @retval EFI_INVALID_PARAMETER  ClusterNo exceeds the MaxCluster of the volume.
408   @retval EFI_DEVICE_ERROR       Read disk error
409 
410 **/
411 EFI_STATUS
412 FatGetNextCluster (
413   IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
414   IN  PEI_FAT_VOLUME        *Volume,
415   IN  UINT32                Cluster,
416   OUT UINT32                *NextCluster
417   );
418 
419 
420 /**
421   Disk reading.
422 
423   @param  PrivateData       the global memory map;
424   @param  BlockDeviceNo     the block device to read;
425   @param  StartingAddress   the starting address.
426   @param  Size              the amount of data to read.
427   @param  Buffer            the buffer holding the data
428 
429   @retval EFI_SUCCESS       The function completed successfully.
430   @retval EFI_DEVICE_ERROR  Something error.
431 
432 **/
433 EFI_STATUS
434 FatReadDisk (
435   IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
436   IN  UINTN                 BlockDeviceNo,
437   IN  UINT64                StartingAddress,
438   IN  UINTN                 Size,
439   OUT VOID                  *Buffer
440   );
441 
442 
443 /**
444   Set a file's CurrentPos and CurrentCluster, then compute StraightReadAmount.
445 
446   @param  PrivateData            the global memory map
447   @param  File                   the file
448   @param  Pos                    the Position which is offset from the file's
449                                  CurrentPos
450 
451   @retval EFI_SUCCESS            Success.
452   @retval EFI_INVALID_PARAMETER  Pos is beyond file's size.
453   @retval EFI_DEVICE_ERROR       Something error while accessing media.
454 
455 **/
456 EFI_STATUS
457 FatSetFilePos (
458   IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
459   IN  PEI_FAT_FILE          *File,
460   IN  UINT32                Pos
461   );
462 
463 
464 /**
465   Reads file data. Updates the file's CurrentPos.
466 
467   @param  PrivateData            Global memory map for accessing global variables
468   @param  File                   The file.
469   @param  Size                   The amount of data to read.
470   @param  Buffer                 The buffer storing the data.
471 
472   @retval EFI_SUCCESS            The data is read.
473   @retval EFI_INVALID_PARAMETER  File is invalid.
474   @retval EFI_DEVICE_ERROR       Something error while accessing media.
475 
476 **/
477 EFI_STATUS
478 FatReadFile (
479   IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
480   IN  PEI_FAT_FILE          *File,
481   IN  UINTN                 Size,
482   OUT VOID                  *Buffer
483   );
484 
485 
486 /**
487   This function reads the next item in the parent directory and
488   initializes the output parameter SubFile (CurrentPos is initialized to 0).
489   The function updates the CurrentPos of the parent dir to after the item read.
490   If no more items were found, the function returns EFI_NOT_FOUND.
491 
492   @param  PrivateData            Global memory map for accessing global variables
493   @param  ParentDir              The parent directory.
494   @param  SubFile                The File structure containing the sub file that
495                                  is caught.
496 
497   @retval EFI_SUCCESS            The next sub file is obtained.
498   @retval EFI_INVALID_PARAMETER  The ParentDir is not a directory.
499   @retval EFI_NOT_FOUND          No more sub file exists.
500   @retval EFI_DEVICE_ERROR       Something error while accessing media.
501 
502 **/
503 EFI_STATUS
504 FatReadNextDirectoryEntry (
505   IN  PEI_FAT_PRIVATE_DATA  *PrivateData,
506   IN  PEI_FAT_FILE          *ParentDir,
507   OUT PEI_FAT_FILE          *SubFile
508   );
509 
510 
511 /**
512   This function finds partitions (logical devices) in physical block devices.
513 
514   @param  PrivateData       Global memory map for accessing global variables.
515 
516 **/
517 VOID
518 FatFindPartitions (
519   IN  PEI_FAT_PRIVATE_DATA  *PrivateData
520   );
521 
522 #endif // _FAT_PEIM_H_
523