3 * Copyright (C) 1998-2002 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.
28 ///////////////////////////////////////////////////////////////////////////////////////
32 ///////////////////////////////////////////////////////////////////////////////////////
33 CACHE_DRIVE CacheManagerDrive
;
34 BOOL CacheManagerInitialized
= FALSE
;
35 BOOL CacheManagerDataInvalid
= FALSE
;
36 ULONG CacheBlockCount
= 0;
37 ULONG CacheSizeLimit
= 0;
38 ULONG CacheSizeCurrent
= 0;
40 BOOL
CacheInitializeDrive(ULONG DriveNumber
)
42 PCACHE_BLOCK NextCacheBlock
;
44 // If we already have a cache for this drive then
45 // by all means lets keep it, unless it is a removable
46 // drive, in which case we'll invalidate the cache
47 if ((CacheManagerInitialized
== TRUE
) &&
48 (DriveNumber
== CacheManagerDrive
.DriveNumber
) &&
49 (DriveNumber
>= 0x80) &&
50 (CacheManagerDataInvalid
!= TRUE
))
55 CacheManagerDataInvalid
= FALSE
;
58 // If we have already been initialized then free
61 if (CacheManagerInitialized
)
63 CacheManagerInitialized
= FALSE
;
65 DbgPrint((DPRINT_CACHE
, "CacheBlockCount: %d\n", CacheBlockCount
));
66 DbgPrint((DPRINT_CACHE
, "CacheSizeLimit: %d\n", CacheSizeLimit
));
67 DbgPrint((DPRINT_CACHE
, "CacheSizeCurrent: %d\n", CacheSizeCurrent
));
69 // Loop through and free the cache blocks
71 while (CacheManagerDrive
.CacheBlockHead
!= NULL
)
73 NextCacheBlock
= (PCACHE_BLOCK
)RtlListGetNext((PLIST_ITEM
)CacheManagerDrive
.CacheBlockHead
);
75 MmFreeMemory(CacheManagerDrive
.CacheBlockHead
->BlockData
);
76 MmFreeMemory(CacheManagerDrive
.CacheBlockHead
);
78 CacheManagerDrive
.CacheBlockHead
= NextCacheBlock
;
82 // Initialize the structure
83 RtlZeroMemory(&CacheManagerDrive
, sizeof(CACHE_DRIVE
));
84 CacheManagerDrive
.DriveNumber
= DriveNumber
;
85 CacheManagerDrive
.LbaSupported
= BiosInt13ExtensionsSupported(DriveNumber
);
86 if (!DiskGetDriveGeometry(DriveNumber
, &CacheManagerDrive
.DriveGeometry
))
91 // If LBA is supported then the block size will be 128 sectors (64k)
92 // If not then the block size is the size of one track
93 if (CacheManagerDrive
.LbaSupported
)
95 // FIXME: Temporarily reduced this to
96 // 64 sectors since not all BIOS calls
97 // support reading as many as 128 sectors
98 CacheManagerDrive
.BlockSize
= 64;//128;
102 CacheManagerDrive
.BlockSize
= CacheManagerDrive
.DriveGeometry
.Sectors
;
106 CacheSizeLimit
= GetSystemMemorySize() / 8;
107 CacheSizeCurrent
= 0;
108 if (CacheSizeLimit
< (64 * 1024))
110 CacheSizeLimit
= (64 * 1024);
113 CacheManagerInitialized
= TRUE
;
115 DbgPrint((DPRINT_CACHE
, "Initializing BIOS drive 0x%x.\n", DriveNumber
));
116 DbgPrint((DPRINT_CACHE
, "LbaSupported = %s.\n", CacheManagerDrive
.LbaSupported
? "TRUE" : "FALSE"));
117 DbgPrint((DPRINT_CACHE
, "Cylinders: %d.\n", CacheManagerDrive
.DriveGeometry
.Cylinders
));
118 DbgPrint((DPRINT_CACHE
, "Heads: %d.\n", CacheManagerDrive
.DriveGeometry
.Heads
));
119 DbgPrint((DPRINT_CACHE
, "Sectors: %d.\n", CacheManagerDrive
.DriveGeometry
.Sectors
));
120 DbgPrint((DPRINT_CACHE
, "BytesPerSector: %d.\n", CacheManagerDrive
.DriveGeometry
.BytesPerSector
));
121 DbgPrint((DPRINT_CACHE
, "BlockSize: %d.\n", CacheManagerDrive
.BlockSize
));
122 DbgPrint((DPRINT_CACHE
, "CacheSizeLimit: %d.\n", CacheSizeLimit
));
127 VOID
CacheInvalidateCacheData(VOID
)
129 CacheManagerDataInvalid
= TRUE
;
132 BOOL
CacheReadDiskSectors(ULONG DiskNumber
, ULONG StartSector
, ULONG SectorCount
, PVOID Buffer
)
134 PCACHE_BLOCK CacheBlock
;
136 ULONG SectorOffsetInStartBlock
;
137 ULONG CopyLengthInStartBlock
;
139 ULONG SectorOffsetInEndBlock
;
143 DbgPrint((DPRINT_CACHE
, "CacheReadDiskSectors() DiskNumber: 0x%x StartSector: %d SectorCount: %d Buffer: 0x%x\n", DiskNumber
, StartSector
, SectorCount
, Buffer
));
145 // If we aren't initialized yet then they can't do this
146 if (CacheManagerInitialized
== FALSE
)
152 // Caculate which blocks we must cache
154 StartBlock
= StartSector
/ CacheManagerDrive
.BlockSize
;
155 SectorOffsetInStartBlock
= StartSector
% CacheManagerDrive
.BlockSize
;
156 CopyLengthInStartBlock
= (SectorCount
> (CacheManagerDrive
.BlockSize
- SectorOffsetInStartBlock
)) ? (CacheManagerDrive
.BlockSize
- SectorOffsetInStartBlock
) : SectorCount
;
157 EndBlock
= (StartSector
+ (SectorCount
- 1)) / CacheManagerDrive
.BlockSize
;
158 SectorOffsetInEndBlock
= (StartSector
+ SectorCount
) % CacheManagerDrive
.BlockSize
;
159 BlockCount
= (EndBlock
- StartBlock
) + 1;
160 DbgPrint((DPRINT_CACHE
, "StartBlock: %d SectorOffsetInStartBlock: %d CopyLengthInStartBlock: %d EndBlock: %d SectorOffsetInEndBlock: %d BlockCount: %d\n", StartBlock
, SectorOffsetInStartBlock
, CopyLengthInStartBlock
, EndBlock
, SectorOffsetInEndBlock
, BlockCount
));
163 // Read the first block into the buffer
168 // Get cache block pointer (this forces the disk sectors into the cache memory)
170 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, StartBlock
);
171 if (CacheBlock
== NULL
)
177 // Copy the portion requested into the buffer
179 RtlCopyMemory(Buffer
,
180 (CacheBlock
->BlockData
+ (SectorOffsetInStartBlock
* CacheManagerDrive
.DriveGeometry
.BytesPerSector
)),
181 (CopyLengthInStartBlock
* CacheManagerDrive
.DriveGeometry
.BytesPerSector
));
182 DbgPrint((DPRINT_CACHE
, "1 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, (CacheBlock
->BlockData
+ (SectorOffsetInStartBlock
* CacheManagerDrive
.DriveGeometry
.BytesPerSector
)), (CopyLengthInStartBlock
* CacheManagerDrive
.DriveGeometry
.BytesPerSector
)));
185 // Update the buffer address
187 Buffer
+= (CopyLengthInStartBlock
* CacheManagerDrive
.DriveGeometry
.BytesPerSector
);
190 // Update the block count
196 // Loop through the middle blocks and read them into the buffer
198 for (Idx
=StartBlock
+1; BlockCount
>1; Idx
++)
201 // Get cache block pointer (this forces the disk sectors into the cache memory)
203 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, Idx
);
204 if (CacheBlock
== NULL
)
210 // Copy the portion requested into the buffer
212 RtlCopyMemory(Buffer
,
213 CacheBlock
->BlockData
,
214 CacheManagerDrive
.BlockSize
* CacheManagerDrive
.DriveGeometry
.BytesPerSector
);
215 DbgPrint((DPRINT_CACHE
, "2 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, CacheBlock
->BlockData
, CacheManagerDrive
.BlockSize
* CacheManagerDrive
.DriveGeometry
.BytesPerSector
));
218 // Update the buffer address
220 Buffer
+= CacheManagerDrive
.BlockSize
* CacheManagerDrive
.DriveGeometry
.BytesPerSector
;
223 // Update the block count
229 // Read the last block into the buffer
234 // Get cache block pointer (this forces the disk sectors into the cache memory)
236 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, EndBlock
);
237 if (CacheBlock
== NULL
)
243 // Copy the portion requested into the buffer
245 RtlCopyMemory(Buffer
,
246 CacheBlock
->BlockData
,
247 SectorOffsetInEndBlock
* CacheManagerDrive
.DriveGeometry
.BytesPerSector
);
248 DbgPrint((DPRINT_CACHE
, "3 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, CacheBlock
->BlockData
, SectorOffsetInEndBlock
* CacheManagerDrive
.DriveGeometry
.BytesPerSector
));
251 // Update the buffer address
253 Buffer
+= SectorOffsetInEndBlock
* CacheManagerDrive
.DriveGeometry
.BytesPerSector
;
256 // Update the block count
264 BOOL
CacheForceDiskSectorsIntoCache(ULONG DiskNumber
, ULONG StartSector
, ULONG SectorCount
)
266 PCACHE_BLOCK CacheBlock
;
272 DbgPrint((DPRINT_CACHE
, "CacheForceDiskSectorsIntoCache() DiskNumber: 0x%x StartSector: %d SectorCount: %d\n", DiskNumber
, StartSector
, SectorCount
));
274 // If we aren't initialized yet then they can't do this
275 if (CacheManagerInitialized
== FALSE
)
281 // Caculate which blocks we must cache
283 StartBlock
= StartSector
/ CacheManagerDrive
.BlockSize
;
284 EndBlock
= (StartSector
+ SectorCount
) / CacheManagerDrive
.BlockSize
;
285 BlockCount
= (EndBlock
- StartBlock
) + 1;
288 // Loop through and cache them
290 for (Idx
=StartBlock
; Idx
<(StartBlock
+BlockCount
); Idx
++)
293 // Get cache block pointer (this forces the disk sectors into the cache memory)
295 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, Idx
);
296 if (CacheBlock
== NULL
)
302 // Lock the sectors into the cache
304 CacheBlock
->LockedInCache
= TRUE
;
310 BOOL
CacheReleaseMemory(ULONG MinimumAmountToRelease
)
312 ULONG AmountReleased
;
314 DbgPrint((DPRINT_CACHE
, "CacheReleaseMemory() MinimumAmountToRelease = %d\n", MinimumAmountToRelease
));
316 // If we aren't initialized yet then they can't do this
317 if (CacheManagerInitialized
== FALSE
)
322 // Loop through and try to free the requested amount of memory
323 for (AmountReleased
=0; AmountReleased
<MinimumAmountToRelease
; )
325 // Try to free a block
326 // If this fails then break out of the loop
327 if (!CacheInternalFreeBlock(&CacheManagerDrive
))
332 // It succeeded so increment the amount of memory we have freed
333 AmountReleased
+= CacheManagerDrive
.BlockSize
* CacheManagerDrive
.DriveGeometry
.BytesPerSector
;
337 return (AmountReleased
>= MinimumAmountToRelease
);