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