xref: /reactos/boot/freeldr/freeldr/lib/mm/mm.c (revision 8d94b2a6)
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 along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #include <freeldr.h>
21 #include <debug.h>
22 
23 #if DBG
24 VOID    DumpMemoryAllocMap(VOID);
25 #endif // DBG
26 
27 DBG_DEFAULT_CHANNEL(MEMORY);
28 
29 PFN_NUMBER LoaderPagesSpanned = 0;
30 
MmAllocateMemoryWithType(SIZE_T MemorySize,TYPE_OF_MEMORY MemoryType)31 PVOID MmAllocateMemoryWithType(SIZE_T MemorySize, TYPE_OF_MEMORY MemoryType)
32 {
33     PFN_NUMBER    PagesNeeded;
34     PFN_NUMBER    FirstFreePageFromEnd;
35     PVOID    MemPointer;
36 
37     if (MemorySize == 0)
38     {
39         WARN("MmAllocateMemory() called for 0 bytes. Returning NULL.\n");
40         UiMessageBoxCritical("Memory allocation failed: MmAllocateMemory() called for 0 bytes.");
41         return NULL;
42     }
43 
44     MemorySize = ROUND_UP(MemorySize, 4);
45 
46     // Find out how many blocks it will take to
47     // satisfy this allocation
48     PagesNeeded = ROUND_UP(MemorySize, MM_PAGE_SIZE) / MM_PAGE_SIZE;
49 
50     // If we don't have enough available mem
51     // then return NULL
52     if (FreePagesInLookupTable < PagesNeeded)
53     {
54         ERR("Memory allocation failed in MmAllocateMemory(). Not enough free memory to allocate %d bytes.\n", MemorySize);
55         UiMessageBoxCritical("Memory allocation failed: out of memory.");
56         return NULL;
57     }
58 
59     FirstFreePageFromEnd = MmFindAvailablePages(PageLookupTableAddress, TotalPagesInLookupTable, PagesNeeded, FALSE);
60 
61     if (FirstFreePageFromEnd == 0)
62     {
63         ERR("Memory allocation failed in MmAllocateMemory(). Not enough free memory to allocate %d bytes.\n", MemorySize);
64         UiMessageBoxCritical("Memory allocation failed: out of memory.");
65         return NULL;
66     }
67 
68     MmAllocatePagesInLookupTable(PageLookupTableAddress, FirstFreePageFromEnd, PagesNeeded, MemoryType);
69 
70     FreePagesInLookupTable -= PagesNeeded;
71     MemPointer = (PVOID)((ULONG_PTR)FirstFreePageFromEnd * MM_PAGE_SIZE);
72 
73     TRACE("Allocated %d bytes (%d pages) of memory (type %ld) starting at page 0x%lx.\n",
74           MemorySize, PagesNeeded, MemoryType, FirstFreePageFromEnd);
75     TRACE("Memory allocation pointer: 0x%x\n", MemPointer);
76 
77     // Update LoaderPagesSpanned count
78     if ((((ULONG_PTR)MemPointer + MemorySize + PAGE_SIZE - 1) >> PAGE_SHIFT) > LoaderPagesSpanned)
79         LoaderPagesSpanned = (((ULONG_PTR)MemPointer + MemorySize + PAGE_SIZE - 1) >> PAGE_SHIFT);
80 
81     // Now return the pointer
82     return MemPointer;
83 }
84 
MmAllocateMemoryAtAddress(SIZE_T MemorySize,PVOID DesiredAddress,TYPE_OF_MEMORY MemoryType)85 PVOID MmAllocateMemoryAtAddress(SIZE_T MemorySize, PVOID DesiredAddress, TYPE_OF_MEMORY MemoryType)
86 {
87     PFN_NUMBER        PagesNeeded;
88     PFN_NUMBER        StartPageNumber;
89     PVOID    MemPointer;
90 
91     if (MemorySize == 0)
92     {
93         WARN("MmAllocateMemoryAtAddress() called for 0 bytes. Returning NULL.\n");
94         UiMessageBoxCritical("Memory allocation failed: MmAllocateMemoryAtAddress() called for 0 bytes.");
95         return NULL;
96     }
97 
98     // Find out how many blocks it will take to
99     // satisfy this allocation
100     PagesNeeded = ROUND_UP(MemorySize, MM_PAGE_SIZE) / MM_PAGE_SIZE;
101 
102     // Get the starting page number
103     StartPageNumber = MmGetPageNumberFromAddress(DesiredAddress);
104 
105     // If we don't have enough available mem
106     // then return NULL
107     if (FreePagesInLookupTable < PagesNeeded)
108     {
109         ERR("Memory allocation failed in MmAllocateMemoryAtAddress(). "
110             "Not enough free memory to allocate %d bytes (requesting %d pages but have only %d). "
111             "\n", MemorySize, PagesNeeded, FreePagesInLookupTable);
112         UiMessageBoxCritical("Memory allocation failed: out of memory.");
113         return NULL;
114     }
115 
116     if (MmAreMemoryPagesAvailable(PageLookupTableAddress, TotalPagesInLookupTable, DesiredAddress, PagesNeeded) == FALSE)
117     {
118         WARN("Memory allocation failed in MmAllocateMemoryAtAddress(). "
119              "Not enough free memory to allocate %d bytes at address %p.\n",
120              MemorySize, DesiredAddress);
121 
122         // Don't tell this to user since caller should try to alloc this memory
123         // at a different address
124         //UiMessageBoxCritical("Memory allocation failed: out of memory.");
125         return NULL;
126     }
127 
128     MmAllocatePagesInLookupTable(PageLookupTableAddress, StartPageNumber, PagesNeeded, MemoryType);
129 
130     FreePagesInLookupTable -= PagesNeeded;
131     MemPointer = (PVOID)((ULONG_PTR)StartPageNumber * MM_PAGE_SIZE);
132 
133     TRACE("Allocated %d bytes (%d pages) of memory starting at page %d.\n", MemorySize, PagesNeeded, StartPageNumber);
134     TRACE("Memory allocation pointer: 0x%x\n", MemPointer);
135 
136     // Update LoaderPagesSpanned count
137     if ((((ULONG_PTR)MemPointer + MemorySize + PAGE_SIZE - 1) >> PAGE_SHIFT) > LoaderPagesSpanned)
138         LoaderPagesSpanned = (((ULONG_PTR)MemPointer + MemorySize + PAGE_SIZE - 1) >> PAGE_SHIFT);
139 
140     // Now return the pointer
141     return MemPointer;
142 }
143 
MmSetMemoryType(PVOID MemoryAddress,SIZE_T MemorySize,TYPE_OF_MEMORY NewType)144 VOID MmSetMemoryType(PVOID MemoryAddress, SIZE_T MemorySize, TYPE_OF_MEMORY NewType)
145 {
146     PFN_NUMBER        PagesNeeded;
147     PFN_NUMBER        StartPageNumber;
148 
149     // Find out how many blocks it will take to
150     // satisfy this allocation
151     PagesNeeded = ROUND_UP(MemorySize, MM_PAGE_SIZE) / MM_PAGE_SIZE;
152 
153     // Get the starting page number
154     StartPageNumber = MmGetPageNumberFromAddress(MemoryAddress);
155 
156     // Set new type for these pages
157     MmAllocatePagesInLookupTable(PageLookupTableAddress, StartPageNumber, PagesNeeded, NewType);
158 }
159 
MmAllocateHighestMemoryBelowAddress(SIZE_T MemorySize,PVOID DesiredAddress,TYPE_OF_MEMORY MemoryType)160 PVOID MmAllocateHighestMemoryBelowAddress(SIZE_T MemorySize, PVOID DesiredAddress, TYPE_OF_MEMORY MemoryType)
161 {
162     PFN_NUMBER        PagesNeeded;
163     PFN_NUMBER        FirstFreePageFromEnd;
164     PFN_NUMBER        DesiredAddressPageNumber;
165     PVOID    MemPointer;
166 
167     if (MemorySize == 0)
168     {
169         WARN("MmAllocateHighestMemoryBelowAddress() called for 0 bytes. Returning NULL.\n");
170         UiMessageBoxCritical("Memory allocation failed: MmAllocateHighestMemoryBelowAddress() called for 0 bytes.");
171         return NULL;
172     }
173 
174     // Find out how many blocks it will take to
175     // satisfy this allocation
176     PagesNeeded = ROUND_UP(MemorySize, MM_PAGE_SIZE) / MM_PAGE_SIZE;
177 
178     // Get the page number for their desired address
179     DesiredAddressPageNumber = (ULONG_PTR)DesiredAddress / MM_PAGE_SIZE;
180 
181     // If we don't have enough available mem
182     // then return NULL
183     if (FreePagesInLookupTable < PagesNeeded)
184     {
185         ERR("Memory allocation failed in MmAllocateHighestMemoryBelowAddress(). Not enough free memory to allocate %d bytes.\n", MemorySize);
186         UiMessageBoxCritical("Memory allocation failed: out of memory.");
187         return NULL;
188     }
189 
190     FirstFreePageFromEnd = MmFindAvailablePagesBeforePage(PageLookupTableAddress, TotalPagesInLookupTable, PagesNeeded, DesiredAddressPageNumber);
191 
192     if (FirstFreePageFromEnd == 0)
193     {
194         ERR("Memory allocation failed in MmAllocateHighestMemoryBelowAddress(). Not enough free memory to allocate %d bytes.\n", MemorySize);
195         UiMessageBoxCritical("Memory allocation failed: out of memory.");
196         return NULL;
197     }
198 
199     MmAllocatePagesInLookupTable(PageLookupTableAddress, FirstFreePageFromEnd, PagesNeeded, MemoryType);
200 
201     FreePagesInLookupTable -= PagesNeeded;
202     MemPointer = (PVOID)((ULONG_PTR)FirstFreePageFromEnd * MM_PAGE_SIZE);
203 
204     TRACE("Allocated %d bytes (%d pages) of memory starting at page %d.\n", MemorySize, PagesNeeded, FirstFreePageFromEnd);
205     TRACE("Memory allocation pointer: 0x%x\n", MemPointer);
206 
207     // Update LoaderPagesSpanned count
208     if ((((ULONG_PTR)MemPointer + MemorySize) >> PAGE_SHIFT) > LoaderPagesSpanned)
209         LoaderPagesSpanned = (((ULONG_PTR)MemPointer + MemorySize) >> PAGE_SHIFT);
210 
211     // Now return the pointer
212     return MemPointer;
213 }
214 
MmFreeMemory(PVOID MemoryPointer)215 VOID MmFreeMemory(PVOID MemoryPointer)
216 {
217 }
218 
219 #if DBG
220 
DumpMemoryAllocMap(VOID)221 VOID DumpMemoryAllocMap(VOID)
222 {
223     PFN_NUMBER    Idx;
224     PPAGE_LOOKUP_TABLE_ITEM        RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTableAddress;
225 
226     DbgPrint("----------- Memory Allocation Bitmap -----------\n");
227 
228     for (Idx=0; Idx<TotalPagesInLookupTable; Idx++)
229     {
230         if ((Idx % 32) == 0)
231         {
232             DbgPrint("\n");
233             DbgPrint("%08x:\t", (Idx * MM_PAGE_SIZE));
234         }
235         else if ((Idx % 4) == 0)
236         {
237             DbgPrint(" ");
238         }
239 
240         switch (RealPageLookupTable[Idx].PageAllocated)
241         {
242         case LoaderFree:
243             DbgPrint("*");
244             break;
245         case LoaderBad:
246             DbgPrint("-");
247             break;
248         case LoaderLoadedProgram:
249             DbgPrint("O");
250             break;
251         case LoaderFirmwareTemporary:
252             DbgPrint("T");
253             break;
254         case LoaderFirmwarePermanent:
255             DbgPrint("P");
256             break;
257         case LoaderOsloaderHeap:
258             DbgPrint("H");
259             break;
260         case LoaderOsloaderStack:
261             DbgPrint("S");
262             break;
263         case LoaderSystemCode:
264             DbgPrint("K");
265             break;
266         case LoaderHalCode:
267             DbgPrint("L");
268             break;
269         case LoaderBootDriver:
270             DbgPrint("B");
271             break;
272         case LoaderStartupPcrPage:
273             DbgPrint("G");
274             break;
275         case LoaderRegistryData:
276             DbgPrint("R");
277             break;
278         case LoaderMemoryData:
279             DbgPrint("M");
280             break;
281         case LoaderNlsData:
282             DbgPrint("N");
283             break;
284         case LoaderSpecialMemory:
285             DbgPrint("C");
286             break;
287         default:
288             DbgPrint("?");
289             break;
290         }
291     }
292 
293     DbgPrint("\n");
294 }
295 #endif // DBG
296 
MmGetMemoryMap(PFN_NUMBER * NoEntries)297 PPAGE_LOOKUP_TABLE_ITEM MmGetMemoryMap(PFN_NUMBER *NoEntries)
298 {
299     PPAGE_LOOKUP_TABLE_ITEM        RealPageLookupTable = (PPAGE_LOOKUP_TABLE_ITEM)PageLookupTableAddress;
300 
301     *NoEntries = TotalPagesInLookupTable;
302 
303     return RealPageLookupTable;
304 }
305 
306