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.
24 DBG_DEFAULT_CHANNEL(MEMORY
);
31 } FREELDR_MEMORY_TYPE
, *PFREELDR_MEMORY_TYPE
;
33 FREELDR_MEMORY_TYPE MemoryTypeArray
[] =
35 { MemoryMaximum
, "Unknown memory" },
36 { MemoryExceptionBlock
, "Exception block" },
37 { MemorySystemBlock
, "System block" },
38 { MemoryFree
, "Free memory" },
39 { MemoryBad
, "Bad memory" },
40 { MemoryLoadedProgram
, "Loaded program" },
41 { MemoryFirmwareTemporary
, "Firmware temporary" },
42 { MemoryFirmwarePermanent
, "Firmware permanent" },
43 { MemoryFreeContiguous
, "Free contiguous memory" },
44 { MemorySpecialMemory
, "Special memory" },
46 ULONG MemoryTypeCount
= sizeof(MemoryTypeArray
) / sizeof(MemoryTypeArray
[0]);
49 PVOID PageLookupTableAddress
= NULL
;
50 ULONG TotalPagesInLookupTable
= 0;
51 ULONG FreePagesInLookupTable
= 0;
52 ULONG LastFreePageHint
= 0;
53 ULONG MmLowestPhysicalPage
= 0xFFFFFFFF;
54 ULONG MmHighestPhysicalPage
= 0;
56 extern ULONG_PTR MmHeapPointer
;
57 extern ULONG_PTR MmHeapStart
;
59 BOOLEAN
MmInitializeMemoryManager(VOID
)
62 const MEMORY_DESCRIPTOR
* MemoryDescriptor
= NULL
;
65 TRACE("Initializing Memory Manager.\n");
68 // Dump the system memory map
69 TRACE("System Memory Map (Base Address, Length, Type):\n");
70 while ((MemoryDescriptor
= ArcGetMemoryDescriptor(MemoryDescriptor
)) != NULL
)
72 TRACE("%x\t %x\t %s\n",
73 MemoryDescriptor
->BasePage
* MM_PAGE_SIZE
,
74 MemoryDescriptor
->PageCount
* MM_PAGE_SIZE
,
75 MmGetSystemMemoryMapTypeString(MemoryDescriptor
->MemoryType
));
79 // Find address for the page lookup table
80 TotalPagesInLookupTable
= MmGetAddressablePageCountIncludingHoles();
81 PageLookupTableAddress
= MmFindLocationForPageLookupTable(TotalPagesInLookupTable
);
82 LastFreePageHint
= MmHighestPhysicalPage
;
84 if (PageLookupTableAddress
== 0)
86 // If we get here then we probably couldn't
87 // find a contiguous chunk of memory big
88 // enough to hold the page lookup table
89 printf("Error initializing memory manager!\n");
93 // Initialize the page lookup table
94 MmInitPageLookupTable(PageLookupTableAddress
, TotalPagesInLookupTable
);
95 MmUpdateLastFreePageHint(PageLookupTableAddress
, TotalPagesInLookupTable
);
97 FreePagesInLookupTable
= MmCountFreePagesInLookupTable(PageLookupTableAddress
, TotalPagesInLookupTable
);
99 MmInitializeHeap(PageLookupTableAddress
);
101 TRACE("Memory Manager initialized. %d pages available.\n", FreePagesInLookupTable
);
105 VOID
MmInitializeHeap(PVOID PageLookupTable
)
111 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
113 // HACK: Make it so it doesn't overlap kernel space
114 Type
= RealPageLookupTable
[0x100].PageAllocated
;
115 MmMarkPagesInLookupTable(PageLookupTableAddress
, 0x100, 0xFF, LoaderSystemCode
);
117 // Find contigious memory block for HEAP:STACK
118 PagesNeeded
= HEAP_PAGES
+ STACK_PAGES
;
119 HeapStart
= MmFindAvailablePages(PageLookupTable
, TotalPagesInLookupTable
, PagesNeeded
, FALSE
);
122 MmMarkPagesInLookupTable(PageLookupTableAddress
, 0x100, 0xFF, Type
);
126 UiMessageBox("Critical error: Can't allocate heap!");
131 bpool(HeapStart
<< MM_PAGE_SHIFT
, PagesNeeded
<< MM_PAGE_SHIFT
);
133 // Mark those pages as used
134 MmMarkPagesInLookupTable(PageLookupTableAddress
, HeapStart
, PagesNeeded
, LoaderOsloaderHeap
);
136 TRACE("Heap initialized, base 0x%08x, pages %d\n", (HeapStart
<< MM_PAGE_SHIFT
), PagesNeeded
);
140 PCSTR
MmGetSystemMemoryMapTypeString(MEMORY_TYPE Type
)
144 for (Index
=1; Index
<MemoryTypeCount
; Index
++)
146 if (MemoryTypeArray
[Index
].Type
== Type
)
148 return MemoryTypeArray
[Index
].TypeString
;
152 return MemoryTypeArray
[0].TypeString
;
156 ULONG
MmGetPageNumberFromAddress(PVOID Address
)
158 return ((ULONG_PTR
)Address
) / MM_PAGE_SIZE
;
161 ULONG
MmGetAddressablePageCountIncludingHoles(VOID
)
163 const MEMORY_DESCRIPTOR
* MemoryDescriptor
= NULL
;
167 // Go through the whole memory map to get max address
169 while ((MemoryDescriptor
= ArcGetMemoryDescriptor(MemoryDescriptor
)) != NULL
)
172 // Check if we got a higher end page address
174 if (MemoryDescriptor
->BasePage
+ MemoryDescriptor
->PageCount
> MmHighestPhysicalPage
)
177 // Yes, remember it if this is real memory
179 if (MemoryDescriptor
->MemoryType
== MemoryFree
) MmHighestPhysicalPage
= MemoryDescriptor
->BasePage
+ MemoryDescriptor
->PageCount
;
183 // Check if we got a higher (usable) start page address
185 if (MemoryDescriptor
->BasePage
< MmLowestPhysicalPage
)
188 // Yes, remember it if this is real memory
190 if (MemoryDescriptor
->MemoryType
== MemoryFree
) MmLowestPhysicalPage
= MemoryDescriptor
->BasePage
;
194 TRACE("lo/hi %lx %lxn", MmLowestPhysicalPage
, MmHighestPhysicalPage
);
195 PageCount
= MmHighestPhysicalPage
- MmLowestPhysicalPage
;
196 TRACE("MmGetAddressablePageCountIncludingHoles() returning 0x%x\n", PageCount
);
200 PVOID
MmFindLocationForPageLookupTable(ULONG TotalPageCount
)
202 const MEMORY_DESCRIPTOR
* MemoryDescriptor
= NULL
;
203 ULONG PageLookupTableSize
;
204 ULONG PageLookupTablePages
;
205 ULONG PageLookupTableStartPage
= 0;
206 PVOID PageLookupTableMemAddress
= NULL
;
209 // Calculate how much pages we need to keep the page lookup table
211 PageLookupTableSize
= TotalPageCount
* sizeof(PAGE_LOOKUP_TABLE_ITEM
);
212 PageLookupTablePages
= PageLookupTableSize
/ MM_PAGE_SIZE
;
215 // Search the highest memory block big enough to contain lookup table
217 while ((MemoryDescriptor
= ArcGetMemoryDescriptor(MemoryDescriptor
)) != NULL
)
220 // Is it suitable memory?
222 if (MemoryDescriptor
->MemoryType
!= MemoryFree
)
225 // No. Process next descriptor
231 // Is the block big enough?
233 if (MemoryDescriptor
->PageCount
< PageLookupTablePages
)
236 // No. Process next descriptor
242 // Is it at a higher address than previous suitable address?
244 if (MemoryDescriptor
->BasePage
< PageLookupTableStartPage
)
247 // No. Process next descriptor
253 // Can we use this address?
255 if (MemoryDescriptor
->BasePage
>= MM_MAX_PAGE
)
258 // No. Process next descriptor
264 // Memory block is more suitable than the previous one
266 PageLookupTableStartPage
= MemoryDescriptor
->BasePage
;
267 PageLookupTableMemAddress
= (PVOID
)((ULONG_PTR
)
268 (MemoryDescriptor
->BasePage
+ MemoryDescriptor
->PageCount
) * MM_PAGE_SIZE
269 - PageLookupTableSize
);
272 TRACE("MmFindLocationForPageLookupTable() returning 0x%x\n", PageLookupTableMemAddress
);
274 return PageLookupTableMemAddress
;
277 VOID
MmInitPageLookupTable(PVOID PageLookupTable
, ULONG TotalPageCount
)
279 const MEMORY_DESCRIPTOR
* MemoryDescriptor
= NULL
;
280 TYPE_OF_MEMORY MemoryMapPageAllocated
;
281 ULONG PageLookupTableStartPage
;
282 ULONG PageLookupTablePageCount
;
284 TRACE("MmInitPageLookupTable()\n");
287 // Mark every page as allocated initially
288 // We will go through and mark pages again according to the memory map
289 // But this will mark any holes not described in the map as allocated
291 MmMarkPagesInLookupTable(PageLookupTable
, MmLowestPhysicalPage
, TotalPageCount
, LoaderFirmwarePermanent
);
294 // Parse the whole memory map
296 while ((MemoryDescriptor
= ArcGetMemoryDescriptor(MemoryDescriptor
)) != NULL
)
299 // Convert ARC memory type to loader memory type
301 switch (MemoryDescriptor
->MemoryType
)
306 // Allocatable memory
308 MemoryMapPageAllocated
= LoaderFree
;
311 case MemoryFirmwarePermanent
:
314 // Firmware permanent memory
316 MemoryMapPageAllocated
= LoaderFirmwarePermanent
;
319 case MemoryFirmwareTemporary
:
322 // Firmware temporary memory
324 MemoryMapPageAllocated
= LoaderFirmwareTemporary
;
327 case MemoryLoadedProgram
:
332 MemoryMapPageAllocated
= LoaderLoadedProgram
;
335 case MemorySpecialMemory
:
340 MemoryMapPageAllocated
= LoaderOsloaderStack
;
346 // Put something sensible here, which won't be overwritten
348 MemoryMapPageAllocated
= LoaderSpecialMemory
;
354 // Mark used pages in the lookup table
356 TRACE("Marking pages as type %d: StartPage: %d PageCount: %d\n", MemoryMapPageAllocated
, MemoryDescriptor
->BasePage
, MemoryDescriptor
->PageCount
);
357 MmMarkPagesInLookupTable(PageLookupTable
, MemoryDescriptor
->BasePage
, MemoryDescriptor
->PageCount
, MemoryMapPageAllocated
);
361 // Mark the pages that the lookup table occupies as reserved
363 PageLookupTableStartPage
= MmGetPageNumberFromAddress(PageLookupTable
);
364 PageLookupTablePageCount
= MmGetPageNumberFromAddress((PVOID
)((ULONG_PTR
)PageLookupTable
+ ROUND_UP(TotalPageCount
* sizeof(PAGE_LOOKUP_TABLE_ITEM
), MM_PAGE_SIZE
))) - PageLookupTableStartPage
;
365 TRACE("Marking the page lookup table pages as reserved StartPage: %d PageCount: %d\n", PageLookupTableStartPage
, PageLookupTablePageCount
);
366 MmMarkPagesInLookupTable(PageLookupTable
, PageLookupTableStartPage
, PageLookupTablePageCount
, LoaderFirmwareTemporary
);
369 VOID
MmMarkPagesInLookupTable(PVOID PageLookupTable
, ULONG StartPage
, ULONG PageCount
, TYPE_OF_MEMORY PageAllocated
)
371 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
374 StartPage
-= MmLowestPhysicalPage
;
375 for (Index
=StartPage
; Index
<(StartPage
+PageCount
); Index
++)
378 if ((Index
<= (StartPage
+ 16)) || (Index
>= (StartPage
+PageCount
-16)))
380 TRACE("Index = %d StartPage = %d PageCount = %d\n", Index
, StartPage
, PageCount
);
383 RealPageLookupTable
[Index
].PageAllocated
= PageAllocated
;
384 RealPageLookupTable
[Index
].PageAllocationLength
= (PageAllocated
!= LoaderFree
) ? 1 : 0;
386 TRACE("MmMarkPagesInLookupTable() Done\n");
389 VOID
MmAllocatePagesInLookupTable(PVOID PageLookupTable
, ULONG StartPage
, ULONG PageCount
, TYPE_OF_MEMORY MemoryType
)
391 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
394 StartPage
-= MmLowestPhysicalPage
;
395 for (Index
=StartPage
; Index
<(StartPage
+PageCount
); Index
++)
397 RealPageLookupTable
[Index
].PageAllocated
= MemoryType
;
398 RealPageLookupTable
[Index
].PageAllocationLength
= (Index
== StartPage
) ? PageCount
: 0;
402 ULONG
MmCountFreePagesInLookupTable(PVOID PageLookupTable
, ULONG TotalPageCount
)
404 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
409 for (Index
=0; Index
<TotalPageCount
; Index
++)
411 if (RealPageLookupTable
[Index
].PageAllocated
== LoaderFree
)
417 return FreePageCount
;
420 ULONG
MmFindAvailablePages(PVOID PageLookupTable
, ULONG TotalPageCount
, ULONG PagesNeeded
, BOOLEAN FromEnd
)
422 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
423 ULONG AvailablePagesSoFar
;
426 if (LastFreePageHint
> TotalPageCount
)
428 LastFreePageHint
= TotalPageCount
;
431 AvailablePagesSoFar
= 0;
434 /* Allocate "high" (from end) pages */
435 for (Index
=LastFreePageHint
-1; Index
>0; Index
--)
437 if (RealPageLookupTable
[Index
].PageAllocated
!= LoaderFree
)
439 AvailablePagesSoFar
= 0;
444 AvailablePagesSoFar
++;
447 if (AvailablePagesSoFar
>= PagesNeeded
)
449 return Index
+ MmLowestPhysicalPage
;
455 TRACE("Alloc low memory, LastFreePageHint %d, TPC %d\n", LastFreePageHint
, TotalPageCount
);
456 /* Allocate "low" pages */
457 for (Index
=1; Index
< LastFreePageHint
; Index
++)
459 if (RealPageLookupTable
[Index
].PageAllocated
!= LoaderFree
)
461 AvailablePagesSoFar
= 0;
466 AvailablePagesSoFar
++;
469 if (AvailablePagesSoFar
>= PagesNeeded
)
471 return Index
- AvailablePagesSoFar
+ 1 + MmLowestPhysicalPage
;
479 ULONG
MmFindAvailablePagesBeforePage(PVOID PageLookupTable
, ULONG TotalPageCount
, ULONG PagesNeeded
, ULONG LastPage
)
481 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
482 ULONG AvailablePagesSoFar
;
485 if (LastPage
> TotalPageCount
)
487 return MmFindAvailablePages(PageLookupTable
, TotalPageCount
, PagesNeeded
, TRUE
);
490 AvailablePagesSoFar
= 0;
491 for (Index
=LastPage
-1; Index
>0; Index
--)
493 if (RealPageLookupTable
[Index
].PageAllocated
!= LoaderFree
)
495 AvailablePagesSoFar
= 0;
500 AvailablePagesSoFar
++;
503 if (AvailablePagesSoFar
>= PagesNeeded
)
505 return Index
+ MmLowestPhysicalPage
;
512 VOID
MmUpdateLastFreePageHint(PVOID PageLookupTable
, ULONG TotalPageCount
)
514 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
517 for (Index
=TotalPageCount
-1; Index
>0; Index
--)
519 if (RealPageLookupTable
[Index
].PageAllocated
== LoaderFree
)
521 LastFreePageHint
= Index
+ 1 + MmLowestPhysicalPage
;
527 BOOLEAN
MmAreMemoryPagesAvailable(PVOID PageLookupTable
, ULONG TotalPageCount
, PVOID PageAddress
, ULONG PageCount
)
529 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
533 StartPage
= MmGetPageNumberFromAddress(PageAddress
);
534 StartPage
-= MmLowestPhysicalPage
;
536 // Make sure they aren't trying to go past the
537 // end of availabe memory
538 if ((StartPage
+ PageCount
) > TotalPageCount
)
543 for (Index
=StartPage
; Index
<(StartPage
+ PageCount
); Index
++)
545 // If this page is allocated then there obviously isn't
546 // memory availabe so return FALSE
547 if (RealPageLookupTable
[Index
].PageAllocated
!= LoaderFree
)