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