2 Cache implementation for EFI FAT File system driver.
4 Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials are licensed and made available
6 under the terms and conditions of the BSD License which accompanies this
7 distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 This function is used by the Data Cache.
21 When this function is called by write command, all entries in this range
22 are older than the contents in disk, so they are invalid; just mark them invalid.
24 When this function is called by read command, if any entry in this range
25 is dirty, it means that the relative info directly readed from media is older than
26 than the info in the cache; So need to update the relative info in the Buffer.
28 @param Volume - FAT file system volume.
29 @param IoMode - This function is called by read command or write command
30 @param StartPageNo - First PageNo to be checked in the cache.
31 @param EndPageNo - Last PageNo to be checked in the cache.
32 @param Buffer - The user buffer need to update. Only when doing the read command
33 and there is dirty cache in the cache range, this parameter will be used.
38 FatFlushDataCacheRange (
39 IN FAT_VOLUME
*Volume
,
51 DISK_CACHE
*DiskCache
;
55 DiskCache
= &Volume
->DiskCache
[CacheData
];
56 BaseAddress
= DiskCache
->CacheBase
;
57 GroupMask
= DiskCache
->GroupMask
;
58 PageAlignment
= DiskCache
->PageAlignment
;
59 PageSize
= (UINTN
)1 << PageAlignment
;
61 for (PageNo
= StartPageNo
; PageNo
< EndPageNo
; PageNo
++) {
62 GroupNo
= PageNo
& GroupMask
;
63 CacheTag
= &DiskCache
->CacheTag
[GroupNo
];
64 if (CacheTag
->RealSize
> 0 && CacheTag
->PageNo
== PageNo
) {
66 // When reading data form disk directly, if some dirty data
67 // in cache is in this rang, this data in the Buffer need to
68 // be updated with the cache's dirty data.
70 if (IoMode
== ReadDisk
) {
71 if (CacheTag
->Dirty
) {
73 Buffer
+ ((PageNo
- StartPageNo
) << PageAlignment
),
74 BaseAddress
+ (GroupNo
<< PageAlignment
),
80 // Make all valid entries in this range invalid.
82 CacheTag
->RealSize
= 0;
90 Exchange the cache page with the image on the disk
92 @param Volume - FAT file system volume.
93 @param DataType - Indicate the cache type.
94 @param IoMode - Indicate whether to load this page from disk or store this page to disk.
95 @param CacheTag - The Cache Tag for the current cache page.
96 @param Task point to task instance.
98 @retval EFI_SUCCESS - Cache page exchanged successfully.
99 @return Others - An error occurred when exchanging cache page.
104 FatExchangeCachePage (
105 IN FAT_VOLUME
*Volume
,
106 IN CACHE_DATA_TYPE DataType
,
108 IN CACHE_TAG
*CacheTag
,
119 DISK_CACHE
*DiskCache
;
123 DiskCache
= &Volume
->DiskCache
[DataType
];
124 PageNo
= CacheTag
->PageNo
;
125 GroupNo
= PageNo
& DiskCache
->GroupMask
;
126 PageAlignment
= DiskCache
->PageAlignment
;
127 PageAddress
= DiskCache
->CacheBase
+ (GroupNo
<< PageAlignment
);
128 EntryPos
= DiskCache
->BaseAddress
+ LShiftU64 (PageNo
, PageAlignment
);
129 RealSize
= CacheTag
->RealSize
;
130 if (IoMode
== ReadDisk
) {
131 RealSize
= (UINTN
)1 << PageAlignment
;
132 MaxSize
= DiskCache
->LimitAddress
- EntryPos
;
133 if (MaxSize
< RealSize
) {
134 DEBUG ((EFI_D_INFO
, "FatDiskIo: Cache Page OutBound occurred! \n"));
135 RealSize
= (UINTN
) MaxSize
;
140 if (DataType
== CacheFat
&& IoMode
== WriteDisk
) {
141 WriteCount
= Volume
->NumFats
;
146 // Only fat table writing will execute more than once
148 Status
= FatDiskIo (Volume
, IoMode
, EntryPos
, RealSize
, PageAddress
, Task
);
149 if (EFI_ERROR (Status
)) {
153 EntryPos
+= Volume
->FatSize
;
154 } while (--WriteCount
> 0);
156 CacheTag
->Dirty
= FALSE
;
157 CacheTag
->RealSize
= RealSize
;
163 Get one cache page by specified PageNo.
165 @param Volume - FAT file system volume.
166 @param CacheDataType - The cache type: CACHE_FAT or CACHE_DATA.
167 @param PageNo - PageNo to match with the cache.
168 @param CacheTag - The Cache Tag for the current cache page.
170 @retval EFI_SUCCESS - Get the cache page successfully.
171 @return other - An error occurred when accessing data.
177 IN FAT_VOLUME
*Volume
,
178 IN CACHE_DATA_TYPE CacheDataType
,
180 IN CACHE_TAG
*CacheTag
186 OldPageNo
= CacheTag
->PageNo
;
187 if (CacheTag
->RealSize
> 0 && OldPageNo
== PageNo
) {
189 // Cache Hit occurred
195 // Write dirty cache page back to disk
197 if (CacheTag
->RealSize
> 0 && CacheTag
->Dirty
) {
198 Status
= FatExchangeCachePage (Volume
, CacheDataType
, WriteDisk
, CacheTag
, NULL
);
199 if (EFI_ERROR (Status
)) {
204 // Load new data from disk;
206 CacheTag
->PageNo
= PageNo
;
207 Status
= FatExchangeCachePage (Volume
, CacheDataType
, ReadDisk
, CacheTag
, NULL
);
214 Read Length bytes from the position of Offset into Buffer, or
215 write Length bytes from Buffer into the position of Offset.
217 @param Volume - FAT file system volume.
218 @param CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.
219 @param IoMode - Indicate the type of disk access.
220 @param PageNo - The number of unaligned cache page.
221 @param Offset - The starting byte of cache page.
222 @param Length - The number of bytes that is read or written
223 @param Buffer - Buffer containing cache data.
225 @retval EFI_SUCCESS - The data was accessed correctly.
226 @return Others - An error occurred when accessing unaligned cache page.
231 FatAccessUnalignedCachePage (
232 IN FAT_VOLUME
*Volume
,
233 IN CACHE_DATA_TYPE CacheDataType
,
244 DISK_CACHE
*DiskCache
;
248 DiskCache
= &Volume
->DiskCache
[CacheDataType
];
249 GroupNo
= PageNo
& DiskCache
->GroupMask
;
250 CacheTag
= &DiskCache
->CacheTag
[GroupNo
];
251 Status
= FatGetCachePage (Volume
, CacheDataType
, PageNo
, CacheTag
);
252 if (!EFI_ERROR (Status
)) {
253 Source
= DiskCache
->CacheBase
+ (GroupNo
<< DiskCache
->PageAlignment
) + Offset
;
254 Destination
= Buffer
;
255 if (IoMode
!= ReadDisk
) {
256 CacheTag
->Dirty
= TRUE
;
257 DiskCache
->Dirty
= TRUE
;
258 Destination
= Source
;
262 CopyMem (Destination
, Source
, Length
);
270 Read BufferSize bytes from the position of Offset into Buffer,
271 or write BufferSize bytes from Buffer into the position of Offset.
273 Base on the parameter of CACHE_DATA_TYPE, the data access will be divided into
274 the access of FAT cache (CACHE_FAT) and the access of Data cache (CACHE_DATA):
276 1. Access of FAT cache (CACHE_FAT): Access the data in the FAT cache, if there is cache
277 page hit, just return the cache page; else update the related cache page and return
278 the right cache page.
279 2. Access of Data cache (CACHE_DATA):
280 The access data will be divided into UnderRun data, Aligned data and OverRun data;
281 The UnderRun data and OverRun data will be accessed by the Data cache,
282 but the Aligned data will be accessed with disk directly.
284 @param Volume - FAT file system volume.
285 @param CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.
286 @param IoMode - Indicate the type of disk access.
287 @param Offset - The starting byte offset to read from.
288 @param BufferSize - Size of Buffer.
289 @param Buffer - Buffer containing cache data.
290 @param Task point to task instance.
292 @retval EFI_SUCCESS - The data was accessed correctly.
293 @retval EFI_MEDIA_CHANGED - The MediaId does not match the current device.
294 @return Others - An error occurred when accessing cache.
299 IN FAT_VOLUME
*Volume
,
300 IN CACHE_DATA_TYPE CacheDataType
,
304 IN OUT UINT8
*Buffer
,
315 UINTN AlignedPageCount
;
317 DISK_CACHE
*DiskCache
;
321 ASSERT (Volume
->CacheBuffer
!= NULL
);
323 Status
= EFI_SUCCESS
;
324 DiskCache
= &Volume
->DiskCache
[CacheDataType
];
325 EntryPos
= Offset
- DiskCache
->BaseAddress
;
326 PageAlignment
= DiskCache
->PageAlignment
;
327 PageSize
= (UINTN
)1 << PageAlignment
;
328 PageNo
= (UINTN
) RShiftU64 (EntryPos
, PageAlignment
);
329 UnderRun
= ((UINTN
) EntryPos
) & (PageSize
- 1);
332 Length
= PageSize
- UnderRun
;
333 if (Length
> BufferSize
) {
337 Status
= FatAccessUnalignedCachePage (Volume
, CacheDataType
, IoMode
, PageNo
, UnderRun
, Length
, Buffer
);
338 if (EFI_ERROR (Status
)) {
343 BufferSize
-= Length
;
347 AlignedPageCount
= BufferSize
>> PageAlignment
;
348 OverRunPageNo
= PageNo
+ AlignedPageCount
;
350 // The access of the Aligned data
352 if (AlignedPageCount
> 0) {
354 // Accessing fat table cannot have alignment data
356 ASSERT (CacheDataType
== CacheData
);
358 EntryPos
= Volume
->RootPos
+ LShiftU64 (PageNo
, PageAlignment
);
359 AlignedSize
= AlignedPageCount
<< PageAlignment
;
360 Status
= FatDiskIo (Volume
, IoMode
, EntryPos
, AlignedSize
, Buffer
, Task
);
361 if (EFI_ERROR (Status
)) {
365 // If these access data over laps the relative cache range, these cache pages need
368 FatFlushDataCacheRange (Volume
, IoMode
, PageNo
, OverRunPageNo
, Buffer
);
369 Buffer
+= AlignedSize
;
370 BufferSize
-= AlignedSize
;
373 // The access of the OverRun data
375 OverRun
= BufferSize
;
378 // Last read is not a complete page
380 Status
= FatAccessUnalignedCachePage (Volume
, CacheDataType
, IoMode
, OverRunPageNo
, 0, OverRun
, Buffer
);
388 Flush all the dirty cache back, include the FAT cache and the Data cache.
390 @param Volume - FAT file system volume.
391 @param Task point to task instance.
393 @retval EFI_SUCCESS - Flush all the dirty cache back successfully
394 @return other - An error occurred when writing the data into the disk
398 FatVolumeFlushCache (
399 IN FAT_VOLUME
*Volume
,
404 CACHE_DATA_TYPE CacheDataType
;
407 DISK_CACHE
*DiskCache
;
410 for (CacheDataType
= (CACHE_DATA_TYPE
) 0; CacheDataType
< CacheMaxType
; CacheDataType
++) {
411 DiskCache
= &Volume
->DiskCache
[CacheDataType
];
412 if (DiskCache
->Dirty
) {
414 // Data cache or fat cache is dirty, write the dirty data back
416 GroupMask
= DiskCache
->GroupMask
;
417 for (GroupIndex
= 0; GroupIndex
<= GroupMask
; GroupIndex
++) {
418 CacheTag
= &DiskCache
->CacheTag
[GroupIndex
];
419 if (CacheTag
->RealSize
> 0 && CacheTag
->Dirty
) {
421 // Write back all Dirty Data Cache Page to disk
423 Status
= FatExchangeCachePage (Volume
, CacheDataType
, WriteDisk
, CacheTag
, Task
);
424 if (EFI_ERROR (Status
)) {
430 DiskCache
->Dirty
= FALSE
;
434 // Flush the block device.
436 Status
= Volume
->BlockIo
->FlushBlocks (Volume
->BlockIo
);
442 Initialize the disk cache according to Volume's FatType.
444 @param Volume - FAT file system volume.
446 @retval EFI_SUCCESS - The disk cache is successfully initialized.
447 @retval EFI_OUT_OF_RESOURCES - Not enough memory to allocate disk cache.
451 FatInitializeDiskCache (
452 IN FAT_VOLUME
*Volume
455 DISK_CACHE
*DiskCache
;
456 UINTN FatCacheGroupCount
;
461 DiskCache
= Volume
->DiskCache
;
463 // Configure the parameters of disk cache
465 if (Volume
->FatType
== Fat12
) {
466 FatCacheGroupCount
= FAT_FATCACHE_GROUP_MIN_COUNT
;
467 DiskCache
[CacheFat
].PageAlignment
= FAT_FATCACHE_PAGE_MIN_ALIGNMENT
;
468 DiskCache
[CacheData
].PageAlignment
= FAT_DATACACHE_PAGE_MIN_ALIGNMENT
;
470 FatCacheGroupCount
= FAT_FATCACHE_GROUP_MAX_COUNT
;
471 DiskCache
[CacheFat
].PageAlignment
= FAT_FATCACHE_PAGE_MAX_ALIGNMENT
;
472 DiskCache
[CacheData
].PageAlignment
= FAT_DATACACHE_PAGE_MAX_ALIGNMENT
;
475 DiskCache
[CacheData
].GroupMask
= FAT_DATACACHE_GROUP_COUNT
- 1;
476 DiskCache
[CacheData
].BaseAddress
= Volume
->RootPos
;
477 DiskCache
[CacheData
].LimitAddress
= Volume
->VolumeSize
;
478 DiskCache
[CacheFat
].GroupMask
= FatCacheGroupCount
- 1;
479 DiskCache
[CacheFat
].BaseAddress
= Volume
->FatPos
;
480 DiskCache
[CacheFat
].LimitAddress
= Volume
->FatPos
+ Volume
->FatSize
;
481 FatCacheSize
= FatCacheGroupCount
<< DiskCache
[CacheFat
].PageAlignment
;
482 DataCacheSize
= FAT_DATACACHE_GROUP_COUNT
<< DiskCache
[CacheData
].PageAlignment
;
484 // Allocate the Fat Cache buffer
486 CacheBuffer
= AllocateZeroPool (FatCacheSize
+ DataCacheSize
);
487 if (CacheBuffer
== NULL
) {
488 return EFI_OUT_OF_RESOURCES
;
491 Volume
->CacheBuffer
= CacheBuffer
;
492 DiskCache
[CacheFat
].CacheBase
= CacheBuffer
;
493 DiskCache
[CacheData
].CacheBase
= CacheBuffer
+ FatCacheSize
;