3 Copyright (c) 2005 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials are licensed and made available
5 under the terms and conditions of the BSD License which accompanies this
6 distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 Cache implementation for EFI FAT File system driver
29 FatFlushDataCacheRange (
30 IN FAT_VOLUME
*Volume
,
40 This function is used by the Data Cache.
42 When this function is called by write command, all entries in this range
43 are older than the contents in disk, so they are invalid; just mark them invalid.
45 When this function is called by read command, if any entry in this range
46 is dirty, it means that the relative info directly readed from media is older than
47 than the info in the cache; So need to update the relative info in the Buffer.
51 Volume - FAT file system volume.
52 IoMode - This function is called by read command or write command
53 StartPageNo - First PageNo to be checked in the cache.
54 EndPageNo - Last PageNo to be checked in the cache.
55 Buffer - The user buffer need to update. Only when doing the read command
56 and there is dirty cache in the cache range, this parameter will be used.
69 DISK_CACHE
*DiskCache
;
73 DiskCache
= &Volume
->DiskCache
[CACHE_DATA
];
74 BaseAddress
= DiskCache
->CacheBase
;
75 GroupMask
= DiskCache
->GroupMask
;
76 PageAlignment
= DiskCache
->PageAlignment
;
77 PageSize
= (UINTN
)1 << PageAlignment
;
79 for (PageNo
= StartPageNo
; PageNo
< EndPageNo
; PageNo
++) {
80 GroupNo
= PageNo
& GroupMask
;
81 CacheTag
= &DiskCache
->CacheTag
[GroupNo
];
82 if (CacheTag
->RealSize
> 0 && CacheTag
->PageNo
== PageNo
) {
84 // When reading data form disk directly, if some dirty data
85 // in cache is in this rang, this data in the Buffer need to
86 // be updated with the cache's dirty data.
88 if (IoMode
== READ_DISK
) {
89 if (CacheTag
->Dirty
) {
91 Buffer
+ ((PageNo
- StartPageNo
) << PageAlignment
),
92 BaseAddress
+ (GroupNo
<< PageAlignment
),
98 // Make all valid entries in this range invalid.
100 CacheTag
->RealSize
= 0;
108 FatExchangeCachePage (
109 IN FAT_VOLUME
*Volume
,
110 IN CACHE_DATA_TYPE DataType
,
112 IN CACHE_TAG
*CacheTag
118 Exchange the cache page with the image on the disk
122 Volume - FAT file system volume.
123 DataType - Indicate the cache type.
124 IoMode - Indicate whether to load this page from disk or store this page to disk.
125 CacheTag - The Cache Tag for the current cache page.
129 EFI_SUCCESS - Cache page exchanged successfully.
130 Others - An error occurred when exchanging cache page.
141 DISK_CACHE
*DiskCache
;
145 DiskCache
= &Volume
->DiskCache
[DataType
];
146 PageNo
= CacheTag
->PageNo
;
147 GroupNo
= PageNo
& DiskCache
->GroupMask
;
148 PageAlignment
= DiskCache
->PageAlignment
;
149 PageAddress
= DiskCache
->CacheBase
+ (GroupNo
<< PageAlignment
);
150 EntryPos
= DiskCache
->BaseAddress
+ LShiftU64 (PageNo
, PageAlignment
);
151 RealSize
= CacheTag
->RealSize
;
152 if (IoMode
== READ_DISK
) {
153 RealSize
= (UINTN
)1 << PageAlignment
;
154 MaxSize
= DiskCache
->LimitAddress
- EntryPos
;
155 if (MaxSize
< RealSize
) {
156 DEBUG ((EFI_D_INFO
, "FatDiskIo: Cache Page OutBound occurred! \n"));
157 RealSize
= (UINTN
) MaxSize
;
162 if (DataType
== CACHE_FAT
&& IoMode
== WRITE_DISK
) {
163 WriteCount
= Volume
->NumFats
;
168 // Only fat table writing will execute more than once
170 Status
= FatDiskIo (Volume
, IoMode
, EntryPos
, RealSize
, PageAddress
);
171 if (EFI_ERROR (Status
)) {
175 EntryPos
+= Volume
->FatSize
;
176 } while (--WriteCount
> 0);
178 CacheTag
->Dirty
= FALSE
;
179 CacheTag
->RealSize
= RealSize
;
186 IN FAT_VOLUME
*Volume
,
187 IN CACHE_DATA_TYPE CacheDataType
,
189 IN CACHE_TAG
*CacheTag
195 Get one cache page by specified PageNo.
199 Volume - FAT file system volume.
200 CacheDataType - The cache type: CACHE_FAT or CACHE_DATA.
201 PageNo - PageNo to match with the cache.
202 CacheTag - The Cache Tag for the current cache page.
206 EFI_SUCCESS - Get the cache page successfully.
207 other - An error occurred when accessing data.
214 OldPageNo
= CacheTag
->PageNo
;
215 if (CacheTag
->RealSize
> 0 && OldPageNo
== PageNo
) {
217 // Cache Hit occurred
223 // Write dirty cache page back to disk
225 if (CacheTag
->RealSize
> 0 && CacheTag
->Dirty
) {
226 Status
= FatExchangeCachePage (Volume
, CacheDataType
, WRITE_DISK
, CacheTag
);
227 if (EFI_ERROR (Status
)) {
232 // Load new data from disk;
234 CacheTag
->PageNo
= PageNo
;
235 Status
= FatExchangeCachePage (Volume
, CacheDataType
, READ_DISK
, CacheTag
);
242 FatAccessUnalignedCachePage (
243 IN FAT_VOLUME
*Volume
,
244 IN CACHE_DATA_TYPE CacheDataType
,
254 Read Length bytes from the position of Offset into Buffer, or
255 write Length bytes from Buffer into the position of Offset.
259 Volume - FAT file system volume.
260 CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.
261 IoMode - Indicate the type of disk access.
262 PageNo - The number of unaligned cache page.
263 Offset - The starting byte of cache page.
264 Length - The number of bytes that is read or written
265 Buffer - Buffer containing cache data.
269 EFI_SUCCESS - The data was accessed correctly.
270 Others - An error occurred when accessing unaligned cache page.
277 DISK_CACHE
*DiskCache
;
281 DiskCache
= &Volume
->DiskCache
[CacheDataType
];
282 GroupNo
= PageNo
& DiskCache
->GroupMask
;
283 CacheTag
= &DiskCache
->CacheTag
[GroupNo
];
284 Status
= FatGetCachePage (Volume
, CacheDataType
, PageNo
, CacheTag
);
285 if (!EFI_ERROR (Status
)) {
286 Source
= DiskCache
->CacheBase
+ (GroupNo
<< DiskCache
->PageAlignment
) + Offset
;
287 Destination
= Buffer
;
288 if (IoMode
!= READ_DISK
) {
289 CacheTag
->Dirty
= TRUE
;
290 DiskCache
->Dirty
= TRUE
;
291 Destination
= Source
;
295 CopyMem (Destination
, Source
, Length
);
303 IN FAT_VOLUME
*Volume
,
304 IN CACHE_DATA_TYPE CacheDataType
,
313 Read BufferSize bytes from the position of Offset into Buffer,
314 or write BufferSize bytes from Buffer into the position of Offset.
316 Base on the parameter of CACHE_DATA_TYPE, the data access will be divided into
317 the access of FAT cache (CACHE_FAT) and the access of Data cache (CACHE_DATA):
319 1. Access of FAT cache (CACHE_FAT): Access the data in the FAT cache, if there is cache
320 page hit, just return the cache page; else update the related cache page and return
321 the right cache page.
322 2. Access of Data cache (CACHE_DATA):
323 The access data will be divided into UnderRun data, Aligned data and OverRun data;
324 The UnderRun data and OverRun data will be accessed by the Data cache,
325 but the Aligned data will be accessed with disk directly.
329 Volume - FAT file system volume.
330 CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.
331 IoMode - Indicate the type of disk access.
332 Offset - The starting byte offset to read from.
333 BufferSize - Size of Buffer.
334 Buffer - Buffer containing cache data.
338 EFI_SUCCESS - The data was accessed correctly.
339 EFI_MEDIA_CHANGED - The MediaId does not match the current device.
340 Others - An error occurred when accessing cache.
351 UINTN AlignedPageCount
;
353 DISK_CACHE
*DiskCache
;
357 ASSERT (Volume
->CacheBuffer
!= NULL
);
359 Status
= EFI_SUCCESS
;
360 DiskCache
= &Volume
->DiskCache
[CacheDataType
];
361 EntryPos
= Offset
- DiskCache
->BaseAddress
;
362 PageAlignment
= DiskCache
->PageAlignment
;
363 PageSize
= (UINTN
)1 << PageAlignment
;
364 PageNo
= (UINTN
) RShiftU64 (EntryPos
, PageAlignment
);
365 UnderRun
= ((UINTN
) EntryPos
) & (PageSize
- 1);
368 Length
= PageSize
- UnderRun
;
369 if (Length
> BufferSize
) {
373 Status
= FatAccessUnalignedCachePage (Volume
, CacheDataType
, IoMode
, PageNo
, UnderRun
, Length
, Buffer
);
374 if (EFI_ERROR (Status
)) {
379 BufferSize
-= Length
;
383 AlignedPageCount
= BufferSize
>> PageAlignment
;
384 OverRunPageNo
= PageNo
+ AlignedPageCount
;
386 // The access of the Aligned data
388 if (AlignedPageCount
> 0) {
390 // Accessing fat table cannot have alignment data
392 ASSERT (CacheDataType
== CACHE_DATA
);
394 EntryPos
= Volume
->RootPos
+ LShiftU64 (PageNo
, PageAlignment
);
395 AlignedSize
= AlignedPageCount
<< PageAlignment
;
396 Status
= FatDiskIo (Volume
, IoMode
, EntryPos
, AlignedSize
, Buffer
);
397 if (EFI_ERROR (Status
)) {
401 // If these access data over laps the relative cache range, these cache pages need
404 FatFlushDataCacheRange (Volume
, IoMode
, PageNo
, OverRunPageNo
, Buffer
);
405 Buffer
+= AlignedSize
;
406 BufferSize
-= AlignedSize
;
409 // The access of the OverRun data
411 OverRun
= BufferSize
;
414 // Last read is not a complete page
416 Status
= FatAccessUnalignedCachePage (Volume
, CacheDataType
, IoMode
, OverRunPageNo
, 0, OverRun
, Buffer
);
423 FatVolumeFlushCache (
424 IN FAT_VOLUME
*Volume
430 Flush all the dirty cache back, include the FAT cache and the Data cache.
434 Volume - FAT file system volume.
438 EFI_SUCCESS - Flush all the dirty cache back successfully
439 other - An error occurred when writing the data into the disk
444 CACHE_DATA_TYPE CacheDataType
;
447 DISK_CACHE
*DiskCache
;
450 for (CacheDataType
= (CACHE_DATA_TYPE
) 0; CacheDataType
< CACHE_MAX_TYPE
; CacheDataType
++) {
451 DiskCache
= &Volume
->DiskCache
[CacheDataType
];
452 if (DiskCache
->Dirty
) {
454 // Data cache or fat cache is dirty, write the dirty data back
456 GroupMask
= DiskCache
->GroupMask
;
457 for (GroupIndex
= 0; GroupIndex
<= GroupMask
; GroupIndex
++) {
458 CacheTag
= &DiskCache
->CacheTag
[GroupIndex
];
459 if (CacheTag
->RealSize
> 0 && CacheTag
->Dirty
) {
461 // Write back all Dirty Data Cache Page to disk
463 Status
= FatExchangeCachePage (Volume
, CacheDataType
, WRITE_DISK
, CacheTag
);
464 if (EFI_ERROR (Status
)) {
470 DiskCache
->Dirty
= FALSE
;
474 // Flush the block device.
476 Status
= Volume
->BlockIo
->FlushBlocks (Volume
->BlockIo
);
481 FatInitializeDiskCache (
482 IN FAT_VOLUME
*Volume
488 Initialize the disk cache according to Volume's FatType.
492 Volume - FAT file system volume.
496 EFI_SUCCESS - The disk cache is successfully initialized.
497 EFI_OUT_OF_RESOURCES - Not enough memory to allocate disk cache.
501 DISK_CACHE
*DiskCache
;
502 UINTN FatCacheGroupCount
;
507 DiskCache
= Volume
->DiskCache
;
509 // Configure the parameters of disk cache
511 if (Volume
->FatType
== FAT12
) {
512 FatCacheGroupCount
= FAT_FATCACHE_GROUP_MIN_COUNT
;
513 DiskCache
[CACHE_FAT
].PageAlignment
= FAT_FATCACHE_PAGE_MIN_ALIGNMENT
;
514 DiskCache
[CACHE_DATA
].PageAlignment
= FAT_DATACACHE_PAGE_MIN_ALIGNMENT
;
516 FatCacheGroupCount
= FAT_FATCACHE_GROUP_MAX_COUNT
;
517 DiskCache
[CACHE_FAT
].PageAlignment
= FAT_FATCACHE_PAGE_MAX_ALIGNMENT
;
518 DiskCache
[CACHE_DATA
].PageAlignment
= FAT_DATACACHE_PAGE_MAX_ALIGNMENT
;
521 DiskCache
[CACHE_DATA
].GroupMask
= FAT_DATACACHE_GROUP_COUNT
- 1;
522 DiskCache
[CACHE_DATA
].BaseAddress
= Volume
->RootPos
;
523 DiskCache
[CACHE_DATA
].LimitAddress
= Volume
->VolumeSize
;
524 DiskCache
[CACHE_FAT
].GroupMask
= FatCacheGroupCount
- 1;
525 DiskCache
[CACHE_FAT
].BaseAddress
= Volume
->FatPos
;
526 DiskCache
[CACHE_FAT
].LimitAddress
= Volume
->FatPos
+ Volume
->FatSize
;
527 FatCacheSize
= FatCacheGroupCount
<< DiskCache
[CACHE_FAT
].PageAlignment
;
528 DataCacheSize
= FAT_DATACACHE_GROUP_COUNT
<< DiskCache
[CACHE_DATA
].PageAlignment
;
530 // Allocate the Fat Cache buffer
532 CacheBuffer
= AllocatePool (FatCacheSize
+ DataCacheSize
);
533 if (CacheBuffer
== NULL
) {
534 return EFI_OUT_OF_RESOURCES
;
537 Volume
->CacheBuffer
= CacheBuffer
;
538 DiskCache
[CACHE_FAT
].CacheBase
= CacheBuffer
;
539 DiskCache
[CACHE_DATA
].CacheBase
= CacheBuffer
+ FatCacheSize
;