]> git.proxmox.com Git - mirror_edk2.git/blame - FatPkg/EnhancedFatDxe/DiskCache.c
1. Correct File header to ## @file 2. Remove unnecessary .common] postfix on section.
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / DiskCache.c
CommitLineData
b9ec9330
QH
1/*++\r
2\r
3Copyright (c) 2005 - 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials are licensed and made available\r
5under the terms and conditions of the BSD License which accompanies this\r
6distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12\r
13Module Name:\r
14\r
15 DiskCache.c\r
16\r
17Abstract:\r
18\r
19 Cache implementation for EFI FAT File system driver\r
20\r
21Revision History\r
22\r
23--*/\r
24\r
25#include "Fat.h"\r
26\r
27STATIC\r
28VOID\r
29FatFlushDataCacheRange (\r
30 IN FAT_VOLUME *Volume,\r
31 IN IO_MODE IoMode,\r
32 IN UINTN StartPageNo,\r
33 IN UINTN EndPageNo,\r
34 OUT UINT8 *Buffer\r
35 )\r
36/*++\r
37\r
38Routine Description:\r
39\r
40 This function is used by the Data Cache.\r
41\r
42 When this function is called by write command, all entries in this range\r
43 are older than the contents in disk, so they are invalid; just mark them invalid.\r
44\r
45 When this function is called by read command, if any entry in this range\r
46 is dirty, it means that the relative info directly readed from media is older than\r
47 than the info in the cache; So need to update the relative info in the Buffer.\r
48\r
49Arguments:\r
50\r
51 Volume - FAT file system volume.\r
52 IoMode - This function is called by read command or write command\r
53 StartPageNo - First PageNo to be checked in the cache.\r
54 EndPageNo - Last PageNo to be checked in the cache.\r
55 Buffer - The user buffer need to update. Only when doing the read command\r
56 and there is dirty cache in the cache range, this parameter will be used.\r
57\r
58Returns:\r
59\r
60 None.\r
61\r
62--*/\r
63{\r
64 UINTN PageNo;\r
65 UINTN GroupNo;\r
66 UINTN GroupMask;\r
67 UINTN PageSize;\r
68 UINT8 PageAlignment;\r
69 DISK_CACHE *DiskCache;\r
70 CACHE_TAG *CacheTag;\r
71 UINT8 *BaseAddress;\r
72\r
73 DiskCache = &Volume->DiskCache[CACHE_DATA];\r
74 BaseAddress = DiskCache->CacheBase;\r
75 GroupMask = DiskCache->GroupMask;\r
76 PageAlignment = DiskCache->PageAlignment;\r
77 PageSize = (UINTN)1 << PageAlignment;\r
78\r
79 for (PageNo = StartPageNo; PageNo < EndPageNo; PageNo++) {\r
80 GroupNo = PageNo & GroupMask;\r
81 CacheTag = &DiskCache->CacheTag[GroupNo];\r
82 if (CacheTag->RealSize > 0 && CacheTag->PageNo == PageNo) {\r
83 //\r
84 // When reading data form disk directly, if some dirty data\r
85 // in cache is in this rang, this data in the Buffer need to\r
86 // be updated with the cache's dirty data.\r
87 //\r
88 if (IoMode == READ_DISK) {\r
89 if (CacheTag->Dirty) {\r
90 CopyMem (\r
91 Buffer + ((PageNo - StartPageNo) << PageAlignment),\r
92 BaseAddress + (GroupNo << PageAlignment),\r
93 PageSize\r
94 );\r
95 }\r
96 } else {\r
97 //\r
98 // Make all valid entries in this range invalid.\r
99 //\r
100 CacheTag->RealSize = 0;\r
101 }\r
102 }\r
103 }\r
104}\r
105\r
106STATIC\r
107EFI_STATUS\r
108FatExchangeCachePage (\r
109 IN FAT_VOLUME *Volume,\r
110 IN CACHE_DATA_TYPE DataType,\r
111 IN IO_MODE IoMode,\r
112 IN CACHE_TAG *CacheTag\r
113 )\r
114/*++\r
115\r
116Routine Description:\r
117\r
118 Exchange the cache page with the image on the disk\r
119\r
120Arguments:\r
121\r
122 Volume - FAT file system volume.\r
123 DataType - Indicate the cache type.\r
124 IoMode - Indicate whether to load this page from disk or store this page to disk.\r
125 CacheTag - The Cache Tag for the current cache page.\r
126\r
127Returns:\r
128\r
129 EFI_SUCCESS - Cache page exchanged successfully.\r
130 Others - An error occurred when exchanging cache page.\r
131\r
132--*/\r
133{\r
134 EFI_STATUS Status;\r
135 UINTN GroupNo;\r
136 UINTN PageNo;\r
137 UINTN WriteCount;\r
138 UINTN RealSize;\r
139 UINT64 EntryPos;\r
140 UINT64 MaxSize;\r
141 DISK_CACHE *DiskCache;\r
142 VOID *PageAddress;\r
143 UINT8 PageAlignment;\r
144\r
145 DiskCache = &Volume->DiskCache[DataType];\r
146 PageNo = CacheTag->PageNo;\r
147 GroupNo = PageNo & DiskCache->GroupMask;\r
148 PageAlignment = DiskCache->PageAlignment;\r
149 PageAddress = DiskCache->CacheBase + (GroupNo << PageAlignment);\r
150 EntryPos = DiskCache->BaseAddress + LShiftU64 (PageNo, PageAlignment);\r
151 RealSize = CacheTag->RealSize;\r
152 if (IoMode == READ_DISK) {\r
153 RealSize = (UINTN)1 << PageAlignment;\r
154 MaxSize = DiskCache->LimitAddress - EntryPos;\r
155 if (MaxSize < RealSize) {\r
156 DEBUG ((EFI_D_INFO, "FatDiskIo: Cache Page OutBound occurred! \n"));\r
157 RealSize = (UINTN) MaxSize;\r
158 }\r
159 }\r
160\r
161 WriteCount = 1;\r
162 if (DataType == CACHE_FAT && IoMode == WRITE_DISK) {\r
163 WriteCount = Volume->NumFats;\r
164 }\r
165\r
166 do {\r
167 //\r
168 // Only fat table writing will execute more than once\r
169 //\r
170 Status = FatDiskIo (Volume, IoMode, EntryPos, RealSize, PageAddress);\r
171 if (EFI_ERROR (Status)) {\r
172 return Status;\r
173 }\r
174\r
175 EntryPos += Volume->FatSize;\r
176 } while (--WriteCount > 0);\r
177\r
178 CacheTag->Dirty = FALSE;\r
179 CacheTag->RealSize = RealSize;\r
180 return EFI_SUCCESS;\r
181}\r
182\r
183STATIC\r
184EFI_STATUS\r
185FatGetCachePage (\r
186 IN FAT_VOLUME *Volume,\r
187 IN CACHE_DATA_TYPE CacheDataType,\r
188 IN UINTN PageNo,\r
189 IN CACHE_TAG *CacheTag\r
190 )\r
191/*++\r
192\r
193Routine Description:\r
194\r
195 Get one cache page by specified PageNo.\r
196\r
197Arguments:\r
198\r
199 Volume - FAT file system volume.\r
200 CacheDataType - The cache type: CACHE_FAT or CACHE_DATA.\r
201 PageNo - PageNo to match with the cache.\r
202 CacheTag - The Cache Tag for the current cache page.\r
203\r
204Returns:\r
205\r
206 EFI_SUCCESS - Get the cache page successfully.\r
207 other - An error occurred when accessing data.\r
208\r
209--*/\r
210{\r
211 EFI_STATUS Status;\r
212 UINTN OldPageNo;\r
213\r
214 OldPageNo = CacheTag->PageNo;\r
215 if (CacheTag->RealSize > 0 && OldPageNo == PageNo) {\r
216 //\r
217 // Cache Hit occurred\r
218 //\r
219 return EFI_SUCCESS;\r
220 }\r
221\r
222 //\r
223 // Write dirty cache page back to disk\r
224 //\r
225 if (CacheTag->RealSize > 0 && CacheTag->Dirty) {\r
226 Status = FatExchangeCachePage (Volume, CacheDataType, WRITE_DISK, CacheTag);\r
227 if (EFI_ERROR (Status)) {\r
228 return Status;\r
229 }\r
230 }\r
231 //\r
232 // Load new data from disk;\r
233 //\r
234 CacheTag->PageNo = PageNo;\r
235 Status = FatExchangeCachePage (Volume, CacheDataType, READ_DISK, CacheTag);\r
236\r
237 return Status;\r
238}\r
239\r
240STATIC\r
241EFI_STATUS\r
242FatAccessUnalignedCachePage (\r
243 IN FAT_VOLUME *Volume,\r
244 IN CACHE_DATA_TYPE CacheDataType,\r
245 IN IO_MODE IoMode,\r
246 IN UINTN PageNo,\r
247 IN UINTN Offset,\r
248 IN UINTN Length,\r
249 IN OUT VOID *Buffer\r
250 )\r
251/*++\r
252Routine Description:\r
253\r
254 Read Length bytes from the position of Offset into Buffer, or\r
255 write Length bytes from Buffer into the position of Offset.\r
256\r
257Arguments:\r
258\r
259 Volume - FAT file system volume.\r
260 CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.\r
261 IoMode - Indicate the type of disk access.\r
262 PageNo - The number of unaligned cache page.\r
263 Offset - The starting byte of cache page.\r
264 Length - The number of bytes that is read or written\r
265 Buffer - Buffer containing cache data.\r
266\r
267Returns:\r
268\r
269 EFI_SUCCESS - The data was accessed correctly.\r
270 Others - An error occurred when accessing unaligned cache page.\r
271\r
272--*/\r
273{\r
274 EFI_STATUS Status;\r
275 VOID *Source;\r
276 VOID *Destination;\r
277 DISK_CACHE *DiskCache;\r
278 CACHE_TAG *CacheTag;\r
279 UINTN GroupNo;\r
280\r
281 DiskCache = &Volume->DiskCache[CacheDataType];\r
282 GroupNo = PageNo & DiskCache->GroupMask;\r
283 CacheTag = &DiskCache->CacheTag[GroupNo];\r
284 Status = FatGetCachePage (Volume, CacheDataType, PageNo, CacheTag);\r
285 if (!EFI_ERROR (Status)) {\r
286 Source = DiskCache->CacheBase + (GroupNo << DiskCache->PageAlignment) + Offset;\r
287 Destination = Buffer;\r
288 if (IoMode != READ_DISK) {\r
289 CacheTag->Dirty = TRUE;\r
290 DiskCache->Dirty = TRUE;\r
291 Destination = Source;\r
292 Source = Buffer;\r
293 }\r
294\r
295 CopyMem (Destination, Source, Length);\r
296 }\r
297\r
298 return Status;\r
299}\r
300\r
301EFI_STATUS\r
302FatAccessCache (\r
303 IN FAT_VOLUME *Volume,\r
304 IN CACHE_DATA_TYPE CacheDataType,\r
305 IN IO_MODE IoMode,\r
306 IN UINT64 Offset,\r
307 IN UINTN BufferSize,\r
308 IN OUT UINT8 *Buffer\r
309 )\r
310/*++\r
311Routine Description:\r
312\r
313 Read BufferSize bytes from the position of Offset into Buffer,\r
314 or write BufferSize bytes from Buffer into the position of Offset.\r
315\r
316 Base on the parameter of CACHE_DATA_TYPE, the data access will be divided into\r
317 the access of FAT cache (CACHE_FAT) and the access of Data cache (CACHE_DATA):\r
318\r
319 1. Access of FAT cache (CACHE_FAT): Access the data in the FAT cache, if there is cache\r
320 page hit, just return the cache page; else update the related cache page and return\r
321 the right cache page.\r
322 2. Access of Data cache (CACHE_DATA):\r
323 The access data will be divided into UnderRun data, Aligned data and OverRun data;\r
324 The UnderRun data and OverRun data will be accessed by the Data cache,\r
325 but the Aligned data will be accessed with disk directly.\r
326\r
327Arguments:\r
328\r
329 Volume - FAT file system volume.\r
330 CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.\r
331 IoMode - Indicate the type of disk access.\r
332 Offset - The starting byte offset to read from.\r
333 BufferSize - Size of Buffer.\r
334 Buffer - Buffer containing cache data.\r
335\r
336Returns:\r
337\r
338 EFI_SUCCESS - The data was accessed correctly.\r
339 EFI_MEDIA_CHANGED - The MediaId does not match the current device.\r
340 Others - An error occurred when accessing cache.\r
341\r
342--*/\r
343{\r
344 EFI_STATUS Status;\r
345 UINTN PageSize;\r
346 UINTN UnderRun;\r
347 UINTN OverRun;\r
348 UINTN AlignedSize;\r
349 UINTN Length;\r
350 UINTN PageNo;\r
351 UINTN AlignedPageCount;\r
352 UINTN OverRunPageNo;\r
353 DISK_CACHE *DiskCache;\r
354 UINT64 EntryPos;\r
355 UINT8 PageAlignment;\r
356\r
357 ASSERT (Volume->CacheBuffer != NULL);\r
358\r
359 Status = EFI_SUCCESS;\r
360 DiskCache = &Volume->DiskCache[CacheDataType];\r
361 EntryPos = Offset - DiskCache->BaseAddress;\r
362 PageAlignment = DiskCache->PageAlignment;\r
363 PageSize = (UINTN)1 << PageAlignment;\r
364 PageNo = (UINTN) RShiftU64 (EntryPos, PageAlignment);\r
365 UnderRun = ((UINTN) EntryPos) & (PageSize - 1);\r
366\r
367 if (UnderRun > 0) {\r
368 Length = PageSize - UnderRun;\r
369 if (Length > BufferSize) {\r
370 Length = BufferSize;\r
371 }\r
372\r
373 Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, PageNo, UnderRun, Length, Buffer);\r
374 if (EFI_ERROR (Status)) {\r
375 return Status;\r
376 }\r
377\r
378 Buffer += Length;\r
379 BufferSize -= Length;\r
380 PageNo++;\r
381 }\r
382\r
383 AlignedPageCount = BufferSize >> PageAlignment;\r
384 OverRunPageNo = PageNo + AlignedPageCount;\r
385 //\r
386 // The access of the Aligned data\r
387 //\r
388 if (AlignedPageCount > 0) {\r
389 //\r
390 // Accessing fat table cannot have alignment data\r
391 //\r
392 ASSERT (CacheDataType == CACHE_DATA);\r
393\r
394 EntryPos = Volume->RootPos + LShiftU64 (PageNo, PageAlignment);\r
395 AlignedSize = AlignedPageCount << PageAlignment;\r
396 Status = FatDiskIo (Volume, IoMode, EntryPos, AlignedSize, Buffer);\r
397 if (EFI_ERROR (Status)) {\r
398 return Status;\r
399 }\r
400 //\r
401 // If these access data over laps the relative cache range, these cache pages need\r
402 // to be updated.\r
403 //\r
404 FatFlushDataCacheRange (Volume, IoMode, PageNo, OverRunPageNo, Buffer);\r
405 Buffer += AlignedSize;\r
406 BufferSize -= AlignedSize;\r
407 }\r
408 //\r
409 // The access of the OverRun data\r
410 //\r
411 OverRun = BufferSize;\r
412 if (OverRun > 0) {\r
413 //\r
414 // Last read is not a complete page\r
415 //\r
416 Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, OverRunPageNo, 0, OverRun, Buffer);\r
417 }\r
418\r
419 return Status;\r
420}\r
421\r
422EFI_STATUS\r
423FatVolumeFlushCache (\r
424 IN FAT_VOLUME *Volume\r
425 )\r
426/*++\r
427\r
428Routine Description:\r
429\r
430 Flush all the dirty cache back, include the FAT cache and the Data cache.\r
431\r
432Arguments:\r
433\r
434 Volume - FAT file system volume.\r
435\r
436Returns:\r
437\r
438 EFI_SUCCESS - Flush all the dirty cache back successfully\r
439 other - An error occurred when writing the data into the disk\r
440\r
441--*/\r
442{\r
443 EFI_STATUS Status;\r
444 CACHE_DATA_TYPE CacheDataType;\r
445 UINTN GroupIndex;\r
446 UINTN GroupMask;\r
447 DISK_CACHE *DiskCache;\r
448 CACHE_TAG *CacheTag;\r
449\r
450 for (CacheDataType = (CACHE_DATA_TYPE) 0; CacheDataType < CACHE_MAX_TYPE; CacheDataType++) {\r
451 DiskCache = &Volume->DiskCache[CacheDataType];\r
452 if (DiskCache->Dirty) {\r
453 //\r
454 // Data cache or fat cache is dirty, write the dirty data back\r
455 //\r
456 GroupMask = DiskCache->GroupMask;\r
457 for (GroupIndex = 0; GroupIndex <= GroupMask; GroupIndex++) {\r
458 CacheTag = &DiskCache->CacheTag[GroupIndex];\r
459 if (CacheTag->RealSize > 0 && CacheTag->Dirty) {\r
460 //\r
461 // Write back all Dirty Data Cache Page to disk\r
462 //\r
463 Status = FatExchangeCachePage (Volume, CacheDataType, WRITE_DISK, CacheTag);\r
464 if (EFI_ERROR (Status)) {\r
465 return Status;\r
466 }\r
467 }\r
468 }\r
469\r
470 DiskCache->Dirty = FALSE;\r
471 }\r
472 }\r
473 //\r
474 // Flush the block device.\r
475 //\r
476 Status = Volume->BlockIo->FlushBlocks (Volume->BlockIo);\r
477 return Status;\r
478}\r
479\r
480EFI_STATUS\r
481FatInitializeDiskCache (\r
482 IN FAT_VOLUME *Volume\r
483 )\r
484/*++\r
485\r
486Routine Description:\r
487\r
488 Initialize the disk cache according to Volume's FatType.\r
489\r
490Arguments:\r
491\r
492 Volume - FAT file system volume.\r
493\r
494Returns:\r
495\r
496 EFI_SUCCESS - The disk cache is successfully initialized.\r
497 EFI_OUT_OF_RESOURCES - Not enough memory to allocate disk cache.\r
498\r
499--*/\r
500{\r
501 DISK_CACHE *DiskCache;\r
502 UINTN FatCacheGroupCount;\r
503 UINTN DataCacheSize;\r
504 UINTN FatCacheSize;\r
505 UINT8 *CacheBuffer;\r
506\r
507 DiskCache = Volume->DiskCache;\r
508 //\r
509 // Configure the parameters of disk cache\r
510 //\r
511 if (Volume->FatType == FAT12) {\r
512 FatCacheGroupCount = FAT_FATCACHE_GROUP_MIN_COUNT;\r
513 DiskCache[CACHE_FAT].PageAlignment = FAT_FATCACHE_PAGE_MIN_ALIGNMENT;\r
514 DiskCache[CACHE_DATA].PageAlignment = FAT_DATACACHE_PAGE_MIN_ALIGNMENT;\r
515 } else {\r
516 FatCacheGroupCount = FAT_FATCACHE_GROUP_MAX_COUNT;\r
517 DiskCache[CACHE_FAT].PageAlignment = FAT_FATCACHE_PAGE_MAX_ALIGNMENT;\r
518 DiskCache[CACHE_DATA].PageAlignment = FAT_DATACACHE_PAGE_MAX_ALIGNMENT;\r
519 }\r
520\r
521 DiskCache[CACHE_DATA].GroupMask = FAT_DATACACHE_GROUP_COUNT - 1;\r
522 DiskCache[CACHE_DATA].BaseAddress = Volume->RootPos;\r
523 DiskCache[CACHE_DATA].LimitAddress = Volume->VolumeSize;\r
524 DiskCache[CACHE_FAT].GroupMask = FatCacheGroupCount - 1;\r
525 DiskCache[CACHE_FAT].BaseAddress = Volume->FatPos;\r
526 DiskCache[CACHE_FAT].LimitAddress = Volume->FatPos + Volume->FatSize;\r
527 FatCacheSize = FatCacheGroupCount << DiskCache[CACHE_FAT].PageAlignment;\r
528 DataCacheSize = FAT_DATACACHE_GROUP_COUNT << DiskCache[CACHE_DATA].PageAlignment;\r
529 //\r
530 // Allocate the Fat Cache buffer\r
531 //\r
532 CacheBuffer = AllocatePool (FatCacheSize + DataCacheSize);\r
533 if (CacheBuffer == NULL) {\r
534 return EFI_OUT_OF_RESOURCES;\r
535 }\r
536\r
537 Volume->CacheBuffer = CacheBuffer;\r
538 DiskCache[CACHE_FAT].CacheBase = CacheBuffer;\r
539 DiskCache[CACHE_DATA].CacheBase = CacheBuffer + FatCacheSize;\r
540 return EFI_SUCCESS;\r
541}\r