FreeLdr Patch. Now fully loads ntoskrnl using a PE Loader, supports /3gb dynamically...
[reactos.git] / reactos / boot / freeldr / freeldr / cache / blocklist.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 <rtl.h>
26 #include <debug.h>
27 #include <arch.h>
28 #include <machine.h>
29
30 // Returns a pointer to a CACHE_BLOCK structure
31 // Adds the block to the cache manager block list
32 // in cache memory if it isn't already there
33 PCACHE_BLOCK CacheInternalGetBlockPointer(PCACHE_DRIVE CacheDrive, ULONG BlockNumber)
34 {
35 PCACHE_BLOCK CacheBlock = NULL;
36
37 DbgPrint((DPRINT_CACHE, "CacheInternalGetBlockPointer() BlockNumber = %d\n", BlockNumber));
38
39 CacheBlock = CacheInternalFindBlock(CacheDrive, BlockNumber);
40
41 if (CacheBlock != NULL)
42 {
43 DbgPrint((DPRINT_CACHE, "Cache hit! BlockNumber: %d CacheBlock->BlockNumber: %d\n", BlockNumber, CacheBlock->BlockNumber));
44
45 return CacheBlock;
46 }
47
48 DbgPrint((DPRINT_CACHE, "Cache miss! BlockNumber: %d\n", BlockNumber));
49
50 CacheBlock = CacheInternalAddBlockToCache(CacheDrive, BlockNumber);
51
52 // Optimize the block list so it has a LRU structure
53 CacheInternalOptimizeBlockList(CacheDrive, CacheBlock);
54
55 return CacheBlock;
56 }
57
58 PCACHE_BLOCK CacheInternalFindBlock(PCACHE_DRIVE CacheDrive, ULONG BlockNumber)
59 {
60 PCACHE_BLOCK CacheBlock = NULL;
61
62 DbgPrint((DPRINT_CACHE, "CacheInternalFindBlock() BlockNumber = %d\n", BlockNumber));
63
64 //
65 // Make sure the block list has entries before I start searching it.
66 //
67 if (!RtlListIsEmpty((PLIST_ITEM)CacheDrive->CacheBlockHead))
68 {
69 //
70 // Search the list and find the BIOS drive number
71 //
72 CacheBlock = CacheDrive->CacheBlockHead;
73
74 while (CacheBlock != NULL)
75 {
76 //
77 // We found the block, so return it
78 //
79 if (CacheBlock->BlockNumber == BlockNumber)
80 {
81 //
82 // Increment the blocks access count
83 //
84 CacheBlock->AccessCount++;
85
86 return CacheBlock;
87 }
88
89 CacheBlock = (PCACHE_BLOCK)RtlListGetNext((PLIST_ITEM)CacheBlock);
90 }
91 }
92
93 return NULL;
94 }
95
96 PCACHE_BLOCK CacheInternalAddBlockToCache(PCACHE_DRIVE CacheDrive, ULONG BlockNumber)
97 {
98 PCACHE_BLOCK CacheBlock = NULL;
99
100 DbgPrint((DPRINT_CACHE, "CacheInternalAddBlockToCache() BlockNumber = %d\n", BlockNumber));
101
102 // Check the size of the cache so we don't exceed our limits
103 CacheInternalCheckCacheSizeLimits(CacheDrive);
104
105 // We will need to add the block to the
106 // drive's list of cached blocks. So allocate
107 // the block memory.
108 CacheBlock = MmAllocateMemory(sizeof(CACHE_BLOCK));
109 if (CacheBlock == NULL)
110 {
111 return NULL;
112 }
113
114 // Now initialize the structure and
115 // allocate room for the block data
116 RtlZeroMemory(CacheBlock, sizeof(CACHE_BLOCK));
117 CacheBlock->BlockNumber = BlockNumber;
118 CacheBlock->BlockData = MmAllocateMemory(CacheDrive->BlockSize * CacheDrive->BytesPerSector);
119 if (CacheBlock->BlockData ==NULL)
120 {
121 MmFreeMemory(CacheBlock);
122 return NULL;
123 }
124
125 // Now try to read in the block
126 if (!MachDiskReadLogicalSectors(CacheDrive->DriveNumber, (BlockNumber * CacheDrive->BlockSize), CacheDrive->BlockSize, (PVOID)DISKREADBUFFER))
127 {
128 MmFreeMemory(CacheBlock->BlockData);
129 MmFreeMemory(CacheBlock);
130 return NULL;
131 }
132 RtlCopyMemory(CacheBlock->BlockData, (PVOID)DISKREADBUFFER, CacheDrive->BlockSize * CacheDrive->BytesPerSector);
133
134 // Add it to our list of blocks managed by the cache
135 if (CacheDrive->CacheBlockHead == NULL)
136 {
137 CacheDrive->CacheBlockHead = CacheBlock;
138 }
139 else
140 {
141 RtlListInsertTail((PLIST_ITEM)CacheDrive->CacheBlockHead, (PLIST_ITEM)CacheBlock);
142 }
143
144 // Update the cache data
145 CacheBlockCount++;
146 CacheSizeCurrent = CacheBlockCount * (CacheDrive->BlockSize * CacheDrive->BytesPerSector);
147
148 CacheInternalDumpBlockList(CacheDrive);
149
150 return CacheBlock;
151 }
152
153 BOOL CacheInternalFreeBlock(PCACHE_DRIVE CacheDrive)
154 {
155 PCACHE_BLOCK CacheBlockToFree;
156
157 DbgPrint((DPRINT_CACHE, "CacheInternalFreeBlock()\n"));
158
159 // Get a pointer to the last item in the block list
160 // that isn't forced to be in the cache and remove
161 // it from the list
162 CacheBlockToFree = (PCACHE_BLOCK)RtlListGetTail((PLIST_ITEM)CacheDrive->CacheBlockHead);
163 while (CacheBlockToFree != NULL && CacheBlockToFree->LockedInCache == TRUE)
164 {
165 CacheBlockToFree = (PCACHE_BLOCK)RtlListGetPrevious((PLIST_ITEM)CacheBlockToFree);
166 }
167
168 // No blocks left in cache that can be freed
169 // so just return
170 if (CacheBlockToFree == NULL)
171 {
172 return FALSE;
173 }
174
175 //
176 // If we are freeing the head of the list then update it's pointer
177 //
178 if (CacheBlockToFree == CacheDrive->CacheBlockHead)
179 {
180 CacheDrive->CacheBlockHead = (PCACHE_BLOCK)RtlListGetNext((PLIST_ITEM)CacheBlockToFree);
181 }
182
183 RtlListRemoveEntry((PLIST_ITEM)CacheBlockToFree);
184
185 // Free the block memory and the block structure
186 MmFreeMemory(CacheBlockToFree->BlockData);
187 MmFreeMemory(CacheBlockToFree);
188
189 // Update the cache data
190 CacheBlockCount--;
191 CacheSizeCurrent = CacheBlockCount * (CacheDrive->BlockSize * CacheDrive->BytesPerSector);
192
193 return TRUE;
194 }
195
196 VOID CacheInternalCheckCacheSizeLimits(PCACHE_DRIVE CacheDrive)
197 {
198 ULONG NewCacheSize;
199
200 DbgPrint((DPRINT_CACHE, "CacheInternalCheckCacheSizeLimits()\n"));
201
202 // Calculate the size of the cache if we added a block
203 NewCacheSize = (CacheBlockCount + 1) * (CacheDrive->BlockSize * CacheDrive->BytesPerSector);
204
205 // Check the new size against the cache size limit
206 if (NewCacheSize > CacheSizeLimit)
207 {
208 CacheInternalFreeBlock(CacheDrive);
209 CacheInternalDumpBlockList(CacheDrive);
210 }
211 }
212
213 VOID CacheInternalDumpBlockList(PCACHE_DRIVE CacheDrive)
214 {
215 PCACHE_BLOCK CacheBlock;
216
217 DbgPrint((DPRINT_CACHE, "Dumping block list for BIOS drive 0x%x.\n", CacheDrive->DriveNumber));
218 DbgPrint((DPRINT_CACHE, "BytesPerSector: %d.\n", CacheDrive->BytesPerSector));
219 DbgPrint((DPRINT_CACHE, "BlockSize: %d.\n", CacheDrive->BlockSize));
220 DbgPrint((DPRINT_CACHE, "CacheSizeLimit: %d.\n", CacheSizeLimit));
221 DbgPrint((DPRINT_CACHE, "CacheSizeCurrent: %d.\n", CacheSizeCurrent));
222 DbgPrint((DPRINT_CACHE, "CacheBlockCount: %d.\n", CacheBlockCount));
223 DbgPrint((DPRINT_CACHE, "Dumping %d cache blocks.\n", RtlListCountEntries((PLIST_ITEM)CacheDrive->CacheBlockHead)));
224
225 CacheBlock = CacheDrive->CacheBlockHead;
226 while (CacheBlock != NULL)
227 {
228 DbgPrint((DPRINT_CACHE, "Cache Block: CacheBlock: 0x%x\n", CacheBlock));
229 DbgPrint((DPRINT_CACHE, "Cache Block: Block Number: %d\n", CacheBlock->BlockNumber));
230 DbgPrint((DPRINT_CACHE, "Cache Block: Access Count: %d\n", CacheBlock->AccessCount));
231 DbgPrint((DPRINT_CACHE, "Cache Block: Block Data: 0x%x\n", CacheBlock->BlockData));
232 DbgPrint((DPRINT_CACHE, "Cache Block: Locked In Cache: %d\n", CacheBlock->LockedInCache));
233
234 if (CacheBlock->BlockData == NULL)
235 {
236 BugCheck((DPRINT_CACHE, "What the heck?!?\n"));
237 }
238
239 CacheBlock = (PCACHE_BLOCK)RtlListGetNext((PLIST_ITEM)CacheBlock);
240 }
241 }
242
243 VOID CacheInternalOptimizeBlockList(PCACHE_DRIVE CacheDrive, PCACHE_BLOCK CacheBlock)
244 {
245
246 DbgPrint((DPRINT_CACHE, "CacheInternalOptimizeBlockList()\n"));
247
248 // Don't do this if this block is already at the head of the list
249 if (CacheBlock != CacheDrive->CacheBlockHead)
250 {
251 // Remove this item from the block list
252 RtlListRemoveEntry((PLIST_ITEM)CacheBlock);
253
254 // Re-insert it at the head of the list
255 RtlListInsertHead((PLIST_ITEM)CacheDrive->CacheBlockHead, (PLIST_ITEM)CacheBlock);
256
257 // Update the head pointer
258 CacheDrive->CacheBlockHead = CacheBlock;
259 }
260 }