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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 ///////////////////////////////////////////////////////////////////////////////////////
29 ///////////////////////////////////////////////////////////////////////////////////////
30 CACHE_DRIVE CacheManagerDrive
;
31 BOOLEAN CacheManagerInitialized
= FALSE
;
32 BOOLEAN CacheManagerDataInvalid
= FALSE
;
33 ULONG CacheBlockCount
= 0;
34 ULONG CacheSizeLimit
= 0;
35 ULONG CacheSizeCurrent
= 0;
37 BOOLEAN
CacheInitializeDrive(ULONG 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 DbgPrint((DPRINT_CACHE
, "CacheBlockCount: %d\n", CacheBlockCount
));
64 DbgPrint((DPRINT_CACHE
, "CacheSizeLimit: %d\n", CacheSizeLimit
));
65 DbgPrint((DPRINT_CACHE
, "CacheSizeCurrent: %d\n", CacheSizeCurrent
));
67 // Loop through and free the cache blocks
69 while (CacheManagerDrive
.CacheBlockHead
!= NULL
)
71 NextCacheBlock
= (PCACHE_BLOCK
)RtlListGetNext((PLIST_ITEM
)CacheManagerDrive
.CacheBlockHead
);
73 MmFreeMemory(CacheManagerDrive
.CacheBlockHead
->BlockData
);
74 MmFreeMemory(CacheManagerDrive
.CacheBlockHead
);
76 CacheManagerDrive
.CacheBlockHead
= NextCacheBlock
;
80 // Initialize the structure
81 RtlZeroMemory(&CacheManagerDrive
, sizeof(CACHE_DRIVE
));
82 CacheManagerDrive
.DriveNumber
= DriveNumber
;
83 if (!MachDiskGetDriveGeometry(DriveNumber
, &DriveGeometry
))
87 CacheManagerDrive
.BytesPerSector
= DriveGeometry
.BytesPerSector
;
89 // Get the number of sectors in each cache block
90 CacheManagerDrive
.BlockSize
= MachDiskGetCacheableBlockCount(DriveNumber
);
93 CacheSizeLimit
= GetSystemMemorySize() / 8;
95 if (CacheSizeLimit
< (64 * 1024))
97 CacheSizeLimit
= (64 * 1024);
100 CacheManagerInitialized
= TRUE
;
102 DbgPrint((DPRINT_CACHE
, "Initializing BIOS drive 0x%x.\n", DriveNumber
));
103 DbgPrint((DPRINT_CACHE
, "BytesPerSector: %d.\n", CacheManagerDrive
.BytesPerSector
));
104 DbgPrint((DPRINT_CACHE
, "BlockSize: %d.\n", CacheManagerDrive
.BlockSize
));
105 DbgPrint((DPRINT_CACHE
, "CacheSizeLimit: %d.\n", CacheSizeLimit
));
110 VOID
CacheInvalidateCacheData(VOID
)
112 CacheManagerDataInvalid
= TRUE
;
115 BOOLEAN
CacheReadDiskSectors(ULONG DiskNumber
, ULONG StartSector
, ULONG SectorCount
, PVOID Buffer
)
117 PCACHE_BLOCK CacheBlock
;
119 ULONG SectorOffsetInStartBlock
;
120 ULONG CopyLengthInStartBlock
;
122 ULONG SectorOffsetInEndBlock
;
126 DbgPrint((DPRINT_CACHE
, "CacheReadDiskSectors() DiskNumber: 0x%x StartSector: %d SectorCount: %d Buffer: 0x%x\n", DiskNumber
, StartSector
, SectorCount
, Buffer
));
128 // If we aren't initialized yet then they can't do this
129 if (CacheManagerInitialized
== FALSE
)
135 // Caculate which blocks we must cache
137 StartBlock
= StartSector
/ CacheManagerDrive
.BlockSize
;
138 SectorOffsetInStartBlock
= StartSector
% CacheManagerDrive
.BlockSize
;
139 CopyLengthInStartBlock
= (SectorCount
> (CacheManagerDrive
.BlockSize
- SectorOffsetInStartBlock
)) ? (CacheManagerDrive
.BlockSize
- SectorOffsetInStartBlock
) : SectorCount
;
140 EndBlock
= (StartSector
+ (SectorCount
- 1)) / CacheManagerDrive
.BlockSize
;
141 SectorOffsetInEndBlock
= 1 + (StartSector
+ (SectorCount
- 1)) % CacheManagerDrive
.BlockSize
;
142 BlockCount
= (EndBlock
- StartBlock
) + 1;
143 DbgPrint((DPRINT_CACHE
, "StartBlock: %d SectorOffsetInStartBlock: %d CopyLengthInStartBlock: %d EndBlock: %d SectorOffsetInEndBlock: %d BlockCount: %d\n", StartBlock
, SectorOffsetInStartBlock
, CopyLengthInStartBlock
, EndBlock
, SectorOffsetInEndBlock
, BlockCount
));
146 // Read the first block into the buffer
151 // Get cache block pointer (this forces the disk sectors into the cache memory)
153 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, StartBlock
);
154 if (CacheBlock
== NULL
)
160 // Copy the portion requested into the buffer
162 RtlCopyMemory(Buffer
,
163 (PVOID
)((ULONG_PTR
)CacheBlock
->BlockData
+ (SectorOffsetInStartBlock
* CacheManagerDrive
.BytesPerSector
)),
164 (CopyLengthInStartBlock
* CacheManagerDrive
.BytesPerSector
));
165 DbgPrint((DPRINT_CACHE
, "1 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, ((ULONG_PTR
)CacheBlock
->BlockData
+ (SectorOffsetInStartBlock
* CacheManagerDrive
.BytesPerSector
)), (CopyLengthInStartBlock
* CacheManagerDrive
.BytesPerSector
)));
168 // Update the buffer address
170 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (CopyLengthInStartBlock
* CacheManagerDrive
.BytesPerSector
));
173 // Update the block count
179 // Loop through the middle blocks and read them into the buffer
181 for (Idx
=StartBlock
+1; BlockCount
>1; Idx
++)
184 // Get cache block pointer (this forces the disk sectors into the cache memory)
186 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, Idx
);
187 if (CacheBlock
== NULL
)
193 // Copy the portion requested into the buffer
195 RtlCopyMemory(Buffer
,
196 CacheBlock
->BlockData
,
197 CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
);
198 DbgPrint((DPRINT_CACHE
, "2 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, CacheBlock
->BlockData
, CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
));
201 // Update the buffer address
203 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
));
206 // Update the block count
212 // Read the last block into the buffer
217 // Get cache block pointer (this forces the disk sectors into the cache memory)
219 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, EndBlock
);
220 if (CacheBlock
== NULL
)
226 // Copy the portion requested into the buffer
228 RtlCopyMemory(Buffer
,
229 CacheBlock
->BlockData
,
230 SectorOffsetInEndBlock
* CacheManagerDrive
.BytesPerSector
);
231 DbgPrint((DPRINT_CACHE
, "3 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, CacheBlock
->BlockData
, SectorOffsetInEndBlock
* CacheManagerDrive
.BytesPerSector
));
234 // Update the buffer address
236 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (SectorOffsetInEndBlock
* CacheManagerDrive
.BytesPerSector
));
239 // Update the block count
247 BOOLEAN
CacheForceDiskSectorsIntoCache(ULONG DiskNumber
, ULONG StartSector
, ULONG SectorCount
)
249 PCACHE_BLOCK CacheBlock
;
255 DbgPrint((DPRINT_CACHE
, "CacheForceDiskSectorsIntoCache() DiskNumber: 0x%x StartSector: %d SectorCount: %d\n", DiskNumber
, StartSector
, SectorCount
));
257 // If we aren't initialized yet then they can't do this
258 if (CacheManagerInitialized
== FALSE
)
264 // Caculate which blocks we must cache
266 StartBlock
= StartSector
/ CacheManagerDrive
.BlockSize
;
267 EndBlock
= (StartSector
+ SectorCount
) / CacheManagerDrive
.BlockSize
;
268 BlockCount
= (EndBlock
- StartBlock
) + 1;
271 // Loop through and cache them
273 for (Idx
=StartBlock
; Idx
<(StartBlock
+BlockCount
); Idx
++)
276 // Get cache block pointer (this forces the disk sectors into the cache memory)
278 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, Idx
);
279 if (CacheBlock
== NULL
)
285 // Lock the sectors into the cache
287 CacheBlock
->LockedInCache
= TRUE
;
293 BOOLEAN
CacheReleaseMemory(ULONG MinimumAmountToRelease
)
295 ULONG AmountReleased
;
297 DbgPrint((DPRINT_CACHE
, "CacheReleaseMemory() MinimumAmountToRelease = %d\n", MinimumAmountToRelease
));
299 // If we aren't initialized yet then they can't do this
300 if (CacheManagerInitialized
== FALSE
)
305 // Loop through and try to free the requested amount of memory
306 for (AmountReleased
=0; AmountReleased
<MinimumAmountToRelease
; )
308 // Try to free a block
309 // If this fails then break out of the loop
310 if (!CacheInternalFreeBlock(&CacheManagerDrive
))
315 // It succeeded so increment the amount of memory we have freed
316 AmountReleased
+= CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
;
320 return (AmountReleased
>= MinimumAmountToRelease
);