Move freeldr to reactos\boot\freeldr.
[reactos.git] / reactos / boot / freeldr / freeldr / cache / cache.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
4 *
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.
9 *
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.
14 *
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.
18 */
19
20
21 #include <freeldr.h>
22 #include "cm.h"
23 #include <mm.h>
24 #include <disk.h>
25 #include <machine.h>
26 #include <rtl.h>
27 #include <debug.h>
28
29 ///////////////////////////////////////////////////////////////////////////////////////
30 //
31 // Internal data
32 //
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;
40
41 BOOL CacheInitializeDrive(U32 DriveNumber)
42 {
43 PCACHE_BLOCK NextCacheBlock;
44 GEOMETRY DriveGeometry;
45
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))
53 {
54 return TRUE;
55 }
56
57 CacheManagerDataInvalid = FALSE;
58
59 //
60 // If we have already been initialized then free
61 // the old data
62 //
63 if (CacheManagerInitialized)
64 {
65 CacheManagerInitialized = FALSE;
66
67 DbgPrint((DPRINT_CACHE, "CacheBlockCount: %d\n", CacheBlockCount));
68 DbgPrint((DPRINT_CACHE, "CacheSizeLimit: %d\n", CacheSizeLimit));
69 DbgPrint((DPRINT_CACHE, "CacheSizeCurrent: %d\n", CacheSizeCurrent));
70 //
71 // Loop through and free the cache blocks
72 //
73 while (CacheManagerDrive.CacheBlockHead != NULL)
74 {
75 NextCacheBlock = (PCACHE_BLOCK)RtlListGetNext((PLIST_ITEM)CacheManagerDrive.CacheBlockHead);
76
77 MmFreeMemory(CacheManagerDrive.CacheBlockHead->BlockData);
78 MmFreeMemory(CacheManagerDrive.CacheBlockHead);
79
80 CacheManagerDrive.CacheBlockHead = NextCacheBlock;
81 }
82 }
83
84 // Initialize the structure
85 RtlZeroMemory(&CacheManagerDrive, sizeof(CACHE_DRIVE));
86 CacheManagerDrive.DriveNumber = DriveNumber;
87 if (!MachDiskGetDriveGeometry(DriveNumber, &DriveGeometry))
88 {
89 return FALSE;
90 }
91 CacheManagerDrive.BytesPerSector = DriveGeometry.BytesPerSector;
92
93 // Get the number of sectors in each cache block
94 CacheManagerDrive.BlockSize = MachDiskGetCacheableBlockCount(DriveNumber);
95
96 CacheBlockCount = 0;
97 CacheSizeLimit = GetSystemMemorySize() / 8;
98 CacheSizeCurrent = 0;
99 if (CacheSizeLimit < (64 * 1024))
100 {
101 CacheSizeLimit = (64 * 1024);
102 }
103
104 CacheManagerInitialized = TRUE;
105
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));
110
111 return TRUE;
112 }
113
114 VOID CacheInvalidateCacheData(VOID)
115 {
116 CacheManagerDataInvalid = TRUE;
117 }
118
119 BOOL CacheReadDiskSectors(U32 DiskNumber, U32 StartSector, U32 SectorCount, PVOID Buffer)
120 {
121 PCACHE_BLOCK CacheBlock;
122 U32 StartBlock;
123 U32 SectorOffsetInStartBlock;
124 U32 CopyLengthInStartBlock;
125 U32 EndBlock;
126 U32 SectorOffsetInEndBlock;
127 U32 BlockCount;
128 U32 Idx;
129
130 DbgPrint((DPRINT_CACHE, "CacheReadDiskSectors() DiskNumber: 0x%x StartSector: %d SectorCount: %d Buffer: 0x%x\n", DiskNumber, StartSector, SectorCount, Buffer));
131
132 // If we aren't initialized yet then they can't do this
133 if (CacheManagerInitialized == FALSE)
134 {
135 return FALSE;
136 }
137
138 //
139 // Caculate which blocks we must cache
140 //
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));
148
149 //
150 // Read the first block into the buffer
151 //
152 if (BlockCount > 0)
153 {
154 //
155 // Get cache block pointer (this forces the disk sectors into the cache memory)
156 //
157 CacheBlock = CacheInternalGetBlockPointer(&CacheManagerDrive, StartBlock);
158 if (CacheBlock == NULL)
159 {
160 return FALSE;
161 }
162
163 //
164 // Copy the portion requested into the buffer
165 //
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)));
170
171 //
172 // Update the buffer address
173 //
174 Buffer += (CopyLengthInStartBlock * CacheManagerDrive.BytesPerSector);
175
176 //
177 // Update the block count
178 //
179 BlockCount--;
180 }
181
182 //
183 // Loop through the middle blocks and read them into the buffer
184 //
185 for (Idx=StartBlock+1; BlockCount>1; Idx++)
186 {
187 //
188 // Get cache block pointer (this forces the disk sectors into the cache memory)
189 //
190 CacheBlock = CacheInternalGetBlockPointer(&CacheManagerDrive, Idx);
191 if (CacheBlock == NULL)
192 {
193 return FALSE;
194 }
195
196 //
197 // Copy the portion requested into the buffer
198 //
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));
203
204 //
205 // Update the buffer address
206 //
207 Buffer += CacheManagerDrive.BlockSize * CacheManagerDrive.BytesPerSector;
208
209 //
210 // Update the block count
211 //
212 BlockCount--;
213 }
214
215 //
216 // Read the last block into the buffer
217 //
218 if (BlockCount > 0)
219 {
220 //
221 // Get cache block pointer (this forces the disk sectors into the cache memory)
222 //
223 CacheBlock = CacheInternalGetBlockPointer(&CacheManagerDrive, EndBlock);
224 if (CacheBlock == NULL)
225 {
226 return FALSE;
227 }
228
229 //
230 // Copy the portion requested into the buffer
231 //
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));
236
237 //
238 // Update the buffer address
239 //
240 Buffer += SectorOffsetInEndBlock * CacheManagerDrive.BytesPerSector;
241
242 //
243 // Update the block count
244 //
245 BlockCount--;
246 }
247
248 return TRUE;
249 }
250
251 BOOL CacheForceDiskSectorsIntoCache(U32 DiskNumber, U32 StartSector, U32 SectorCount)
252 {
253 PCACHE_BLOCK CacheBlock;
254 U32 StartBlock;
255 U32 EndBlock;
256 U32 BlockCount;
257 U32 Idx;
258
259 DbgPrint((DPRINT_CACHE, "CacheForceDiskSectorsIntoCache() DiskNumber: 0x%x StartSector: %d SectorCount: %d\n", DiskNumber, StartSector, SectorCount));
260
261 // If we aren't initialized yet then they can't do this
262 if (CacheManagerInitialized == FALSE)
263 {
264 return FALSE;
265 }
266
267 //
268 // Caculate which blocks we must cache
269 //
270 StartBlock = StartSector / CacheManagerDrive.BlockSize;
271 EndBlock = (StartSector + SectorCount) / CacheManagerDrive.BlockSize;
272 BlockCount = (EndBlock - StartBlock) + 1;
273
274 //
275 // Loop through and cache them
276 //
277 for (Idx=StartBlock; Idx<(StartBlock+BlockCount); Idx++)
278 {
279 //
280 // Get cache block pointer (this forces the disk sectors into the cache memory)
281 //
282 CacheBlock = CacheInternalGetBlockPointer(&CacheManagerDrive, Idx);
283 if (CacheBlock == NULL)
284 {
285 return FALSE;
286 }
287
288 //
289 // Lock the sectors into the cache
290 //
291 CacheBlock->LockedInCache = TRUE;
292 }
293
294 return TRUE;
295 }
296
297 BOOL CacheReleaseMemory(U32 MinimumAmountToRelease)
298 {
299 U32 AmountReleased;
300
301 DbgPrint((DPRINT_CACHE, "CacheReleaseMemory() MinimumAmountToRelease = %d\n", MinimumAmountToRelease));
302
303 // If we aren't initialized yet then they can't do this
304 if (CacheManagerInitialized == FALSE)
305 {
306 return FALSE;
307 }
308
309 // Loop through and try to free the requested amount of memory
310 for (AmountReleased=0; AmountReleased<MinimumAmountToRelease; )
311 {
312 // Try to free a block
313 // If this fails then break out of the loop
314 if (!CacheInternalFreeBlock(&CacheManagerDrive))
315 {
316 break;
317 }
318
319 // It succeeded so increment the amount of memory we have freed
320 AmountReleased += CacheManagerDrive.BlockSize * CacheManagerDrive.BytesPerSector;
321 }
322
323 // Return status
324 return (AmountReleased >= MinimumAmountToRelease);
325 }