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 | }
|
---|