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 _text_start__
;
23 extern unsigned int _text_end__
;
25 extern unsigned int _init_start__
;
26 extern unsigned int _init_end__
;
28 extern unsigned int _bss_end__
;
31 static BOOLEAN IsThisAnNtAsSystem
= FALSE
;
32 static MM_SYSTEM_SIZE MmSystemSize
= MmSmallSystem
;
34 PHYSICAL_ADDRESS MmSharedDataPagePhysicalAddress
;
36 PVOID MiNonPagedPoolStart
;
37 ULONG MiNonPagedPoolLength
;
39 extern ULONG init_stack
;
40 extern ULONG init_stack_top
;
41 extern ULONG trap_stack
;
43 VOID INIT_FUNCTION NTAPI
MmInitVirtualMemory(ULONG_PTR LastKernelAddress
, ULONG KernelLength
);
45 #if defined (ALLOC_PRAGMA)
46 #pragma alloc_text(INIT, MmInitVirtualMemory)
47 #pragma alloc_text(INIT, MmInit1)
48 #pragma alloc_text(INIT, MmInit2)
49 #pragma alloc_text(INIT, MmInit3)
52 /* FUNCTIONS ****************************************************************/
57 BOOLEAN STDCALL
MmIsThisAnNtAsSystem(VOID
)
59 return(IsThisAnNtAsSystem
);
65 MM_SYSTEM_SIZE STDCALL
MmQuerySystemSize(VOID
)
72 MiShutdownMemoryManager(VOID
)
78 MmInitVirtualMemory(ULONG_PTR LastKernelAddress
,
81 * FUNCTION: Intialize the memory areas list
83 * bp = Pointer to the boot parameters
84 * kernel_len = Length of the kernel
89 ULONG ParamLength
= KernelLength
;
91 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
95 DPRINT("MmInitVirtualMemory(%x, %x)\n",LastKernelAddress
, KernelLength
);
97 BoundaryAddressMultiple
.QuadPart
= 0;
98 LastKernelAddress
= PAGE_ROUND_UP(LastKernelAddress
);
102 /* Start the paged and nonpaged pool at a 4MB boundary. */
103 MiNonPagedPoolStart
= (PVOID
)ROUND_UP((ULONG_PTR
)LastKernelAddress
+ PAGE_SIZE
, 0x400000);
104 MiNonPagedPoolLength
= MM_NONPAGED_POOL_SIZE
;
106 MmPagedPoolBase
= (PVOID
)ROUND_UP((ULONG_PTR
)MiNonPagedPoolStart
+ MiNonPagedPoolLength
+ PAGE_SIZE
, 0x400000);
107 MmPagedPoolSize
= MM_PAGED_POOL_SIZE
;
109 DPRINT("NonPagedPool %x - %x, PagedPool %x - %x\n", MiNonPagedPoolStart
, (ULONG_PTR
)MiNonPagedPoolStart
+ MiNonPagedPoolLength
- 1,
110 MmPagedPoolBase
, (ULONG_PTR
)MmPagedPoolBase
+ MmPagedPoolSize
- 1);
112 MiInitializeNonPagedPool();
115 * Setup the system area descriptor list
117 MiInitPageDirectoryMap();
119 BaseAddress
= (PVOID
)KPCR_BASE
;
120 MmCreateMemoryArea(MmGetKernelAddressSpace(),
123 PAGE_SIZE
* MAXIMUM_PROCESSORS
,
128 BoundaryAddressMultiple
);
130 /* Local APIC base */
131 BaseAddress
= (PVOID
)0xFEE00000;
132 MmCreateMemoryArea(MmGetKernelAddressSpace(),
140 BoundaryAddressMultiple
);
143 BaseAddress
= (PVOID
)0xFEC00000;
144 MmCreateMemoryArea(MmGetKernelAddressSpace(),
152 BoundaryAddressMultiple
);
154 BaseAddress
= (PVOID
)0xFF3A0000;
155 MmCreateMemoryArea(MmGetKernelAddressSpace(),
163 BoundaryAddressMultiple
);
165 BaseAddress
= (PVOID
)KERNEL_BASE
;
166 Length
= PAGE_ROUND_UP(((ULONG_PTR
)&_text_end__
)) - KERNEL_BASE
;
167 ParamLength
= ParamLength
- Length
;
170 * No need to lock the address space at this point since no
171 * other threads are running.
173 MmCreateMemoryArea(MmGetKernelAddressSpace(),
181 BoundaryAddressMultiple
);
183 BaseAddress
= (PVOID
)PAGE_ROUND_UP(((ULONG_PTR
)&_text_end__
));
184 ASSERT(BaseAddress
== (PVOID
)&_init_start__
);
185 Length
= PAGE_ROUND_UP(((ULONG_PTR
)&_init_end__
)) -
186 PAGE_ROUND_UP(((ULONG_PTR
)&_text_end__
));
187 ParamLength
= ParamLength
- Length
;
189 MmCreateMemoryArea(MmGetKernelAddressSpace(),
197 BoundaryAddressMultiple
);
199 Length
= PAGE_ROUND_UP(((ULONG_PTR
)&_bss_end__
)) -
200 PAGE_ROUND_UP(((ULONG_PTR
)&_init_end__
));
201 ParamLength
= ParamLength
- Length
;
202 DPRINT("Length %x\n",Length
);
203 BaseAddress
= (PVOID
)PAGE_ROUND_UP(((ULONG_PTR
)&_init_end__
));
204 DPRINT("BaseAddress %x\n",BaseAddress
);
207 * No need to lock the address space at this point since we are
208 * the only thread running.
210 MmCreateMemoryArea(MmGetKernelAddressSpace(),
218 BoundaryAddressMultiple
);
220 BaseAddress
= (PVOID
)PAGE_ROUND_UP(((ULONG_PTR
)&_bss_end__
));
221 Length
= LastKernelAddress
- (ULONG_PTR
)BaseAddress
;
222 MmCreateMemoryArea(MmGetKernelAddressSpace(),
230 BoundaryAddressMultiple
);
232 BaseAddress
= MiNonPagedPoolStart
;
233 MmCreateMemoryArea(MmGetKernelAddressSpace(),
236 MiNonPagedPoolLength
,
241 BoundaryAddressMultiple
);
243 BaseAddress
= MmPagedPoolBase
;
244 Status
= MmCreateMemoryArea(MmGetKernelAddressSpace(),
245 MEMORY_AREA_PAGED_POOL
,
252 BoundaryAddressMultiple
);
254 MmInitializePagedPool();
257 * Create the kernel mapping of the user/kernel shared memory.
259 BaseAddress
= (PVOID
)KI_USER_SHARED_DATA
;
261 MmCreateMemoryArea(MmGetKernelAddressSpace(),
269 BoundaryAddressMultiple
);
270 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Pfn
);
271 MmSharedDataPagePhysicalAddress
.QuadPart
= Pfn
<< PAGE_SHIFT
;
272 Status
= MmCreateVirtualMapping(NULL
,
273 (PVOID
)KI_USER_SHARED_DATA
,
277 if (!NT_SUCCESS(Status
))
279 DbgPrint("Unable to create virtual mapping\n");
282 RtlZeroMemory(BaseAddress
, Length
);
287 MmInitializeMemoryConsumer(MC_USER
, MmTrimUserMemory
);
293 MmInit1(ULONG_PTR FirstKrnlPhysAddr
,
294 ULONG_PTR LastKrnlPhysAddr
,
295 ULONG_PTR LastKernelAddress
,
296 PADDRESS_RANGE BIOSMemoryMap
,
297 ULONG AddressRangeCount
,
300 * FUNCTION: Initalize memory managment
305 ULONG_PTR MappingAddress
;
307 DPRINT("MmInit1(FirstKrnlPhysAddr, %p, LastKrnlPhysAddr %p, LastKernelAddress %p)\n",
312 if ((BIOSMemoryMap
!= NULL
) && (AddressRangeCount
> 0))
314 // If we have a bios memory map, recalulate the memory size
316 for (i
= 0; i
< AddressRangeCount
; i
++)
318 if (BIOSMemoryMap
[i
].Type
== 1
319 && (BIOSMemoryMap
[i
].BaseAddrLow
+ BIOSMemoryMap
[i
].LengthLow
+ PAGE_SIZE
-1) / PAGE_SIZE
> last
)
321 last
= (BIOSMemoryMap
[i
].BaseAddrLow
+ BIOSMemoryMap
[i
].LengthLow
+ PAGE_SIZE
-1) / PAGE_SIZE
;
324 if ((last
- 256) * 4 > KeLoaderBlock
.MemHigher
)
326 KeLoaderBlock
.MemHigher
= (last
- 256) * 4;
330 if (KeLoaderBlock
.MemHigher
>= (MaxMem
- 1) * 1024)
332 KeLoaderBlock
.MemHigher
= (MaxMem
- 1) * 1024;
335 /* Set memory limits */
336 MmUserProbeAddress
= (ULONG_PTR
)MmSystemRangeStart
- 0x10000;
337 MmHighestUserAddress
= (PVOID
)(MmUserProbeAddress
- 1);
340 * Initialize memory managment statistics
342 MmStats
.NrTotalPages
= 0;
343 MmStats
.NrSystemPages
= 0;
344 MmStats
.NrUserPages
= 0;
345 MmStats
.NrReservedPages
= 0;
346 MmStats
.NrUserPages
= 0;
347 MmStats
.NrFreePages
= 0;
348 MmStats
.NrLockedPages
= 0;
349 MmStats
.PagingRequestsInLastMinute
= 0;
350 MmStats
.PagingRequestsInLastFiveMinutes
= 0;
351 MmStats
.PagingRequestsInLastFifteenMinutes
= 0;
354 * Free all pages not used for kernel memory
355 * (we assume the kernel occupies a continuous range of physical
358 DPRINT("first krnl %x\nlast krnl %x\n",FirstKrnlPhysAddr
,
362 * Free physical memory not used by the kernel
364 MmStats
.NrTotalPages
= KeLoaderBlock
.MemHigher
/4;
365 if (!MmStats
.NrTotalPages
)
367 DbgPrint("Memory not detected, default to 8 MB\n");
368 MmStats
.NrTotalPages
= 2048;
372 /* add 1MB for standard memory (not extended) */
373 MmStats
.NrTotalPages
+= 256;
376 MmStats
.NrTotalPages
+= 16;
380 * Initialize the kernel address space
382 MmInitializeKernelAddressSpace();
384 MmInitGlobalKernelPageDirectory();
386 DbgPrint("Used memory %dKb\n", (MmStats
.NrTotalPages
* PAGE_SIZE
) / 1024);
387 DPRINT1("Kernel Stack Limits. InitTop = 0x%x, Init = 0x%x\n", init_stack_top
, init_stack
);
389 LastKernelAddress
= (ULONG_PTR
)MmInitializePageList(
392 MmStats
.NrTotalPages
,
393 PAGE_ROUND_UP(LastKernelAddress
),
396 kernel_len
= LastKrnlPhysAddr
- FirstKrnlPhysAddr
;
398 /* Unmap the guard pages from the initial stacks */
399 MmDeleteVirtualMapping(NULL
, (PVOID
)(init_stack
- PAGE_SIZE
), FALSE
, NULL
, NULL
);
400 MmDeleteVirtualMapping(NULL
, (PVOID
)(trap_stack
- PAGE_SIZE
), FALSE
, NULL
, NULL
);
406 /* In SMP mode we unmap the low memory pagetable in MmInit3.
407 The APIC needs the mapping of the first pages
408 while the processors are starting up.
409 We unmap all pages except page 2 and 3. */
410 for (MappingAddress
= 0;
411 MappingAddress
< 1024 * PAGE_SIZE
;
412 MappingAddress
+= PAGE_SIZE
)
414 if (MappingAddress
!= 2 * PAGE_SIZE
&&
415 MappingAddress
!= 3 * PAGE_SIZE
)
417 MmRawDeleteVirtualMapping((PVOID
)MappingAddress
);
421 MmDeletePageTable(NULL
, 0);
424 DPRINT("Invalidating between %x and %x\n",
425 LastKernelAddress
, KERNEL_BASE
+ 0x00600000);
426 for (MappingAddress
= LastKernelAddress
;
427 MappingAddress
< KERNEL_BASE
+ 0x00600000;
428 MappingAddress
+= PAGE_SIZE
)
430 MmRawDeleteVirtualMapping((PVOID
)MappingAddress
);
433 DPRINT("Almost done MmInit()\n");
435 * Intialize memory areas
437 MmInitVirtualMemory(LastKernelAddress
, kernel_len
);
439 MmInitializeMdlImplementation();
447 MmInitializeRmapList();
448 MmInitializePageOp();
449 MmInitSectionImplementation();
462 /* In SMP mode we can unmap the low memory
463 if all processors are started. */
464 MmDeletePageTable(NULL
, 0);
467 MmInitZeroPageThread();
468 MmCreatePhysicalMemorySection();
469 MiInitBalancerThread();
472 * Initialise the modified page writer.
476 /* FIXME: Read parameters from memory */
480 MiFreeInitMemoryPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
481 PFN_TYPE Page
, SWAPENTRY SwapEntry
,
484 ASSERT(SwapEntry
== 0);
487 MmReleasePageMemoryConsumer(MC_NPPOOL
, Page
);
493 MiFreeInitMemory(VOID
)
495 MmLockAddressSpace(MmGetKernelAddressSpace());
496 MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
497 (PVOID
)&_init_start__
,
498 MiFreeInitMemoryPage
,
500 MmUnlockAddressSpace(MmGetKernelAddressSpace());