2 Cache implementation for EFI FAT File system driver.
4 Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
13 This function is used by the Data Cache.
15 When this function is called by write command, all entries in this range
16 are older than the contents in disk, so they are invalid; just mark them invalid.
18 When this function is called by read command, if any entry in this range
19 is dirty, it means that the relative info directly read from media is older than
20 than the info in the cache; So need to update the relative info in the Buffer.
22 @param Volume - FAT file system volume.
23 @param IoMode - This function is called by read command or write command
24 @param StartPageNo - First PageNo to be checked in the cache.
25 @param EndPageNo - Last PageNo to be checked in the cache.
26 @param Buffer - The user buffer need to update. Only when doing the read command
27 and there is dirty cache in the cache range, this parameter will be used.
32 FatFlushDataCacheRange (
33 IN FAT_VOLUME
*Volume
,
45 DISK_CACHE
*DiskCache
;
49 DiskCache
= &Volume
->DiskCache
[CacheData
];
50 BaseAddress
= DiskCache
->CacheBase
;
51 GroupMask
= DiskCache
->GroupMask
;
52 PageAlignment
= DiskCache
->PageAlignment
;
53 PageSize
= (UINTN
)1 << PageAlignment
;
55 for (PageNo
= StartPageNo
; PageNo
< EndPageNo
; PageNo
++) {
56 GroupNo
= PageNo
& GroupMask
;
57 CacheTag
= &DiskCache
->CacheTag
[GroupNo
];
58 if (CacheTag
->RealSize
> 0 && CacheTag
->PageNo
== PageNo
) {
60 // When reading data form disk directly, if some dirty data
61 // in cache is in this rang, this data in the Buffer need to
62 // be updated with the cache's dirty data.
64 if (IoMode
== ReadDisk
) {
65 if (CacheTag
->Dirty
) {
67 Buffer
+ ((PageNo
- StartPageNo
) << PageAlignment
),
68 BaseAddress
+ (GroupNo
<< PageAlignment
),
74 // Make all valid entries in this range invalid.
76 CacheTag
->RealSize
= 0;
84 Exchange the cache page with the image on the disk
86 @param Volume - FAT file system volume.
87 @param DataType - Indicate the cache type.
88 @param IoMode - Indicate whether to load this page from disk or store this page to disk.
89 @param CacheTag - The Cache Tag for the current cache page.
90 @param Task point to task instance.
92 @retval EFI_SUCCESS - Cache page exchanged successfully.
93 @return Others - An error occurred when exchanging cache page.
98 FatExchangeCachePage (
99 IN FAT_VOLUME
*Volume
,
100 IN CACHE_DATA_TYPE DataType
,
102 IN CACHE_TAG
*CacheTag
,
113 DISK_CACHE
*DiskCache
;
117 DiskCache
= &Volume
->DiskCache
[DataType
];
118 PageNo
= CacheTag
->PageNo
;
119 GroupNo
= PageNo
& DiskCache
->GroupMask
;
120 PageAlignment
= DiskCache
->PageAlignment
;
121 PageAddress
= DiskCache
->CacheBase
+ (GroupNo
<< PageAlignment
);
122 EntryPos
= DiskCache
->BaseAddress
+ LShiftU64 (PageNo
, PageAlignment
);
123 RealSize
= CacheTag
->RealSize
;
124 if (IoMode
== ReadDisk
) {
125 RealSize
= (UINTN
)1 << PageAlignment
;
126 MaxSize
= DiskCache
->LimitAddress
- EntryPos
;
127 if (MaxSize
< RealSize
) {
128 DEBUG ((EFI_D_INFO
, "FatDiskIo: Cache Page OutBound occurred! \n"));
129 RealSize
= (UINTN
) MaxSize
;
134 if (DataType
== CacheFat
&& IoMode
== WriteDisk
) {
135 WriteCount
= Volume
->NumFats
;
140 // Only fat table writing will execute more than once
142 Status
= FatDiskIo (Volume
, IoMode
, EntryPos
, RealSize
, PageAddress
, Task
);
143 if (EFI_ERROR (Status
)) {
147 EntryPos
+= Volume
->FatSize
;
148 } while (--WriteCount
> 0);
150 CacheTag
->Dirty
= FALSE
;
151 CacheTag
->RealSize
= RealSize
;
157 Get one cache page by specified PageNo.
159 @param Volume - FAT file system volume.
160 @param CacheDataType - The cache type: CACHE_FAT or CACHE_DATA.
161 @param PageNo - PageNo to match with the cache.
162 @param CacheTag - The Cache Tag for the current cache page.
164 @retval EFI_SUCCESS - Get the cache page successfully.
165 @return other - An error occurred when accessing data.
171 IN FAT_VOLUME
*Volume
,
172 IN CACHE_DATA_TYPE CacheDataType
,
174 IN CACHE_TAG
*CacheTag
180 OldPageNo
= CacheTag
->PageNo
;
181 if (CacheTag
->RealSize
> 0 && OldPageNo
== PageNo
) {
183 // Cache Hit occurred
189 // Write dirty cache page back to disk
191 if (CacheTag
->RealSize
> 0 && CacheTag
->Dirty
) {
192 Status
= FatExchangeCachePage (Volume
, CacheDataType
, WriteDisk
, CacheTag
, NULL
);
193 if (EFI_ERROR (Status
)) {
198 // Load new data from disk;
200 CacheTag
->PageNo
= PageNo
;
201 Status
= FatExchangeCachePage (Volume
, CacheDataType
, ReadDisk
, CacheTag
, NULL
);
208 Read Length bytes from the position of Offset into Buffer, or
209 write Length bytes from Buffer into the position of Offset.
211 @param Volume - FAT file system volume.
212 @param CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.
213 @param IoMode - Indicate the type of disk access.
214 @param PageNo - The number of unaligned cache page.
215 @param Offset - The starting byte of cache page.
216 @param Length - The number of bytes that is read or written
217 @param Buffer - Buffer containing cache data.
219 @retval EFI_SUCCESS - The data was accessed correctly.
220 @return Others - An error occurred when accessing unaligned cache page.
225 FatAccessUnalignedCachePage (
226 IN FAT_VOLUME
*Volume
,
227 IN CACHE_DATA_TYPE CacheDataType
,
238 DISK_CACHE
*DiskCache
;
242 DiskCache
= &Volume
->DiskCache
[CacheDataType
];
243 GroupNo
= PageNo
& DiskCache
->GroupMask
;
244 CacheTag
= &DiskCache
->CacheTag
[GroupNo
];
245 Status
= FatGetCachePage (Volume
, CacheDataType
, PageNo
, CacheTag
);
246 if (!EFI_ERROR (Status
)) {
247 Source
= DiskCache
->CacheBase
+ (GroupNo
<< DiskCache
->PageAlignment
) + Offset
;
248 Destination
= Buffer
;
249 if (IoMode
!= ReadDisk
) {
250 CacheTag
->Dirty
= TRUE
;
251 DiskCache
->Dirty
= TRUE
;
252 Destination
= Source
;
256 CopyMem (Destination
, Source
, Length
);
264 Read BufferSize bytes from the position of Offset into Buffer,
265 or write BufferSize bytes from Buffer into the position of Offset.
267 Base on the parameter of CACHE_DATA_TYPE, the data access will be divided into
268 the access of FAT cache (CACHE_FAT) and the access of Data cache (CACHE_DATA):
270 1. Access of FAT cache (CACHE_FAT): Access the data in the FAT cache, if there is cache
271 page hit, just return the cache page; else update the related cache page and return
272 the right cache page.
273 2. Access of Data cache (CACHE_DATA):
274 The access data will be divided into UnderRun data, Aligned data and OverRun data;
275 The UnderRun data and OverRun data will be accessed by the Data cache,
276 but the Aligned data will be accessed with disk directly.
278 @param Volume - FAT file system volume.
279 @param CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.
280 @param IoMode - Indicate the type of disk access.
281 @param Offset - The starting byte offset to read from.
282 @param BufferSize - Size of Buffer.
283 @param Buffer - Buffer containing cache data.
284 @param Task point to task instance.
286 @retval EFI_SUCCESS - The data was accessed correctly.
287 @retval EFI_MEDIA_CHANGED - The MediaId does not match the current device.
288 @return Others - An error occurred when accessing cache.
293 IN FAT_VOLUME
*Volume
,
294 IN CACHE_DATA_TYPE CacheDataType
,
298 IN OUT UINT8
*Buffer
,
309 UINTN AlignedPageCount
;
311 DISK_CACHE
*DiskCache
;
315 ASSERT (Volume
->CacheBuffer
!= NULL
);
317 Status
= EFI_SUCCESS
;
318 DiskCache
= &Volume
->DiskCache
[CacheDataType
];
319 EntryPos
= Offset
- DiskCache
->BaseAddress
;
320 PageAlignment
= DiskCache
->PageAlignment
;
321 PageSize
= (UINTN
)1 << PageAlignment
;
322 PageNo
= (UINTN
) RShiftU64 (EntryPos
, PageAlignment
);
323 UnderRun
= ((UINTN
) EntryPos
) & (PageSize
- 1);
326 Length
= PageSize
- UnderRun
;
327 if (Length
> BufferSize
) {
331 Status
= FatAccessUnalignedCachePage (Volume
, CacheDataType
, IoMode
, PageNo
, UnderRun
, Length
, Buffer
);
332 if (EFI_ERROR (Status
)) {
337 BufferSize
-= Length
;
341 AlignedPageCount
= BufferSize
>> PageAlignment
;
342 OverRunPageNo
= PageNo
+ AlignedPageCount
;
344 // The access of the Aligned data
346 if (AlignedPageCount
> 0) {
348 // Accessing fat table cannot have alignment data
350 ASSERT (CacheDataType
== CacheData
);
352 EntryPos
= Volume
->RootPos
+ LShiftU64 (PageNo
, PageAlignment
);
353 AlignedSize
= AlignedPageCount
<< PageAlignment
;
354 Status
= FatDiskIo (Volume
, IoMode
, EntryPos
, AlignedSize
, Buffer
, Task
);
355 if (EFI_ERROR (Status
)) {
359 // If these access data over laps the relative cache range, these cache pages need
362 FatFlushDataCacheRange (Volume
, IoMode
, PageNo
, OverRunPageNo
, Buffer
);
363 Buffer
+= AlignedSize
;
364 BufferSize
-= AlignedSize
;
367 // The access of the OverRun data
369 OverRun
= BufferSize
;
372 // Last read is not a complete page
374 Status
= FatAccessUnalignedCachePage (Volume
, CacheDataType
, IoMode
, OverRunPageNo
, 0, OverRun
, Buffer
);
382 Flush all the dirty cache back, include the FAT cache and the Data cache.
384 @param Volume - FAT file system volume.
385 @param Task point to task instance.
387 @retval EFI_SUCCESS - Flush all the dirty cache back successfully
388 @return other - An error occurred when writing the data into the disk
392 FatVolumeFlushCache (
393 IN FAT_VOLUME
*Volume
,
398 CACHE_DATA_TYPE CacheDataType
;
401 DISK_CACHE
*DiskCache
;
404 for (CacheDataType
= (CACHE_DATA_TYPE
) 0; CacheDataType
< CacheMaxType
; CacheDataType
++) {
405 DiskCache
= &Volume
->DiskCache
[CacheDataType
];
406 if (DiskCache
->Dirty
) {
408 // Data cache or fat cache is dirty, write the dirty data back
410 GroupMask
= DiskCache
->GroupMask
;
411 for (GroupIndex
= 0; GroupIndex
<= GroupMask
; GroupIndex
++) {
412 CacheTag
= &DiskCache
->CacheTag
[GroupIndex
];
413 if (CacheTag
->RealSize
> 0 && CacheTag
->Dirty
) {
415 // Write back all Dirty Data Cache Page to disk
417 Status
= FatExchangeCachePage (Volume
, CacheDataType
, WriteDisk
, CacheTag
, Task
);
418 if (EFI_ERROR (Status
)) {
424 DiskCache
->Dirty
= FALSE
;
428 // Flush the block device.
430 Status
= Volume
->BlockIo
->FlushBlocks (Volume
->BlockIo
);
436 Initialize the disk cache according to Volume's FatType.
438 @param Volume - FAT file system volume.
440 @retval EFI_SUCCESS - The disk cache is successfully initialized.
441 @retval EFI_OUT_OF_RESOURCES - Not enough memory to allocate disk cache.
445 FatInitializeDiskCache (
446 IN FAT_VOLUME
*Volume
449 DISK_CACHE
*DiskCache
;
450 UINTN FatCacheGroupCount
;
455 DiskCache
= Volume
->DiskCache
;
457 // Configure the parameters of disk cache
459 if (Volume
->FatType
== Fat12
) {
460 FatCacheGroupCount
= FAT_FATCACHE_GROUP_MIN_COUNT
;
461 DiskCache
[CacheFat
].PageAlignment
= FAT_FATCACHE_PAGE_MIN_ALIGNMENT
;
462 DiskCache
[CacheData
].PageAlignment
= FAT_DATACACHE_PAGE_MIN_ALIGNMENT
;
464 FatCacheGroupCount
= FAT_FATCACHE_GROUP_MAX_COUNT
;
465 DiskCache
[CacheFat
].PageAlignment
= FAT_FATCACHE_PAGE_MAX_ALIGNMENT
;
466 DiskCache
[CacheData
].PageAlignment
= FAT_DATACACHE_PAGE_MAX_ALIGNMENT
;
469 DiskCache
[CacheData
].GroupMask
= FAT_DATACACHE_GROUP_COUNT
- 1;
470 DiskCache
[CacheData
].BaseAddress
= Volume
->RootPos
;
471 DiskCache
[CacheData
].LimitAddress
= Volume
->VolumeSize
;
472 DiskCache
[CacheFat
].GroupMask
= FatCacheGroupCount
- 1;
473 DiskCache
[CacheFat
].BaseAddress
= Volume
->FatPos
;
474 DiskCache
[CacheFat
].LimitAddress
= Volume
->FatPos
+ Volume
->FatSize
;
475 FatCacheSize
= FatCacheGroupCount
<< DiskCache
[CacheFat
].PageAlignment
;
476 DataCacheSize
= FAT_DATACACHE_GROUP_COUNT
<< DiskCache
[CacheData
].PageAlignment
;
478 // Allocate the Fat Cache buffer
480 CacheBuffer
= AllocateZeroPool (FatCacheSize
+ DataCacheSize
);
481 if (CacheBuffer
== NULL
) {
482 return EFI_OUT_OF_RESOURCES
;
485 Volume
->CacheBuffer
= CacheBuffer
;
486 DiskCache
[CacheFat
].CacheBase
= CacheBuffer
;
487 DiskCache
[CacheData
].CacheBase
= CacheBuffer
+ FatCacheSize
;