]> git.proxmox.com Git - mirror_edk2.git/blame - FatPkg/EnhancedFatDxe/DiskCache.c
FatPkg/EnhancedFatDxe: Make the variable name follow rule
[mirror_edk2.git] / FatPkg / EnhancedFatDxe / DiskCache.c
CommitLineData
b9ec9330
QH
1/*++\r
2\r
149d6335 3Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>\r
6163cc98 4This program and the accompanying materials are licensed and made available\r
b9ec9330
QH
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
c1680e88 73 DiskCache = &Volume->DiskCache[CacheData];\r
b9ec9330
QH
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
c1680e88 88 if (IoMode == ReadDisk) {\r
b9ec9330
QH
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
149d6335
RN
112 IN CACHE_TAG *CacheTag,\r
113 IN FAT_TASK *Task\r
b9ec9330
QH
114 )\r
115/*++\r
116\r
117Routine Description:\r
118\r
119 Exchange the cache page with the image on the disk\r
120\r
121Arguments:\r
122\r
123 Volume - FAT file system volume.\r
124 DataType - Indicate the cache type.\r
125 IoMode - Indicate whether to load this page from disk or store this page to disk.\r
126 CacheTag - The Cache Tag for the current cache page.\r
127\r
128Returns:\r
129\r
130 EFI_SUCCESS - Cache page exchanged successfully.\r
131 Others - An error occurred when exchanging cache page.\r
132\r
133--*/\r
134{\r
135 EFI_STATUS Status;\r
136 UINTN GroupNo;\r
137 UINTN PageNo;\r
138 UINTN WriteCount;\r
139 UINTN RealSize;\r
140 UINT64 EntryPos;\r
141 UINT64 MaxSize;\r
142 DISK_CACHE *DiskCache;\r
143 VOID *PageAddress;\r
144 UINT8 PageAlignment;\r
145\r
146 DiskCache = &Volume->DiskCache[DataType];\r
147 PageNo = CacheTag->PageNo;\r
148 GroupNo = PageNo & DiskCache->GroupMask;\r
149 PageAlignment = DiskCache->PageAlignment;\r
150 PageAddress = DiskCache->CacheBase + (GroupNo << PageAlignment);\r
151 EntryPos = DiskCache->BaseAddress + LShiftU64 (PageNo, PageAlignment);\r
152 RealSize = CacheTag->RealSize;\r
c1680e88 153 if (IoMode == ReadDisk) {\r
b9ec9330
QH
154 RealSize = (UINTN)1 << PageAlignment;\r
155 MaxSize = DiskCache->LimitAddress - EntryPos;\r
156 if (MaxSize < RealSize) {\r
157 DEBUG ((EFI_D_INFO, "FatDiskIo: Cache Page OutBound occurred! \n"));\r
158 RealSize = (UINTN) MaxSize;\r
159 }\r
160 }\r
161\r
162 WriteCount = 1;\r
c1680e88 163 if (DataType == CacheFat && IoMode == WriteDisk) {\r
b9ec9330
QH
164 WriteCount = Volume->NumFats;\r
165 }\r
166\r
167 do {\r
168 //\r
169 // Only fat table writing will execute more than once\r
170 //\r
149d6335 171 Status = FatDiskIo (Volume, IoMode, EntryPos, RealSize, PageAddress, Task);\r
b9ec9330
QH
172 if (EFI_ERROR (Status)) {\r
173 return Status;\r
174 }\r
175\r
176 EntryPos += Volume->FatSize;\r
177 } while (--WriteCount > 0);\r
178\r
179 CacheTag->Dirty = FALSE;\r
180 CacheTag->RealSize = RealSize;\r
181 return EFI_SUCCESS;\r
182}\r
183\r
184STATIC\r
185EFI_STATUS\r
186FatGetCachePage (\r
187 IN FAT_VOLUME *Volume,\r
188 IN CACHE_DATA_TYPE CacheDataType,\r
189 IN UINTN PageNo,\r
190 IN CACHE_TAG *CacheTag\r
191 )\r
192/*++\r
193\r
194Routine Description:\r
195\r
196 Get one cache page by specified PageNo.\r
197\r
198Arguments:\r
199\r
200 Volume - FAT file system volume.\r
201 CacheDataType - The cache type: CACHE_FAT or CACHE_DATA.\r
202 PageNo - PageNo to match with the cache.\r
203 CacheTag - The Cache Tag for the current cache page.\r
204\r
205Returns:\r
206\r
207 EFI_SUCCESS - Get the cache page successfully.\r
208 other - An error occurred when accessing data.\r
209\r
210--*/\r
211{\r
212 EFI_STATUS Status;\r
213 UINTN OldPageNo;\r
214\r
215 OldPageNo = CacheTag->PageNo;\r
216 if (CacheTag->RealSize > 0 && OldPageNo == PageNo) {\r
217 //\r
218 // Cache Hit occurred\r
219 //\r
220 return EFI_SUCCESS;\r
221 }\r
222\r
223 //\r
224 // Write dirty cache page back to disk\r
225 //\r
226 if (CacheTag->RealSize > 0 && CacheTag->Dirty) {\r
c1680e88 227 Status = FatExchangeCachePage (Volume, CacheDataType, WriteDisk, CacheTag, NULL);\r
b9ec9330
QH
228 if (EFI_ERROR (Status)) {\r
229 return Status;\r
230 }\r
231 }\r
232 //\r
233 // Load new data from disk;\r
234 //\r
235 CacheTag->PageNo = PageNo;\r
c1680e88 236 Status = FatExchangeCachePage (Volume, CacheDataType, ReadDisk, CacheTag, NULL);\r
b9ec9330
QH
237\r
238 return Status;\r
239}\r
240\r
241STATIC\r
242EFI_STATUS\r
243FatAccessUnalignedCachePage (\r
244 IN FAT_VOLUME *Volume,\r
245 IN CACHE_DATA_TYPE CacheDataType,\r
246 IN IO_MODE IoMode,\r
247 IN UINTN PageNo,\r
248 IN UINTN Offset,\r
249 IN UINTN Length,\r
250 IN OUT VOID *Buffer\r
251 )\r
252/*++\r
253Routine Description:\r
254\r
255 Read Length bytes from the position of Offset into Buffer, or\r
256 write Length bytes from Buffer into the position of Offset.\r
257\r
258Arguments:\r
259\r
260 Volume - FAT file system volume.\r
261 CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.\r
262 IoMode - Indicate the type of disk access.\r
263 PageNo - The number of unaligned cache page.\r
264 Offset - The starting byte of cache page.\r
265 Length - The number of bytes that is read or written\r
266 Buffer - Buffer containing cache data.\r
267\r
268Returns:\r
269\r
270 EFI_SUCCESS - The data was accessed correctly.\r
271 Others - An error occurred when accessing unaligned cache page.\r
272\r
273--*/\r
274{\r
275 EFI_STATUS Status;\r
276 VOID *Source;\r
277 VOID *Destination;\r
278 DISK_CACHE *DiskCache;\r
279 CACHE_TAG *CacheTag;\r
280 UINTN GroupNo;\r
281\r
282 DiskCache = &Volume->DiskCache[CacheDataType];\r
283 GroupNo = PageNo & DiskCache->GroupMask;\r
284 CacheTag = &DiskCache->CacheTag[GroupNo];\r
285 Status = FatGetCachePage (Volume, CacheDataType, PageNo, CacheTag);\r
286 if (!EFI_ERROR (Status)) {\r
287 Source = DiskCache->CacheBase + (GroupNo << DiskCache->PageAlignment) + Offset;\r
288 Destination = Buffer;\r
c1680e88 289 if (IoMode != ReadDisk) {\r
b9ec9330
QH
290 CacheTag->Dirty = TRUE;\r
291 DiskCache->Dirty = TRUE;\r
292 Destination = Source;\r
293 Source = Buffer;\r
294 }\r
295\r
296 CopyMem (Destination, Source, Length);\r
297 }\r
298\r
299 return Status;\r
300}\r
301\r
302EFI_STATUS\r
303FatAccessCache (\r
304 IN FAT_VOLUME *Volume,\r
305 IN CACHE_DATA_TYPE CacheDataType,\r
306 IN IO_MODE IoMode,\r
307 IN UINT64 Offset,\r
308 IN UINTN BufferSize,\r
149d6335
RN
309 IN OUT UINT8 *Buffer,\r
310 IN FAT_TASK *Task\r
b9ec9330
QH
311 )\r
312/*++\r
313Routine Description:\r
314\r
315 Read BufferSize bytes from the position of Offset into Buffer,\r
316 or write BufferSize bytes from Buffer into the position of Offset.\r
317\r
318 Base on the parameter of CACHE_DATA_TYPE, the data access will be divided into\r
319 the access of FAT cache (CACHE_FAT) and the access of Data cache (CACHE_DATA):\r
320\r
321 1. Access of FAT cache (CACHE_FAT): Access the data in the FAT cache, if there is cache\r
322 page hit, just return the cache page; else update the related cache page and return\r
323 the right cache page.\r
324 2. Access of Data cache (CACHE_DATA):\r
325 The access data will be divided into UnderRun data, Aligned data and OverRun data;\r
326 The UnderRun data and OverRun data will be accessed by the Data cache,\r
327 but the Aligned data will be accessed with disk directly.\r
328\r
329Arguments:\r
330\r
331 Volume - FAT file system volume.\r
332 CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.\r
333 IoMode - Indicate the type of disk access.\r
334 Offset - The starting byte offset to read from.\r
335 BufferSize - Size of Buffer.\r
336 Buffer - Buffer containing cache data.\r
337\r
338Returns:\r
339\r
340 EFI_SUCCESS - The data was accessed correctly.\r
341 EFI_MEDIA_CHANGED - The MediaId does not match the current device.\r
342 Others - An error occurred when accessing cache.\r
343\r
344--*/\r
345{\r
346 EFI_STATUS Status;\r
347 UINTN PageSize;\r
348 UINTN UnderRun;\r
349 UINTN OverRun;\r
350 UINTN AlignedSize;\r
351 UINTN Length;\r
352 UINTN PageNo;\r
353 UINTN AlignedPageCount;\r
354 UINTN OverRunPageNo;\r
355 DISK_CACHE *DiskCache;\r
356 UINT64 EntryPos;\r
357 UINT8 PageAlignment;\r
358\r
359 ASSERT (Volume->CacheBuffer != NULL);\r
360\r
361 Status = EFI_SUCCESS;\r
362 DiskCache = &Volume->DiskCache[CacheDataType];\r
363 EntryPos = Offset - DiskCache->BaseAddress;\r
364 PageAlignment = DiskCache->PageAlignment;\r
365 PageSize = (UINTN)1 << PageAlignment;\r
366 PageNo = (UINTN) RShiftU64 (EntryPos, PageAlignment);\r
367 UnderRun = ((UINTN) EntryPos) & (PageSize - 1);\r
368\r
369 if (UnderRun > 0) {\r
370 Length = PageSize - UnderRun;\r
371 if (Length > BufferSize) {\r
372 Length = BufferSize;\r
373 }\r
374\r
375 Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, PageNo, UnderRun, Length, Buffer);\r
376 if (EFI_ERROR (Status)) {\r
377 return Status;\r
378 }\r
379\r
380 Buffer += Length;\r
381 BufferSize -= Length;\r
382 PageNo++;\r
383 }\r
384\r
385 AlignedPageCount = BufferSize >> PageAlignment;\r
386 OverRunPageNo = PageNo + AlignedPageCount;\r
387 //\r
388 // The access of the Aligned data\r
389 //\r
390 if (AlignedPageCount > 0) {\r
391 //\r
392 // Accessing fat table cannot have alignment data\r
393 //\r
c1680e88 394 ASSERT (CacheDataType == CacheData);\r
b9ec9330
QH
395\r
396 EntryPos = Volume->RootPos + LShiftU64 (PageNo, PageAlignment);\r
397 AlignedSize = AlignedPageCount << PageAlignment;\r
149d6335 398 Status = FatDiskIo (Volume, IoMode, EntryPos, AlignedSize, Buffer, Task);\r
b9ec9330
QH
399 if (EFI_ERROR (Status)) {\r
400 return Status;\r
401 }\r
402 //\r
403 // If these access data over laps the relative cache range, these cache pages need\r
404 // to be updated.\r
405 //\r
406 FatFlushDataCacheRange (Volume, IoMode, PageNo, OverRunPageNo, Buffer);\r
407 Buffer += AlignedSize;\r
408 BufferSize -= AlignedSize;\r
409 }\r
410 //\r
411 // The access of the OverRun data\r
412 //\r
413 OverRun = BufferSize;\r
414 if (OverRun > 0) {\r
415 //\r
416 // Last read is not a complete page\r
417 //\r
418 Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, OverRunPageNo, 0, OverRun, Buffer);\r
419 }\r
420\r
421 return Status;\r
422}\r
423\r
424EFI_STATUS\r
425FatVolumeFlushCache (\r
149d6335
RN
426 IN FAT_VOLUME *Volume,\r
427 IN FAT_TASK *Task\r
b9ec9330
QH
428 )\r
429/*++\r
430\r
431Routine Description:\r
432\r
433 Flush all the dirty cache back, include the FAT cache and the Data cache.\r
434\r
435Arguments:\r
436\r
437 Volume - FAT file system volume.\r
438\r
439Returns:\r
440\r
441 EFI_SUCCESS - Flush all the dirty cache back successfully\r
442 other - An error occurred when writing the data into the disk\r
443\r
444--*/\r
445{\r
446 EFI_STATUS Status;\r
447 CACHE_DATA_TYPE CacheDataType;\r
448 UINTN GroupIndex;\r
449 UINTN GroupMask;\r
450 DISK_CACHE *DiskCache;\r
451 CACHE_TAG *CacheTag;\r
452\r
c1680e88 453 for (CacheDataType = (CACHE_DATA_TYPE) 0; CacheDataType < CacheMaxType; CacheDataType++) {\r
b9ec9330
QH
454 DiskCache = &Volume->DiskCache[CacheDataType];\r
455 if (DiskCache->Dirty) {\r
456 //\r
457 // Data cache or fat cache is dirty, write the dirty data back\r
458 //\r
459 GroupMask = DiskCache->GroupMask;\r
460 for (GroupIndex = 0; GroupIndex <= GroupMask; GroupIndex++) {\r
461 CacheTag = &DiskCache->CacheTag[GroupIndex];\r
462 if (CacheTag->RealSize > 0 && CacheTag->Dirty) {\r
463 //\r
464 // Write back all Dirty Data Cache Page to disk\r
465 //\r
c1680e88 466 Status = FatExchangeCachePage (Volume, CacheDataType, WriteDisk, CacheTag, Task);\r
b9ec9330
QH
467 if (EFI_ERROR (Status)) {\r
468 return Status;\r
469 }\r
470 }\r
471 }\r
472\r
473 DiskCache->Dirty = FALSE;\r
474 }\r
475 }\r
476 //\r
477 // Flush the block device.\r
478 //\r
479 Status = Volume->BlockIo->FlushBlocks (Volume->BlockIo);\r
480 return Status;\r
481}\r
482\r
483EFI_STATUS\r
484FatInitializeDiskCache (\r
485 IN FAT_VOLUME *Volume\r
486 )\r
487/*++\r
488\r
489Routine Description:\r
490\r
491 Initialize the disk cache according to Volume's FatType.\r
492\r
493Arguments:\r
494\r
495 Volume - FAT file system volume.\r
496\r
497Returns:\r
498\r
499 EFI_SUCCESS - The disk cache is successfully initialized.\r
500 EFI_OUT_OF_RESOURCES - Not enough memory to allocate disk cache.\r
501\r
502--*/\r
503{\r
504 DISK_CACHE *DiskCache;\r
505 UINTN FatCacheGroupCount;\r
506 UINTN DataCacheSize;\r
507 UINTN FatCacheSize;\r
508 UINT8 *CacheBuffer;\r
509\r
510 DiskCache = Volume->DiskCache;\r
511 //\r
512 // Configure the parameters of disk cache\r
513 //\r
c1680e88 514 if (Volume->FatType == Fat12) {\r
b9ec9330 515 FatCacheGroupCount = FAT_FATCACHE_GROUP_MIN_COUNT;\r
c1680e88
DB
516 DiskCache[CacheFat].PageAlignment = FAT_FATCACHE_PAGE_MIN_ALIGNMENT;\r
517 DiskCache[CacheData].PageAlignment = FAT_DATACACHE_PAGE_MIN_ALIGNMENT;\r
b9ec9330
QH
518 } else {\r
519 FatCacheGroupCount = FAT_FATCACHE_GROUP_MAX_COUNT;\r
c1680e88
DB
520 DiskCache[CacheFat].PageAlignment = FAT_FATCACHE_PAGE_MAX_ALIGNMENT;\r
521 DiskCache[CacheData].PageAlignment = FAT_DATACACHE_PAGE_MAX_ALIGNMENT;\r
b9ec9330
QH
522 }\r
523\r
c1680e88
DB
524 DiskCache[CacheData].GroupMask = FAT_DATACACHE_GROUP_COUNT - 1;\r
525 DiskCache[CacheData].BaseAddress = Volume->RootPos;\r
526 DiskCache[CacheData].LimitAddress = Volume->VolumeSize;\r
527 DiskCache[CacheFat].GroupMask = FatCacheGroupCount - 1;\r
528 DiskCache[CacheFat].BaseAddress = Volume->FatPos;\r
529 DiskCache[CacheFat].LimitAddress = Volume->FatPos + Volume->FatSize;\r
530 FatCacheSize = FatCacheGroupCount << DiskCache[CacheFat].PageAlignment;\r
531 DataCacheSize = FAT_DATACACHE_GROUP_COUNT << DiskCache[CacheData].PageAlignment;\r
b9ec9330
QH
532 //\r
533 // Allocate the Fat Cache buffer\r
534 //\r
f4500fc1 535 CacheBuffer = AllocateZeroPool (FatCacheSize + DataCacheSize);\r
b9ec9330
QH
536 if (CacheBuffer == NULL) {\r
537 return EFI_OUT_OF_RESOURCES;\r
538 }\r
539\r
540 Volume->CacheBuffer = CacheBuffer;\r
c1680e88
DB
541 DiskCache[CacheFat].CacheBase = CacheBuffer;\r
542 DiskCache[CacheData].CacheBase = CacheBuffer + FatCacheSize;\r
b9ec9330
QH
543 return EFI_SUCCESS;\r
544}\r