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