]> git.proxmox.com Git - mirror_edk2.git/blob - FatPkg/FatPei/FatLiteLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 #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 }