Improved memory management
[reactos.git] / freeldr / freeldr / mm / mm.c
1 /*
2 * FreeLoader
3 * Copyright (C) 1998-2002 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 <mm.h>
22 #include "mem.h"
23 #include <rtl.h>
24 #include <debug.h>
25 #include <ui.h>
26
27
28 #ifdef DEBUG
29 ULONG AllocationCount = 0;
30
31 VOID VerifyHeap(VOID);
32 VOID DumpMemoryAllocMap(VOID);
33 VOID IncrementAllocationCount(VOID);
34 VOID DecrementAllocationCount(VOID);
35 VOID MemAllocTest(VOID);
36 #endif // DEBUG
37
38 PVOID AllocateMemory(ULONG NumberOfBytes)
39 {
40 ULONG BlocksNeeded;
41 ULONG Idx;
42 ULONG NumFree;
43 PVOID MemPointer;
44
45 if (NumberOfBytes == 0)
46 {
47 DbgPrint((DPRINT_MEMORY, "AllocateMemory() called for 0 bytes. Returning NULL.\n"));
48 return NULL;
49 }
50
51 // Find out how many blocks it will take to
52 // satisfy this allocation
53 BlocksNeeded = ROUND_UP(NumberOfBytes, MEM_BLOCK_SIZE) / MEM_BLOCK_SIZE;
54
55 // Now loop through our array of blocks and
56 // see if we have enough space
57 for (Idx=0,NumFree=0; Idx<HeapMemBlockCount; Idx++)
58 {
59 // Check this block and see if it is already allocated
60 // If so reset our counter and continue the loop
61 if (HeapMemBlockArray[Idx].MemBlockAllocated)
62 {
63 NumFree = 0;
64 continue;
65 }
66 else
67 {
68 // It is free memory so lets increment our count
69 NumFree++;
70 }
71
72 // If we have found enough blocks to satisfy the request
73 // then we're done searching
74 if (NumFree >= BlocksNeeded)
75 {
76 break;
77 }
78 }
79 Idx++;
80
81 // If we don't have enough available mem
82 // then return NULL
83 if (NumFree < BlocksNeeded)
84 {
85 DbgPrint((DPRINT_MEMORY, "Memory allocation failed. Not enough free memory to allocate %d bytes. AllocationCount: %d\n", NumberOfBytes, AllocationCount));
86 MessageBox("Memory allocation failed: out of memory.");
87 return NULL;
88 }
89
90 // Subtract the block count from Idx and we have
91 // the start block of the memory
92 Idx -= NumFree;
93
94 // Now we know which block to give them
95 MemPointer = HeapBaseAddress + (Idx * MEM_BLOCK_SIZE);
96
97 // Now loop through and mark all the blocks as allocated
98 for (NumFree=0; NumFree<BlocksNeeded; NumFree++)
99 {
100 HeapMemBlockArray[Idx + NumFree].MemBlockAllocated = TRUE;
101 HeapMemBlockArray[Idx + NumFree].BlocksAllocated = NumFree ? 0 : BlocksNeeded; // Mark only the first block with the count
102 }
103
104 #ifdef DEBUG
105 IncrementAllocationCount();
106 DbgPrint((DPRINT_MEMORY, "Allocated %d bytes (%d blocks) of memory starting at block %d. AllocCount: %d\n", NumberOfBytes, BlocksNeeded, Idx, AllocationCount));
107 VerifyHeap();
108 #endif // DEBUG
109
110 // Now return the pointer
111 return MemPointer;
112 }
113
114 VOID FreeMemory(PVOID MemBlock)
115 {
116 ULONG BlockNumber;
117 ULONG BlockCount;
118 ULONG Idx;
119
120 #ifdef DEBUG
121
122 // Make sure we didn't get a bogus pointer
123 if ((MemBlock < HeapBaseAddress) || (MemBlock > (HeapBaseAddress + HeapLengthInBytes)))
124 {
125 BugCheck((DPRINT_MEMORY, "Bogus memory pointer (0x%x) passed to FreeMemory()\n", MemBlock));
126 }
127 #endif // DEBUG
128
129 // Find out the block number if the first
130 // block of memory they allocated
131 BlockNumber = (MemBlock - HeapBaseAddress) / MEM_BLOCK_SIZE;
132 BlockCount = HeapMemBlockArray[BlockNumber].BlocksAllocated;
133
134 #ifdef DEBUG
135 // Make sure we didn't get a bogus pointer
136 if ((BlockCount < 1) || (BlockCount > HeapMemBlockCount))
137 {
138 BugCheck((DPRINT_MEMORY, "Invalid block count in heap page header. HeapMemBlockArray[BlockNumber].BlocksAllocated = %d\n", HeapMemBlockArray[BlockNumber].BlocksAllocated));
139 }
140 #endif
141
142 // Loop through our array and mark all the
143 // blocks as free
144 for (Idx=BlockNumber; Idx<(BlockNumber + BlockCount); Idx++)
145 {
146 HeapMemBlockArray[Idx].MemBlockAllocated = FALSE;
147 HeapMemBlockArray[Idx].BlocksAllocated = 0;
148 }
149
150 #ifdef DEBUG
151 DecrementAllocationCount();
152 DbgPrint((DPRINT_MEMORY, "Freed %d blocks of memory starting at block %d. AllocationCount: %d\n", BlockCount, BlockNumber, AllocationCount));
153 VerifyHeap();
154 #endif // DEBUG
155 }
156
157 #ifdef DEBUG
158 VOID VerifyHeap(VOID)
159 {
160 ULONG Idx;
161 ULONG Idx2;
162 ULONG Count;
163
164 if (DUMP_MEM_MAP_ON_VERIFY)
165 {
166 DumpMemoryAllocMap();
167 }
168
169 // Loop through the array and verify that
170 // everything is kosher
171 for (Idx=0; Idx<HeapMemBlockCount; Idx++)
172 {
173 // Check if this block is allocation
174 if (HeapMemBlockArray[Idx].MemBlockAllocated)
175 {
176 // This is the first block in the run so it
177 // had better have a length that is within range
178 if ((HeapMemBlockArray[Idx].BlocksAllocated < 1) || (HeapMemBlockArray[Idx].BlocksAllocated > (HeapMemBlockCount - Idx)))
179 {
180 BugCheck((DPRINT_MEMORY, "Allocation length out of range in heap table. HeapMemBlockArray[Idx].BlocksAllocated = %d\n", HeapMemBlockArray[Idx].BlocksAllocated));
181 }
182
183 // Now go through and verify that the rest of
184 // this run has the blocks marked allocated
185 // with a length of zero but don't check the
186 // first one because we already did
187 Count = HeapMemBlockArray[Idx].BlocksAllocated;
188 for (Idx2=1; Idx2<Count; Idx2++)
189 {
190 // Make sure it's allocated
191 if (HeapMemBlockArray[Idx + Idx2].MemBlockAllocated != TRUE)
192 {
193 BugCheck((DPRINT_MEMORY, "Heap table indicates hole in memory allocation. HeapMemBlockArray[Idx + Idx2].MemBlockAllocated != TRUE\n"));
194 }
195
196 // Make sure the length is zero
197 if (HeapMemBlockArray[Idx + Idx2].BlocksAllocated != 0)
198 {
199 BugCheck((DPRINT_MEMORY, "Allocation chain has non-zero value in non-first block in heap table. HeapMemBlockArray[Idx + Idx2].BlocksAllocated != 0\n"));
200 }
201 }
202
203 // Move on to the next run
204 Idx += (Count - 1);
205 }
206 else
207 {
208 // Nope, not allocated so make sure the length is zero
209 if (HeapMemBlockArray[Idx].BlocksAllocated != 0)
210 {
211 BugCheck((DPRINT_MEMORY, "Free block is start of memory allocation. HeapMemBlockArray[Idx].BlocksAllocated != 0\n"));
212 }
213 }
214 }
215 }
216
217 VOID DumpMemoryAllocMap(VOID)
218 {
219 ULONG Idx;
220
221 DbgPrint((DPRINT_MEMORY, "----------- Memory Allocation Bitmap -----------\n"));
222
223 for (Idx=0; Idx<HeapMemBlockCount; Idx++)
224 {
225 if ((Idx % 32) == 0)
226 {
227 DbgPrint((DPRINT_MEMORY, "\n"));
228 DbgPrint((DPRINT_MEMORY, "%x:\t", (Idx * 256)));
229 }
230 else if ((Idx % 4) == 0)
231 {
232 DbgPrint((DPRINT_MEMORY, " "));
233 }
234
235 if (HeapMemBlockArray[Idx].MemBlockAllocated)
236 {
237 DbgPrint((DPRINT_MEMORY, "X"));
238 }
239 else
240 {
241 DbgPrint((DPRINT_MEMORY, "*"));
242 }
243 }
244
245 DbgPrint((DPRINT_MEMORY, "\n"));
246 }
247
248 VOID IncrementAllocationCount(VOID)
249 {
250 AllocationCount++;
251 }
252
253 VOID DecrementAllocationCount(VOID)
254 {
255 AllocationCount--;
256 }
257
258 VOID MemAllocTest(VOID)
259 {
260 PVOID MemPtr1;
261 PVOID MemPtr2;
262 PVOID MemPtr3;
263 PVOID MemPtr4;
264 PVOID MemPtr5;
265
266 MemPtr1 = AllocateMemory(4096);
267 printf("MemPtr1: 0x%x\n", (int)MemPtr1);
268 getch();
269 MemPtr2 = AllocateMemory(4096);
270 printf("MemPtr2: 0x%x\n", (int)MemPtr2);
271 getch();
272 MemPtr3 = AllocateMemory(4096);
273 printf("MemPtr3: 0x%x\n", (int)MemPtr3);
274 DumpMemoryAllocMap();
275 VerifyHeap();
276 getch();
277
278 FreeMemory(MemPtr2);
279 getch();
280
281 MemPtr4 = AllocateMemory(2048);
282 printf("MemPtr4: 0x%x\n", (int)MemPtr4);
283 getch();
284 MemPtr5 = AllocateMemory(4096);
285 printf("MemPtr5: 0x%x\n", (int)MemPtr5);
286 getch();
287 }
288 #endif // DEBUG
289
290 // Returns the amount of total usuable memory available to the memory manager
291 ULONG GetSystemMemorySize(VOID)
292 {
293 return HeapLengthInBytes;
294 }