Merge freeldr from amd64 branch:
[reactos.git] / reactos / boot / freeldr / freeldr / mm / mm.c
1 /*
2 * FreeLoader
3 * Copyright (C) 2006-2008 Aleksey Bragin <aleksey@reactos.org>
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 #ifdef DBG
24 VOID DumpMemoryAllocMap(VOID);
25 VOID MemAllocTest(VOID);
26 #endif // DBG
27
28 ULONG LoaderPagesSpanned = 0;
29
30 PVOID MmAllocateMemoryWithType(ULONG MemorySize, TYPE_OF_MEMORY MemoryType)
31 {
32 ULONG PagesNeeded;
33 ULONG FirstFreePageFromEnd;
34 PVOID MemPointer;
35
36 if (MemorySize == 0)
37 {
38 DPRINTM(DPRINT_MEMORY, "MmAllocateMemory() called for 0 bytes. Returning NULL.\n");
39 UiMessageBoxCritical("Memory allocation failed: MmAllocateMemory() called for 0 bytes.");
40 return NULL;
41 }
42
43 MemorySize = ROUND_UP(MemorySize, 4);
44
45 // Find out how many blocks it will take to
46 // satisfy this allocation
47 PagesNeeded = ROUND_UP(MemorySize, MM_PAGE_SIZE) / MM_PAGE_SIZE;
48
49 // If we don't have enough available mem
50 // then return NULL
51 if (FreePagesInLookupTable < PagesNeeded)
52 {
53 DPRINTM(DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemory(). Not enough free memory to allocate %d bytes.\n", MemorySize);
54 UiMessageBoxCritical("Memory allocation failed: out of memory.");
55 return NULL;
56 }
57
58 FirstFreePageFromEnd = MmFindAvailablePages(PageLookupTableAddress, TotalPagesInLookupTable, PagesNeeded, FALSE);
59
60 if (FirstFreePageFromEnd == 0)
61 {
62 DPRINTM(DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemory(). Not enough free memory to allocate %d bytes.\n", MemorySize);
63 UiMessageBoxCritical("Memory allocation failed: out of memory.");
64 return NULL;
65 }
66
67 MmAllocatePagesInLookupTable(PageLookupTableAddress, FirstFreePageFromEnd, PagesNeeded, MemoryType);
68
69 FreePagesInLookupTable -= PagesNeeded;
70 MemPointer = (PVOID)((ULONG_PTR)FirstFreePageFromEnd * MM_PAGE_SIZE);
71
72 #ifdef DBG
73 DPRINTM(DPRINT_MEMORY, "Allocated %d bytes (%d pages) of memory starting at page %d.\n", MemorySize, PagesNeeded, FirstFreePageFromEnd);
74 DPRINTM(DPRINT_MEMORY, "Memory allocation pointer: 0x%x\n", MemPointer);
75 #endif // DBG
76
77 // Update LoaderPagesSpanned count
78 if ((((ULONG_PTR)MemPointer + MemorySize) >> PAGE_SHIFT) > LoaderPagesSpanned)
79 LoaderPagesSpanned = (((ULONG_PTR)MemPointer + MemorySize) >> PAGE_SHIFT);
80
81 // Now return the pointer
82 return MemPointer;
83 }
84
85 PVOID MmHeapAlloc(ULONG MemorySize)
86 {
87 PVOID Result;
88 LONG CurAlloc, TotalFree, MaxFree, NumberOfGets, NumberOfRels;
89
90 if (MemorySize > MM_PAGE_SIZE)
91 {
92 DPRINTM(DPRINT_MEMORY, "Consider using other functions to allocate %d bytes of memory!\n", MemorySize);
93 }
94
95 // Get the buffer from BGET pool
96 Result = bget(MemorySize);
97
98 if (Result == NULL)
99 {
100 DPRINTM(DPRINT_MEMORY, "Heap allocation for %d bytes failed\n", MemorySize);
101 }
102
103 // Gather some stats
104 bstats(&CurAlloc, &TotalFree, &MaxFree, &NumberOfGets, &NumberOfRels);
105
106 DPRINTM(DPRINT_MEMORY, "Current alloced %d bytes, free %d bytes, allocs %d, frees %d\n",
107 CurAlloc, TotalFree, NumberOfGets, NumberOfRels);
108
109 return Result;
110 }
111
112 VOID MmHeapFree(PVOID MemoryPointer)
113 {
114 // Release the buffer to the pool
115 brel(MemoryPointer);
116 }
117
118 PVOID MmAllocateMemory(ULONG MemorySize)
119 {
120 // Temporary forwarder...
121 return MmAllocateMemoryWithType(MemorySize, LoaderOsloaderHeap);
122 }
123
124 PVOID MmAllocateMemoryAtAddress(ULONG MemorySize, PVOID DesiredAddress, TYPE_OF_MEMORY MemoryType)
125 {
126 ULONG PagesNeeded;
127 ULONG StartPageNumber;
128 PVOID MemPointer;
129
130 if (MemorySize == 0)
131 {
132 DPRINTM(DPRINT_MEMORY, "MmAllocateMemoryAtAddress() called for 0 bytes. Returning NULL.\n");
133 UiMessageBoxCritical("Memory allocation failed: MmAllocateMemoryAtAddress() called for 0 bytes.");
134 return NULL;
135 }
136
137 // Find out how many blocks it will take to
138 // satisfy this allocation
139 PagesNeeded = ROUND_UP(MemorySize, MM_PAGE_SIZE) / MM_PAGE_SIZE;
140
141 // Get the starting page number
142 StartPageNumber = MmGetPageNumberFromAddress(DesiredAddress);
143
144 // If we don't have enough available mem
145 // then return NULL
146 if (FreePagesInLookupTable < PagesNeeded)
147 {
148 DPRINTM(DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemoryAtAddress(). "
149 "Not enough free memory to allocate %d bytes (requesting %d pages but have only %d). "
150 "\n", MemorySize, PagesNeeded, FreePagesInLookupTable);
151 UiMessageBoxCritical("Memory allocation failed: out of memory.");
152 return NULL;
153 }
154
155 if (MmAreMemoryPagesAvailable(PageLookupTableAddress, TotalPagesInLookupTable, DesiredAddress, PagesNeeded) == FALSE)
156 {
157 DPRINTM(DPRINT_MEMORY, "Memory allocation failed in MmAllocateMemoryAtAddress(). "
158 "Not enough free memory to allocate %d bytes at address %p.\n",
159 MemorySize, DesiredAddress);
160
161 // Don't tell this to user since caller should try to alloc this memory
162 // at a different address
163 //UiMessageBoxCritical("Memory allocation failed: out of memory.");
164 return NULL;
165 }
166
167 MmAllocatePagesInLookupTable(PageLookupTableAddress, StartPageNumber, PagesNeeded, MemoryType);
168
169 FreePagesInLookupTable -= PagesNeeded;
170 MemPointer = (PVOID)((ULONG_PTR)StartPageNumber * MM_PAGE_SIZE);
171
172 #ifdef DBG
173 DPRINTM(DPRINT_MEMORY, "Allocated %d bytes (%d pages) of memory starting at page %d.\n", MemorySize, PagesNeeded, StartPageNumber);
174 DPRINTM(DPRINT_MEMORY, "Memory allocation pointer: 0x%x\n", MemPointer);
175 #endif // DBG
176
177 // Update LoaderPagesSpanned count
178 if ((((ULONG_PTR)MemPointer + MemorySize) >> PAGE_SHIFT) > LoaderPagesSpanned)
179 LoaderPagesSpanned = (((ULONG_PTR)MemPointer + MemorySize) >> PAGE_SHIFT);
180
181 // Now return the pointer
182 return MemPointer;
183 }
184
185 VOID MmSetMemoryType(PVOID MemoryAddress, ULONG MemorySize, TYPE_OF_MEMORY NewType)
186 {
187 ULONG PagesNeeded;
188 ULONG StartPageNumber;
189
190 // Find out how many blocks it will take to
191 // satisfy this allocation
192 PagesNeeded = ROUND_UP(MemorySize, MM_PAGE_SIZE) / MM_PAGE_SIZE;
193
194 // Get the starting page number
195 StartPageNumber = MmGetPageNumberFromAddress(MemoryAddress);
196
197 // Set new type for these pages
198 MmAllocatePagesInLookupTable(PageLookupTableAddress, StartPageNumber, PagesNeeded, NewType);
199 }
200
201 PVOID MmAllocateHighestMemoryBelowAddress(ULONG MemorySize, PVOID DesiredAddress, TYPE_OF_MEMORY MemoryType)
202 {
203 ULONG PagesNeeded;
204 ULONG FirstFreePageFromEnd;
205 ULONG DesiredAddressPageNumber;
206 PVOID MemPointer;
207
208 if (MemorySize == 0)
209 {
210 DPRINTM(DPRINT_MEMORY, "MmAllocateHighestMemoryBelowAddress() called for 0 bytes. Returning NULL.\n");
211 UiMessageBoxCritical("Memory allocation failed: MmAllocateHighestMemoryBelowAddress() called for 0 bytes.");
212 return NULL;
213 }
214
215 // Find out how many blocks it will take to
216 // satisfy this allocation
217 PagesNeeded = ROUND_UP(MemorySize, MM_PAGE_SIZE) / MM_PAGE_SIZE;
218
219 // Get the page number for their desired address
220 DesiredAddressPageNumber = (ULONG_PTR)DesiredAddress / MM_PAGE_SIZE;
221
222 // If we don't have enough available mem
223 // then return NULL
224 if (FreePagesInLookupTable < PagesNeeded)
225 {
226 DPRINTM(DPRINT_MEMORY, "Memory allocation failed in MmAllocateHighestMemoryBelowAddress(). Not enough free memory to allocate %d bytes.\n", MemorySize);
227 UiMessageBoxCritical("Memory allocation failed: out of memory.");
228 return NULL;
229 }
230
231 FirstFreePageFromEnd = MmFindAvailablePagesBeforePage(PageLookupTableAddress, TotalPagesInLookupTable, PagesNeeded, DesiredAddressPageNumber);
232
233 if (FirstFreePageFromEnd == 0)
234 {
235 DPRINTM(DPRINT_MEMORY, "Memory allocation failed in MmAllocateHighestMemoryBelowAddress(). Not enough free memory to allocate %d bytes.\n", MemorySize);
236 UiMessageBoxCritical("Memory allocation failed: out of memory.");
237 return NULL;
238 }
239
240 MmAllocatePagesInLookupTable(PageLookupTableAddress, FirstFreePageFromEnd, PagesNeeded, MemoryType);
241
242 FreePagesInLookupTable -= PagesNeeded;
243 MemPointer = (PVOID)((ULONG_PTR)FirstFreePageFromEnd * MM_PAGE_SIZE);
244
245 #ifdef DBG
246 DPRINTM(DPRINT_MEMORY, "Allocated %d bytes (%d pages) of memory starting at page %d.\n", MemorySize, PagesNeeded, FirstFreePageFromEnd);
247 DPRINTM(DPRINT_MEMORY, "Memory allocation pointer: 0x%x\n", MemPointer);
248 #endif // DBG
249
250 // Update LoaderPagesSpanned count
251 if ((((ULONG_PTR)MemPointer + MemorySize) >> PAGE_SHIFT) > LoaderPagesSpanned)
252 LoaderPagesSpanned = (((ULONG_PTR)MemPointer + MemorySize) >> PAGE_SHIFT);
253
254 // Now return the pointer
255 return MemPointer;
256 }
257
258 VOID MmFreeMemory(PVOID MemoryPointer)
259 {
260 }
261
262 #ifdef DBG
263
264 VOID DumpMemoryAllocMap(VOID)
265 {
266 ULONG Idx;
267 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTableAddress;
268
269 DPRINTM(DPRINT_MEMORY, "----------- Memory Allocation Bitmap -----------\n");
270
271 for (Idx=0; Idx<TotalPagesInLookupTable; Idx++)
272 {
273 if ((Idx % 32) == 0)
274 {
275 DPRINTM(DPRINT_MEMORY, "\n");
276 DPRINTM(DPRINT_MEMORY, "%08x:\t", (Idx * MM_PAGE_SIZE));
277 }
278 else if ((Idx % 4) == 0)
279 {
280 DPRINTM(DPRINT_MEMORY, " ");
281 }
282
283 switch (RealPageLookupTable[Idx].PageAllocated)
284 {
285 case LoaderFree:
286 DPRINTM(DPRINT_MEMORY, "*");
287 break;
288 case LoaderBad:
289 DPRINTM(DPRINT_MEMORY, "-");
290 break;
291 case LoaderLoadedProgram:
292 DPRINTM(DPRINT_MEMORY, "O");
293 break;
294 case LoaderFirmwareTemporary:
295 DPRINTM(DPRINT_MEMORY, "T");
296 break;
297 case LoaderFirmwarePermanent:
298 DPRINTM(DPRINT_MEMORY, "P");
299 break;
300 case LoaderOsloaderHeap:
301 DPRINTM(DPRINT_MEMORY, "H");
302 break;
303 case LoaderOsloaderStack:
304 DPRINTM(DPRINT_MEMORY, "S");
305 break;
306 case LoaderSystemCode:
307 DPRINTM(DPRINT_MEMORY, "K");
308 break;
309 case LoaderHalCode:
310 DPRINTM(DPRINT_MEMORY, "L");
311 break;
312 case LoaderBootDriver:
313 DPRINTM(DPRINT_MEMORY, "B");
314 break;
315 case LoaderStartupPcrPage:
316 DPRINTM(DPRINT_MEMORY, "G");
317 break;
318 case LoaderRegistryData:
319 DPRINTM(DPRINT_MEMORY, "R");
320 break;
321 case LoaderMemoryData:
322 DPRINTM(DPRINT_MEMORY, "M");
323 break;
324 case LoaderNlsData:
325 DPRINTM(DPRINT_MEMORY, "N");
326 break;
327 case LoaderSpecialMemory:
328 DPRINTM(DPRINT_MEMORY, "C");
329 break;
330 default:
331 DPRINTM(DPRINT_MEMORY, "?");
332 break;
333 }
334 }
335
336 DPRINTM(DPRINT_MEMORY, "\n");
337 }
338 #endif // DBG
339
340 ULONG GetSystemMemorySize(VOID)
341 {
342 return (TotalPagesInLookupTable * MM_PAGE_SIZE);
343 }
344
345 PPAGE_LOOKUP_TABLE_ITEM MmGetMemoryMap(ULONG *NoEntries)
346 {
347 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTableAddress;
348
349 *NoEntries = TotalPagesInLookupTable;
350
351 return RealPageLookupTable;
352 }