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;
51 ULONG MmLowestPhysicalPage
= 0xFFFFFFFF;
52 ULONG MmHighestPhysicalPage
= 0;
54 extern ULONG_PTR MmHeapPointer
;
55 extern ULONG_PTR MmHeapStart
;
57 BOOLEAN
MmInitializeMemoryManager(VOID
)
60 const MEMORY_DESCRIPTOR
* MemoryDescriptor
= NULL
;
63 DPRINTM(DPRINT_MEMORY
, "Initializing Memory Manager.\n");
66 // Dump the system memory map
67 DPRINTM(DPRINT_MEMORY
, "System Memory Map (Base Address, Length, Type):\n");
68 while ((MemoryDescriptor
= ArcGetMemoryDescriptor(MemoryDescriptor
)) != NULL
)
70 DPRINTM(DPRINT_MEMORY
, "%x\t %x\t %s\n",
71 MemoryDescriptor
->BasePage
* MM_PAGE_SIZE
,
72 MemoryDescriptor
->PageCount
* MM_PAGE_SIZE
,
73 MmGetSystemMemoryMapTypeString(MemoryDescriptor
->MemoryType
));
77 // Find address for the page lookup table
78 TotalPagesInLookupTable
= MmGetAddressablePageCountIncludingHoles();
79 PageLookupTableAddress
= MmFindLocationForPageLookupTable(TotalPagesInLookupTable
);
80 LastFreePageHint
= MmHighestPhysicalPage
;
82 if (PageLookupTableAddress
== 0)
84 // If we get here then we probably couldn't
85 // find a contiguous chunk of memory big
86 // enough to hold the page lookup table
87 printf("Error initializing memory manager!\n");
91 // Initialize the page lookup table
92 MmInitPageLookupTable(PageLookupTableAddress
, TotalPagesInLookupTable
);
93 MmUpdateLastFreePageHint(PageLookupTableAddress
, TotalPagesInLookupTable
);
95 FreePagesInLookupTable
= MmCountFreePagesInLookupTable(PageLookupTableAddress
, TotalPagesInLookupTable
);
97 MmInitializeHeap(PageLookupTableAddress
);
99 DPRINTM(DPRINT_MEMORY
, "Memory Manager initialized. %d pages available.\n", FreePagesInLookupTable
);
103 VOID
MmInitializeHeap(PVOID PageLookupTable
)
109 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
111 // HACK: Make it so it doesn't overlap kernel space
112 Type
= RealPageLookupTable
[0x100].PageAllocated
;
113 MmMarkPagesInLookupTable(PageLookupTableAddress
, 0x100, 0xFF, LoaderSystemCode
);
115 // Find contigious memory block for HEAP:STACK
116 PagesNeeded
= HEAP_PAGES
+ STACK_PAGES
;
117 HeapStart
= MmFindAvailablePages(PageLookupTable
, TotalPagesInLookupTable
, PagesNeeded
, FALSE
);
120 MmMarkPagesInLookupTable(PageLookupTableAddress
, 0x100, 0xFF, Type
);
124 UiMessageBox("Critical error: Can't allocate heap!");
129 bpool(HeapStart
<< MM_PAGE_SHIFT
, PagesNeeded
<< MM_PAGE_SHIFT
);
131 // Mark those pages as used
132 MmMarkPagesInLookupTable(PageLookupTableAddress
, HeapStart
, PagesNeeded
, LoaderOsloaderHeap
);
134 DPRINTM(DPRINT_MEMORY
, "Heap initialized, base 0x%08x, pages %d\n", (HeapStart
<< MM_PAGE_SHIFT
), PagesNeeded
);
138 PCSTR
MmGetSystemMemoryMapTypeString(MEMORY_TYPE Type
)
142 for (Index
=1; Index
<MemoryTypeCount
; Index
++)
144 if (MemoryTypeArray
[Index
].Type
== Type
)
146 return MemoryTypeArray
[Index
].TypeString
;
150 return MemoryTypeArray
[0].TypeString
;
154 ULONG
MmGetPageNumberFromAddress(PVOID Address
)
156 return ((ULONG_PTR
)Address
) / MM_PAGE_SIZE
;
159 ULONG
MmGetAddressablePageCountIncludingHoles(VOID
)
161 const MEMORY_DESCRIPTOR
* MemoryDescriptor
= NULL
;
165 // Go through the whole memory map to get max address
167 while ((MemoryDescriptor
= ArcGetMemoryDescriptor(MemoryDescriptor
)) != NULL
)
170 // Check if we got a higher end page address
172 if (MemoryDescriptor
->BasePage
+ MemoryDescriptor
->PageCount
> MmHighestPhysicalPage
)
175 // Yes, remember it if this is real memory
177 if (MemoryDescriptor
->MemoryType
== MemoryFree
) MmHighestPhysicalPage
= MemoryDescriptor
->BasePage
+ MemoryDescriptor
->PageCount
;
181 // Check if we got a higher (usable) start page address
183 if (MemoryDescriptor
->BasePage
< MmLowestPhysicalPage
)
186 // Yes, remember it if this is real memory
188 if (MemoryDescriptor
->MemoryType
== MemoryFree
) MmLowestPhysicalPage
= MemoryDescriptor
->BasePage
;
192 DPRINTM(DPRINT_MEMORY
, "lo/hi %lx %lxn", MmLowestPhysicalPage
, MmHighestPhysicalPage
);
193 PageCount
= MmHighestPhysicalPage
- MmLowestPhysicalPage
;
194 DPRINTM(DPRINT_MEMORY
, "MmGetAddressablePageCountIncludingHoles() returning 0x%x\n", PageCount
);
198 PVOID
MmFindLocationForPageLookupTable(ULONG TotalPageCount
)
200 const MEMORY_DESCRIPTOR
* MemoryDescriptor
= NULL
;
201 ULONG PageLookupTableSize
;
202 ULONG PageLookupTablePages
;
203 ULONG PageLookupTableStartPage
= 0;
204 PVOID PageLookupTableMemAddress
= NULL
;
207 // Calculate how much pages we need to keep the page lookup table
209 PageLookupTableSize
= TotalPageCount
* sizeof(PAGE_LOOKUP_TABLE_ITEM
);
210 PageLookupTablePages
= PageLookupTableSize
/ MM_PAGE_SIZE
;
213 // Search the highest memory block big enough to contain lookup table
215 while ((MemoryDescriptor
= ArcGetMemoryDescriptor(MemoryDescriptor
)) != NULL
)
218 // Is it suitable memory?
220 if (MemoryDescriptor
->MemoryType
!= MemoryFree
)
223 // No. Process next descriptor
229 // Is the block big enough?
231 if (MemoryDescriptor
->PageCount
< PageLookupTablePages
)
234 // No. Process next descriptor
240 // Is it at a higher address than previous suitable address?
242 if (MemoryDescriptor
->BasePage
< PageLookupTableStartPage
)
245 // No. Process next descriptor
251 // Can we use this address?
253 if (MemoryDescriptor
->BasePage
>= MM_MAX_PAGE
)
256 // No. Process next descriptor
262 // Memory block is more suitable than the previous one
264 PageLookupTableStartPage
= MemoryDescriptor
->BasePage
;
265 PageLookupTableMemAddress
= (PVOID
)((ULONG_PTR
)
266 (MemoryDescriptor
->BasePage
+ MemoryDescriptor
->PageCount
) * MM_PAGE_SIZE
267 - PageLookupTableSize
);
270 DPRINTM(DPRINT_MEMORY
, "MmFindLocationForPageLookupTable() returning 0x%x\n", PageLookupTableMemAddress
);
272 return PageLookupTableMemAddress
;
275 VOID
MmInitPageLookupTable(PVOID PageLookupTable
, ULONG TotalPageCount
)
277 const MEMORY_DESCRIPTOR
* MemoryDescriptor
= NULL
;
278 TYPE_OF_MEMORY MemoryMapPageAllocated
;
279 ULONG PageLookupTableStartPage
;
280 ULONG PageLookupTablePageCount
;
282 DPRINTM(DPRINT_MEMORY
, "MmInitPageLookupTable()\n");
285 // Mark every page as allocated initially
286 // We will go through and mark pages again according to the memory map
287 // But this will mark any holes not described in the map as allocated
289 MmMarkPagesInLookupTable(PageLookupTable
, MmLowestPhysicalPage
, TotalPageCount
, LoaderFirmwarePermanent
);
292 // Parse the whole memory map
294 while ((MemoryDescriptor
= ArcGetMemoryDescriptor(MemoryDescriptor
)) != NULL
)
297 // Convert ARC memory type to loader memory type
299 switch (MemoryDescriptor
->MemoryType
)
304 // Allocatable memory
306 MemoryMapPageAllocated
= LoaderFree
;
309 case MemoryFirmwarePermanent
:
312 // Firmware permanent memory
314 MemoryMapPageAllocated
= LoaderFirmwarePermanent
;
317 case MemoryFirmwareTemporary
:
320 // Firmware temporary memory
322 MemoryMapPageAllocated
= LoaderFirmwareTemporary
;
325 case MemoryLoadedProgram
:
330 MemoryMapPageAllocated
= LoaderLoadedProgram
;
333 case MemorySpecialMemory
:
338 MemoryMapPageAllocated
= LoaderOsloaderStack
;
344 // Put something sensible here, which won't be overwritten
346 MemoryMapPageAllocated
= LoaderSpecialMemory
;
352 // Mark used pages in the lookup table
354 DPRINTM(DPRINT_MEMORY
, "Marking pages as type %d: StartPage: %d PageCount: %d\n", MemoryMapPageAllocated
, MemoryDescriptor
->BasePage
, MemoryDescriptor
->PageCount
);
355 MmMarkPagesInLookupTable(PageLookupTable
, MemoryDescriptor
->BasePage
, MemoryDescriptor
->PageCount
, MemoryMapPageAllocated
);
359 // Mark the pages that the lookup table occupies as reserved
361 PageLookupTableStartPage
= MmGetPageNumberFromAddress(PageLookupTable
);
362 PageLookupTablePageCount
= MmGetPageNumberFromAddress((PVOID
)((ULONG_PTR
)PageLookupTable
+ ROUND_UP(TotalPageCount
* sizeof(PAGE_LOOKUP_TABLE_ITEM
), MM_PAGE_SIZE
))) - PageLookupTableStartPage
;
363 DPRINTM(DPRINT_MEMORY
, "Marking the page lookup table pages as reserved StartPage: %d PageCount: %d\n", PageLookupTableStartPage
, PageLookupTablePageCount
);
364 MmMarkPagesInLookupTable(PageLookupTable
, PageLookupTableStartPage
, PageLookupTablePageCount
, LoaderFirmwareTemporary
);
367 VOID
MmMarkPagesInLookupTable(PVOID PageLookupTable
, ULONG StartPage
, ULONG PageCount
, TYPE_OF_MEMORY PageAllocated
)
369 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
372 StartPage
-= MmLowestPhysicalPage
;
373 for (Index
=StartPage
; Index
<(StartPage
+PageCount
); Index
++)
376 if ((Index
<= (StartPage
+ 16)) || (Index
>= (StartPage
+PageCount
-16)))
378 DPRINTM(DPRINT_MEMORY
, "Index = %d StartPage = %d PageCount = %d\n", Index
, StartPage
, PageCount
);
381 RealPageLookupTable
[Index
].PageAllocated
= PageAllocated
;
382 RealPageLookupTable
[Index
].PageAllocationLength
= (PageAllocated
!= LoaderFree
) ? 1 : 0;
384 DPRINTM(DPRINT_MEMORY
, "MmMarkPagesInLookupTable() Done\n");
387 VOID
MmAllocatePagesInLookupTable(PVOID PageLookupTable
, ULONG StartPage
, ULONG PageCount
, TYPE_OF_MEMORY MemoryType
)
389 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
392 StartPage
-= MmLowestPhysicalPage
;
393 for (Index
=StartPage
; Index
<(StartPage
+PageCount
); Index
++)
395 RealPageLookupTable
[Index
].PageAllocated
= MemoryType
;
396 RealPageLookupTable
[Index
].PageAllocationLength
= (Index
== StartPage
) ? PageCount
: 0;
400 ULONG
MmCountFreePagesInLookupTable(PVOID PageLookupTable
, ULONG TotalPageCount
)
402 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
407 for (Index
=0; Index
<TotalPageCount
; Index
++)
409 if (RealPageLookupTable
[Index
].PageAllocated
== LoaderFree
)
415 return FreePageCount
;
418 ULONG
MmFindAvailablePages(PVOID PageLookupTable
, ULONG TotalPageCount
, ULONG PagesNeeded
, BOOLEAN FromEnd
)
420 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
421 ULONG AvailablePagesSoFar
;
424 if (LastFreePageHint
> TotalPageCount
)
426 LastFreePageHint
= TotalPageCount
;
429 AvailablePagesSoFar
= 0;
432 /* Allocate "high" (from end) pages */
433 for (Index
=LastFreePageHint
-1; Index
>0; Index
--)
435 if (RealPageLookupTable
[Index
].PageAllocated
!= LoaderFree
)
437 AvailablePagesSoFar
= 0;
442 AvailablePagesSoFar
++;
445 if (AvailablePagesSoFar
>= PagesNeeded
)
447 return Index
+ MmLowestPhysicalPage
;
453 DPRINTM(DPRINT_MEMORY
, "Alloc low memory, LastFreePageHint %d, TPC %d\n", LastFreePageHint
, TotalPageCount
);
454 /* Allocate "low" pages */
455 for (Index
=1; Index
< LastFreePageHint
; Index
++)
457 if (RealPageLookupTable
[Index
].PageAllocated
!= LoaderFree
)
459 AvailablePagesSoFar
= 0;
464 AvailablePagesSoFar
++;
467 if (AvailablePagesSoFar
>= PagesNeeded
)
469 return Index
- AvailablePagesSoFar
+ 1 + MmLowestPhysicalPage
;
477 ULONG
MmFindAvailablePagesBeforePage(PVOID PageLookupTable
, ULONG TotalPageCount
, ULONG PagesNeeded
, ULONG LastPage
)
479 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
480 ULONG AvailablePagesSoFar
;
483 if (LastPage
> TotalPageCount
)
485 return MmFindAvailablePages(PageLookupTable
, TotalPageCount
, PagesNeeded
, TRUE
);
488 AvailablePagesSoFar
= 0;
489 for (Index
=LastPage
-1; Index
>0; Index
--)
491 if (RealPageLookupTable
[Index
].PageAllocated
!= LoaderFree
)
493 AvailablePagesSoFar
= 0;
498 AvailablePagesSoFar
++;
501 if (AvailablePagesSoFar
>= PagesNeeded
)
503 return Index
+ MmLowestPhysicalPage
;
510 VOID
MmUpdateLastFreePageHint(PVOID PageLookupTable
, ULONG TotalPageCount
)
512 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
515 for (Index
=TotalPageCount
-1; Index
>0; Index
--)
517 if (RealPageLookupTable
[Index
].PageAllocated
== LoaderFree
)
519 LastFreePageHint
= Index
+ 1 + MmLowestPhysicalPage
;
525 BOOLEAN
MmAreMemoryPagesAvailable(PVOID PageLookupTable
, ULONG TotalPageCount
, PVOID PageAddress
, ULONG PageCount
)
527 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
531 StartPage
= MmGetPageNumberFromAddress(PageAddress
);
532 StartPage
-= MmLowestPhysicalPage
;
534 // Make sure they aren't trying to go past the
535 // end of availabe memory
536 if ((StartPage
+ PageCount
) > TotalPageCount
)
541 for (Index
=StartPage
; Index
<(StartPage
+ PageCount
); Index
++)
543 // If this page is allocated then there obviously isn't
544 // memory availabe so return FALSE
545 if (RealPageLookupTable
[Index
].PageAllocated
!= LoaderFree
)