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.
23 ///////////////////////////////////////////////////////////////////////////////////////
27 ///////////////////////////////////////////////////////////////////////////////////////
28 CACHE_DRIVE CacheManagerDrive
;
29 BOOLEAN CacheManagerInitialized
= FALSE
;
30 BOOLEAN CacheManagerDataInvalid
= FALSE
;
31 ULONG CacheBlockCount
= 0;
32 ULONG CacheSizeLimit
= 0;
33 ULONG CacheSizeCurrent
= 0;
35 BOOLEAN
CacheInitializeDrive(ULONG DriveNumber
)
37 PCACHE_BLOCK NextCacheBlock
;
38 GEOMETRY DriveGeometry
;
40 // If we already have a cache for this drive then
41 // by all means lets keep it, unless it is a removable
42 // drive, in which case we'll invalidate the cache
43 if ((CacheManagerInitialized
== TRUE
) &&
44 (DriveNumber
== CacheManagerDrive
.DriveNumber
) &&
45 (DriveNumber
>= 0x80) &&
46 (CacheManagerDataInvalid
!= TRUE
))
51 CacheManagerDataInvalid
= FALSE
;
54 // If we have already been initialized then free
57 if (CacheManagerInitialized
)
59 CacheManagerInitialized
= FALSE
;
61 DbgPrint((DPRINT_CACHE
, "CacheBlockCount: %d\n", CacheBlockCount
));
62 DbgPrint((DPRINT_CACHE
, "CacheSizeLimit: %d\n", CacheSizeLimit
));
63 DbgPrint((DPRINT_CACHE
, "CacheSizeCurrent: %d\n", CacheSizeCurrent
));
65 // Loop through and free the cache blocks
67 while (!IsListEmpty(&CacheManagerDrive
.CacheBlockHead
))
69 NextCacheBlock
= CONTAINING_RECORD(RemoveHeadList(&CacheManagerDrive
.CacheBlockHead
),
73 MmHeapFree(NextCacheBlock
->BlockData
);
74 MmHeapFree(NextCacheBlock
);
78 // Initialize the structure
79 RtlZeroMemory(&CacheManagerDrive
, sizeof(CACHE_DRIVE
));
80 InitializeListHead(&CacheManagerDrive
.CacheBlockHead
);
81 CacheManagerDrive
.DriveNumber
= DriveNumber
;
82 if (!MachDiskGetDriveGeometry(DriveNumber
, &DriveGeometry
))
86 CacheManagerDrive
.BytesPerSector
= DriveGeometry
.BytesPerSector
;
88 // Get the number of sectors in each cache block
89 CacheManagerDrive
.BlockSize
= MachDiskGetCacheableBlockCount(DriveNumber
);
92 CacheSizeLimit
= GetSystemMemorySize() / 8;
94 if (CacheSizeLimit
< (64 * 1024))
96 CacheSizeLimit
= (64 * 1024);
99 CacheManagerInitialized
= TRUE
;
101 DbgPrint((DPRINT_CACHE
, "Initializing BIOS drive 0x%x.\n", DriveNumber
));
102 DbgPrint((DPRINT_CACHE
, "BytesPerSector: %d.\n", CacheManagerDrive
.BytesPerSector
));
103 DbgPrint((DPRINT_CACHE
, "BlockSize: %d.\n", CacheManagerDrive
.BlockSize
));
104 DbgPrint((DPRINT_CACHE
, "CacheSizeLimit: %d.\n", CacheSizeLimit
));
109 VOID
CacheInvalidateCacheData(VOID
)
111 CacheManagerDataInvalid
= TRUE
;
114 BOOLEAN
CacheReadDiskSectors(ULONG DiskNumber
, ULONG StartSector
, ULONG SectorCount
, PVOID Buffer
)
116 PCACHE_BLOCK CacheBlock
;
118 ULONG SectorOffsetInStartBlock
;
119 ULONG CopyLengthInStartBlock
;
121 ULONG SectorOffsetInEndBlock
;
125 DbgPrint((DPRINT_CACHE
, "CacheReadDiskSectors() DiskNumber: 0x%x StartSector: %d SectorCount: %d Buffer: 0x%x\n", DiskNumber
, StartSector
, SectorCount
, Buffer
));
127 // If we aren't initialized yet then they can't do this
128 if (CacheManagerInitialized
== FALSE
)
134 // Caculate which blocks we must cache
136 StartBlock
= StartSector
/ CacheManagerDrive
.BlockSize
;
137 SectorOffsetInStartBlock
= StartSector
% CacheManagerDrive
.BlockSize
;
138 CopyLengthInStartBlock
= (SectorCount
> (CacheManagerDrive
.BlockSize
- SectorOffsetInStartBlock
)) ? (CacheManagerDrive
.BlockSize
- SectorOffsetInStartBlock
) : SectorCount
;
139 EndBlock
= (StartSector
+ (SectorCount
- 1)) / CacheManagerDrive
.BlockSize
;
140 SectorOffsetInEndBlock
= 1 + (StartSector
+ (SectorCount
- 1)) % CacheManagerDrive
.BlockSize
;
141 BlockCount
= (EndBlock
- StartBlock
) + 1;
142 DbgPrint((DPRINT_CACHE
, "StartBlock: %d SectorOffsetInStartBlock: %d CopyLengthInStartBlock: %d EndBlock: %d SectorOffsetInEndBlock: %d BlockCount: %d\n", StartBlock
, SectorOffsetInStartBlock
, CopyLengthInStartBlock
, EndBlock
, SectorOffsetInEndBlock
, BlockCount
));
145 // Read the first block into the buffer
150 // Get cache block pointer (this forces the disk sectors into the cache memory)
152 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, StartBlock
);
153 if (CacheBlock
== NULL
)
159 // Copy the portion requested into the buffer
161 RtlCopyMemory(Buffer
,
162 (PVOID
)((ULONG_PTR
)CacheBlock
->BlockData
+ (SectorOffsetInStartBlock
* CacheManagerDrive
.BytesPerSector
)),
163 (CopyLengthInStartBlock
* CacheManagerDrive
.BytesPerSector
));
164 DbgPrint((DPRINT_CACHE
, "1 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, ((ULONG_PTR
)CacheBlock
->BlockData
+ (SectorOffsetInStartBlock
* CacheManagerDrive
.BytesPerSector
)), (CopyLengthInStartBlock
* CacheManagerDrive
.BytesPerSector
)));
167 // Update the buffer address
169 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (CopyLengthInStartBlock
* CacheManagerDrive
.BytesPerSector
));
172 // Update the block count
178 // Loop through the middle blocks and read them into the buffer
180 for (Idx
=StartBlock
+1; BlockCount
>1; Idx
++)
183 // Get cache block pointer (this forces the disk sectors into the cache memory)
185 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, Idx
);
186 if (CacheBlock
== NULL
)
192 // Copy the portion requested into the buffer
194 RtlCopyMemory(Buffer
,
195 CacheBlock
->BlockData
,
196 CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
);
197 DbgPrint((DPRINT_CACHE
, "2 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, CacheBlock
->BlockData
, CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
));
200 // Update the buffer address
202 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
));
205 // Update the block count
211 // Read the last block into the buffer
216 // Get cache block pointer (this forces the disk sectors into the cache memory)
218 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, EndBlock
);
219 if (CacheBlock
== NULL
)
225 // Copy the portion requested into the buffer
227 RtlCopyMemory(Buffer
,
228 CacheBlock
->BlockData
,
229 SectorOffsetInEndBlock
* CacheManagerDrive
.BytesPerSector
);
230 DbgPrint((DPRINT_CACHE
, "3 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, CacheBlock
->BlockData
, SectorOffsetInEndBlock
* CacheManagerDrive
.BytesPerSector
));
233 // Update the buffer address
235 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (SectorOffsetInEndBlock
* CacheManagerDrive
.BytesPerSector
));
238 // Update the block count
246 BOOLEAN
CacheForceDiskSectorsIntoCache(ULONG DiskNumber
, ULONG StartSector
, ULONG SectorCount
)
248 PCACHE_BLOCK CacheBlock
;
254 DbgPrint((DPRINT_CACHE
, "CacheForceDiskSectorsIntoCache() DiskNumber: 0x%x StartSector: %d SectorCount: %d\n", DiskNumber
, StartSector
, SectorCount
));
256 // If we aren't initialized yet then they can't do this
257 if (CacheManagerInitialized
== FALSE
)
263 // Caculate which blocks we must cache
265 StartBlock
= StartSector
/ CacheManagerDrive
.BlockSize
;
266 EndBlock
= (StartSector
+ SectorCount
) / CacheManagerDrive
.BlockSize
;
267 BlockCount
= (EndBlock
- StartBlock
) + 1;
270 // Loop through and cache them
272 for (Idx
=StartBlock
; Idx
<(StartBlock
+BlockCount
); Idx
++)
275 // Get cache block pointer (this forces the disk sectors into the cache memory)
277 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, Idx
);
278 if (CacheBlock
== NULL
)
284 // Lock the sectors into the cache
286 CacheBlock
->LockedInCache
= TRUE
;
292 BOOLEAN
CacheReleaseMemory(ULONG MinimumAmountToRelease
)
294 ULONG AmountReleased
;
296 DbgPrint((DPRINT_CACHE
, "CacheReleaseMemory() MinimumAmountToRelease = %d\n", MinimumAmountToRelease
));
298 // If we aren't initialized yet then they can't do this
299 if (CacheManagerInitialized
== FALSE
)
304 // Loop through and try to free the requested amount of memory
305 for (AmountReleased
=0; AmountReleased
<MinimumAmountToRelease
; )
307 // Try to free a block
308 // If this fails then break out of the loop
309 if (!CacheInternalFreeBlock(&CacheManagerDrive
))
314 // It succeeded so increment the amount of memory we have freed
315 AmountReleased
+= CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
;
319 return (AmountReleased
>= MinimumAmountToRelease
);