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
) &&
46 (DriveNumber
== CacheManagerDrive
.DriveNumber
) &&
47 (DriveNumber
>= 0x80) &&
48 (!CacheManagerDataInvalid
))
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
);
95 CacheSizeLimit
= TotalPagesInLookupTable
/ 8 * MM_PAGE_SIZE
;
96 CacheSizeLimit
= min(CacheSizeLimit
, TEMP_HEAP_SIZE
- (128 * 1024));
98 CacheManagerInitialized
= TRUE
;
100 TRACE("Initializing BIOS drive 0x%x.\n", DriveNumber
);
101 TRACE("BytesPerSector: %d.\n", CacheManagerDrive
.BytesPerSector
);
102 TRACE("BlockSize: %d.\n", CacheManagerDrive
.BlockSize
);
103 TRACE("CacheSizeLimit: %d.\n", CacheSizeLimit
);
108 VOID
CacheInvalidateCacheData(VOID
)
110 CacheManagerDataInvalid
= TRUE
;
113 BOOLEAN
CacheReadDiskSectors(UCHAR DiskNumber
, ULONGLONG StartSector
, ULONG SectorCount
, PVOID Buffer
)
115 PCACHE_BLOCK CacheBlock
;
117 ULONG SectorOffsetInStartBlock
;
118 ULONG CopyLengthInStartBlock
;
120 ULONG SectorOffsetInEndBlock
;
124 TRACE("CacheReadDiskSectors() DiskNumber: 0x%x StartSector: %I64d SectorCount: %d Buffer: 0x%x\n", DiskNumber
, StartSector
, SectorCount
, Buffer
);
126 // If we aren't initialized yet then they can't do this
127 if (CacheManagerInitialized
== FALSE
)
133 // Calculate which blocks we must cache
135 StartBlock
= (ULONG
)(StartSector
/ CacheManagerDrive
.BlockSize
);
136 SectorOffsetInStartBlock
= (ULONG
)(StartSector
% CacheManagerDrive
.BlockSize
);
137 CopyLengthInStartBlock
= (ULONG
)((SectorCount
> (CacheManagerDrive
.BlockSize
- SectorOffsetInStartBlock
)) ? (CacheManagerDrive
.BlockSize
- SectorOffsetInStartBlock
) : SectorCount
);
138 EndBlock
= (ULONG
)((StartSector
+ (SectorCount
- 1)) / CacheManagerDrive
.BlockSize
);
139 SectorOffsetInEndBlock
= (ULONG
)(1 + (StartSector
+ (SectorCount
- 1)) % CacheManagerDrive
.BlockSize
);
140 BlockCount
= (EndBlock
- StartBlock
) + 1;
141 TRACE("StartBlock: %d SectorOffsetInStartBlock: %d CopyLengthInStartBlock: %d EndBlock: %d SectorOffsetInEndBlock: %d BlockCount: %d\n", StartBlock
, SectorOffsetInStartBlock
, CopyLengthInStartBlock
, EndBlock
, SectorOffsetInEndBlock
, BlockCount
);
144 // Read the first block into the buffer
149 // Get cache block pointer (this forces the disk sectors into the cache memory)
151 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, StartBlock
);
152 if (CacheBlock
== NULL
)
158 // Copy the portion requested into the buffer
160 RtlCopyMemory(Buffer
,
161 (PVOID
)((ULONG_PTR
)CacheBlock
->BlockData
+ (SectorOffsetInStartBlock
* CacheManagerDrive
.BytesPerSector
)),
162 (CopyLengthInStartBlock
* CacheManagerDrive
.BytesPerSector
));
163 TRACE("1 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, ((ULONG_PTR
)CacheBlock
->BlockData
+ (SectorOffsetInStartBlock
* CacheManagerDrive
.BytesPerSector
)), (CopyLengthInStartBlock
* CacheManagerDrive
.BytesPerSector
));
166 // Update the buffer address
168 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (CopyLengthInStartBlock
* CacheManagerDrive
.BytesPerSector
));
171 // Update the block count
177 // Loop through the middle blocks and read them into the buffer
179 for (Idx
=StartBlock
+1; BlockCount
>1; Idx
++)
182 // Get cache block pointer (this forces the disk sectors into the cache memory)
184 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, Idx
);
185 if (CacheBlock
== NULL
)
191 // Copy the portion requested into the buffer
193 RtlCopyMemory(Buffer
,
194 CacheBlock
->BlockData
,
195 CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
);
196 TRACE("2 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, CacheBlock
->BlockData
, CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
);
199 // Update the buffer address
201 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (CacheManagerDrive
.BlockSize
* CacheManagerDrive
.BytesPerSector
));
204 // Update the block count
210 // Read the last block into the buffer
215 // Get cache block pointer (this forces the disk sectors into the cache memory)
217 CacheBlock
= CacheInternalGetBlockPointer(&CacheManagerDrive
, EndBlock
);
218 if (CacheBlock
== NULL
)
224 // Copy the portion requested into the buffer
226 RtlCopyMemory(Buffer
,
227 CacheBlock
->BlockData
,
228 SectorOffsetInEndBlock
* CacheManagerDrive
.BytesPerSector
);
229 TRACE("3 - RtlCopyMemory(0x%x, 0x%x, %d)\n", Buffer
, CacheBlock
->BlockData
, SectorOffsetInEndBlock
* CacheManagerDrive
.BytesPerSector
);
232 // Update the buffer address
234 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ (SectorOffsetInEndBlock
* CacheManagerDrive
.BytesPerSector
));
237 // Update the block count
246 BOOLEAN
CacheForceDiskSectorsIntoCache(UCHAR DiskNumber
, ULONGLONG StartSector
, ULONG SectorCount
)
248 PCACHE_BLOCK CacheBlock
;
254 TRACE("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 // Calculate 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
;
293 BOOLEAN
CacheReleaseMemory(ULONG MinimumAmountToRelease
)
295 ULONG AmountReleased
;
297 TRACE("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
);