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.
29 ///////////////////////////////////////////////////////////////////////////////////////
33 ///////////////////////////////////////////////////////////////////////////////////////
34 CACHE_DRIVE CacheManagerDrive
;
35 BOOL CacheManagerInitialized
= FALSE
;
36 BOOL CacheManagerDataInvalid
= FALSE
;
37 U32 CacheBlockCount
= 0;
38 U32 CacheSizeLimit
= 0;
39 U32 CacheSizeCurrent
= 0;
41 BOOL
CacheInitializeDrive(U32 DriveNumber
)
43 PCACHE_BLOCK NextCacheBlock
;
44 GEOMETRY DriveGeometry
;
46 // If we already have a cache for this drive then
47 // by all means lets keep it, unless it is a removable
48 // drive, in which case we'll invalidate the cache
49 if ((CacheManagerInitialized
== TRUE
) &&
50 (DriveNumber
== CacheManagerDrive
.DriveNumber
) &&
51 (DriveNumber
>= 0x80) &&
52 (CacheManagerDataInvalid
!= TRUE
))
57 CacheManagerDataInvalid
= FALSE
;
60 // If we have already been initialized then free
63 if (CacheManagerInitialized
)
65 CacheManagerInitialized
= FALSE
;
67 DbgPrint((DPRINT_CACHE
, "CacheBlockCount: %d\n", CacheBlockCount
));
68 DbgPrint((DPRINT_CACHE
, "CacheSizeLimit: %d\n", CacheSizeLimit
));
69 DbgPrint((DPRINT_CACHE
, "CacheSizeCurrent: %d\n", CacheSizeCurrent
));
71 // Loop through and free the cache blocks
73 while (CacheManagerDrive
.CacheBlockHead
!= NULL
)
75 NextCacheBlock
= (PCACHE_BLOCK
)RtlListGetNext((PLIST_ITEM
)CacheManagerDrive
.CacheBlockHead
);
77 MmFreeMemory(CacheManagerDrive
.CacheBlockHead
->BlockData
);
78 MmFreeMemory(CacheManagerDrive
.CacheBlockHead
);
80 CacheManagerDrive
.CacheBlockHead
= NextCacheBlock
;
84 // Initialize the structure
85 RtlZeroMemory(&CacheManagerDrive
, sizeof(CACHE_DRIVE
));
86 CacheManagerDrive
.DriveNumber
= DriveNumber
;
87 if (!MachDiskGetDriveGeometry(DriveNumber
, &DriveGeometry
))
91 CacheManagerDrive
.BytesPerSector
= DriveGeometry
.BytesPerSector
;
93 // Get the number of sectors in each cache block
94 CacheManagerDrive
.BlockSize
= MachDiskGetCacheableBlockCount(DriveNumber
);
97 CacheSizeLimit
= GetSystemMemorySize() / 8;
99 if (CacheSizeLimit
< (64 * 1024))
101 CacheSizeLimit
= (64 * 1024);
104 CacheManagerInitialized
= TRUE
;
106 DbgPrint((DPRINT_CACHE
, "Initializing BIOS drive 0x%x.\n", DriveNumber
));
107 DbgPrint((DPRINT_CACHE
, "BytesPerSector: %d.\n", CacheManagerDrive
.BytesPerSector
));
108 DbgPrint((DPRINT_CACHE
, "BlockSize: %d.\n", CacheManagerDrive
.BlockSize
));
109 DbgPrint((DPRINT_CACHE
, "CacheSizeLimit: %d.\n", CacheSizeLimit
));
114 VOID
CacheInvalidateCacheData(VOID
)
116 CacheManagerDataInvalid
= TRUE
;
119 BOOL
CacheReadDiskSectors(U32 DiskNumber
, U32 StartSector
, U32 SectorCount
, PVOID Buffer
)
121 PCACHE_BLOCK CacheBlock
;
123 U32 SectorOffsetInStartBlock
;
124 U32 CopyLengthInStartBlock
;
126 U32 SectorOffsetInEndBlock
;
130 DbgPrint((DPRINT_CACHE
, "CacheReadDiskSectors() DiskNumber: 0x%x StartSector: %d SectorCount: %d Buffer: 0x%x\n", DiskNumber
, StartSector
, SectorCount
, Buffer
));
132 // If we aren't initialized yet then they can't do this
133 if (CacheManagerInitialized
== FALSE
)
139 // Caculate which blocks we must cache
141 StartBlock
= StartSector
/ CacheManagerDrive
.BlockSize
;
142 SectorOffsetInStartBlock
= StartSector
% CacheManagerDrive
.BlockSize
;
143 CopyLengthInStartBlock
= (SectorCount
> (CacheManagerDrive
.BlockSize
- SectorOffsetInStartBlock
)) ? (CacheManagerDrive
.BlockSize
- SectorOffsetInStartBlock
) : SectorCount
;
144 EndBlock
= (StartSector
+ (SectorCount
- 1)) / CacheManagerDrive
.BlockSize
;
145 SectorOffsetInEndBlock
= (StartSector
+ SectorCount
) % CacheManagerDrive
.BlockSize
;
146 BlockCount
= (EndBlock
- StartBlock
) + 1;
147 DbgPrint((DPRINT_CACHE
, "StartBlock: %d SectorOffsetInStartBlock: %d CopyLengthInStartBlock: %d EndBlock: %d SectorOffsetInEndBlock: %d BlockCount: %d\n", StartBlock
, SectorOffsetInStartBlock
, CopyLengthInStartBlock
, EndBlock
, SectorOffsetInEndBlock
, BlockCount
));
150 // Read the first block into the buffer
155 // Get cache block pointer (this forces the disk sectors into the cache memory)
157 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, StartBlock
);
158 if (CacheBlock
== NULL
)
164 // Copy the portion requested into the buffer
166 RtlCopyMemory(Buffer
,
167 (CacheBlock
->BlockData
+ (SectorOffsetInStartBlock
* CacheManagerDrive
.BytesPerSector
)),
168 (CopyLengthInStartBlock
* CacheManagerDrive
.BytesPerSector
));
169 DbgPrint((DPRINT_CACHE
, "1 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, (CacheBlock
->BlockData
+ (SectorOffsetInStartBlock
* CacheManagerDrive
.BytesPerSector
)), (CopyLengthInStartBlock
* CacheManagerDrive
.BytesPerSector
)));
172 // Update the buffer address
174 Buffer
+= (CopyLengthInStartBlock
* CacheManagerDrive
.BytesPerSector
);
177 // Update the block count
183 // Loop through the middle blocks and read them into the buffer
185 for (Idx
=StartBlock
+1; BlockCount
>1; Idx
++)
188 // Get cache block pointer (this forces the disk sectors into the cache memory)
190 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, Idx
);
191 if (CacheBlock
== NULL
)
197 // Copy the portion requested into the buffer
199 RtlCopyMemory(Buffer
,
200 CacheBlock
->BlockData
,
201 CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
);
202 DbgPrint((DPRINT_CACHE
, "2 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, CacheBlock
->BlockData
, CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
));
205 // Update the buffer address
207 Buffer
+= CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
;
210 // Update the block count
216 // Read the last block into the buffer
221 // Get cache block pointer (this forces the disk sectors into the cache memory)
223 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, EndBlock
);
224 if (CacheBlock
== NULL
)
230 // Copy the portion requested into the buffer
232 RtlCopyMemory(Buffer
,
233 CacheBlock
->BlockData
,
234 SectorOffsetInEndBlock
* CacheManagerDrive
.BytesPerSector
);
235 DbgPrint((DPRINT_CACHE
, "3 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, CacheBlock
->BlockData
, SectorOffsetInEndBlock
* CacheManagerDrive
.BytesPerSector
));
238 // Update the buffer address
240 Buffer
+= SectorOffsetInEndBlock
* CacheManagerDrive
.BytesPerSector
;
243 // Update the block count
251 BOOL
CacheForceDiskSectorsIntoCache(U32 DiskNumber
, U32 StartSector
, U32 SectorCount
)
253 PCACHE_BLOCK CacheBlock
;
259 DbgPrint((DPRINT_CACHE
, "CacheForceDiskSectorsIntoCache() DiskNumber: 0x%x StartSector: %d SectorCount: %d\n", DiskNumber
, StartSector
, SectorCount
));
261 // If we aren't initialized yet then they can't do this
262 if (CacheManagerInitialized
== FALSE
)
268 // Caculate which blocks we must cache
270 StartBlock
= StartSector
/ CacheManagerDrive
.BlockSize
;
271 EndBlock
= (StartSector
+ SectorCount
) / CacheManagerDrive
.BlockSize
;
272 BlockCount
= (EndBlock
- StartBlock
) + 1;
275 // Loop through and cache them
277 for (Idx
=StartBlock
; Idx
<(StartBlock
+BlockCount
); Idx
++)
280 // Get cache block pointer (this forces the disk sectors into the cache memory)
282 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, Idx
);
283 if (CacheBlock
== NULL
)
289 // Lock the sectors into the cache
291 CacheBlock
->LockedInCache
= TRUE
;
297 BOOL
CacheReleaseMemory(U32 MinimumAmountToRelease
)
301 DbgPrint((DPRINT_CACHE
, "CacheReleaseMemory() MinimumAmountToRelease = %d\n", MinimumAmountToRelease
));
303 // If we aren't initialized yet then they can't do this
304 if (CacheManagerInitialized
== FALSE
)
309 // Loop through and try to free the requested amount of memory
310 for (AmountReleased
=0; AmountReleased
<MinimumAmountToRelease
; )
312 // Try to free a block
313 // If this fails then break out of the loop
314 if (!CacheInternalFreeBlock(&CacheManagerDrive
))
319 // It succeeded so increment the amount of memory we have freed
320 AmountReleased
+= CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
;
324 return (AmountReleased
>= MinimumAmountToRelease
);