]> git.proxmox.com Git - mirror_edk2.git/blame - FatPkg/FatPei/FatLiteLib.c
Maintainers.txt: update mailing list information
[mirror_edk2.git] / FatPkg / FatPei / FatLiteLib.c
CommitLineData
2f4dfa84
JJ
1/** @file\r
2 General purpose supporting 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
12\r
13#define CHAR_FAT_VALID 0x01\r
14\r
15\r
16/**\r
17 Converts a union code character to upper case.\r
18 This functions converts a unicode character to upper case.\r
19 If the input Letter is not a lower-cased letter,\r
20 the original value is returned.\r
21\r
e38f26a2 22 @param Letter The input unicode character.\r
2f4dfa84
JJ
23\r
24 @return The upper cased letter.\r
25\r
26**/\r
27CHAR16\r
28ToUpper (\r
29 IN CHAR16 Letter\r
30 )\r
31{\r
32 if ('a' <= Letter && Letter <= 'z') {\r
33 Letter = (CHAR16) (Letter - 0x20);\r
34 }\r
35\r
36 return Letter;\r
37}\r
38\r
39\r
40/**\r
41 Reads a block of data from the block device by calling\r
42 underlying Block I/O service.\r
43\r
e38f26a2
LG
44 @param PrivateData Global memory map for accessing global variables\r
45 @param BlockDeviceNo The index for the block device number.\r
46 @param Lba The logic block address to read data from.\r
47 @param BufferSize The size of data in byte to read.\r
48 @param Buffer The buffer of the\r
2f4dfa84 49\r
e38f26a2
LG
50 @retval EFI_DEVICE_ERROR The specified block device number exceeds the maximum\r
51 device number.\r
52 @retval EFI_DEVICE_ERROR The maximum address has exceeded the maximum address\r
2f4dfa84
JJ
53 of the block device.\r
54\r
55**/\r
56EFI_STATUS\r
57FatReadBlock (\r
58 IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
59 IN UINTN BlockDeviceNo,\r
60 IN EFI_PEI_LBA Lba,\r
61 IN UINTN BufferSize,\r
62 OUT VOID *Buffer\r
63 )\r
64{\r
65 EFI_STATUS Status;\r
66 PEI_FAT_BLOCK_DEVICE *BlockDev;\r
67\r
68 if (BlockDeviceNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {\r
69 return EFI_DEVICE_ERROR;\r
70 }\r
71\r
72 Status = EFI_SUCCESS;\r
73 BlockDev = &(PrivateData->BlockDevice[BlockDeviceNo]);\r
74\r
75 if (BufferSize > MultU64x32 (BlockDev->LastBlock - Lba + 1, BlockDev->BlockSize)) {\r
76 return EFI_DEVICE_ERROR;\r
77 }\r
78\r
79 if (!BlockDev->Logical) {\r
80 //\r
81 // Status = BlockDev->ReadFunc\r
82 // (PrivateData->PeiServices, BlockDev->PhysicalDevNo, Lba, BufferSize, Buffer);\r
83 //\r
8a467be1
FT
84 if (BlockDev->BlockIo2 != NULL) {\r
85 Status = BlockDev->BlockIo2->ReadBlocks (\r
86 (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),\r
87 BlockDev->BlockIo2,\r
88 BlockDev->PhysicalDevNo,\r
89 Lba,\r
90 BufferSize,\r
91 Buffer\r
92 );\r
93 } else {\r
94 Status = BlockDev->BlockIo->ReadBlocks (\r
2f4dfa84
JJ
95 (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),\r
96 BlockDev->BlockIo,\r
97 BlockDev->PhysicalDevNo,\r
98 Lba,\r
99 BufferSize,\r
100 Buffer\r
101 );\r
8a467be1 102 }\r
2f4dfa84
JJ
103\r
104 } else {\r
105 Status = FatReadDisk (\r
106 PrivateData,\r
107 BlockDev->ParentDevNo,\r
108 BlockDev->StartingPos + MultU64x32 (Lba, BlockDev->BlockSize),\r
109 BufferSize,\r
110 Buffer\r
111 );\r
112 }\r
113\r
114 return Status;\r
115}\r
116\r
117\r
118/**\r
119 Find a cache block designated to specific Block device and Lba.\r
120 If not found, invalidate an oldest one and use it. (LRU cache)\r
121\r
e38f26a2
LG
122 @param PrivateData the global memory map.\r
123 @param BlockDeviceNo the Block device.\r
124 @param Lba the Logical Block Address\r
125 @param CachePtr Ptr to the starting address of the memory holding the\r
126 data;\r
2f4dfa84
JJ
127\r
128 @retval EFI_SUCCESS The function completed successfully.\r
129 @retval EFI_DEVICE_ERROR Something error while accessing media.\r
130\r
131**/\r
132EFI_STATUS\r
133FatGetCacheBlock (\r
134 IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
135 IN UINTN BlockDeviceNo,\r
136 IN UINT64 Lba,\r
137 OUT CHAR8 **CachePtr\r
138 )\r
139{\r
140 EFI_STATUS Status;\r
141 PEI_FAT_CACHE_BUFFER *CacheBuffer;\r
142 INTN Index;\r
143 STATIC UINT8 Seed;\r
144\r
145 Status = EFI_SUCCESS;\r
146 CacheBuffer = NULL;\r
147\r
148 //\r
149 // go through existing cache buffers\r
150 //\r
151 for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {\r
152 CacheBuffer = &(PrivateData->CacheBuffer[Index]);\r
153 if (CacheBuffer->Valid && CacheBuffer->BlockDeviceNo == BlockDeviceNo && CacheBuffer->Lba == Lba) {\r
154 break;\r
155 }\r
156 }\r
157\r
158 if (Index < PEI_FAT_CACHE_SIZE) {\r
159 *CachePtr = (CHAR8 *) CacheBuffer->Buffer;\r
160 return EFI_SUCCESS;\r
161 }\r
162 //\r
163 // We have to find an invalid cache buffer\r
164 //\r
165 for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {\r
166 if (!PrivateData->CacheBuffer[Index].Valid) {\r
167 break;\r
168 }\r
169 }\r
170 //\r
171 // Use the cache buffer\r
172 //\r
173 if (Index == PEI_FAT_CACHE_SIZE) {\r
174 Index = (Seed++) % PEI_FAT_CACHE_SIZE;\r
175 }\r
e38f26a2 176\r
2f4dfa84 177 //\r
e38f26a2 178 // Current device ID should be less than maximum device ID.\r
2f4dfa84
JJ
179 //\r
180 if (BlockDeviceNo >= PEI_FAT_MAX_BLOCK_DEVICE) {\r
181 return EFI_DEVICE_ERROR;\r
182 }\r
183\r
184 CacheBuffer = &(PrivateData->CacheBuffer[Index]);\r
185\r
186 CacheBuffer->BlockDeviceNo = BlockDeviceNo;\r
187 CacheBuffer->Lba = Lba;\r
188 CacheBuffer->Size = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;\r
189\r
190 //\r
191 // Read in the data\r
192 //\r
193 Status = FatReadBlock (\r
194 PrivateData,\r
195 BlockDeviceNo,\r
196 Lba,\r
197 CacheBuffer->Size,\r
198 CacheBuffer->Buffer\r
199 );\r
200 if (EFI_ERROR (Status)) {\r
201 return EFI_DEVICE_ERROR;\r
202 }\r
203\r
204 CacheBuffer->Valid = TRUE;\r
205 *CachePtr = (CHAR8 *) CacheBuffer->Buffer;\r
206\r
207 return Status;\r
208}\r
209\r
210\r
211/**\r
212 Disk reading.\r
213\r
e38f26a2
LG
214 @param PrivateData the global memory map;\r
215 @param BlockDeviceNo the block device to read;\r
216 @param StartingAddress the starting address.\r
217 @param Size the amount of data to read.\r
218 @param Buffer the buffer holding the data\r
2f4dfa84
JJ
219\r
220 @retval EFI_SUCCESS The function completed successfully.\r
221 @retval EFI_DEVICE_ERROR Something error.\r
222\r
223**/\r
224EFI_STATUS\r
225FatReadDisk (\r
226 IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
227 IN UINTN BlockDeviceNo,\r
228 IN UINT64 StartingAddress,\r
229 IN UINTN Size,\r
230 OUT VOID *Buffer\r
231 )\r
232{\r
233 EFI_STATUS Status;\r
234 UINT32 BlockSize;\r
235 CHAR8 *BufferPtr;\r
236 CHAR8 *CachePtr;\r
237 UINT32 Offset;\r
238 UINT64 Lba;\r
239 UINT64 OverRunLba;\r
240 UINTN Amount;\r
241\r
242 Status = EFI_SUCCESS;\r
243 BufferPtr = Buffer;\r
244 BlockSize = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;\r
245\r
246 //\r
247 // Read underrun\r
248 //\r
249 Lba = DivU64x32Remainder (StartingAddress, BlockSize, &Offset);\r
250 Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, Lba, &CachePtr);\r
251 if (EFI_ERROR (Status)) {\r
252 return EFI_DEVICE_ERROR;\r
253 }\r
254\r
255 Amount = Size < (BlockSize - Offset) ? Size : (BlockSize - Offset);\r
256 CopyMem (BufferPtr, CachePtr + Offset, Amount);\r
257\r
258 if (Size == Amount) {\r
259 return EFI_SUCCESS;\r
260 }\r
261\r
262 Size -= Amount;\r
263 BufferPtr += Amount;\r
264 StartingAddress += Amount;\r
265 Lba += 1;\r
266\r
267 //\r
268 // Read aligned parts\r
269 //\r
270 OverRunLba = Lba + DivU64x32Remainder (Size, BlockSize, &Offset);\r
271\r
272 Size -= Offset;\r
273 Status = FatReadBlock (PrivateData, BlockDeviceNo, Lba, Size, BufferPtr);\r
274 if (EFI_ERROR (Status)) {\r
275 return EFI_DEVICE_ERROR;\r
276 }\r
277\r
278 BufferPtr += Size;\r
279\r
280 //\r
281 // Read overrun\r
282 //\r
283 if (Offset != 0) {\r
284 Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, OverRunLba, &CachePtr);\r
285 if (EFI_ERROR (Status)) {\r
286 return EFI_DEVICE_ERROR;\r
287 }\r
288\r
289 CopyMem (BufferPtr, CachePtr, Offset);\r
290 }\r
291\r
292 return Status;\r
293}\r
294\r
295\r
296/**\r
297 This version is different from the version in Unicode collation\r
298 protocol in that this version strips off trailing blanks.\r
299 Converts an 8.3 FAT file name using an OEM character set\r
300 to a Null-terminated Unicode string.\r
301 Here does not expand DBCS FAT chars.\r
302\r
e38f26a2
LG
303 @param FatSize The size of the string Fat in bytes.\r
304 @param Fat A pointer to a Null-terminated string that contains\r
305 an 8.3 file name using an OEM character set.\r
306 @param Str A pointer to a Null-terminated Unicode string. The\r
307 string must be allocated in advance to hold FatSize\r
2f4dfa84
JJ
308 Unicode characters\r
309\r
310**/\r
311VOID\r
312EngFatToStr (\r
313 IN UINTN FatSize,\r
314 IN CHAR8 *Fat,\r
315 OUT CHAR16 *Str\r
316 )\r
317{\r
318 CHAR16 *String;\r
319\r
320 String = Str;\r
321 //\r
322 // No DBCS issues, just expand and add null terminate to end of string\r
323 //\r
324 while (*Fat != 0 && FatSize != 0) {\r
3ba5368d
SZ
325 if (*Fat == ' ') {\r
326 break;\r
327 }\r
2f4dfa84
JJ
328 *String = *Fat;\r
329 String += 1;\r
330 Fat += 1;\r
331 FatSize -= 1;\r
2f4dfa84 332 }\r
3ba5368d
SZ
333\r
334 *String = 0;\r
2f4dfa84
JJ
335}\r
336\r
337\r
338/**\r
339 Performs a case-insensitive comparison of two Null-terminated Unicode strings.\r
340\r
e38f26a2
LG
341 @param PrivateData Global memory map for accessing global variables\r
342 @param Str1 First string to perform case insensitive comparison.\r
2f4dfa84
JJ
343 @param Str2 Second string to perform case insensitive comparison.\r
344\r
345**/\r
346BOOLEAN\r
347EngStriColl (\r
348 IN PEI_FAT_PRIVATE_DATA *PrivateData,\r
349 IN CHAR16 *Str1,\r
350 IN CHAR16 *Str2\r
351 )\r
352{\r
353 CHAR16 UpperS1;\r
354 CHAR16 UpperS2;\r
355\r
356 UpperS1 = ToUpper (*Str1);\r
357 UpperS2 = ToUpper (*Str2);\r
358 while (*Str1 != 0) {\r
359 if (UpperS1 != UpperS2) {\r
360 return FALSE;\r
361 }\r
362\r
363 Str1++;\r
364 Str2++;\r
365 UpperS1 = ToUpper (*Str1);\r
366 UpperS2 = ToUpper (*Str2);\r
367 }\r
368\r
369 return (BOOLEAN) ((*Str2 != 0) ? FALSE : TRUE);\r
370}\r