3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 DBG_DEFAULT_CHANNEL(CACHE
);
25 // Returns a pointer to a CACHE_BLOCK structure
26 // Adds the block to the cache manager block list
27 // in cache memory if it isn't already there
28 PCACHE_BLOCK
CacheInternalGetBlockPointer(PCACHE_DRIVE CacheDrive
, ULONG BlockNumber
)
30 PCACHE_BLOCK CacheBlock
= NULL
;
32 TRACE("CacheInternalGetBlockPointer() BlockNumber = %d\n", BlockNumber
);
34 CacheBlock
= CacheInternalFindBlock(CacheDrive
, BlockNumber
);
36 if (CacheBlock
!= NULL
)
38 TRACE("Cache hit! BlockNumber: %d CacheBlock->BlockNumber: %d\n", BlockNumber
, CacheBlock
->BlockNumber
);
43 TRACE("Cache miss! BlockNumber: %d\n", BlockNumber
);
45 CacheBlock
= CacheInternalAddBlockToCache(CacheDrive
, BlockNumber
);
47 // Optimize the block list so it has a LRU structure
48 CacheInternalOptimizeBlockList(CacheDrive
, CacheBlock
);
53 PCACHE_BLOCK
CacheInternalFindBlock(PCACHE_DRIVE CacheDrive
, ULONG BlockNumber
)
55 PCACHE_BLOCK CacheBlock
= NULL
;
57 TRACE("CacheInternalFindBlock() BlockNumber = %d\n", BlockNumber
);
60 // Make sure the block list has entries before I start searching it.
62 if (!IsListEmpty(&CacheDrive
->CacheBlockHead
))
65 // Search the list and find the BIOS drive number
67 CacheBlock
= CONTAINING_RECORD(CacheDrive
->CacheBlockHead
.Flink
, CACHE_BLOCK
, ListEntry
);
69 while (&CacheBlock
->ListEntry
!= &CacheDrive
->CacheBlockHead
)
72 // We found the block, so return it
74 if (CacheBlock
->BlockNumber
== BlockNumber
)
77 // Increment the blocks access count
79 CacheBlock
->AccessCount
++;
84 CacheBlock
= CONTAINING_RECORD(CacheBlock
->ListEntry
.Flink
, CACHE_BLOCK
, ListEntry
);
91 PCACHE_BLOCK
CacheInternalAddBlockToCache(PCACHE_DRIVE CacheDrive
, ULONG BlockNumber
)
93 PCACHE_BLOCK CacheBlock
= NULL
;
95 TRACE("CacheInternalAddBlockToCache() BlockNumber = %d\n", BlockNumber
);
97 // Check the size of the cache so we don't exceed our limits
98 CacheInternalCheckCacheSizeLimits(CacheDrive
);
100 // We will need to add the block to the
101 // drive's list of cached blocks. So allocate
103 CacheBlock
= FrLdrTempAlloc(sizeof(CACHE_BLOCK
), TAG_CACHE_BLOCK
);
104 if (CacheBlock
== NULL
)
109 // Now initialize the structure and
110 // allocate room for the block data
111 RtlZeroMemory(CacheBlock
, sizeof(CACHE_BLOCK
));
112 CacheBlock
->BlockNumber
= BlockNumber
;
113 CacheBlock
->BlockData
= FrLdrTempAlloc(CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
,
115 if (CacheBlock
->BlockData
==NULL
)
117 FrLdrTempFree(CacheBlock
, TAG_CACHE_BLOCK
);
121 // Now try to read in the block
122 if (!MachDiskReadLogicalSectors(CacheDrive
->DriveNumber
, (BlockNumber
* CacheDrive
->BlockSize
), CacheDrive
->BlockSize
, (PVOID
)DISKREADBUFFER
))
124 FrLdrTempFree(CacheBlock
->BlockData
, TAG_CACHE_DATA
);
125 FrLdrTempFree(CacheBlock
, TAG_CACHE_BLOCK
);
128 RtlCopyMemory(CacheBlock
->BlockData
, (PVOID
)DISKREADBUFFER
, CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
130 // Add it to our list of blocks managed by the cache
131 InsertTailList(&CacheDrive
->CacheBlockHead
, &CacheBlock
->ListEntry
);
133 // Update the cache data
135 CacheSizeCurrent
= CacheBlockCount
* (CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
137 CacheInternalDumpBlockList(CacheDrive
);
142 BOOLEAN
CacheInternalFreeBlock(PCACHE_DRIVE CacheDrive
)
144 PCACHE_BLOCK CacheBlockToFree
;
146 TRACE("CacheInternalFreeBlock()\n");
148 // Get a pointer to the last item in the block list
149 // that isn't forced to be in the cache and remove
151 CacheBlockToFree
= CONTAINING_RECORD(CacheDrive
->CacheBlockHead
.Blink
, CACHE_BLOCK
, ListEntry
);
152 while (&CacheBlockToFree
->ListEntry
!= &CacheDrive
->CacheBlockHead
&& CacheBlockToFree
->LockedInCache
== TRUE
)
154 CacheBlockToFree
= CONTAINING_RECORD(CacheBlockToFree
->ListEntry
.Blink
, CACHE_BLOCK
, ListEntry
);
157 // No blocks left in cache that can be freed
159 if (IsListEmpty(&CacheDrive
->CacheBlockHead
))
164 RemoveEntryList(&CacheBlockToFree
->ListEntry
);
166 // Free the block memory and the block structure
167 FrLdrTempFree(CacheBlockToFree
->BlockData
, TAG_CACHE_DATA
);
168 FrLdrTempFree(CacheBlockToFree
, TAG_CACHE_BLOCK
);
170 // Update the cache data
172 CacheSizeCurrent
= CacheBlockCount
* (CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
177 VOID
CacheInternalCheckCacheSizeLimits(PCACHE_DRIVE CacheDrive
)
181 TRACE("CacheInternalCheckCacheSizeLimits()\n");
183 // Calculate the size of the cache if we added a block
184 NewCacheSize
= (CacheBlockCount
+ 1) * (CacheDrive
->BlockSize
* CacheDrive
->BytesPerSector
);
186 // Check the new size against the cache size limit
187 if (NewCacheSize
> CacheSizeLimit
)
189 CacheInternalFreeBlock(CacheDrive
);
190 CacheInternalDumpBlockList(CacheDrive
);
194 VOID
CacheInternalDumpBlockList(PCACHE_DRIVE CacheDrive
)
196 PCACHE_BLOCK CacheBlock
;
198 TRACE("Dumping block list for BIOS drive 0x%x.\n", CacheDrive
->DriveNumber
);
199 TRACE("BytesPerSector: %d.\n", CacheDrive
->BytesPerSector
);
200 TRACE("BlockSize: %d.\n", CacheDrive
->BlockSize
);
201 TRACE("CacheSizeLimit: %d.\n", CacheSizeLimit
);
202 TRACE("CacheSizeCurrent: %d.\n", CacheSizeCurrent
);
203 TRACE("CacheBlockCount: %d.\n", CacheBlockCount
);
205 CacheBlock
= CONTAINING_RECORD(CacheDrive
->CacheBlockHead
.Flink
, CACHE_BLOCK
, ListEntry
);
206 while (&CacheBlock
->ListEntry
!= &CacheDrive
->CacheBlockHead
)
208 TRACE("Cache Block: CacheBlock: 0x%x\n", CacheBlock
);
209 TRACE("Cache Block: Block Number: %d\n", CacheBlock
->BlockNumber
);
210 TRACE("Cache Block: Access Count: %d\n", CacheBlock
->AccessCount
);
211 TRACE("Cache Block: Block Data: 0x%x\n", CacheBlock
->BlockData
);
212 TRACE("Cache Block: Locked In Cache: %d\n", CacheBlock
->LockedInCache
);
214 if (CacheBlock
->BlockData
== NULL
)
216 BugCheck("CacheBlock->BlockData == NULL\n");
219 CacheBlock
= CONTAINING_RECORD(CacheBlock
->ListEntry
.Flink
, CACHE_BLOCK
, ListEntry
);
223 VOID
CacheInternalOptimizeBlockList(PCACHE_DRIVE CacheDrive
, PCACHE_BLOCK CacheBlock
)
226 TRACE("CacheInternalOptimizeBlockList()\n");
228 // Don't do this if this block is already at the head of the list
229 if (&CacheBlock
->ListEntry
!= CacheDrive
->CacheBlockHead
.Flink
)
231 // Remove this item from the block list
232 RemoveEntryList(&CacheBlock
->ListEntry
);
234 // Re-insert it at the head of the list
235 InsertHeadList(&CacheDrive
->CacheBlockHead
, &CacheBlock
->ListEntry
);