3 * Copyright (C) 2006-2008 Aleksey Bragin <aleksey@reactos.org>
4 * Copyright (C) 2006-2009 Hervé Poussineau <hpoussin@reactos.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 } FREELDR_MEMORY_TYPE
, *PFREELDR_MEMORY_TYPE
;
31 FREELDR_MEMORY_TYPE MemoryTypeArray
[] =
33 { MemoryMaximum
, "Unknown memory" },
34 { MemoryExceptionBlock
, "Exception block" },
35 { MemorySystemBlock
, "System block" },
36 { MemoryFree
, "Free memory" },
37 { MemoryBad
, "Bad memory" },
38 { MemoryLoadedProgram
, "Loaded program" },
39 { MemoryFirmwareTemporary
, "Firmware temporary" },
40 { MemoryFirmwarePermanent
, "Firmware permanent" },
41 { MemoryFreeContiguous
, "Free contiguous memory" },
42 { MemorySpecialMemory
, "Special memory" },
44 ULONG MemoryTypeCount
= sizeof(MemoryTypeArray
) / sizeof(MemoryTypeArray
[0]);
47 PVOID PageLookupTableAddress
= NULL
;
48 ULONG TotalPagesInLookupTable
= 0;
49 ULONG FreePagesInLookupTable
= 0;
50 ULONG LastFreePageHint
= 0;
52 extern ULONG_PTR MmHeapPointer
;
53 extern ULONG_PTR MmHeapStart
;
55 BOOLEAN
MmInitializeMemoryManager(VOID
)
58 MEMORY_DESCRIPTOR
* MemoryDescriptor
= NULL
;
61 DPRINTM(DPRINT_MEMORY
, "Initializing Memory Manager.\n");
64 // Dump the system memory map
65 DPRINTM(DPRINT_MEMORY
, "System Memory Map (Base Address, Length, Type):\n");
66 while ((MemoryDescriptor
= ArcGetMemoryDescriptor(MemoryDescriptor
)) != NULL
)
68 DPRINTM(DPRINT_MEMORY
, "%x\t %x\t %s\n",
69 MemoryDescriptor
->BasePage
* MM_PAGE_SIZE
,
70 MemoryDescriptor
->PageCount
* MM_PAGE_SIZE
,
71 MmGetSystemMemoryMapTypeString(MemoryDescriptor
->MemoryType
));
75 // Find address for the page lookup table
76 TotalPagesInLookupTable
= MmGetAddressablePageCountIncludingHoles();
77 PageLookupTableAddress
= MmFindLocationForPageLookupTable(TotalPagesInLookupTable
);
78 LastFreePageHint
= TotalPagesInLookupTable
;
80 if (PageLookupTableAddress
== 0)
82 // If we get here then we probably couldn't
83 // find a contiguous chunk of memory big
84 // enough to hold the page lookup table
85 printf("Error initializing memory manager!\n");
89 // Initialize the page lookup table
90 MmInitPageLookupTable(PageLookupTableAddress
, TotalPagesInLookupTable
);
91 MmUpdateLastFreePageHint(PageLookupTableAddress
, TotalPagesInLookupTable
);
93 FreePagesInLookupTable
= MmCountFreePagesInLookupTable(PageLookupTableAddress
, TotalPagesInLookupTable
);
95 MmInitializeHeap(PageLookupTableAddress
);
97 DPRINTM(DPRINT_MEMORY
, "Memory Manager initialized. %d pages available.\n", FreePagesInLookupTable
);
101 VOID
MmInitializeHeap(PVOID PageLookupTable
)
106 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
108 // HACK: Make it so it doesn't overlap kernel space
109 Type
= RealPageLookupTable
[0x100].PageAllocated
;
110 MmMarkPagesInLookupTable(PageLookupTableAddress
, 0x100, 0xFF, LoaderSystemCode
);
112 // Find contigious memory block for HEAP:STACK
113 PagesNeeded
= HEAP_PAGES
+ STACK_PAGES
;
114 HeapStart
= MmFindAvailablePages(PageLookupTable
, TotalPagesInLookupTable
, PagesNeeded
, FALSE
);
117 MmMarkPagesInLookupTable(PageLookupTableAddress
, 0x100, 0xFF, Type
);
121 UiMessageBox("Critical error: Can't allocate heap!");
126 bpool(HeapStart
<< MM_PAGE_SHIFT
, PagesNeeded
<< MM_PAGE_SHIFT
);
128 // Mark those pages as used
129 MmMarkPagesInLookupTable(PageLookupTableAddress
, HeapStart
, PagesNeeded
, LoaderOsloaderHeap
);
131 DPRINTM(DPRINT_MEMORY
, "Heap initialized, base 0x%08x, pages %d\n", (HeapStart
<< MM_PAGE_SHIFT
), PagesNeeded
);
135 PCSTR
MmGetSystemMemoryMapTypeString(MEMORY_TYPE Type
)
139 for (Index
=1; Index
<MemoryTypeCount
; Index
++)
141 if (MemoryTypeArray
[Index
].Type
== Type
)
143 return MemoryTypeArray
[Index
].TypeString
;
147 return MemoryTypeArray
[0].TypeString
;
151 ULONG
MmGetPageNumberFromAddress(PVOID Address
)
153 return ((ULONG_PTR
)Address
) / MM_PAGE_SIZE
;
156 ULONG
MmGetAddressablePageCountIncludingHoles(VOID
)
158 MEMORY_DESCRIPTOR
* MemoryDescriptor
= NULL
;
162 // Go through the whole memory map to get max address
164 while ((MemoryDescriptor
= ArcGetMemoryDescriptor(MemoryDescriptor
)) != NULL
)
167 // Check if we got a higher end page address
169 if (MemoryDescriptor
->BasePage
+ MemoryDescriptor
->PageCount
> EndPage
)
174 EndPage
= MemoryDescriptor
->BasePage
+ MemoryDescriptor
->PageCount
;
178 DPRINTM(DPRINT_MEMORY
, "MmGetAddressablePageCountIncludingHoles() returning 0x%x\n", EndPage
);
183 PVOID
MmFindLocationForPageLookupTable(ULONG TotalPageCount
)
185 MEMORY_DESCRIPTOR
* MemoryDescriptor
= NULL
;
186 ULONG PageLookupTableSize
;
187 ULONG PageLookupTablePages
;
188 ULONG PageLookupTableStartPage
= 0;
189 PVOID PageLookupTableMemAddress
= NULL
;
192 // Calculate how much pages we need to keep the page lookup table
194 PageLookupTableSize
= TotalPageCount
* sizeof(PAGE_LOOKUP_TABLE_ITEM
);
195 PageLookupTablePages
= PageLookupTableSize
/ MM_PAGE_SIZE
;
198 // Search the highest memory block big enough to contain lookup table
200 while ((MemoryDescriptor
= ArcGetMemoryDescriptor(MemoryDescriptor
)) != NULL
)
203 // Is it suitable memory?
205 if (MemoryDescriptor
->MemoryType
!= MemoryFree
)
208 // No. Process next descriptor
214 // Is the block big enough?
216 if (MemoryDescriptor
->PageCount
< PageLookupTablePages
)
219 // No. Process next descriptor
225 // Is it at a higher address than previous suitable address?
227 if (MemoryDescriptor
->BasePage
< PageLookupTableStartPage
)
230 // No. Process next descriptor
236 // Memory block is more suitable than the previous one
238 PageLookupTableStartPage
= MemoryDescriptor
->BasePage
;
239 PageLookupTableMemAddress
= (PVOID
)((ULONG_PTR
)
240 (MemoryDescriptor
->BasePage
+ MemoryDescriptor
->PageCount
) * MM_PAGE_SIZE
241 - PageLookupTableSize
);
244 DPRINTM(DPRINT_MEMORY
, "MmFindLocationForPageLookupTable() returning 0x%x\n", PageLookupTableMemAddress
);
246 return PageLookupTableMemAddress
;
249 VOID
MmInitPageLookupTable(PVOID PageLookupTable
, ULONG TotalPageCount
)
251 MEMORY_DESCRIPTOR
* MemoryDescriptor
= NULL
;
252 TYPE_OF_MEMORY MemoryMapPageAllocated
;
253 ULONG PageLookupTableStartPage
;
254 ULONG PageLookupTablePageCount
;
256 DPRINTM(DPRINT_MEMORY
, "MmInitPageLookupTable()\n");
259 // Mark every page as allocated initially
260 // We will go through and mark pages again according to the memory map
261 // But this will mark any holes not described in the map as allocated
263 MmMarkPagesInLookupTable(PageLookupTable
, 0, TotalPageCount
, LoaderFirmwarePermanent
);
266 // Parse the whole memory map
268 while ((MemoryDescriptor
= ArcGetMemoryDescriptor(MemoryDescriptor
)) != NULL
)
271 // Convert ARC memory type to loader memory type
273 switch (MemoryDescriptor
->MemoryType
)
278 // Allocatable memory
280 MemoryMapPageAllocated
= LoaderFree
;
283 case MemoryFirmwarePermanent
:
286 // Firmware permanent memory
288 MemoryMapPageAllocated
= LoaderFirmwarePermanent
;
291 case MemoryFirmwareTemporary
:
294 // Firmware temporary memory
296 MemoryMapPageAllocated
= LoaderFirmwareTemporary
;
299 case MemoryLoadedProgram
:
304 MemoryMapPageAllocated
= LoaderLoadedProgram
;
307 case MemorySpecialMemory
:
310 // Special reserved memory
312 MemoryMapPageAllocated
= LoaderSpecialMemory
;
318 // Put something sensible here, which won't be overwritten
320 MemoryMapPageAllocated
= LoaderSpecialMemory
;
326 // Mark used pages in the lookup table
328 DPRINTM(DPRINT_MEMORY
, "Marking pages as type %d: StartPage: %d PageCount: %d\n", MemoryMapPageAllocated
, MemoryDescriptor
->BasePage
, MemoryDescriptor
->PageCount
);
329 MmMarkPagesInLookupTable(PageLookupTable
, MemoryDescriptor
->BasePage
, MemoryDescriptor
->PageCount
, MemoryMapPageAllocated
);
333 // Mark the pages that the lookup table occupies as reserved
335 PageLookupTableStartPage
= MmGetPageNumberFromAddress(PageLookupTable
);
336 PageLookupTablePageCount
= MmGetPageNumberFromAddress((PVOID
)((ULONG_PTR
)PageLookupTable
+ ROUND_UP(TotalPageCount
* sizeof(PAGE_LOOKUP_TABLE_ITEM
), MM_PAGE_SIZE
))) - PageLookupTableStartPage
;
337 DPRINTM(DPRINT_MEMORY
, "Marking the page lookup table pages as reserved StartPage: %d PageCount: %d\n", PageLookupTableStartPage
, PageLookupTablePageCount
);
338 MmMarkPagesInLookupTable(PageLookupTable
, PageLookupTableStartPage
, PageLookupTablePageCount
, LoaderFirmwareTemporary
);
341 VOID
MmMarkPagesInLookupTable(PVOID PageLookupTable
, ULONG StartPage
, ULONG PageCount
, TYPE_OF_MEMORY PageAllocated
)
343 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
346 for (Index
=StartPage
; Index
<(StartPage
+PageCount
); Index
++)
349 if ((Index
<= (StartPage
+ 16)) || (Index
>= (StartPage
+PageCount
-16)))
351 DPRINTM(DPRINT_MEMORY
, "Index = %d StartPage = %d PageCount = %d\n", Index
, StartPage
, PageCount
);
354 RealPageLookupTable
[Index
].PageAllocated
= PageAllocated
;
355 RealPageLookupTable
[Index
].PageAllocationLength
= (PageAllocated
!= LoaderFree
) ? 1 : 0;
357 DPRINTM(DPRINT_MEMORY
, "MmMarkPagesInLookupTable() Done\n");
360 VOID
MmAllocatePagesInLookupTable(PVOID PageLookupTable
, ULONG StartPage
, ULONG PageCount
, TYPE_OF_MEMORY MemoryType
)
362 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
365 for (Index
=StartPage
; Index
<(StartPage
+PageCount
); Index
++)
367 RealPageLookupTable
[Index
].PageAllocated
= MemoryType
;
368 RealPageLookupTable
[Index
].PageAllocationLength
= (Index
== StartPage
) ? PageCount
: 0;
372 ULONG
MmCountFreePagesInLookupTable(PVOID PageLookupTable
, ULONG TotalPageCount
)
374 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
379 for (Index
=0; Index
<TotalPageCount
; Index
++)
381 if (RealPageLookupTable
[Index
].PageAllocated
== LoaderFree
)
387 return FreePageCount
;
390 ULONG
MmFindAvailablePages(PVOID PageLookupTable
, ULONG TotalPageCount
, ULONG PagesNeeded
, BOOLEAN FromEnd
)
392 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
393 ULONG AvailablePagesSoFar
;
396 if (LastFreePageHint
> TotalPageCount
)
398 LastFreePageHint
= TotalPageCount
;
401 AvailablePagesSoFar
= 0;
404 /* Allocate "high" (from end) pages */
405 for (Index
=LastFreePageHint
-1; Index
>0; Index
--)
407 if (RealPageLookupTable
[Index
].PageAllocated
!= LoaderFree
)
409 AvailablePagesSoFar
= 0;
414 AvailablePagesSoFar
++;
417 if (AvailablePagesSoFar
>= PagesNeeded
)
425 DPRINTM(DPRINT_MEMORY
, "Alloc low memory, LastFreePageHint %d, TPC %d\n", LastFreePageHint
, TotalPageCount
);
426 /* Allocate "low" pages */
427 for (Index
=1; Index
< LastFreePageHint
; Index
++)
429 if (RealPageLookupTable
[Index
].PageAllocated
!= LoaderFree
)
431 AvailablePagesSoFar
= 0;
436 AvailablePagesSoFar
++;
439 if (AvailablePagesSoFar
>= PagesNeeded
)
441 return Index
- AvailablePagesSoFar
+ 1;
449 ULONG
MmFindAvailablePagesBeforePage(PVOID PageLookupTable
, ULONG TotalPageCount
, ULONG PagesNeeded
, ULONG LastPage
)
451 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
452 ULONG AvailablePagesSoFar
;
455 if (LastPage
> TotalPageCount
)
457 return MmFindAvailablePages(PageLookupTable
, TotalPageCount
, PagesNeeded
, TRUE
);
460 AvailablePagesSoFar
= 0;
461 for (Index
=LastPage
-1; Index
>0; Index
--)
463 if (RealPageLookupTable
[Index
].PageAllocated
!= LoaderFree
)
465 AvailablePagesSoFar
= 0;
470 AvailablePagesSoFar
++;
473 if (AvailablePagesSoFar
>= PagesNeeded
)
482 VOID
MmUpdateLastFreePageHint(PVOID PageLookupTable
, ULONG TotalPageCount
)
484 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
487 for (Index
=TotalPageCount
-1; Index
>0; Index
--)
489 if (RealPageLookupTable
[Index
].PageAllocated
== LoaderFree
)
491 LastFreePageHint
= Index
+ 1;
497 BOOLEAN
MmAreMemoryPagesAvailable(PVOID PageLookupTable
, ULONG TotalPageCount
, PVOID PageAddress
, ULONG PageCount
)
499 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
503 StartPage
= MmGetPageNumberFromAddress(PageAddress
);
505 // Make sure they aren't trying to go past the
506 // end of availabe memory
507 if ((StartPage
+ PageCount
) > TotalPageCount
)
512 for (Index
=StartPage
; Index
<(StartPage
+ PageCount
); Index
++)
514 // If this page is allocated then there obviously isn't
515 // memory availabe so return FALSE
516 if (RealPageLookupTable
[Index
].PageAllocated
!= LoaderFree
)