Fixed a bug in the LBA extensions detection code.
[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 DbgPrint((DPRINT_MEMORY, "Memory allocation pointer: 0x%x\n", MemPointer));
108 VerifyHeap();
109 #endif // DEBUG
110
111 // Now return the pointer
112 return MemPointer;
113 }
114
115 VOID FreeMemory(PVOID MemBlock)
116 {
117 ULONG BlockNumber;
118 ULONG BlockCount;
119 ULONG Idx;
120
121 #ifdef DEBUG
122
123 // Make sure we didn't get a bogus pointer
124 if ((MemBlock < HeapBaseAddress) || (MemBlock > (HeapBaseAddress + HeapLengthInBytes)))
125 {
126 BugCheck((DPRINT_MEMORY, "Bogus memory pointer (0x%x) passed to FreeMemory()\n", MemBlock));
127 }
128 #endif // DEBUG
129
130 // Find out the block number if the first
131 // block of memory they allocated
132 BlockNumber = (MemBlock - HeapBaseAddress) / MEM_BLOCK_SIZE;
133 BlockCount = HeapMemBlockArray[BlockNumber].BlocksAllocated;
134
135 #ifdef DEBUG
136 // Make sure we didn't get a bogus pointer
137 if ((BlockCount < 1) || (BlockCount > HeapMemBlockCount))
138 {
139 BugCheck((DPRINT_MEMORY, "Invalid block count in heap page header. HeapMemBlockArray[BlockNumber].BlocksAllocated = %d\n", HeapMemBlockArray[BlockNumber].BlocksAllocated));
140 }
141 #endif
142
143 // Loop through our array and mark all the
144 // blocks as free
145 for (Idx=BlockNumber; Idx<(BlockNumber + BlockCount); Idx++)
146 {
147 HeapMemBlockArray[Idx].MemBlockAllocated = FALSE;
148 HeapMemBlockArray[Idx].BlocksAllocated = 0;
149 }
150
151 #ifdef DEBUG
152 DecrementAllocationCount();
153 DbgPrint((DPRINT_MEMORY, "Freed %d blocks of memory starting at block %d. AllocationCount: %d\n", BlockCount, BlockNumber, AllocationCount));
154 VerifyHeap();
155 #endif // DEBUG
156 }
157
158 #ifdef DEBUG
159 VOID VerifyHeap(VOID)
160 {
161 ULONG Idx;
162 ULONG Idx2;
163 ULONG Count;
164
165 if (DUMP_MEM_MAP_ON_VERIFY)
166 {
167 DumpMemoryAllocMap();
168 }
169
170 // Loop through the array and verify that
171 // everything is kosher
172 for (Idx=0; Idx<HeapMemBlockCount; Idx++)
173 {
174 // Check if this block is allocation
175 if (HeapMemBlockArray[Idx].MemBlockAllocated)
176 {
177 // This is the first block in the run so it
178 // had better have a length that is within range
179 if ((HeapMemBlockArray[Idx].BlocksAllocated < 1) || (HeapMemBlockArray[Idx].BlocksAllocated > (HeapMemBlockCount - Idx)))
180 {
181 BugCheck((DPRINT_MEMORY, "Allocation length out of range in heap table. HeapMemBlockArray[Idx].BlocksAllocated = %d\n", HeapMemBlockArray[Idx].BlocksAllocated));
182 }
183
184 // Now go through and verify that the rest of
185 // this run has the blocks marked allocated
186 // with a length of zero but don't check the
187 // first one because we already did
188 Count = HeapMemBlockArray[Idx].BlocksAllocated;
189 for (Idx2=1; Idx2<Count; Idx2++)
190 {
191 // Make sure it's allocated
192 if (HeapMemBlockArray[Idx + Idx2].MemBlockAllocated != TRUE)
193 {
194 BugCheck((DPRINT_MEMORY, "Heap table indicates hole in memory allocation. HeapMemBlockArray[Idx + Idx2].MemBlockAllocated != TRUE\n"));
195 }
196
197 // Make sure the length is zero
198 if (HeapMemBlockArray[Idx + Idx2].BlocksAllocated != 0)
199 {
200 BugCheck((DPRINT_MEMORY, "Allocation chain has non-zero value in non-first block in heap table. HeapMemBlockArray[Idx + Idx2].BlocksAllocated != 0\n"));
201 }
202 }
203
204 // Move on to the next run
205 Idx += (Count - 1);
206 }
207 else
208 {
209 // Nope, not allocated so make sure the length is zero
210 if (HeapMemBlockArray[Idx].BlocksAllocated != 0)
211 {
212 BugCheck((DPRINT_MEMORY, "Free block is start of memory allocation. HeapMemBlockArray[Idx].BlocksAllocated != 0\n"));
213 }
214 }
215 }
216 }
217
218 VOID DumpMemoryAllocMap(VOID)
219 {
220 ULONG Idx;
221
222 DbgPrint((DPRINT_MEMORY, "----------- Memory Allocation Bitmap -----------\n"));
223
224 for (Idx=0; Idx<HeapMemBlockCount; Idx++)
225 {
226 if ((Idx % 32) == 0)
227 {
228 DbgPrint((DPRINT_MEMORY, "\n"));
229 DbgPrint((DPRINT_MEMORY, "%x:\t", HeapBaseAddress + (Idx * 256)));
230 }
231 else if ((Idx % 4) == 0)
232 {
233 DbgPrint((DPRINT_MEMORY, " "));
234 }
235
236 if (HeapMemBlockArray[Idx].MemBlockAllocated)
237 {
238 DbgPrint((DPRINT_MEMORY, "X"));
239 }
240 else
241 {
242 DbgPrint((DPRINT_MEMORY, "*"));
243 }
244 }
245
246 DbgPrint((DPRINT_MEMORY, "\n"));
247 }
248
249 VOID IncrementAllocationCount(VOID)
250 {
251 AllocationCount++;
252 }
253
254 VOID DecrementAllocationCount(VOID)
255 {
256 AllocationCount--;
257 }
258
259 VOID MemAllocTest(VOID)
260 {
261 PVOID MemPtr1;
262 PVOID MemPtr2;
263 PVOID MemPtr3;
264 PVOID MemPtr4;
265 PVOID MemPtr5;
266
267 MemPtr1 = AllocateMemory(4096);
268 printf("MemPtr1: 0x%x\n", (int)MemPtr1);
269 getch();
270 MemPtr2 = AllocateMemory(4096);
271 printf("MemPtr2: 0x%x\n", (int)MemPtr2);
272 getch();
273 MemPtr3 = AllocateMemory(4096);
274 printf("MemPtr3: 0x%x\n", (int)MemPtr3);
275 DumpMemoryAllocMap();
276 VerifyHeap();
277 getch();
278
279 FreeMemory(MemPtr2);
280 getch();
281
282 MemPtr4 = AllocateMemory(2048);
283 printf("MemPtr4: 0x%x\n", (int)MemPtr4);
284 getch();
285 MemPtr5 = AllocateMemory(4096);
286 printf("MemPtr5: 0x%x\n", (int)MemPtr5);
287 getch();
288 }
289 #endif // DEBUG
290
291 // Returns the amount of total usuable memory available to the memory manager
292 ULONG GetSystemMemorySize(VOID)
293 {
294 return HeapLengthInBytes;
295 }