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 | #define CHAR_FAT_VALID 0x01
|
---|
13 |
|
---|
14 | /**
|
---|
15 | Converts a union code character to upper case.
|
---|
16 | This functions converts a unicode character to upper case.
|
---|
17 | If the input Letter is not a lower-cased letter,
|
---|
18 | the original value is returned.
|
---|
19 |
|
---|
20 | @param Letter The input unicode character.
|
---|
21 |
|
---|
22 | @return The upper cased letter.
|
---|
23 |
|
---|
24 | **/
|
---|
25 | CHAR16
|
---|
26 | ToUpper (
|
---|
27 | IN CHAR16 Letter
|
---|
28 | )
|
---|
29 | {
|
---|
30 | if (('a' <= Letter) && (Letter <= 'z')) {
|
---|
31 | Letter = (CHAR16)(Letter - 0x20);
|
---|
32 | }
|
---|
33 |
|
---|
34 | return Letter;
|
---|
35 | }
|
---|
36 |
|
---|
37 | /**
|
---|
38 | Reads a block of data from the block device by calling
|
---|
39 | underlying Block I/O service.
|
---|
40 |
|
---|
41 | @param PrivateData Global memory map for accessing global variables
|
---|
42 | @param BlockDeviceNo The index for the block device number.
|
---|
43 | @param Lba The logic block address to read data from.
|
---|
44 | @param BufferSize The size of data in byte to read.
|
---|
45 | @param Buffer The buffer of the
|
---|
46 |
|
---|
47 | @retval EFI_DEVICE_ERROR The specified block device number exceeds the maximum
|
---|
48 | device number.
|
---|
49 | @retval EFI_DEVICE_ERROR The maximum address has exceeded the maximum address
|
---|
50 | of the block device.
|
---|
51 |
|
---|
52 | **/
|
---|
53 | EFI_STATUS
|
---|
54 | FatReadBlock (
|
---|
55 | IN PEI_FAT_PRIVATE_DATA *PrivateData,
|
---|
56 | IN UINTN BlockDeviceNo,
|
---|
57 | IN EFI_PEI_LBA Lba,
|
---|
58 | IN UINTN BufferSize,
|
---|
59 | OUT VOID *Buffer
|
---|
60 | )
|
---|
61 | {
|
---|
62 | EFI_STATUS Status;
|
---|
63 | PEI_FAT_BLOCK_DEVICE *BlockDev;
|
---|
64 |
|
---|
65 | if (BlockDeviceNo > PEI_FAT_MAX_BLOCK_DEVICE - 1) {
|
---|
66 | return EFI_DEVICE_ERROR;
|
---|
67 | }
|
---|
68 |
|
---|
69 | Status = EFI_SUCCESS;
|
---|
70 | BlockDev = &(PrivateData->BlockDevice[BlockDeviceNo]);
|
---|
71 |
|
---|
72 | if (BufferSize > MultU64x32 (BlockDev->LastBlock - Lba + 1, BlockDev->BlockSize)) {
|
---|
73 | return EFI_DEVICE_ERROR;
|
---|
74 | }
|
---|
75 |
|
---|
76 | if (!BlockDev->Logical) {
|
---|
77 | //
|
---|
78 | // Status = BlockDev->ReadFunc
|
---|
79 | // (PrivateData->PeiServices, BlockDev->PhysicalDevNo, Lba, BufferSize, Buffer);
|
---|
80 | //
|
---|
81 | if (BlockDev->BlockIo2 != NULL) {
|
---|
82 | Status = BlockDev->BlockIo2->ReadBlocks (
|
---|
83 | (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),
|
---|
84 | BlockDev->BlockIo2,
|
---|
85 | BlockDev->PhysicalDevNo,
|
---|
86 | Lba,
|
---|
87 | BufferSize,
|
---|
88 | Buffer
|
---|
89 | );
|
---|
90 | } else {
|
---|
91 | Status = BlockDev->BlockIo->ReadBlocks (
|
---|
92 | (EFI_PEI_SERVICES **)GetPeiServicesTablePointer (),
|
---|
93 | BlockDev->BlockIo,
|
---|
94 | BlockDev->PhysicalDevNo,
|
---|
95 | Lba,
|
---|
96 | BufferSize,
|
---|
97 | Buffer
|
---|
98 | );
|
---|
99 | }
|
---|
100 | } else {
|
---|
101 | Status = FatReadDisk (
|
---|
102 | PrivateData,
|
---|
103 | BlockDev->ParentDevNo,
|
---|
104 | BlockDev->StartingPos + MultU64x32 (Lba, BlockDev->BlockSize),
|
---|
105 | BufferSize,
|
---|
106 | Buffer
|
---|
107 | );
|
---|
108 | }
|
---|
109 |
|
---|
110 | return Status;
|
---|
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 | //
|
---|
159 | // We have to find an invalid cache buffer
|
---|
160 | //
|
---|
161 | for (Index = 0; Index < PEI_FAT_CACHE_SIZE; Index++) {
|
---|
162 | if (!PrivateData->CacheBuffer[Index].Valid) {
|
---|
163 | break;
|
---|
164 | }
|
---|
165 | }
|
---|
166 |
|
---|
167 | //
|
---|
168 | // Use the cache buffer
|
---|
169 | //
|
---|
170 | if (Index == PEI_FAT_CACHE_SIZE) {
|
---|
171 | Index = (Seed++) % PEI_FAT_CACHE_SIZE;
|
---|
172 | }
|
---|
173 |
|
---|
174 | //
|
---|
175 | // Current device ID should be less than maximum device ID.
|
---|
176 | //
|
---|
177 | if (BlockDeviceNo >= PEI_FAT_MAX_BLOCK_DEVICE) {
|
---|
178 | return EFI_DEVICE_ERROR;
|
---|
179 | }
|
---|
180 |
|
---|
181 | CacheBuffer = &(PrivateData->CacheBuffer[Index]);
|
---|
182 |
|
---|
183 | CacheBuffer->BlockDeviceNo = BlockDeviceNo;
|
---|
184 | CacheBuffer->Lba = Lba;
|
---|
185 | CacheBuffer->Size = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;
|
---|
186 |
|
---|
187 | //
|
---|
188 | // Read in the data
|
---|
189 | //
|
---|
190 | Status = FatReadBlock (
|
---|
191 | PrivateData,
|
---|
192 | BlockDeviceNo,
|
---|
193 | Lba,
|
---|
194 | CacheBuffer->Size,
|
---|
195 | CacheBuffer->Buffer
|
---|
196 | );
|
---|
197 | if (EFI_ERROR (Status)) {
|
---|
198 | return EFI_DEVICE_ERROR;
|
---|
199 | }
|
---|
200 |
|
---|
201 | CacheBuffer->Valid = TRUE;
|
---|
202 | *CachePtr = (CHAR8 *)CacheBuffer->Buffer;
|
---|
203 |
|
---|
204 | return Status;
|
---|
205 | }
|
---|
206 |
|
---|
207 | /**
|
---|
208 | Disk reading.
|
---|
209 |
|
---|
210 | @param PrivateData the global memory map;
|
---|
211 | @param BlockDeviceNo the block device to read;
|
---|
212 | @param StartingAddress the starting address.
|
---|
213 | @param Size the amount of data to read.
|
---|
214 | @param Buffer the buffer holding the data
|
---|
215 |
|
---|
216 | @retval EFI_SUCCESS The function completed successfully.
|
---|
217 | @retval EFI_DEVICE_ERROR Something error.
|
---|
218 |
|
---|
219 | **/
|
---|
220 | EFI_STATUS
|
---|
221 | FatReadDisk (
|
---|
222 | IN PEI_FAT_PRIVATE_DATA *PrivateData,
|
---|
223 | IN UINTN BlockDeviceNo,
|
---|
224 | IN UINT64 StartingAddress,
|
---|
225 | IN UINTN Size,
|
---|
226 | OUT VOID *Buffer
|
---|
227 | )
|
---|
228 | {
|
---|
229 | EFI_STATUS Status;
|
---|
230 | UINT32 BlockSize;
|
---|
231 | CHAR8 *BufferPtr;
|
---|
232 | CHAR8 *CachePtr;
|
---|
233 | UINT32 Offset;
|
---|
234 | UINT64 Lba;
|
---|
235 | UINT64 OverRunLba;
|
---|
236 | UINTN Amount;
|
---|
237 |
|
---|
238 | Status = EFI_SUCCESS;
|
---|
239 | BufferPtr = Buffer;
|
---|
240 | BlockSize = PrivateData->BlockDevice[BlockDeviceNo].BlockSize;
|
---|
241 |
|
---|
242 | //
|
---|
243 | // Read underrun
|
---|
244 | //
|
---|
245 | Lba = DivU64x32Remainder (StartingAddress, BlockSize, &Offset);
|
---|
246 | Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, Lba, &CachePtr);
|
---|
247 | if (EFI_ERROR (Status)) {
|
---|
248 | return EFI_DEVICE_ERROR;
|
---|
249 | }
|
---|
250 |
|
---|
251 | Amount = Size < (BlockSize - Offset) ? Size : (BlockSize - Offset);
|
---|
252 | CopyMem (BufferPtr, CachePtr + Offset, Amount);
|
---|
253 |
|
---|
254 | if (Size == Amount) {
|
---|
255 | return EFI_SUCCESS;
|
---|
256 | }
|
---|
257 |
|
---|
258 | Size -= Amount;
|
---|
259 | BufferPtr += Amount;
|
---|
260 | StartingAddress += Amount;
|
---|
261 | Lba += 1;
|
---|
262 |
|
---|
263 | //
|
---|
264 | // Read aligned parts
|
---|
265 | //
|
---|
266 | OverRunLba = Lba + DivU64x32Remainder (Size, BlockSize, &Offset);
|
---|
267 |
|
---|
268 | Size -= Offset;
|
---|
269 | Status = FatReadBlock (PrivateData, BlockDeviceNo, Lba, Size, BufferPtr);
|
---|
270 | if (EFI_ERROR (Status)) {
|
---|
271 | return EFI_DEVICE_ERROR;
|
---|
272 | }
|
---|
273 |
|
---|
274 | BufferPtr += Size;
|
---|
275 |
|
---|
276 | //
|
---|
277 | // Read overrun
|
---|
278 | //
|
---|
279 | if (Offset != 0) {
|
---|
280 | Status = FatGetCacheBlock (PrivateData, BlockDeviceNo, OverRunLba, &CachePtr);
|
---|
281 | if (EFI_ERROR (Status)) {
|
---|
282 | return EFI_DEVICE_ERROR;
|
---|
283 | }
|
---|
284 |
|
---|
285 | CopyMem (BufferPtr, CachePtr, Offset);
|
---|
286 | }
|
---|
287 |
|
---|
288 | return Status;
|
---|
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 | if (*Fat == ' ') {
|
---|
321 | break;
|
---|
322 | }
|
---|
323 |
|
---|
324 | *String = *Fat;
|
---|
325 | String += 1;
|
---|
326 | Fat += 1;
|
---|
327 | FatSize -= 1;
|
---|
328 | }
|
---|
329 |
|
---|
330 | *String = 0;
|
---|
331 | }
|
---|
332 |
|
---|
333 | /**
|
---|
334 | Performs a case-insensitive comparison of two Null-terminated Unicode strings.
|
---|
335 |
|
---|
336 | @param PrivateData Global memory map for accessing global variables
|
---|
337 | @param Str1 First string to perform case insensitive comparison.
|
---|
338 | @param Str2 Second string to perform case insensitive comparison.
|
---|
339 |
|
---|
340 | **/
|
---|
341 | BOOLEAN
|
---|
342 | EngStriColl (
|
---|
343 | IN PEI_FAT_PRIVATE_DATA *PrivateData,
|
---|
344 | IN CHAR16 *Str1,
|
---|
345 | IN CHAR16 *Str2
|
---|
346 | )
|
---|
347 | {
|
---|
348 | CHAR16 UpperS1;
|
---|
349 | CHAR16 UpperS2;
|
---|
350 |
|
---|
351 | UpperS1 = ToUpper (*Str1);
|
---|
352 | UpperS2 = ToUpper (*Str2);
|
---|
353 | while (*Str1 != 0) {
|
---|
354 | if (UpperS1 != UpperS2) {
|
---|
355 | return FALSE;
|
---|
356 | }
|
---|
357 |
|
---|
358 | Str1++;
|
---|
359 | Str2++;
|
---|
360 | UpperS1 = ToUpper (*Str1);
|
---|
361 | UpperS2 = ToUpper (*Str2);
|
---|
362 | }
|
---|
363 |
|
---|
364 | return (BOOLEAN)((*Str2 != 0) ? FALSE : TRUE);
|
---|
365 | }
|
---|