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 ///////////////////////////////////////////////////////////////////////////////////////
29 ///////////////////////////////////////////////////////////////////////////////////////
30 CACHE_DRIVE CacheManagerDrive
;
31 BOOLEAN CacheManagerInitialized
= FALSE
;
32 BOOLEAN CacheManagerDataInvalid
= FALSE
;
33 ULONG CacheBlockCount
= 0;
34 SIZE_T CacheSizeLimit
= 0;
35 SIZE_T CacheSizeCurrent
= 0;
37 BOOLEAN
CacheInitializeDrive(UCHAR DriveNumber
)
39 PCACHE_BLOCK NextCacheBlock
;
40 GEOMETRY DriveGeometry
;
42 // If we already have a cache for this drive then
43 // by all means lets keep it, unless it is a removable
44 // drive, in which case we'll invalidate the cache
45 if ((CacheManagerInitialized
== TRUE
) &&
46 (DriveNumber
== CacheManagerDrive
.DriveNumber
) &&
47 (DriveNumber
>= 0x80) &&
48 (CacheManagerDataInvalid
!= TRUE
))
53 CacheManagerDataInvalid
= FALSE
;
56 // If we have already been initialized then free
59 if (CacheManagerInitialized
)
61 CacheManagerInitialized
= FALSE
;
63 TRACE("CacheBlockCount: %d\n", CacheBlockCount
);
64 TRACE("CacheSizeLimit: %d\n", CacheSizeLimit
);
65 TRACE("CacheSizeCurrent: %d\n", CacheSizeCurrent
);
67 // Loop through and free the cache blocks
69 while (!IsListEmpty(&CacheManagerDrive
.CacheBlockHead
))
71 NextCacheBlock
= CONTAINING_RECORD(RemoveHeadList(&CacheManagerDrive
.CacheBlockHead
),
75 FrLdrTempFree(NextCacheBlock
->BlockData
, TAG_CACHE_DATA
);
76 FrLdrTempFree(NextCacheBlock
, TAG_CACHE_BLOCK
);
80 // Initialize the structure
81 RtlZeroMemory(&CacheManagerDrive
, sizeof(CACHE_DRIVE
));
82 InitializeListHead(&CacheManagerDrive
.CacheBlockHead
);
83 CacheManagerDrive
.DriveNumber
= DriveNumber
;
84 if (!MachDiskGetDriveGeometry(DriveNumber
, &DriveGeometry
))
88 CacheManagerDrive
.BytesPerSector
= DriveGeometry
.BytesPerSector
;
90 // Get the number of sectors in each cache block
91 CacheManagerDrive
.BlockSize
= MachDiskGetCacheableBlockCount(DriveNumber
);
94 CacheSizeLimit
= TotalPagesInLookupTable
/ 8 * MM_PAGE_SIZE
;
96 if (CacheSizeLimit
> TEMP_HEAP_SIZE
- (128 * 1024))
98 CacheSizeLimit
= TEMP_HEAP_SIZE
- (128 * 1024);
101 CacheManagerInitialized
= TRUE
;
103 TRACE("Initializing BIOS drive 0x%x.\n", DriveNumber
);
104 TRACE("BytesPerSector: %d.\n", CacheManagerDrive
.BytesPerSector
);
105 TRACE("BlockSize: %d.\n", CacheManagerDrive
.BlockSize
);
106 TRACE("CacheSizeLimit: %d.\n", CacheSizeLimit
);
111 VOID
CacheInvalidateCacheData(VOID
)
113 CacheManagerDataInvalid
= TRUE
;
116 BOOLEAN
CacheReadDiskSectors(UCHAR DiskNumber
, ULONGLONG StartSector
, ULONG SectorCount
, PVOID Buffer
)
118 PCACHE_BLOCK CacheBlock
;
120 ULONG SectorOffsetInStartBlock
;
121 ULONG CopyLengthInStartBlock
;
123 ULONG SectorOffsetInEndBlock
;
127 TRACE("CacheReadDiskSectors() DiskNumber: 0x%x StartSector: %I64d SectorCount: %d Buffer: 0x%x\n", DiskNumber
, StartSector
, SectorCount
, Buffer
);
129 // If we aren't initialized yet then they can't do this
130 if (CacheManagerInitialized
== FALSE
)
136 // Caculate which blocks we must cache
138 StartBlock
= (ULONG
)(StartSector
/ CacheManagerDrive
.BlockSize
);
139 SectorOffsetInStartBlock
= (ULONG
)(StartSector
% CacheManagerDrive
.BlockSize
);
140 CopyLengthInStartBlock
= (ULONG
)((SectorCount
> (CacheManagerDrive
.BlockSize
- SectorOffsetInStartBlock
)) ? (CacheManagerDrive
.BlockSize
- SectorOffsetInStartBlock
) : SectorCount
);
141 EndBlock
= (ULONG
)((StartSector
+ (SectorCount
- 1)) / CacheManagerDrive
.BlockSize
);
142 SectorOffsetInEndBlock
= (ULONG
)(1 + (StartSector
+ (SectorCount
- 1)) % CacheManagerDrive
.BlockSize
);
143 BlockCount
= (EndBlock
- StartBlock
) + 1;
144 TRACE("StartBlock: %d SectorOffsetInStartBlock: %d CopyLengthInStartBlock: %d EndBlock: %d SectorOffsetInEndBlock: %d BlockCount: %d\n", StartBlock
, SectorOffsetInStartBlock
, CopyLengthInStartBlock
, EndBlock
, SectorOffsetInEndBlock
, BlockCount
);
147 // Read the first block into the buffer
152 // Get cache block pointer (this forces the disk sectors into the cache memory)
154 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, StartBlock
);
155 if (CacheBlock
== NULL
)
161 // Copy the portion requested into the buffer
163 RtlCopyMemory(Buffer
,
164 (PVOID
)((ULONG_PTR
)CacheBlock
->BlockData
+ (SectorOffsetInStartBlock
* CacheManagerDrive
.BytesPerSector
)),
165 (CopyLengthInStartBlock
* CacheManagerDrive
.BytesPerSector
));
166 TRACE("1 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, ((ULONG_PTR
)CacheBlock
->BlockData
+ (SectorOffsetInStartBlock
* CacheManagerDrive
.BytesPerSector
)), (CopyLengthInStartBlock
* CacheManagerDrive
.BytesPerSector
));
169 // Update the buffer address
171 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (CopyLengthInStartBlock
* CacheManagerDrive
.BytesPerSector
));
174 // Update the block count
180 // Loop through the middle blocks and read them into the buffer
182 for (Idx
=StartBlock
+1; BlockCount
>1; Idx
++)
185 // Get cache block pointer (this forces the disk sectors into the cache memory)
187 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, Idx
);
188 if (CacheBlock
== NULL
)
194 // Copy the portion requested into the buffer
196 RtlCopyMemory(Buffer
,
197 CacheBlock
->BlockData
,
198 CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
);
199 TRACE("2 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, CacheBlock
->BlockData
, CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
);
202 // Update the buffer address
204 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
));
207 // Update the block count
213 // Read the last block into the buffer
218 // Get cache block pointer (this forces the disk sectors into the cache memory)
220 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, EndBlock
);
221 if (CacheBlock
== NULL
)
227 // Copy the portion requested into the buffer
229 RtlCopyMemory(Buffer
,
230 CacheBlock
->BlockData
,
231 SectorOffsetInEndBlock
* CacheManagerDrive
.BytesPerSector
);
232 TRACE("3 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, CacheBlock
->BlockData
, SectorOffsetInEndBlock
* CacheManagerDrive
.BytesPerSector
);
235 // Update the buffer address
237 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (SectorOffsetInEndBlock
* CacheManagerDrive
.BytesPerSector
));
240 // Update the block count
249 BOOLEAN
CacheForceDiskSectorsIntoCache(UCHAR DiskNumber
, ULONGLONG StartSector
, ULONG SectorCount
)
251 PCACHE_BLOCK CacheBlock
;
257 TRACE("CacheForceDiskSectorsIntoCache() DiskNumber: 0x%x StartSector: %d SectorCount: %d\n", DiskNumber
, StartSector
, SectorCount
);
259 // If we aren't initialized yet then they can't do this
260 if (CacheManagerInitialized
== FALSE
)
266 // Caculate which blocks we must cache
268 StartBlock
= StartSector
/ CacheManagerDrive
.BlockSize
;
269 EndBlock
= (StartSector
+ SectorCount
) / CacheManagerDrive
.BlockSize
;
270 BlockCount
= (EndBlock
- StartBlock
) + 1;
273 // Loop through and cache them
275 for (Idx
=StartBlock
; Idx
<(StartBlock
+BlockCount
); Idx
++)
278 // Get cache block pointer (this forces the disk sectors into the cache memory)
280 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, Idx
);
281 if (CacheBlock
== NULL
)
287 // Lock the sectors into the cache
289 CacheBlock
->LockedInCache
= TRUE
;
296 BOOLEAN
CacheReleaseMemory(ULONG MinimumAmountToRelease
)
298 ULONG AmountReleased
;
300 TRACE("CacheReleaseMemory() MinimumAmountToRelease = %d\n", MinimumAmountToRelease
);
302 // If we aren't initialized yet then they can't do this
303 if (CacheManagerInitialized
== FALSE
)
308 // Loop through and try to free the requested amount of memory
309 for (AmountReleased
=0; AmountReleased
<MinimumAmountToRelease
; )
311 // Try to free a block
312 // If this fails then break out of the loop
313 if (!CacheInternalFreeBlock(&CacheManagerDrive
))
318 // It succeeded so increment the amount of memory we have freed
319 AmountReleased
+= CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
;
323 return (AmountReleased
>= MinimumAmountToRelease
);