1 /* $Id: mminit.c,v 1.64 2004/08/01 07:24:58 hbirr Exp $
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
7 * PROGRAMMER: David Welch (welch@cwcom.net)
12 /* INCLUDES *****************************************************************/
14 #include <ddk/ntddk.h>
16 #include <internal/i386/segment.h>
17 #include <internal/mm.h>
18 #include <internal/ntoskrnl.h>
19 #include <internal/io.h>
20 #include <internal/ps.h>
21 #include <internal/pool.h>
24 #include <internal/debug.h>
26 /* GLOBALS *****************************************************************/
29 * Compiler defined symbols
31 extern unsigned int _text_start__
;
32 extern unsigned int _text_end__
;
34 extern unsigned int _init_start__
;
35 extern unsigned int _init_end__
;
37 extern unsigned int _bss_end__
;
40 static BOOLEAN IsThisAnNtAsSystem
= FALSE
;
41 static MM_SYSTEM_SIZE MmSystemSize
= MmSmallSystem
;
43 static MEMORY_AREA
* kernel_text_desc
= NULL
;
44 static MEMORY_AREA
* kernel_init_desc
= NULL
;
45 static MEMORY_AREA
* kernel_map_desc
= NULL
;
46 static MEMORY_AREA
* kernel_kpcr_desc
= NULL
;
47 static MEMORY_AREA
* kernel_data_desc
= NULL
;
48 static MEMORY_AREA
* kernel_param_desc
= NULL
;
49 static MEMORY_AREA
* kernel_pool_desc
= NULL
;
50 static MEMORY_AREA
* kernel_shared_data_desc
= NULL
;
51 static MEMORY_AREA
* kernel_mapped_vga_framebuffer_desc
= NULL
;
52 static MEMORY_AREA
* MiKernelMapDescriptor
= NULL
;
53 static MEMORY_AREA
* MiPagedPoolDescriptor
= NULL
;
55 PHYSICAL_ADDRESS MmSharedDataPagePhysicalAddress
;
57 PVOID MiNonPagedPoolStart
;
58 ULONG MiNonPagedPoolLength
;
59 PVOID MiKernelMapStart
;
60 ULONG MiKernelMapLength
;
62 /* FUNCTIONS ****************************************************************/
67 BOOLEAN STDCALL
MmIsThisAnNtAsSystem(VOID
)
69 return(IsThisAnNtAsSystem
);
75 MM_SYSTEM_SIZE STDCALL
MmQuerySystemSize(VOID
)
80 VOID
MiShutdownMemoryManager(VOID
)
84 MmInitVirtualMemory(ULONG LastKernelAddress
,
87 * FUNCTION: Intialize the memory areas list
89 * bp = Pointer to the boot parameters
90 * kernel_len = Length of the kernel
95 ULONG ParamLength
= KernelLength
;
97 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
100 DPRINT("MmInitVirtualMemory(%x, %x)\n",LastKernelAddress
, KernelLength
);
102 BoundaryAddressMultiple
.QuadPart
= 0;
103 LastKernelAddress
= PAGE_ROUND_UP(LastKernelAddress
);
107 /* Don't change the start of kernel map. Pte's must always exist for this region. */
108 MiKernelMapStart
= (char*)LastKernelAddress
+ PAGE_SIZE
;
109 MiKernelMapLength
= MM_KERNEL_MAP_SIZE
;
111 MiNonPagedPoolStart
= (char*)MiKernelMapStart
+ MiKernelMapLength
+ PAGE_SIZE
;
112 MiNonPagedPoolLength
= MM_NONPAGED_POOL_SIZE
;
114 MmPagedPoolBase
= (char*)MiNonPagedPoolStart
+ MiNonPagedPoolLength
+ PAGE_SIZE
;
115 MmPagedPoolSize
= MM_PAGED_POOL_SIZE
;
119 MiInitializeNonPagedPool();
122 * Setup the system area descriptor list
124 BaseAddress
= (PVOID
)0xf0000000;
125 MmCreateMemoryArea(NULL
,
126 MmGetKernelAddressSpace(),
134 BoundaryAddressMultiple
);
136 BaseAddress
= (PVOID
)KPCR_BASE
;
137 MmCreateMemoryArea(NULL
,
138 MmGetKernelAddressSpace(),
141 PAGE_SIZE
* MAXIMUM_PROCESSORS
,
146 BoundaryAddressMultiple
);
148 BaseAddress
= (PVOID
)0xFF3A0000;
149 MmCreateMemoryArea(NULL
,
150 MmGetKernelAddressSpace(),
155 &kernel_mapped_vga_framebuffer_desc
,
158 BoundaryAddressMultiple
);
160 BaseAddress
= (PVOID
)KERNEL_BASE
;
161 Length
= PAGE_ROUND_UP(((ULONG
)&_text_end__
)) - KERNEL_BASE
;
162 ParamLength
= ParamLength
- Length
;
165 * No need to lock the address space at this point since no
166 * other threads are running.
168 MmCreateMemoryArea(NULL
,
169 MmGetKernelAddressSpace(),
177 BoundaryAddressMultiple
);
179 BaseAddress
= (PVOID
)PAGE_ROUND_UP(((ULONG
)&_text_end__
));
180 assert (BaseAddress
== (PVOID
)&_init_start__
);
181 Length
= PAGE_ROUND_UP(((ULONG
)&_init_end__
)) -
182 PAGE_ROUND_UP(((ULONG
)&_text_end__
));
183 ParamLength
= ParamLength
- Length
;
185 MmCreateMemoryArea(NULL
,
186 MmGetKernelAddressSpace(),
194 BoundaryAddressMultiple
);
196 Length
= PAGE_ROUND_UP(((ULONG
)&_bss_end__
)) -
197 PAGE_ROUND_UP(((ULONG
)&_init_end__
));
198 ParamLength
= ParamLength
- Length
;
199 DPRINT("Length %x\n",Length
);
200 BaseAddress
= (PVOID
)PAGE_ROUND_UP(((ULONG
)&_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(NULL
,
208 MmGetKernelAddressSpace(),
216 BoundaryAddressMultiple
);
218 BaseAddress
= (PVOID
)PAGE_ROUND_UP(((ULONG
)&_bss_end__
));
219 Length
= LastKernelAddress
- (ULONG
)BaseAddress
;
220 MmCreateMemoryArea(NULL
,
221 MmGetKernelAddressSpace(),
229 BoundaryAddressMultiple
);
231 BaseAddress
= MiNonPagedPoolStart
;
232 MmCreateMemoryArea(NULL
,
233 MmGetKernelAddressSpace(),
236 MiNonPagedPoolLength
,
241 BoundaryAddressMultiple
);
243 BaseAddress
= MiKernelMapStart
;
244 Status
= MmCreateMemoryArea(NULL
,
245 MmGetKernelAddressSpace(),
250 &MiKernelMapDescriptor
,
253 BoundaryAddressMultiple
);
255 BaseAddress
= MmPagedPoolBase
;
256 Status
= MmCreateMemoryArea(NULL
,
257 MmGetKernelAddressSpace(),
258 MEMORY_AREA_PAGED_POOL
,
262 &MiPagedPoolDescriptor
,
265 BoundaryAddressMultiple
);
267 MmInitializePagedPool();
270 * Create the kernel mapping of the user/kernel shared memory.
272 BaseAddress
= (PVOID
)KI_USER_SHARED_DATA
;
274 MmCreateMemoryArea(NULL
,
275 MmGetKernelAddressSpace(),
280 &kernel_shared_data_desc
,
283 BoundaryAddressMultiple
);
284 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Pfn
);
285 MmSharedDataPagePhysicalAddress
.QuadPart
= Pfn
<< PAGE_SHIFT
;
286 Status
= MmCreateVirtualMapping(NULL
,
287 (PVOID
)KI_USER_SHARED_DATA
,
291 if (!NT_SUCCESS(Status
))
293 DbgPrint("Unable to create virtual mapping\n");
296 RtlZeroMemory(BaseAddress
, Length
);
301 MmInitializeMemoryConsumer(MC_USER
, MmTrimUserMemory
);
305 MmInit1(ULONG FirstKrnlPhysAddr
,
306 ULONG LastKrnlPhysAddr
,
307 ULONG LastKernelAddress
,
308 PADDRESS_RANGE BIOSMemoryMap
,
309 ULONG AddressRangeCount
,
312 * FUNCTION: Initalize memory managment
319 extern unsigned int unmap_me
, unmap_me2
, unmap_me3
;
322 DPRINT("MmInit1(FirstKrnlPhysAddr, %x, LastKrnlPhysAddr %x, LastKernelAddress %x)\n",
328 if ((BIOSMemoryMap
!= NULL
) && (AddressRangeCount
> 0))
330 // If we have a bios memory map, recalulate the memory size
332 for (i
= 0; i
< AddressRangeCount
; i
++)
334 if (BIOSMemoryMap
[i
].Type
== 1
335 && (BIOSMemoryMap
[i
].BaseAddrLow
+ BIOSMemoryMap
[i
].LengthLow
+ PAGE_SIZE
-1) / PAGE_SIZE
> last
)
337 last
= (BIOSMemoryMap
[i
].BaseAddrLow
+ BIOSMemoryMap
[i
].LengthLow
+ PAGE_SIZE
-1) / PAGE_SIZE
;
340 if ((last
- 256) * 4 > KeLoaderBlock
.MemHigher
)
342 KeLoaderBlock
.MemHigher
= (last
- 256) * 4;
346 if (KeLoaderBlock
.MemHigher
>= (MaxMem
- 1) * 1024)
348 KeLoaderBlock
.MemHigher
= (MaxMem
- 1) * 1024;
352 * FIXME: Set this based on the system command line
354 MmSystemRangeStart
= (PVOID
)KERNEL_BASE
; // 0xC0000000
355 MmUserProbeAddress
= (PVOID
)0x7fff0000;
356 MmHighestUserAddress
= (PVOID
)0x7ffeffff;
358 MmInitGlobalKernelPageDirectory();
361 * Initialize memory managment statistics
363 MmStats
.NrTotalPages
= 0;
364 MmStats
.NrSystemPages
= 0;
365 MmStats
.NrUserPages
= 0;
366 MmStats
.NrReservedPages
= 0;
367 MmStats
.NrUserPages
= 0;
368 MmStats
.NrFreePages
= 0;
369 MmStats
.NrLockedPages
= 0;
370 MmStats
.PagingRequestsInLastMinute
= 0;
371 MmStats
.PagingRequestsInLastFiveMinutes
= 0;
372 MmStats
.PagingRequestsInLastFifteenMinutes
= 0;
375 * Initialize the kernel address space
377 MmInitializeKernelAddressSpace();
383 /* In SMP mode we unmap the low memory in MmInit3.
384 The APIC needs the mapping of the first pages
385 while the processors are starting up. */
386 MmDeletePageTable(NULL
, 0);
389 * Free all pages not used for kernel memory
390 * (we assume the kernel occupies a continuous range of physical
393 DPRINT("first krnl %x\nlast krnl %x\n",FirstKrnlPhysAddr
,
397 * Free physical memory not used by the kernel
399 MmStats
.NrTotalPages
= KeLoaderBlock
.MemHigher
/4;
400 if (!MmStats
.NrTotalPages
)
402 DbgPrint("Memory not detected, default to 8 MB\n");
403 MmStats
.NrTotalPages
= 2048;
407 /* add 1MB for standard memory (not extended) */
408 MmStats
.NrTotalPages
+= 256;
411 MmStats
.NrTotalPages
+= 16;
414 DbgPrint("Used memory %dKb\n", (MmStats
.NrTotalPages
* PAGE_SIZE
) / 1024);
416 LastKernelAddress
= (ULONG
)MmInitializePageList((PVOID
)FirstKrnlPhysAddr
,
417 (PVOID
)LastKrnlPhysAddr
,
418 MmStats
.NrTotalPages
,
419 PAGE_ROUND_UP(LastKernelAddress
),
422 kernel_len
= LastKrnlPhysAddr
- FirstKrnlPhysAddr
;
425 * Create a trap for null pointer references and protect text
429 DPRINT("_text_start__ %x _init_end__ %x\n",(int)&_text_start__
,(int)&_init_end__
);
430 for (i
=PAGE_ROUND_DOWN(((int)&_text_start__
));
431 i
<PAGE_ROUND_UP(((int)&_init_end__
));i
=i
+PAGE_SIZE
)
433 MmSetPageProtect(NULL
,
438 DPRINT("Invalidating between %x and %x\n",
439 LastKernelAddress
, 0xc0600000);
440 for (i
=(LastKernelAddress
); i
<0xc0600000; i
+=PAGE_SIZE
)
442 MmRawDeleteVirtualMapping((PVOID
)(i
));
445 DPRINT("Invalidating between %x and %x\n",
446 0xd0100000, 0xd0400000);
447 for (i
=0xd0100000; i
<0xd0400000; i
+=PAGE_SIZE
)
449 MmRawDeleteVirtualMapping((PVOID
)(i
));
452 DPRINT("Almost done MmInit()\n");
454 /* FIXME: This is broken in SMP mode */
455 MmDeleteVirtualMapping(NULL
, (PVOID
)&unmap_me
, TRUE
, NULL
, NULL
);
456 MmDeleteVirtualMapping(NULL
, (PVOID
)&unmap_me2
, TRUE
, NULL
, NULL
);
457 MmDeleteVirtualMapping(NULL
, (PVOID
)&unmap_me3
, TRUE
, NULL
, NULL
);
460 * Intialize memory areas
462 MmInitVirtualMemory(LastKernelAddress
, kernel_len
);
464 MmInitializeMdlImplementation();
470 MmInitializeRmapList();
471 MmInitializePageOp();
472 MmInitSectionImplementation();
483 /* In SMP mode we can unmap the low memory
484 if all processors are started. */
485 MmDeletePageTable(NULL
, 0);
488 MmInitZeroPageThread();
489 MmCreatePhysicalMemorySection();
490 MiInitBalancerThread();
493 * Initialise the modified page writer.
497 /* FIXME: Read parameters from memory */
501 MiFreeInitMemoryPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
502 PFN_TYPE Page
, SWAPENTRY SwapEntry
,
505 assert(SwapEntry
== 0);
508 MmReleasePageMemoryConsumer(MC_NPPOOL
, Page
);
513 MiFreeInitMemory(VOID
)
515 MmLockAddressSpace(MmGetKernelAddressSpace());
516 MmFreeMemoryArea(MmGetKernelAddressSpace(),
517 (PVOID
)&_init_start__
,
518 PAGE_ROUND_UP((ULONG
)&_init_end__
) - (ULONG
)_init_start__
,
519 MiFreeInitMemoryPage
,
521 MmUnlockAddressSpace(MmGetKernelAddressSpace());