forgot this one: a stubbed out loader.c copied from i386
[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 #include <freeldr.h>
21 #include <debug.h>
22
23 ///////////////////////////////////////////////////////////////////////////////////////
24 //
25 // Internal data
26 //
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;
34
35 BOOLEAN CacheInitializeDrive(ULONG DriveNumber)
36 {
37 PCACHE_BLOCK NextCacheBlock;
38 GEOMETRY DriveGeometry;
39
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))
47 {
48 return TRUE;
49 }
50
51 CacheManagerDataInvalid = FALSE;
52
53 //
54 // If we have already been initialized then free
55 // the old data
56 //
57 if (CacheManagerInitialized)
58 {
59 CacheManagerInitialized = FALSE;
60
61 DbgPrint((DPRINT_CACHE, "CacheBlockCount: %d\n", CacheBlockCount));
62 DbgPrint((DPRINT_CACHE, "CacheSizeLimit: %d\n", CacheSizeLimit));
63 DbgPrint((DPRINT_CACHE, "CacheSizeCurrent: %d\n", CacheSizeCurrent));
64 //
65 // Loop through and free the cache blocks
66 //
67 while (!IsListEmpty(&CacheManagerDrive.CacheBlockHead))
68 {
69 NextCacheBlock = CONTAINING_RECORD(RemoveHeadList(&CacheManagerDrive.CacheBlockHead),
70 CACHE_BLOCK,
71 ListEntry);
72
73 MmHeapFree(NextCacheBlock->BlockData);
74 MmHeapFree(NextCacheBlock);
75 }
76 }
77
78 // Initialize the structure
79 RtlZeroMemory(&CacheManagerDrive, sizeof(CACHE_DRIVE));
80 InitializeListHead(&CacheManagerDrive.CacheBlockHead);
81 CacheManagerDrive.DriveNumber = DriveNumber;
82 if (!MachDiskGetDriveGeometry(DriveNumber, &DriveGeometry))
83 {
84 return FALSE;
85 }
86 CacheManagerDrive.BytesPerSector = DriveGeometry.BytesPerSector;
87
88 // Get the number of sectors in each cache block
89 CacheManagerDrive.BlockSize = MachDiskGetCacheableBlockCount(DriveNumber);
90
91 CacheBlockCount = 0;
92 CacheSizeLimit = GetSystemMemorySize() / 8;
93 CacheSizeCurrent = 0;
94 if (CacheSizeLimit < (64 * 1024))
95 {
96 CacheSizeLimit = (64 * 1024);
97 }
98
99 CacheManagerInitialized = TRUE;
100
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));
105
106 return TRUE;
107 }
108
109 VOID CacheInvalidateCacheData(VOID)
110 {
111 CacheManagerDataInvalid = TRUE;
112 }
113
114 BOOLEAN CacheReadDiskSectors(ULONG DiskNumber, ULONG StartSector, ULONG SectorCount, PVOID Buffer)
115 {
116 PCACHE_BLOCK CacheBlock;
117 ULONG StartBlock;
118 ULONG SectorOffsetInStartBlock;
119 ULONG CopyLengthInStartBlock;
120 ULONG EndBlock;
121 ULONG SectorOffsetInEndBlock;
122 ULONG BlockCount;
123 ULONG Idx;
124
125 DbgPrint((DPRINT_CACHE, "CacheReadDiskSectors() DiskNumber: 0x%x StartSector: %d SectorCount: %d Buffer: 0x%x\n", DiskNumber, StartSector, SectorCount, Buffer));
126
127 // If we aren't initialized yet then they can't do this
128 if (CacheManagerInitialized == FALSE)
129 {
130 return FALSE;
131 }
132
133 //
134 // Caculate which blocks we must cache
135 //
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));
143
144 //
145 // Read the first block into the buffer
146 //
147 if (BlockCount > 0)
148 {
149 //
150 // Get cache block pointer (this forces the disk sectors into the cache memory)
151 //
152 CacheBlock = CacheInternalGetBlockPointer(&CacheManagerDrive, StartBlock);
153 if (CacheBlock == NULL)
154 {
155 return FALSE;
156 }
157
158 //
159 // Copy the portion requested into the buffer
160 //
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)));
165
166 //
167 // Update the buffer address
168 //
169 Buffer = (PVOID)((ULONG_PTR)Buffer + (CopyLengthInStartBlock * CacheManagerDrive.BytesPerSector));
170
171 //
172 // Update the block count
173 //
174 BlockCount--;
175 }
176
177 //
178 // Loop through the middle blocks and read them into the buffer
179 //
180 for (Idx=StartBlock+1; BlockCount>1; Idx++)
181 {
182 //
183 // Get cache block pointer (this forces the disk sectors into the cache memory)
184 //
185 CacheBlock = CacheInternalGetBlockPointer(&CacheManagerDrive, Idx);
186 if (CacheBlock == NULL)
187 {
188 return FALSE;
189 }
190
191 //
192 // Copy the portion requested into the buffer
193 //
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));
198
199 //
200 // Update the buffer address
201 //
202 Buffer = (PVOID)((ULONG_PTR)Buffer + (CacheManagerDrive.BlockSize * CacheManagerDrive.BytesPerSector));
203
204 //
205 // Update the block count
206 //
207 BlockCount--;
208 }
209
210 //
211 // Read the last block into the buffer
212 //
213 if (BlockCount > 0)
214 {
215 //
216 // Get cache block pointer (this forces the disk sectors into the cache memory)
217 //
218 CacheBlock = CacheInternalGetBlockPointer(&CacheManagerDrive, EndBlock);
219 if (CacheBlock == NULL)
220 {
221 return FALSE;
222 }
223
224 //
225 // Copy the portion requested into the buffer
226 //
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));
231
232 //
233 // Update the buffer address
234 //
235 Buffer = (PVOID)((ULONG_PTR)Buffer + (SectorOffsetInEndBlock * CacheManagerDrive.BytesPerSector));
236
237 //
238 // Update the block count
239 //
240 BlockCount--;
241 }
242
243 return TRUE;
244 }
245
246 BOOLEAN CacheForceDiskSectorsIntoCache(ULONG DiskNumber, ULONG StartSector, ULONG SectorCount)
247 {
248 PCACHE_BLOCK CacheBlock;
249 ULONG StartBlock;
250 ULONG EndBlock;
251 ULONG BlockCount;
252 ULONG Idx;
253
254 DbgPrint((DPRINT_CACHE, "CacheForceDiskSectorsIntoCache() DiskNumber: 0x%x StartSector: %d SectorCount: %d\n", DiskNumber, StartSector, SectorCount));
255
256 // If we aren't initialized yet then they can't do this
257 if (CacheManagerInitialized == FALSE)
258 {
259 return FALSE;
260 }
261
262 //
263 // Caculate which blocks we must cache
264 //
265 StartBlock = StartSector / CacheManagerDrive.BlockSize;
266 EndBlock = (StartSector + SectorCount) / CacheManagerDrive.BlockSize;
267 BlockCount = (EndBlock - StartBlock) + 1;
268
269 //
270 // Loop through and cache them
271 //
272 for (Idx=StartBlock; Idx<(StartBlock+BlockCount); Idx++)
273 {
274 //
275 // Get cache block pointer (this forces the disk sectors into the cache memory)
276 //
277 CacheBlock = CacheInternalGetBlockPointer(&CacheManagerDrive, Idx);
278 if (CacheBlock == NULL)
279 {
280 return FALSE;
281 }
282
283 //
284 // Lock the sectors into the cache
285 //
286 CacheBlock->LockedInCache = TRUE;
287 }
288
289 return TRUE;
290 }
291
292 BOOLEAN CacheReleaseMemory(ULONG MinimumAmountToRelease)
293 {
294 ULONG AmountReleased;
295
296 DbgPrint((DPRINT_CACHE, "CacheReleaseMemory() MinimumAmountToRelease = %d\n", MinimumAmountToRelease));
297
298 // If we aren't initialized yet then they can't do this
299 if (CacheManagerInitialized == FALSE)
300 {
301 return FALSE;
302 }
303
304 // Loop through and try to free the requested amount of memory
305 for (AmountReleased=0; AmountReleased<MinimumAmountToRelease; )
306 {
307 // Try to free a block
308 // If this fails then break out of the loop
309 if (!CacheInternalFreeBlock(&CacheManagerDrive))
310 {
311 break;
312 }
313
314 // It succeeded so increment the amount of memory we have freed
315 AmountReleased += CacheManagerDrive.BlockSize * CacheManagerDrive.BytesPerSector;
316 }
317
318 // Return status
319 return (AmountReleased >= MinimumAmountToRelease);
320 }