3 * COPYRIGHT: See COPYING in the top directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/mminit.c
6 * PURPOSE: Kernel memory managment initialization functions
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS *****************************************************************/
20 * Compiler defined symbols
22 extern unsigned int _image_base__
;
23 extern unsigned int _text_start__
;
24 extern unsigned int _text_end__
;
26 extern unsigned int _init_start__
;
27 extern unsigned int _init_end__
;
29 extern unsigned int _bss_end__
;
32 static BOOLEAN IsThisAnNtAsSystem
= FALSE
;
33 MM_SYSTEMSIZE MmSystemSize
= MmSmallSystem
;
35 PHYSICAL_ADDRESS MmSharedDataPagePhysicalAddress
;
37 PVOID MiNonPagedPoolStart
;
38 ULONG MiNonPagedPoolLength
;
40 VOID INIT_FUNCTION NTAPI
MmInitVirtualMemory(ULONG_PTR LastKernelAddress
, ULONG KernelLength
);
42 #if defined (ALLOC_PRAGMA)
43 #pragma alloc_text(INIT, MmInitVirtualMemory)
44 #pragma alloc_text(INIT, MmInit1)
45 #pragma alloc_text(INIT, MmInit2)
46 #pragma alloc_text(INIT, MmInit3)
49 /* FUNCTIONS ****************************************************************/
54 BOOLEAN STDCALL
MmIsThisAnNtAsSystem(VOID
)
56 return(IsThisAnNtAsSystem
);
62 MM_SYSTEMSIZE STDCALL
MmQuerySystemSize(VOID
)
69 MiShutdownMemoryManager(VOID
)
75 MmInitVirtualMemory(ULONG_PTR LastKernelAddress
,
78 * FUNCTION: Intialize the memory areas list
80 * bp = Pointer to the boot parameters
81 * kernel_len = Length of the kernel
86 ULONG ParamLength
= KernelLength
;
88 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
92 DPRINT("MmInitVirtualMemory(%x, %x)\n",LastKernelAddress
, KernelLength
);
94 BoundaryAddressMultiple
.QuadPart
= 0;
95 LastKernelAddress
= PAGE_ROUND_UP(LastKernelAddress
);
99 /* Start the paged and nonpaged pool at a 4MB boundary. */
100 MiNonPagedPoolStart
= (PVOID
)ROUND_UP((ULONG_PTR
)LastKernelAddress
+ PAGE_SIZE
, 0x400000);
101 MiNonPagedPoolLength
= MM_NONPAGED_POOL_SIZE
;
103 MmPagedPoolBase
= (PVOID
)ROUND_UP((ULONG_PTR
)MiNonPagedPoolStart
+ MiNonPagedPoolLength
+ PAGE_SIZE
, 0x400000);
104 MmPagedPoolSize
= MM_PAGED_POOL_SIZE
;
106 DPRINT("NonPagedPool %x - %x, PagedPool %x - %x\n", MiNonPagedPoolStart
, (ULONG_PTR
)MiNonPagedPoolStart
+ MiNonPagedPoolLength
- 1,
107 MmPagedPoolBase
, (ULONG_PTR
)MmPagedPoolBase
+ MmPagedPoolSize
- 1);
109 MiInitializeNonPagedPool();
112 * Setup the system area descriptor list
114 MiInitPageDirectoryMap();
116 BaseAddress
= (PVOID
)KPCR_BASE
;
117 MmCreateMemoryArea(MmGetKernelAddressSpace(),
120 PAGE_SIZE
* MAXIMUM_PROCESSORS
,
125 BoundaryAddressMultiple
);
127 /* Local APIC base */
128 BaseAddress
= (PVOID
)0xFEE00000;
129 MmCreateMemoryArea(MmGetKernelAddressSpace(),
137 BoundaryAddressMultiple
);
140 BaseAddress
= (PVOID
)0xFEC00000;
141 MmCreateMemoryArea(MmGetKernelAddressSpace(),
149 BoundaryAddressMultiple
);
151 BaseAddress
= (PVOID
)0xFF3A0000;
152 MmCreateMemoryArea(MmGetKernelAddressSpace(),
160 BoundaryAddressMultiple
);
162 BaseAddress
= (PVOID
)&_image_base__
;
163 Length
= PAGE_ROUND_UP(((ULONG_PTR
)&_text_end__
)) - (ULONG_PTR
)&_image_base__
;
164 ParamLength
= ParamLength
- Length
;
167 * No need to lock the address space at this point since no
168 * other threads are running.
170 MmCreateMemoryArea(MmGetKernelAddressSpace(),
178 BoundaryAddressMultiple
);
180 BaseAddress
= (PVOID
)PAGE_ROUND_UP(((ULONG_PTR
)&_text_end__
));
181 ASSERT(BaseAddress
== (PVOID
)&_init_start__
);
182 Length
= PAGE_ROUND_UP(((ULONG_PTR
)&_init_end__
)) -
183 PAGE_ROUND_UP(((ULONG_PTR
)&_text_end__
));
184 ParamLength
= ParamLength
- Length
;
186 MmCreateMemoryArea(MmGetKernelAddressSpace(),
194 BoundaryAddressMultiple
);
196 Length
= PAGE_ROUND_UP(((ULONG_PTR
)&_bss_end__
)) -
197 PAGE_ROUND_UP(((ULONG_PTR
)&_init_end__
));
198 ParamLength
= ParamLength
- Length
;
199 DPRINT("Length %x\n",Length
);
200 BaseAddress
= (PVOID
)PAGE_ROUND_UP(((ULONG_PTR
)&_init_end__
));
201 DPRINT("BaseAddress %x\n",BaseAddress
);
204 * No need to lock the address space at this point since we are
205 * the only thread running.
207 MmCreateMemoryArea(MmGetKernelAddressSpace(),
215 BoundaryAddressMultiple
);
217 BaseAddress
= (PVOID
)PAGE_ROUND_UP(((ULONG_PTR
)&_bss_end__
));
218 Length
= LastKernelAddress
- (ULONG_PTR
)BaseAddress
;
219 MmCreateMemoryArea(MmGetKernelAddressSpace(),
227 BoundaryAddressMultiple
);
229 BaseAddress
= MiNonPagedPoolStart
;
230 MmCreateMemoryArea(MmGetKernelAddressSpace(),
233 MiNonPagedPoolLength
,
238 BoundaryAddressMultiple
);
240 BaseAddress
= MmPagedPoolBase
;
241 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
242 MEMORY_AREA_PAGED_POOL
,
249 BoundaryAddressMultiple
);
251 MmInitializePagedPool();
254 * Create the kernel mapping of the user/kernel shared memory.
256 BaseAddress
= (PVOID
)KI_USER_SHARED_DATA
;
258 MmCreateMemoryArea(MmGetKernelAddressSpace(),
266 BoundaryAddressMultiple
);
267 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Pfn
);
268 MmSharedDataPagePhysicalAddress
.QuadPart
= Pfn
<< PAGE_SHIFT
;
269 Status
= MmCreateVirtualMapping(NULL
,
270 (PVOID
)KI_USER_SHARED_DATA
,
274 if (!NT_SUCCESS(Status
))
276 DbgPrint("Unable to create virtual mapping\n");
279 RtlZeroMemory(BaseAddress
, Length
);
284 MmInitializeMemoryConsumer(MC_USER
, MmTrimUserMemory
);
290 MmInit1(ULONG_PTR FirstKrnlPhysAddr
,
291 ULONG_PTR LastKrnlPhysAddr
,
292 ULONG_PTR LastKernelAddress
,
293 PADDRESS_RANGE BIOSMemoryMap
,
294 ULONG AddressRangeCount
,
297 * FUNCTION: Initalize memory managment
302 ULONG_PTR MappingAddress
;
303 PLDR_DATA_TABLE_ENTRY LdrEntry
;
305 DPRINT("MmInit1(FirstKrnlPhysAddr, %p, LastKrnlPhysAddr %p, LastKernelAddress %p)\n",
310 /* Set the page directory */
311 PsGetCurrentProcess()->Pcb
.DirectoryTableBase
.LowPart
= (ULONG
)MmGetPageDirectory();
313 if ((BIOSMemoryMap
!= NULL
) && (AddressRangeCount
> 0))
315 // If we have a bios memory map, recalulate the memory size
317 for (i
= 0; i
< AddressRangeCount
; i
++)
319 if (BIOSMemoryMap
[i
].Type
== 1
320 && (BIOSMemoryMap
[i
].BaseAddrLow
+ BIOSMemoryMap
[i
].LengthLow
+ PAGE_SIZE
-1) / PAGE_SIZE
> last
)
322 last
= (BIOSMemoryMap
[i
].BaseAddrLow
+ BIOSMemoryMap
[i
].LengthLow
+ PAGE_SIZE
-1) / PAGE_SIZE
;
325 if ((last
- 256) * 4 > MmFreeLdrMemHigher
)
327 MmFreeLdrMemHigher
= (last
- 256) * 4;
332 if (!MmFreeLdrMemHigher
) MmFreeLdrMemHigher
= 65536;
333 if (!MmFreeLdrPageDirectoryEnd
) MmFreeLdrPageDirectoryEnd
= 0x40000;
334 if (!FirstKrnlPhysAddr
)
336 /* Get the kernel entry */
337 LdrEntry
= CONTAINING_RECORD(KeLoaderBlock
->LoadOrderListHead
.Flink
,
338 LDR_DATA_TABLE_ENTRY
,
341 /* Get the addresses */
342 FirstKrnlPhysAddr
= (ULONG_PTR
)LdrEntry
->DllBase
- KSEG0_BASE
;
344 /* FIXME: How do we get the last address? */
347 if (MmFreeLdrMemHigher
>= (MaxMem
- 1) * 1024)
349 MmFreeLdrMemHigher
= (MaxMem
- 1) * 1024;
352 /* Set memory limits */
353 MmUserProbeAddress
= (ULONG_PTR
)MmSystemRangeStart
- 0x10000;
354 MmHighestUserAddress
= (PVOID
)(MmUserProbeAddress
- 1);
357 * Initialize memory managment statistics
359 MmStats
.NrTotalPages
= 0;
360 MmStats
.NrSystemPages
= 0;
361 MmStats
.NrUserPages
= 0;
362 MmStats
.NrReservedPages
= 0;
363 MmStats
.NrUserPages
= 0;
364 MmStats
.NrFreePages
= 0;
365 MmStats
.NrLockedPages
= 0;
366 MmStats
.PagingRequestsInLastMinute
= 0;
367 MmStats
.PagingRequestsInLastFiveMinutes
= 0;
368 MmStats
.PagingRequestsInLastFifteenMinutes
= 0;
371 * Free all pages not used for kernel memory
372 * (we assume the kernel occupies a continuous range of physical
375 DPRINT("first krnl %x\nlast krnl %x\n",FirstKrnlPhysAddr
,
379 * Free physical memory not used by the kernel
381 MmStats
.NrTotalPages
= MmFreeLdrMemHigher
/4;
382 if (!MmStats
.NrTotalPages
)
384 DbgPrint("Memory not detected, default to 8 MB\n");
385 MmStats
.NrTotalPages
= 2048;
389 /* add 1MB for standard memory (not extended) */
390 MmStats
.NrTotalPages
+= 256;
393 MmStats
.NrTotalPages
+= 16;
397 * Initialize the kernel address space
399 MmInitializeKernelAddressSpace();
401 MmInitGlobalKernelPageDirectory();
403 DbgPrint("Used memory %dKb\n", (MmStats
.NrTotalPages
* PAGE_SIZE
) / 1024);
405 LastKernelAddress
= (ULONG_PTR
)MmInitializePageList(
408 MmStats
.NrTotalPages
,
409 PAGE_ROUND_UP(LastKernelAddress
),
412 kernel_len
= LastKrnlPhysAddr
- FirstKrnlPhysAddr
;
418 /* In SMP mode we unmap the low memory pagetable in MmInit3.
419 The APIC needs the mapping of the first pages
420 while the processors are starting up.
421 We unmap all pages except page 2 and 3. */
422 for (MappingAddress
= 0;
423 MappingAddress
< 1024 * PAGE_SIZE
;
424 MappingAddress
+= PAGE_SIZE
)
426 if (MappingAddress
!= 2 * PAGE_SIZE
&&
427 MappingAddress
!= 3 * PAGE_SIZE
)
429 MmRawDeleteVirtualMapping((PVOID
)MappingAddress
);
433 MmDeletePageTable(NULL
, 0);
436 DPRINT("Invalidating between %x and %x\n",
437 LastKernelAddress
, KSEG0_BASE
+ 0x00600000);
438 for (MappingAddress
= LastKernelAddress
;
439 MappingAddress
< KSEG0_BASE
+ 0x00600000;
440 MappingAddress
+= PAGE_SIZE
)
442 MmRawDeleteVirtualMapping((PVOID
)MappingAddress
);
445 DPRINT("Almost done MmInit()\n");
447 * Intialize memory areas
449 MmInitVirtualMemory(LastKernelAddress
, kernel_len
);
451 MmInitializeMdlImplementation();
454 BOOLEAN RmapReady
, PageOpReady
, SectionsReady
, PagingReady
;
461 MmInitializeRmapList();
463 MmInitializePageOp();
465 MmInitSectionImplementation();
466 SectionsReady
= TRUE
;
480 /* In SMP mode we can unmap the low memory
481 if all processors are started. */
482 MmDeletePageTable(NULL
, 0);
485 MmCreatePhysicalMemorySection();
486 MiInitBalancerThread();
489 * Initialise the modified page writer.
493 /* FIXME: Read parameters from memory */
497 MiFreeInitMemoryPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
498 PFN_TYPE Page
, SWAPENTRY SwapEntry
,
501 ASSERT(SwapEntry
== 0);
504 MmReleasePageMemoryConsumer(MC_NPPOOL
, Page
);
510 MiFreeInitMemory(VOID
)
512 MmLockAddressSpace(MmGetKernelAddressSpace());
513 MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
514 (PVOID
)&_init_start__
,
515 MiFreeInitMemoryPage
,
517 MmUnlockAddressSpace(MmGetKernelAddressSpace());