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 // HACK: Make it so it doesn't overlap kernel space
107 MmMarkPagesInLookupTable(PageLookupTableAddress
, 0x100, 0xFF, LoaderSystemCode
);
109 // Find contigious memory block for HEAP:STACK
110 PagesNeeded
= HEAP_PAGES
+ STACK_PAGES
;
111 HeapStart
= MmFindAvailablePages(PageLookupTable
, TotalPagesInLookupTable
, PagesNeeded
, FALSE
);
114 MmMarkPagesInLookupTable(PageLookupTableAddress
, 0x100, 0xFF, LoaderFree
);
118 UiMessageBox("Critical error: Can't allocate heap!");
123 bpool(HeapStart
<< MM_PAGE_SHIFT
, PagesNeeded
<< MM_PAGE_SHIFT
);
125 // Mark those pages as used
126 MmMarkPagesInLookupTable(PageLookupTableAddress
, HeapStart
, PagesNeeded
, LoaderOsloaderHeap
);
128 DPRINTM(DPRINT_MEMORY
, "Heap initialized, base 0x%08x, pages %d\n", (HeapStart
<< MM_PAGE_SHIFT
), PagesNeeded
);
132 PCSTR
MmGetSystemMemoryMapTypeString(MEMORY_TYPE Type
)
136 for (Index
=1; Index
<MemoryTypeCount
; Index
++)
138 if (MemoryTypeArray
[Index
].Type
== Type
)
140 return MemoryTypeArray
[Index
].TypeString
;
144 return MemoryTypeArray
[0].TypeString
;
148 ULONG
MmGetPageNumberFromAddress(PVOID Address
)
150 return ((ULONG_PTR
)Address
) / MM_PAGE_SIZE
;
153 ULONG
MmGetAddressablePageCountIncludingHoles(VOID
)
155 MEMORY_DESCRIPTOR
* MemoryDescriptor
= NULL
;
159 // Go through the whole memory map to get max address
161 while ((MemoryDescriptor
= ArcGetMemoryDescriptor(MemoryDescriptor
)) != NULL
)
164 // Check if we got a higher end page address
166 if (MemoryDescriptor
->BasePage
+ MemoryDescriptor
->PageCount
> EndPage
)
171 EndPage
= MemoryDescriptor
->BasePage
+ MemoryDescriptor
->PageCount
;
175 DPRINTM(DPRINT_MEMORY
, "MmGetAddressablePageCountIncludingHoles() returning 0x%x\n", EndPage
);
180 PVOID
MmFindLocationForPageLookupTable(ULONG TotalPageCount
)
182 MEMORY_DESCRIPTOR
* MemoryDescriptor
= NULL
;
183 ULONG PageLookupTableSize
;
184 ULONG PageLookupTablePages
;
185 ULONG PageLookupTableStartPage
= 0;
186 PVOID PageLookupTableMemAddress
= NULL
;
189 // Calculate how much pages we need to keep the page lookup table
191 PageLookupTableSize
= TotalPageCount
* sizeof(PAGE_LOOKUP_TABLE_ITEM
);
192 PageLookupTablePages
= PageLookupTableSize
/ MM_PAGE_SIZE
;
195 // Search the highest memory block big enough to contain lookup table
197 while ((MemoryDescriptor
= ArcGetMemoryDescriptor(MemoryDescriptor
)) != NULL
)
200 // Is it suitable memory?
202 if (MemoryDescriptor
->MemoryType
!= MemoryFree
)
205 // No. Process next descriptor
211 // Is the block big enough?
213 if (MemoryDescriptor
->PageCount
< PageLookupTablePages
)
216 // No. Process next descriptor
222 // Is it at a higher address than previous suitable address?
224 if (MemoryDescriptor
->BasePage
< PageLookupTableStartPage
)
227 // No. Process next descriptor
233 // Memory block is more suitable than the previous one
235 PageLookupTableStartPage
= MemoryDescriptor
->BasePage
;
236 PageLookupTableMemAddress
= (PVOID
)((ULONG_PTR
)
237 (MemoryDescriptor
->BasePage
+ MemoryDescriptor
->PageCount
) * MM_PAGE_SIZE
238 - PageLookupTableSize
);
241 DPRINTM(DPRINT_MEMORY
, "MmFindLocationForPageLookupTable() returning 0x%x\n", PageLookupTableMemAddress
);
243 return PageLookupTableMemAddress
;
246 VOID
MmInitPageLookupTable(PVOID PageLookupTable
, ULONG TotalPageCount
)
248 MEMORY_DESCRIPTOR
* MemoryDescriptor
= NULL
;
249 TYPE_OF_MEMORY MemoryMapPageAllocated
;
250 ULONG PageLookupTableStartPage
;
251 ULONG PageLookupTablePageCount
;
253 DPRINTM(DPRINT_MEMORY
, "MmInitPageLookupTable()\n");
256 // Mark every page as allocated initially
257 // We will go through and mark pages again according to the memory map
258 // But this will mark any holes not described in the map as allocated
260 MmMarkPagesInLookupTable(PageLookupTable
, 0, TotalPageCount
, LoaderFirmwarePermanent
);
263 // Parse the whole memory map
265 while ((MemoryDescriptor
= ArcGetMemoryDescriptor(MemoryDescriptor
)) != NULL
)
268 // Convert ARC memory type to loader memory type
270 switch (MemoryDescriptor
->MemoryType
)
275 // Allocatable memory
277 MemoryMapPageAllocated
= LoaderFree
;
280 case MemoryFirmwarePermanent
:
283 // Firmware permanent memory
285 MemoryMapPageAllocated
= LoaderFirmwarePermanent
;
288 case MemoryFirmwareTemporary
:
291 // Firmware temporary memory
293 MemoryMapPageAllocated
= LoaderFirmwareTemporary
;
296 case MemoryLoadedProgram
:
301 MemoryMapPageAllocated
= LoaderLoadedProgram
;
304 case MemorySpecialMemory
:
307 // Special reserved memory
309 MemoryMapPageAllocated
= LoaderSpecialMemory
;
315 // Put something sensible here, which won't be overwritten
317 MemoryMapPageAllocated
= LoaderSpecialMemory
;
323 // Mark used pages in the lookup table
325 DPRINTM(DPRINT_MEMORY
, "Marking pages as type %d: StartPage: %d PageCount: %d\n", MemoryMapPageAllocated
, MemoryDescriptor
->BasePage
, MemoryDescriptor
->PageCount
);
326 MmMarkPagesInLookupTable(PageLookupTable
, MemoryDescriptor
->BasePage
, MemoryDescriptor
->PageCount
, MemoryMapPageAllocated
);
330 // Mark the pages that the lookup table occupies as reserved
332 PageLookupTableStartPage
= MmGetPageNumberFromAddress(PageLookupTable
);
333 PageLookupTablePageCount
= MmGetPageNumberFromAddress((PVOID
)((ULONG_PTR
)PageLookupTable
+ ROUND_UP(TotalPageCount
* sizeof(PAGE_LOOKUP_TABLE_ITEM
), MM_PAGE_SIZE
))) - PageLookupTableStartPage
;
334 DPRINTM(DPRINT_MEMORY
, "Marking the page lookup table pages as reserved StartPage: %d PageCount: %d\n", PageLookupTableStartPage
, PageLookupTablePageCount
);
335 MmMarkPagesInLookupTable(PageLookupTable
, PageLookupTableStartPage
, PageLookupTablePageCount
, LoaderFirmwareTemporary
);
338 VOID
MmMarkPagesInLookupTable(PVOID PageLookupTable
, ULONG StartPage
, ULONG PageCount
, TYPE_OF_MEMORY PageAllocated
)
340 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
343 for (Index
=StartPage
; Index
<(StartPage
+PageCount
); Index
++)
346 if ((Index
<= (StartPage
+ 16)) || (Index
>= (StartPage
+PageCount
-16)))
348 DPRINTM(DPRINT_MEMORY
, "Index = %d StartPage = %d PageCount = %d\n", Index
, StartPage
, PageCount
);
351 RealPageLookupTable
[Index
].PageAllocated
= PageAllocated
;
352 RealPageLookupTable
[Index
].PageAllocationLength
= (PageAllocated
!= LoaderFree
) ? 1 : 0;
354 DPRINTM(DPRINT_MEMORY
, "MmMarkPagesInLookupTable() Done\n");
357 VOID
MmAllocatePagesInLookupTable(PVOID PageLookupTable
, ULONG StartPage
, ULONG PageCount
, TYPE_OF_MEMORY MemoryType
)
359 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
362 for (Index
=StartPage
; Index
<(StartPage
+PageCount
); Index
++)
364 RealPageLookupTable
[Index
].PageAllocated
= MemoryType
;
365 RealPageLookupTable
[Index
].PageAllocationLength
= (Index
== StartPage
) ? PageCount
: 0;
369 ULONG
MmCountFreePagesInLookupTable(PVOID PageLookupTable
, ULONG TotalPageCount
)
371 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
376 for (Index
=0; Index
<TotalPageCount
; Index
++)
378 if (RealPageLookupTable
[Index
].PageAllocated
== LoaderFree
)
384 return FreePageCount
;
387 ULONG
MmFindAvailablePages(PVOID PageLookupTable
, ULONG TotalPageCount
, ULONG PagesNeeded
, BOOLEAN FromEnd
)
389 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
390 ULONG AvailablePagesSoFar
;
393 if (LastFreePageHint
> TotalPageCount
)
395 LastFreePageHint
= TotalPageCount
;
398 AvailablePagesSoFar
= 0;
401 /* Allocate "high" (from end) pages */
402 for (Index
=LastFreePageHint
-1; Index
>0; Index
--)
404 if (RealPageLookupTable
[Index
].PageAllocated
!= LoaderFree
)
406 AvailablePagesSoFar
= 0;
411 AvailablePagesSoFar
++;
414 if (AvailablePagesSoFar
>= PagesNeeded
)
422 DPRINTM(DPRINT_MEMORY
, "Alloc low memory, LastFreePageHint %d, TPC %d\n", LastFreePageHint
, TotalPageCount
);
423 /* Allocate "low" pages */
424 for (Index
=1; Index
< LastFreePageHint
; Index
++)
426 if (RealPageLookupTable
[Index
].PageAllocated
!= LoaderFree
)
428 AvailablePagesSoFar
= 0;
433 AvailablePagesSoFar
++;
436 if (AvailablePagesSoFar
>= PagesNeeded
)
438 return Index
- AvailablePagesSoFar
+ 1;
446 ULONG
MmFindAvailablePagesBeforePage(PVOID PageLookupTable
, ULONG TotalPageCount
, ULONG PagesNeeded
, ULONG LastPage
)
448 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
449 ULONG AvailablePagesSoFar
;
452 if (LastPage
> TotalPageCount
)
454 return MmFindAvailablePages(PageLookupTable
, TotalPageCount
, PagesNeeded
, TRUE
);
457 AvailablePagesSoFar
= 0;
458 for (Index
=LastPage
-1; Index
>0; Index
--)
460 if (RealPageLookupTable
[Index
].PageAllocated
!= LoaderFree
)
462 AvailablePagesSoFar
= 0;
467 AvailablePagesSoFar
++;
470 if (AvailablePagesSoFar
>= PagesNeeded
)
479 VOID
MmUpdateLastFreePageHint(PVOID PageLookupTable
, ULONG TotalPageCount
)
481 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
484 for (Index
=TotalPageCount
-1; Index
>0; Index
--)
486 if (RealPageLookupTable
[Index
].PageAllocated
== LoaderFree
)
488 LastFreePageHint
= Index
+ 1;
494 BOOLEAN
MmAreMemoryPagesAvailable(PVOID PageLookupTable
, ULONG TotalPageCount
, PVOID PageAddress
, ULONG PageCount
)
496 PPAGE_LOOKUP_TABLE_ITEM RealPageLookupTable
= (PPAGE_LOOKUP_TABLE_ITEM
)PageLookupTable
;
500 StartPage
= MmGetPageNumberFromAddress(PageAddress
);
502 // Make sure they aren't trying to go past the
503 // end of availabe memory
504 if ((StartPage
+ PageCount
) > TotalPageCount
)
509 for (Index
=StartPage
; Index
<(StartPage
+ PageCount
); Index
++)
511 // If this page is allocated then there obviously isn't
512 // memory availabe so return FALSE
513 if (RealPageLookupTable
[Index
].PageAllocated
!= LoaderFree
)