TianoCore EDK2 master
Loading...
Searching...
No Matches
DiskCache.c
Go to the documentation of this file.
1
9#include "Fat.h"
10
18VOID
20 IN CACHE_TAG *CacheTag
21 )
22{
23 if (CacheTag == NULL) {
24 ASSERT (CacheTag != NULL);
25 return;
26 }
27
28 ZeroMem (CacheTag->DirtyBlocks, sizeof (CacheTag->DirtyBlocks));
29 CacheTag->Dirty = FALSE;
30}
31
41VOID
43 IN UINTN BitNumber,
44 IN DIRTY_BLOCKS *DirtyBlocks
45 )
46{
47 UINTN BlockIndex;
48 UINTN BitIndex;
49
50 //
51 // ASSERTs checking BitNumber are DEBUG build only to verify the assumptions in the
52 // Fat.h defines (See Fat.h lines to describe DIRTY_BITS)
53 //
54 ASSERT (BitNumber < DIRTY_BITS);
55
56 BlockIndex = BitNumber / DIRTY_BITS_PER_BLOCK;
57 BitIndex = BitNumber % DIRTY_BITS_PER_BLOCK;
58 DirtyBlocks[BlockIndex] |= LShiftU64 (1ull, BitIndex);
59}
60
70BOOLEAN
72 IN UINTN BitNumber,
73 IN DIRTY_BLOCKS *DirtyBlocks
74 )
75{
76 UINTN BlockIndex;
77 UINTN BitIndex;
78
79 ASSERT (BitNumber < DIRTY_BITS);
80
81 BlockIndex = BitNumber / DIRTY_BITS_PER_BLOCK;
82 BitIndex = BitNumber % DIRTY_BITS_PER_BLOCK;
83 return (DirtyBlocks[BlockIndex] & LShiftU64 (1ull, BitIndex)) != 0;
84}
85
97VOID
99 IN DISK_CACHE *DiskCache,
100 IN CACHE_TAG *CacheTag,
101 IN UINTN Offset,
102 IN UINTN Length
103 )
104{
105 UINTN Bit;
106 UINTN LastBit;
107
108 Bit = Offset / DiskCache->BlockSize;
109 LastBit = (Offset + Length - 1) / DiskCache->BlockSize;
110
111 ASSERT (Bit <= LastBit);
112 ASSERT (LastBit <= DIRTY_BITS);
113
114 do {
115 SetBitInDirtyBlock (Bit, CacheTag->DirtyBlocks);
116 } while (++Bit <= LastBit);
117
118 CacheTag->Dirty = TRUE;
119}
120
144STATIC
147 IN CACHE_TAG *CacheTag,
148 IN CACHE_DATA_TYPE DataType,
149 IN FAT_VOLUME *Volume,
150 IN IO_MODE IoMode,
151 IN UINT64 Offset,
152 IN UINTN BufferSize,
153 IN OUT VOID *Buffer,
154 IN FAT_TASK *Task
155 )
156{
157 DISK_CACHE *DiskCache;
158 UINTN BlockIndexInTag;
159 VOID *WriteBuffer;
160 UINTN LastBit;
161 UINT64 StartPos;
162 EFI_STATUS Status;
163 UINTN WriteSize;
164
165 Status = EFI_SUCCESS;
166 if ((IoMode == WriteDisk) && (CacheTag->RealSize != 0)) {
167 DiskCache = &Volume->DiskCache[DataType];
168 WriteBuffer = Buffer;
169 LastBit = (CacheTag->RealSize - 1) / DiskCache->BlockSize;
170 StartPos = Offset;
171 BlockIndexInTag = 0;
172 WriteSize = 0;
173
174 do {
175 if (IsBitInBlockDirty (BlockIndexInTag, CacheTag->DirtyBlocks)) {
176 do {
177 WriteSize += DiskCache->BlockSize;
178 BlockIndexInTag++;
179 if (BlockIndexInTag > LastBit) {
180 break;
181 }
182 } while (IsBitInBlockDirty (BlockIndexInTag, CacheTag->DirtyBlocks));
183
184 Status = FatDiskIo (Volume, IoMode, StartPos, WriteSize, WriteBuffer, Task);
185 if (EFI_ERROR (Status)) {
186 return Status;
187 }
188
189 StartPos += WriteSize + DiskCache->BlockSize;
190 WriteBuffer = (VOID *)((UINTN)WriteBuffer + WriteSize + DiskCache->BlockSize);
191 WriteSize = 0;
192 BlockIndexInTag++;
193 } else {
194 StartPos += DiskCache->BlockSize;
195 WriteBuffer = (VOID *)((UINTN)WriteBuffer + DiskCache->BlockSize);
196 BlockIndexInTag++;
197 }
198 } while (BlockIndexInTag <= LastBit);
199
200 ASSERT (WriteSize == 0);
201 } else {
202 Status = FatDiskIo (Volume, IoMode, Offset, BufferSize, Buffer, Task);
203 if (EFI_ERROR (Status)) {
204 return Status;
205 }
206 }
207
208 return Status;
209}
210
230STATIC
231VOID
233 IN FAT_VOLUME *Volume,
234 IN IO_MODE IoMode,
235 IN UINTN StartPageNo,
236 IN UINTN EndPageNo,
237 OUT UINT8 *Buffer
238 )
239{
240 UINTN PageNo;
241 UINTN GroupNo;
242 UINTN GroupMask;
243 UINTN PageSize;
244 UINT8 PageAlignment;
245 DISK_CACHE *DiskCache;
246 CACHE_TAG *CacheTag;
247 UINT8 *BaseAddress;
248
249 DiskCache = &Volume->DiskCache[CacheData];
250 BaseAddress = DiskCache->CacheBase;
251 GroupMask = DiskCache->GroupMask;
252 PageAlignment = DiskCache->PageAlignment;
253 PageSize = (UINTN)1 << PageAlignment;
254
255 for (PageNo = StartPageNo; PageNo < EndPageNo; PageNo++) {
256 GroupNo = PageNo & GroupMask;
257 CacheTag = &DiskCache->CacheTag[GroupNo];
258 if ((CacheTag->RealSize > 0) && (CacheTag->PageNo == PageNo)) {
259 //
260 // When reading data from disk directly, if some dirty data
261 // in cache is in this range, this data in the Buffer needs to
262 // be updated with the cache's dirty data.
263 //
264 if (IoMode == ReadDisk) {
265 if (CacheTag->Dirty) {
266 CopyMem (
267 Buffer + ((PageNo - StartPageNo) << PageAlignment),
268 BaseAddress + (GroupNo << PageAlignment),
269 PageSize
270 );
271 }
272 } else {
273 //
274 // Make all valid entries in this range invalid.
275 //
276 CacheTag->RealSize = 0;
277 }
278 }
279 }
280}
281
296STATIC
299 IN FAT_VOLUME *Volume,
300 IN CACHE_DATA_TYPE DataType,
301 IN IO_MODE IoMode,
302 IN CACHE_TAG *CacheTag,
303 IN FAT_TASK *Task
304 )
305{
306 EFI_STATUS Status;
307 UINTN GroupNo;
308 UINTN PageNo;
309 UINTN WriteCount;
310 UINTN RealSize;
311 UINT64 EntryPos;
312 UINT64 MaxSize;
313 DISK_CACHE *DiskCache;
314 VOID *PageAddress;
315 UINT8 PageAlignment;
316
317 DiskCache = &Volume->DiskCache[DataType];
318 PageNo = CacheTag->PageNo;
319 GroupNo = PageNo & DiskCache->GroupMask;
320 PageAlignment = DiskCache->PageAlignment;
321 PageAddress = DiskCache->CacheBase + (GroupNo << PageAlignment);
322 EntryPos = (DiskCache->BaseAddress + LShiftU64 (PageNo, PageAlignment));
323 RealSize = CacheTag->RealSize;
324 if (IoMode == ReadDisk) {
325 RealSize = (UINTN)1 << PageAlignment;
326 MaxSize = DiskCache->LimitAddress - EntryPos;
327 if (MaxSize < RealSize) {
328 DEBUG ((DEBUG_INFO, "FatDiskIo: Cache Page OutBound occurred! \n"));
329 RealSize = (UINTN)MaxSize;
330 }
331 }
332
333 WriteCount = 1;
334 if ((DataType == CacheFat) && (IoMode == WriteDisk)) {
335 WriteCount = Volume->NumFats;
336 }
337
338 do {
339 //
340 // Only fat table writing will execute more than once
341 //
342 Status = CacheFatDiskIo (CacheTag, DataType, Volume, IoMode, EntryPos, RealSize, PageAddress, Task);
343 if (EFI_ERROR (Status)) {
344 return Status;
345 }
346
347 EntryPos += Volume->FatSize;
348 } while (--WriteCount > 0);
349
350 ClearCacheTagDirtyState (CacheTag);
351 CacheTag->RealSize = RealSize;
352 return EFI_SUCCESS;
353}
354
368STATIC
371 IN FAT_VOLUME *Volume,
372 IN CACHE_DATA_TYPE CacheDataType,
373 IN UINTN PageNo,
374 IN CACHE_TAG *CacheTag
375 )
376{
377 EFI_STATUS Status;
378 UINTN OldPageNo;
379
380 OldPageNo = CacheTag->PageNo;
381 if ((CacheTag->RealSize > 0) && (OldPageNo == PageNo)) {
382 //
383 // Cache Hit occurred
384 //
385 return EFI_SUCCESS;
386 }
387
388 //
389 // Write dirty cache page back to disk
390 //
391 if ((CacheTag->RealSize > 0) && CacheTag->Dirty) {
392 Status = FatExchangeCachePage (Volume, CacheDataType, WriteDisk, CacheTag, NULL);
393 if (EFI_ERROR (Status)) {
394 return Status;
395 }
396 }
397
398 //
399 // Load new data from disk;
400 //
401 CacheTag->PageNo = PageNo;
402 Status = FatExchangeCachePage (Volume, CacheDataType, ReadDisk, CacheTag, NULL);
403
404 return Status;
405}
406
424STATIC
427 IN FAT_VOLUME *Volume,
428 IN CACHE_DATA_TYPE CacheDataType,
429 IN IO_MODE IoMode,
430 IN UINTN PageNo,
431 IN UINTN Offset,
432 IN UINTN Length,
433 IN OUT VOID *Buffer
434 )
435{
436 EFI_STATUS Status;
437 VOID *Source;
438 VOID *Destination;
439 DISK_CACHE *DiskCache;
440 CACHE_TAG *CacheTag;
441 UINTN GroupNo;
442
443 DiskCache = &Volume->DiskCache[CacheDataType];
444 GroupNo = PageNo & DiskCache->GroupMask;
445 CacheTag = &DiskCache->CacheTag[GroupNo];
446 Status = FatGetCachePage (Volume, CacheDataType, PageNo, CacheTag);
447 if (!EFI_ERROR (Status)) {
448 Source = DiskCache->CacheBase + (GroupNo << DiskCache->PageAlignment) + Offset;
449 Destination = Buffer;
450 if (IoMode != ReadDisk) {
451 SetCacheTagDirty (DiskCache, CacheTag, Offset, Length);
452 DiskCache->Dirty = TRUE;
453 Destination = Source;
454 Source = Buffer;
455 }
456
457 CopyMem (Destination, Source, Length);
458 }
459
460 return Status;
461}
462
494 IN FAT_VOLUME *Volume,
495 IN CACHE_DATA_TYPE CacheDataType,
496 IN IO_MODE IoMode,
497 IN UINT64 Offset,
498 IN UINTN BufferSize,
499 IN OUT UINT8 *Buffer,
500 IN FAT_TASK *Task
501 )
502{
503 EFI_STATUS Status;
504 UINTN PageSize;
505 UINTN UnderRun;
506 UINTN OverRun;
507 UINTN AlignedSize;
508 UINTN Length;
509 UINTN PageNo;
510 UINTN AlignedPageCount;
511 UINTN OverRunPageNo;
512 DISK_CACHE *DiskCache;
513 UINT64 EntryPos;
514 UINT8 PageAlignment;
515
516 ASSERT (Volume->CacheBuffer != NULL);
517
518 Status = EFI_SUCCESS;
519 DiskCache = &Volume->DiskCache[CacheDataType];
520 EntryPos = Offset - DiskCache->BaseAddress;
521 PageAlignment = DiskCache->PageAlignment;
522 PageSize = (UINTN)1 << PageAlignment;
523 PageNo = (UINTN)RShiftU64 (EntryPos, PageAlignment);
524 UnderRun = ((UINTN)EntryPos) & (PageSize - 1);
525
526 if (UnderRun > 0) {
527 Length = PageSize - UnderRun;
528 if (Length > BufferSize) {
529 Length = BufferSize;
530 }
531
532 Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, PageNo, UnderRun, Length, Buffer);
533 if (EFI_ERROR (Status)) {
534 return Status;
535 }
536
537 Buffer += Length;
538 BufferSize -= Length;
539 PageNo++;
540 }
541
542 AlignedPageCount = BufferSize >> PageAlignment;
543 OverRunPageNo = PageNo + AlignedPageCount;
544 //
545 // The access of the Aligned data
546 //
547 if (AlignedPageCount > 0) {
548 //
549 // Accessing fat table cannot have alignment data
550 //
551 ASSERT (CacheDataType == CacheData);
552
553 EntryPos = Volume->RootPos + LShiftU64 (PageNo, PageAlignment);
554 AlignedSize = AlignedPageCount << PageAlignment;
555 Status = FatDiskIo (Volume, IoMode, EntryPos, AlignedSize, Buffer, Task);
556 if (EFI_ERROR (Status)) {
557 return Status;
558 }
559
560 //
561 // If these access data over laps the relative cache range, these cache pages need
562 // to be updated.
563 //
564 FatFlushDataCacheRange (Volume, IoMode, PageNo, OverRunPageNo, Buffer);
565 Buffer += AlignedSize;
566 BufferSize -= AlignedSize;
567 }
568
569 //
570 // The access of the OverRun data
571 //
572 OverRun = BufferSize;
573 if (OverRun > 0) {
574 //
575 // Last read is not a complete page
576 //
577 Status = FatAccessUnalignedCachePage (Volume, CacheDataType, IoMode, OverRunPageNo, 0, OverRun, Buffer);
578 }
579
580 return Status;
581}
582
596 IN FAT_VOLUME *Volume,
597 IN FAT_TASK *Task
598 )
599{
600 EFI_STATUS Status;
601 CACHE_DATA_TYPE CacheDataType;
602 UINTN GroupIndex;
603 UINTN GroupMask;
604 DISK_CACHE *DiskCache;
605 CACHE_TAG *CacheTag;
606
607 for (CacheDataType = (CACHE_DATA_TYPE)0; CacheDataType < CacheMaxType; CacheDataType++) {
608 DiskCache = &Volume->DiskCache[CacheDataType];
609 if (DiskCache->Dirty) {
610 //
611 // Data cache or fat cache is dirty, write the dirty data back
612 //
613 GroupMask = DiskCache->GroupMask;
614 for (GroupIndex = 0; GroupIndex <= GroupMask; GroupIndex++) {
615 CacheTag = &DiskCache->CacheTag[GroupIndex];
616 if ((CacheTag->RealSize > 0) && CacheTag->Dirty) {
617 //
618 // Write back all Dirty Data Cache Page to disk
619 //
620 Status = FatExchangeCachePage (Volume, CacheDataType, WriteDisk, CacheTag, Task);
621 if (EFI_ERROR (Status)) {
622 return Status;
623 }
624 }
625 }
626
627 DiskCache->Dirty = FALSE;
628 }
629 }
630
631 //
632 // Flush the block device.
633 //
634 Status = Volume->BlockIo->FlushBlocks (Volume->BlockIo);
635 return Status;
636}
637
650 IN FAT_VOLUME *Volume
651 )
652{
653 DISK_CACHE *DiskCache;
654 UINTN FatCacheGroupCount;
655 UINTN DataCacheSize;
656 UINTN FatCacheSize;
657 UINT8 *CacheBuffer;
658
659 DiskCache = Volume->DiskCache;
660 //
661 // Configure the parameters of disk cache
662 //
663 if (Volume->FatType == Fat12) {
664 FatCacheGroupCount = FAT_FATCACHE_GROUP_MIN_COUNT;
665 DiskCache[CacheFat].PageAlignment = FAT_FATCACHE_PAGE_MIN_ALIGNMENT;
666 DiskCache[CacheData].PageAlignment = FAT_DATACACHE_PAGE_MIN_ALIGNMENT;
667 } else {
668 FatCacheGroupCount = FAT_FATCACHE_GROUP_MAX_COUNT;
669 DiskCache[CacheFat].PageAlignment = FAT_FATCACHE_PAGE_MAX_ALIGNMENT;
670 DiskCache[CacheData].PageAlignment = FAT_DATACACHE_PAGE_MAX_ALIGNMENT;
671 }
672
673 DiskCache[CacheData].GroupMask = FAT_DATACACHE_GROUP_COUNT - 1;
674 DiskCache[CacheData].BaseAddress = Volume->RootPos;
675 DiskCache[CacheData].LimitAddress = Volume->VolumeSize;
676 DiskCache[CacheFat].GroupMask = FatCacheGroupCount - 1;
677 DiskCache[CacheFat].BaseAddress = Volume->FatPos;
678 DiskCache[CacheFat].LimitAddress = Volume->FatPos + Volume->FatSize;
679 FatCacheSize = FatCacheGroupCount << DiskCache[CacheFat].PageAlignment;
680 DataCacheSize = FAT_DATACACHE_GROUP_COUNT << DiskCache[CacheData].PageAlignment;
681 //
682 // Allocate the Fat Cache buffer
683 //
684 CacheBuffer = AllocateZeroPool (FatCacheSize + DataCacheSize);
685 if (CacheBuffer == NULL) {
686 return EFI_OUT_OF_RESOURCES;
687 }
688
689 Volume->CacheBuffer = CacheBuffer;
690 DiskCache[CacheFat].CacheBase = CacheBuffer;
691 DiskCache[CacheData].CacheBase = CacheBuffer + FatCacheSize;
692
693 DiskCache[CacheFat].BlockSize = Volume->BlockIo->Media->BlockSize;
694 DiskCache[CacheData].BlockSize = Volume->BlockIo->Media->BlockSize;
695
696 return EFI_SUCCESS;
697}
UINT64 UINTN
UINT64 EFIAPI RShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: RShiftU64.c:28
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition: LShiftU64.c:28
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_STATUS FatInitializeDiskCache(IN FAT_VOLUME *Volume)
Definition: DiskCache.c:649
STATIC VOID SetCacheTagDirty(IN DISK_CACHE *DiskCache, IN CACHE_TAG *CacheTag, IN UINTN Offset, IN UINTN Length)
Definition: DiskCache.c:98
STATIC VOID ClearCacheTagDirtyState(IN CACHE_TAG *CacheTag)
Definition: DiskCache.c:19
EFI_STATUS FatVolumeFlushCache(IN FAT_VOLUME *Volume, IN FAT_TASK *Task)
Definition: DiskCache.c:595
STATIC VOID FatFlushDataCacheRange(IN FAT_VOLUME *Volume, IN IO_MODE IoMode, IN UINTN StartPageNo, IN UINTN EndPageNo, OUT UINT8 *Buffer)
Definition: DiskCache.c:232
STATIC EFI_STATUS FatAccessUnalignedCachePage(IN FAT_VOLUME *Volume, IN CACHE_DATA_TYPE CacheDataType, IN IO_MODE IoMode, IN UINTN PageNo, IN UINTN Offset, IN UINTN Length, IN OUT VOID *Buffer)
Definition: DiskCache.c:426
STATIC VOID SetBitInDirtyBlock(IN UINTN BitNumber, IN DIRTY_BLOCKS *DirtyBlocks)
Definition: DiskCache.c:42
STATIC EFI_STATUS FatGetCachePage(IN FAT_VOLUME *Volume, IN CACHE_DATA_TYPE CacheDataType, IN UINTN PageNo, IN CACHE_TAG *CacheTag)
Definition: DiskCache.c:370
STATIC EFI_STATUS CacheFatDiskIo(IN CACHE_TAG *CacheTag, IN CACHE_DATA_TYPE DataType, IN FAT_VOLUME *Volume, IN IO_MODE IoMode, IN UINT64 Offset, IN UINTN BufferSize, IN OUT VOID *Buffer, IN FAT_TASK *Task)
Definition: DiskCache.c:146
STATIC EFI_STATUS FatExchangeCachePage(IN FAT_VOLUME *Volume, IN CACHE_DATA_TYPE DataType, IN IO_MODE IoMode, IN CACHE_TAG *CacheTag, IN FAT_TASK *Task)
Definition: DiskCache.c:298
STATIC BOOLEAN IsBitInBlockDirty(IN UINTN BitNumber, IN DIRTY_BLOCKS *DirtyBlocks)
Definition: DiskCache.c:71
EFI_STATUS FatAccessCache(IN FAT_VOLUME *Volume, IN CACHE_DATA_TYPE CacheDataType, IN IO_MODE IoMode, IN UINT64 Offset, IN UINTN BufferSize, IN OUT UINT8 *Buffer, IN FAT_TASK *Task)
Definition: DiskCache.c:493
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
EFI_STATUS FatDiskIo(IN FAT_VOLUME *Volume, IN IO_MODE IoMode, IN UINT64 Offset, IN UINTN BufferSize, IN OUT VOID *Buffer, IN FAT_TASK *Task)
Definition: Misc.c:315
#define NULL
Definition: Base.h:319
#define STATIC
Definition: Base.h:264
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define DEBUG(Expression)
Definition: DebugLib.h:434
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
Definition: Fat.h:158
Definition: Fat.h:227