3 Copyright (c) 2005 - 2013, Intel Corporation. All rights reserved.<BR>
4 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
,
119 Exchange the cache page with the image on the disk
123 Volume - FAT file system volume.
124 DataType - Indicate the cache type.
125 IoMode - Indicate whether to load this page from disk or store this page to disk.
126 CacheTag - The Cache Tag for the current cache page.
130 EFI_SUCCESS - Cache page exchanged successfully.
131 Others - An error occurred when exchanging cache page.
142 DISK_CACHE
*DiskCache
;
146 DiskCache
= &Volume
->DiskCache
[DataType
];
147 PageNo
= CacheTag
->PageNo
;
148 GroupNo
= PageNo
& DiskCache
->GroupMask
;
149 PageAlignment
= DiskCache
->PageAlignment
;
150 PageAddress
= DiskCache
->CacheBase
+ (GroupNo
<< PageAlignment
);
151 EntryPos
= DiskCache
->BaseAddress
+ LShiftU64 (PageNo
, PageAlignment
);
152 RealSize
= CacheTag
->RealSize
;
153 if (IoMode
== READ_DISK
) {
154 RealSize
= (UINTN
)1 << PageAlignment
;
155 MaxSize
= DiskCache
->LimitAddress
- EntryPos
;
156 if (MaxSize
< RealSize
) {
157 DEBUG ((EFI_D_INFO
, "FatDiskIo: Cache Page OutBound occurred! \n"));
158 RealSize
= (UINTN
) MaxSize
;
163 if (DataType
== CACHE_FAT
&& IoMode
== WRITE_DISK
) {
164 WriteCount
= Volume
->NumFats
;
169 // Only fat table writing will execute more than once
171 Status
= FatDiskIo (Volume
, IoMode
, EntryPos
, RealSize
, PageAddress
, Task
);
172 if (EFI_ERROR (Status
)) {
176 EntryPos
+= Volume
->FatSize
;
177 } while (--WriteCount
> 0);
179 CacheTag
->Dirty
= FALSE
;
180 CacheTag
->RealSize
= RealSize
;
187 IN FAT_VOLUME
*Volume
,
188 IN CACHE_DATA_TYPE CacheDataType
,
190 IN CACHE_TAG
*CacheTag
196 Get one cache page by specified PageNo.
200 Volume - FAT file system volume.
201 CacheDataType - The cache type: CACHE_FAT or CACHE_DATA.
202 PageNo - PageNo to match with the cache.
203 CacheTag - The Cache Tag for the current cache page.
207 EFI_SUCCESS - Get the cache page successfully.
208 other - An error occurred when accessing data.
215 OldPageNo
= CacheTag
->PageNo
;
216 if (CacheTag
->RealSize
> 0 && OldPageNo
== PageNo
) {
218 // Cache Hit occurred
224 // Write dirty cache page back to disk
226 if (CacheTag
->RealSize
> 0 && CacheTag
->Dirty
) {
227 Status
= FatExchangeCachePage (Volume
, CacheDataType
, WRITE_DISK
, CacheTag
, NULL
);
228 if (EFI_ERROR (Status
)) {
233 // Load new data from disk;
235 CacheTag
->PageNo
= PageNo
;
236 Status
= FatExchangeCachePage (Volume
, CacheDataType
, READ_DISK
, CacheTag
, NULL
);
243 FatAccessUnalignedCachePage (
244 IN FAT_VOLUME
*Volume
,
245 IN CACHE_DATA_TYPE CacheDataType
,
255 Read Length bytes from the position of Offset into Buffer, or
256 write Length bytes from Buffer into the position of Offset.
260 Volume - FAT file system volume.
261 CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.
262 IoMode - Indicate the type of disk access.
263 PageNo - The number of unaligned cache page.
264 Offset - The starting byte of cache page.
265 Length - The number of bytes that is read or written
266 Buffer - Buffer containing cache data.
270 EFI_SUCCESS - The data was accessed correctly.
271 Others - An error occurred when accessing unaligned cache page.
278 DISK_CACHE
*DiskCache
;
282 DiskCache
= &Volume
->DiskCache
[CacheDataType
];
283 GroupNo
= PageNo
& DiskCache
->GroupMask
;
284 CacheTag
= &DiskCache
->CacheTag
[GroupNo
];
285 Status
= FatGetCachePage (Volume
, CacheDataType
, PageNo
, CacheTag
);
286 if (!EFI_ERROR (Status
)) {
287 Source
= DiskCache
->CacheBase
+ (GroupNo
<< DiskCache
->PageAlignment
) + Offset
;
288 Destination
= Buffer
;
289 if (IoMode
!= READ_DISK
) {
290 CacheTag
->Dirty
= TRUE
;
291 DiskCache
->Dirty
= TRUE
;
292 Destination
= Source
;
296 CopyMem (Destination
, Source
, Length
);
304 IN FAT_VOLUME
*Volume
,
305 IN CACHE_DATA_TYPE CacheDataType
,
309 IN OUT UINT8
*Buffer
,
315 Read BufferSize bytes from the position of Offset into Buffer,
316 or write BufferSize bytes from Buffer into the position of Offset.
318 Base on the parameter of CACHE_DATA_TYPE, the data access will be divided into
319 the access of FAT cache (CACHE_FAT) and the access of Data cache (CACHE_DATA):
321 1. Access of FAT cache (CACHE_FAT): Access the data in the FAT cache, if there is cache
322 page hit, just return the cache page; else update the related cache page and return
323 the right cache page.
324 2. Access of Data cache (CACHE_DATA):
325 The access data will be divided into UnderRun data, Aligned data and OverRun data;
326 The UnderRun data and OverRun data will be accessed by the Data cache,
327 but the Aligned data will be accessed with disk directly.
331 Volume - FAT file system volume.
332 CacheDataType - The type of cache: CACHE_DATA or CACHE_FAT.
333 IoMode - Indicate the type of disk access.
334 Offset - The starting byte offset to read from.
335 BufferSize - Size of Buffer.
336 Buffer - Buffer containing cache data.
340 EFI_SUCCESS - The data was accessed correctly.
341 EFI_MEDIA_CHANGED - The MediaId does not match the current device.
342 Others - An error occurred when accessing cache.
353 UINTN AlignedPageCount
;
355 DISK_CACHE
*DiskCache
;
359 ASSERT (Volume
->CacheBuffer
!= NULL
);
361 Status
= EFI_SUCCESS
;
362 DiskCache
= &Volume
->DiskCache
[CacheDataType
];
363 EntryPos
= Offset
- DiskCache
->BaseAddress
;
364 PageAlignment
= DiskCache
->PageAlignment
;
365 PageSize
= (UINTN
)1 << PageAlignment
;
366 PageNo
= (UINTN
) RShiftU64 (EntryPos
, PageAlignment
);
367 UnderRun
= ((UINTN
) EntryPos
) & (PageSize
- 1);
370 Length
= PageSize
- UnderRun
;
371 if (Length
> BufferSize
) {
375 Status
= FatAccessUnalignedCachePage (Volume
, CacheDataType
, IoMode
, PageNo
, UnderRun
, Length
, Buffer
);
376 if (EFI_ERROR (Status
)) {
381 BufferSize
-= Length
;
385 AlignedPageCount
= BufferSize
>> PageAlignment
;
386 OverRunPageNo
= PageNo
+ AlignedPageCount
;
388 // The access of the Aligned data
390 if (AlignedPageCount
> 0) {
392 // Accessing fat table cannot have alignment data
394 ASSERT (CacheDataType
== CACHE_DATA
);
396 EntryPos
= Volume
->RootPos
+ LShiftU64 (PageNo
, PageAlignment
);
397 AlignedSize
= AlignedPageCount
<< PageAlignment
;
398 Status
= FatDiskIo (Volume
, IoMode
, EntryPos
, AlignedSize
, Buffer
, Task
);
399 if (EFI_ERROR (Status
)) {
403 // If these access data over laps the relative cache range, these cache pages need
406 FatFlushDataCacheRange (Volume
, IoMode
, PageNo
, OverRunPageNo
, Buffer
);
407 Buffer
+= AlignedSize
;
408 BufferSize
-= AlignedSize
;
411 // The access of the OverRun data
413 OverRun
= BufferSize
;
416 // Last read is not a complete page
418 Status
= FatAccessUnalignedCachePage (Volume
, CacheDataType
, IoMode
, OverRunPageNo
, 0, OverRun
, Buffer
);
425 FatVolumeFlushCache (
426 IN FAT_VOLUME
*Volume
,
433 Flush all the dirty cache back, include the FAT cache and the Data cache.
437 Volume - FAT file system volume.
441 EFI_SUCCESS - Flush all the dirty cache back successfully
442 other - An error occurred when writing the data into the disk
447 CACHE_DATA_TYPE CacheDataType
;
450 DISK_CACHE
*DiskCache
;
453 for (CacheDataType
= (CACHE_DATA_TYPE
) 0; CacheDataType
< CACHE_MAX_TYPE
; CacheDataType
++) {
454 DiskCache
= &Volume
->DiskCache
[CacheDataType
];
455 if (DiskCache
->Dirty
) {
457 // Data cache or fat cache is dirty, write the dirty data back
459 GroupMask
= DiskCache
->GroupMask
;
460 for (GroupIndex
= 0; GroupIndex
<= GroupMask
; GroupIndex
++) {
461 CacheTag
= &DiskCache
->CacheTag
[GroupIndex
];
462 if (CacheTag
->RealSize
> 0 && CacheTag
->Dirty
) {
464 // Write back all Dirty Data Cache Page to disk
466 Status
= FatExchangeCachePage (Volume
, CacheDataType
, WRITE_DISK
, CacheTag
, Task
);
467 if (EFI_ERROR (Status
)) {
473 DiskCache
->Dirty
= FALSE
;
477 // Flush the block device.
479 Status
= Volume
->BlockIo
->FlushBlocks (Volume
->BlockIo
);
484 FatInitializeDiskCache (
485 IN FAT_VOLUME
*Volume
491 Initialize the disk cache according to Volume's FatType.
495 Volume - FAT file system volume.
499 EFI_SUCCESS - The disk cache is successfully initialized.
500 EFI_OUT_OF_RESOURCES - Not enough memory to allocate disk cache.
504 DISK_CACHE
*DiskCache
;
505 UINTN FatCacheGroupCount
;
510 DiskCache
= Volume
->DiskCache
;
512 // Configure the parameters of disk cache
514 if (Volume
->FatType
== FAT12
) {
515 FatCacheGroupCount
= FAT_FATCACHE_GROUP_MIN_COUNT
;
516 DiskCache
[CACHE_FAT
].PageAlignment
= FAT_FATCACHE_PAGE_MIN_ALIGNMENT
;
517 DiskCache
[CACHE_DATA
].PageAlignment
= FAT_DATACACHE_PAGE_MIN_ALIGNMENT
;
519 FatCacheGroupCount
= FAT_FATCACHE_GROUP_MAX_COUNT
;
520 DiskCache
[CACHE_FAT
].PageAlignment
= FAT_FATCACHE_PAGE_MAX_ALIGNMENT
;
521 DiskCache
[CACHE_DATA
].PageAlignment
= FAT_DATACACHE_PAGE_MAX_ALIGNMENT
;
524 DiskCache
[CACHE_DATA
].GroupMask
= FAT_DATACACHE_GROUP_COUNT
- 1;
525 DiskCache
[CACHE_DATA
].BaseAddress
= Volume
->RootPos
;
526 DiskCache
[CACHE_DATA
].LimitAddress
= Volume
->VolumeSize
;
527 DiskCache
[CACHE_FAT
].GroupMask
= FatCacheGroupCount
- 1;
528 DiskCache
[CACHE_FAT
].BaseAddress
= Volume
->FatPos
;
529 DiskCache
[CACHE_FAT
].LimitAddress
= Volume
->FatPos
+ Volume
->FatSize
;
530 FatCacheSize
= FatCacheGroupCount
<< DiskCache
[CACHE_FAT
].PageAlignment
;
531 DataCacheSize
= FAT_DATACACHE_GROUP_COUNT
<< DiskCache
[CACHE_DATA
].PageAlignment
;
533 // Allocate the Fat Cache buffer
535 CacheBuffer
= AllocateZeroPool (FatCacheSize
+ DataCacheSize
);
536 if (CacheBuffer
== NULL
) {
537 return EFI_OUT_OF_RESOURCES
;
540 Volume
->CacheBuffer
= CacheBuffer
;
541 DiskCache
[CACHE_FAT
].CacheBase
= CacheBuffer
;
542 DiskCache
[CACHE_DATA
].CacheBase
= CacheBuffer
+ FatCacheSize
;