- NDK 0.98, now with versionned headers. Too many changes to list, see the TinyKRNL...
[reactos.git] / reactos / ntoskrnl / mm / mminit.c
1 /* $Id$
2 *
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 *
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS *****************************************************************/
18
19 /*
20 * Compiler defined symbols
21 */
22 extern unsigned int _text_start__;
23 extern unsigned int _text_end__;
24
25 extern unsigned int _init_start__;
26 extern unsigned int _init_end__;
27
28 extern unsigned int _bss_end__;
29
30
31 static BOOLEAN IsThisAnNtAsSystem = FALSE;
32 static MM_SYSTEM_SIZE MmSystemSize = MmSmallSystem;
33
34 PHYSICAL_ADDRESS MmSharedDataPagePhysicalAddress;
35
36 PVOID MiNonPagedPoolStart;
37 ULONG MiNonPagedPoolLength;
38
39 extern ULONG init_stack;
40 extern ULONG init_stack_top;
41 extern ULONG trap_stack;
42
43 VOID INIT_FUNCTION NTAPI MmInitVirtualMemory(ULONG_PTR LastKernelAddress, ULONG KernelLength);
44
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)
50 #endif
51
52 /* FUNCTIONS ****************************************************************/
53
54 /*
55 * @implemented
56 */
57 BOOLEAN STDCALL MmIsThisAnNtAsSystem(VOID)
58 {
59 return(IsThisAnNtAsSystem);
60 }
61
62 /*
63 * @implemented
64 */
65 MM_SYSTEM_SIZE STDCALL MmQuerySystemSize(VOID)
66 {
67 return(MmSystemSize);
68 }
69
70 VOID
71 NTAPI
72 MiShutdownMemoryManager(VOID)
73 {}
74
75 VOID
76 INIT_FUNCTION
77 NTAPI
78 MmInitVirtualMemory(ULONG_PTR LastKernelAddress,
79 ULONG KernelLength)
80 /*
81 * FUNCTION: Intialize the memory areas list
82 * ARGUMENTS:
83 * bp = Pointer to the boot parameters
84 * kernel_len = Length of the kernel
85 */
86 {
87 PVOID BaseAddress;
88 ULONG Length;
89 ULONG ParamLength = KernelLength;
90 NTSTATUS Status;
91 PHYSICAL_ADDRESS BoundaryAddressMultiple;
92 PFN_TYPE Pfn;
93 PMEMORY_AREA MArea;
94
95 DPRINT("MmInitVirtualMemory(%x, %x)\n",LastKernelAddress, KernelLength);
96
97 BoundaryAddressMultiple.QuadPart = 0;
98 LastKernelAddress = PAGE_ROUND_UP(LastKernelAddress);
99
100 MmInitMemoryAreas();
101
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;
105
106 MmPagedPoolBase = (PVOID)ROUND_UP((ULONG_PTR)MiNonPagedPoolStart + MiNonPagedPoolLength + PAGE_SIZE, 0x400000);
107 MmPagedPoolSize = MM_PAGED_POOL_SIZE;
108
109 DPRINT("NonPagedPool %x - %x, PagedPool %x - %x\n", MiNonPagedPoolStart, (ULONG_PTR)MiNonPagedPoolStart + MiNonPagedPoolLength - 1,
110 MmPagedPoolBase, (ULONG_PTR)MmPagedPoolBase + MmPagedPoolSize - 1);
111
112 MiInitializeNonPagedPool();
113
114 /*
115 * Setup the system area descriptor list
116 */
117 MiInitPageDirectoryMap();
118
119 BaseAddress = (PVOID)KPCR_BASE;
120 MmCreateMemoryArea(MmGetKernelAddressSpace(),
121 MEMORY_AREA_SYSTEM,
122 &BaseAddress,
123 PAGE_SIZE * MAXIMUM_PROCESSORS,
124 PAGE_READWRITE,
125 &MArea,
126 TRUE,
127 0,
128 BoundaryAddressMultiple);
129
130 /* Local APIC base */
131 BaseAddress = (PVOID)0xFEE00000;
132 MmCreateMemoryArea(MmGetKernelAddressSpace(),
133 MEMORY_AREA_SYSTEM,
134 &BaseAddress,
135 PAGE_SIZE,
136 PAGE_READWRITE,
137 &MArea,
138 TRUE,
139 0,
140 BoundaryAddressMultiple);
141
142 /* i/o APIC base */
143 BaseAddress = (PVOID)0xFEC00000;
144 MmCreateMemoryArea(MmGetKernelAddressSpace(),
145 MEMORY_AREA_SYSTEM,
146 &BaseAddress,
147 PAGE_SIZE,
148 PAGE_READWRITE,
149 &MArea,
150 TRUE,
151 0,
152 BoundaryAddressMultiple);
153
154 BaseAddress = (PVOID)0xFF3A0000;
155 MmCreateMemoryArea(MmGetKernelAddressSpace(),
156 MEMORY_AREA_SYSTEM,
157 &BaseAddress,
158 0x20000,
159 PAGE_READWRITE,
160 &MArea,
161 TRUE,
162 0,
163 BoundaryAddressMultiple);
164
165 BaseAddress = (PVOID)KERNEL_BASE;
166 Length = PAGE_ROUND_UP(((ULONG_PTR)&_text_end__)) - KERNEL_BASE;
167 ParamLength = ParamLength - Length;
168
169 /*
170 * No need to lock the address space at this point since no
171 * other threads are running.
172 */
173 MmCreateMemoryArea(MmGetKernelAddressSpace(),
174 MEMORY_AREA_SYSTEM,
175 &BaseAddress,
176 Length,
177 PAGE_EXECUTE_READ,
178 &MArea,
179 TRUE,
180 0,
181 BoundaryAddressMultiple);
182
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;
188
189 MmCreateMemoryArea(MmGetKernelAddressSpace(),
190 MEMORY_AREA_SYSTEM,
191 &BaseAddress,
192 Length,
193 PAGE_EXECUTE_READ,
194 &MArea,
195 TRUE,
196 0,
197 BoundaryAddressMultiple);
198
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);
205
206 /*
207 * No need to lock the address space at this point since we are
208 * the only thread running.
209 */
210 MmCreateMemoryArea(MmGetKernelAddressSpace(),
211 MEMORY_AREA_SYSTEM,
212 &BaseAddress,
213 Length,
214 PAGE_READWRITE,
215 &MArea,
216 TRUE,
217 0,
218 BoundaryAddressMultiple);
219
220 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG_PTR)&_bss_end__));
221 Length = LastKernelAddress - (ULONG_PTR)BaseAddress;
222 MmCreateMemoryArea(MmGetKernelAddressSpace(),
223 MEMORY_AREA_SYSTEM,
224 &BaseAddress,
225 Length,
226 PAGE_READWRITE,
227 &MArea,
228 TRUE,
229 0,
230 BoundaryAddressMultiple);
231
232 BaseAddress = MiNonPagedPoolStart;
233 MmCreateMemoryArea(MmGetKernelAddressSpace(),
234 MEMORY_AREA_SYSTEM,
235 &BaseAddress,
236 MiNonPagedPoolLength,
237 PAGE_READWRITE,
238 &MArea,
239 TRUE,
240 0,
241 BoundaryAddressMultiple);
242
243 BaseAddress = MmPagedPoolBase;
244 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
245 MEMORY_AREA_PAGED_POOL,
246 &BaseAddress,
247 MmPagedPoolSize,
248 PAGE_READWRITE,
249 &MArea,
250 TRUE,
251 0,
252 BoundaryAddressMultiple);
253
254 MmInitializePagedPool();
255
256 /*
257 * Create the kernel mapping of the user/kernel shared memory.
258 */
259 BaseAddress = (PVOID)KI_USER_SHARED_DATA;
260 Length = PAGE_SIZE;
261 MmCreateMemoryArea(MmGetKernelAddressSpace(),
262 MEMORY_AREA_SYSTEM,
263 &BaseAddress,
264 Length,
265 PAGE_READWRITE,
266 &MArea,
267 TRUE,
268 0,
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,
274 PAGE_READWRITE,
275 &Pfn,
276 1);
277 if (!NT_SUCCESS(Status))
278 {
279 DbgPrint("Unable to create virtual mapping\n");
280 KEBUGCHECK(0);
281 }
282 RtlZeroMemory(BaseAddress, Length);
283
284 /*
285 *
286 */
287 MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory);
288 }
289
290 VOID
291 INIT_FUNCTION
292 NTAPI
293 MmInit1(ULONG_PTR FirstKrnlPhysAddr,
294 ULONG_PTR LastKrnlPhysAddr,
295 ULONG_PTR LastKernelAddress,
296 PADDRESS_RANGE BIOSMemoryMap,
297 ULONG AddressRangeCount,
298 ULONG MaxMem)
299 /*
300 * FUNCTION: Initalize memory managment
301 */
302 {
303 ULONG i;
304 ULONG kernel_len;
305 ULONG_PTR MappingAddress;
306
307 DPRINT("MmInit1(FirstKrnlPhysAddr, %p, LastKrnlPhysAddr %p, LastKernelAddress %p)\n",
308 FirstKrnlPhysAddr,
309 LastKrnlPhysAddr,
310 LastKernelAddress);
311
312 if ((BIOSMemoryMap != NULL) && (AddressRangeCount > 0))
313 {
314 // If we have a bios memory map, recalulate the memory size
315 ULONG last = 0;
316 for (i = 0; i < AddressRangeCount; i++)
317 {
318 if (BIOSMemoryMap[i].Type == 1
319 && (BIOSMemoryMap[i].BaseAddrLow + BIOSMemoryMap[i].LengthLow + PAGE_SIZE -1) / PAGE_SIZE > last)
320 {
321 last = (BIOSMemoryMap[i].BaseAddrLow + BIOSMemoryMap[i].LengthLow + PAGE_SIZE -1) / PAGE_SIZE;
322 }
323 }
324 if ((last - 256) * 4 > KeLoaderBlock.MemHigher)
325 {
326 KeLoaderBlock.MemHigher = (last - 256) * 4;
327 }
328 }
329
330 if (KeLoaderBlock.MemHigher >= (MaxMem - 1) * 1024)
331 {
332 KeLoaderBlock.MemHigher = (MaxMem - 1) * 1024;
333 }
334
335 /* Set memory limits */
336 MmUserProbeAddress = (ULONG_PTR)MmSystemRangeStart - 0x10000;
337 MmHighestUserAddress = (PVOID)(MmUserProbeAddress - 1);
338
339 /*
340 * Initialize memory managment statistics
341 */
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;
352
353 /*
354 * Free all pages not used for kernel memory
355 * (we assume the kernel occupies a continuous range of physical
356 * memory)
357 */
358 DPRINT("first krnl %x\nlast krnl %x\n",FirstKrnlPhysAddr,
359 LastKrnlPhysAddr);
360
361 /*
362 * Free physical memory not used by the kernel
363 */
364 MmStats.NrTotalPages = KeLoaderBlock.MemHigher/4;
365 if (!MmStats.NrTotalPages)
366 {
367 DbgPrint("Memory not detected, default to 8 MB\n");
368 MmStats.NrTotalPages = 2048;
369 }
370 else
371 {
372 /* add 1MB for standard memory (not extended) */
373 MmStats.NrTotalPages += 256;
374 }
375 #ifdef BIOS_MEM_FIX
376 MmStats.NrTotalPages += 16;
377 #endif
378
379 /*
380 * Initialize the kernel address space
381 */
382 MmInitializeKernelAddressSpace();
383
384 MmInitGlobalKernelPageDirectory();
385
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);
388
389 LastKernelAddress = (ULONG_PTR)MmInitializePageList(
390 FirstKrnlPhysAddr,
391 LastKrnlPhysAddr,
392 MmStats.NrTotalPages,
393 PAGE_ROUND_UP(LastKernelAddress),
394 BIOSMemoryMap,
395 AddressRangeCount);
396 kernel_len = LastKrnlPhysAddr - FirstKrnlPhysAddr;
397
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);
401
402 /*
403 * Unmap low memory
404 */
405 #ifdef CONFIG_SMP
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)
413 {
414 if (MappingAddress != 2 * PAGE_SIZE &&
415 MappingAddress != 3 * PAGE_SIZE)
416 {
417 MmRawDeleteVirtualMapping((PVOID)MappingAddress);
418 }
419 }
420 #else
421 MmDeletePageTable(NULL, 0);
422 #endif
423
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)
429 {
430 MmRawDeleteVirtualMapping((PVOID)MappingAddress);
431 }
432
433 DPRINT("Almost done MmInit()\n");
434 /*
435 * Intialize memory areas
436 */
437 MmInitVirtualMemory(LastKernelAddress, kernel_len);
438
439 MmInitializeMdlImplementation();
440 }
441
442 VOID
443 NTAPI
444 INIT_FUNCTION
445 MmInit2(VOID)
446 {
447 MmInitializeRmapList();
448 MmInitializePageOp();
449 MmInitSectionImplementation();
450 MmInitPagingFile();
451 }
452
453 VOID
454 INIT_FUNCTION
455 NTAPI
456 MmInit3(VOID)
457 {
458 /*
459 * Unmap low memory
460 */
461 #ifdef CONFIG_SMP
462 /* In SMP mode we can unmap the low memory
463 if all processors are started. */
464 MmDeletePageTable(NULL, 0);
465 #endif
466
467 MmInitZeroPageThread();
468 MmCreatePhysicalMemorySection();
469 MiInitBalancerThread();
470
471 /*
472 * Initialise the modified page writer.
473 */
474 MmInitMpwThread();
475
476 /* FIXME: Read parameters from memory */
477 }
478
479 VOID STATIC
480 MiFreeInitMemoryPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
481 PFN_TYPE Page, SWAPENTRY SwapEntry,
482 BOOLEAN Dirty)
483 {
484 ASSERT(SwapEntry == 0);
485 if (Page != 0)
486 {
487 MmReleasePageMemoryConsumer(MC_NPPOOL, Page);
488 }
489 }
490
491 VOID
492 NTAPI
493 MiFreeInitMemory(VOID)
494 {
495 MmLockAddressSpace(MmGetKernelAddressSpace());
496 MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
497 (PVOID)&_init_start__,
498 MiFreeInitMemoryPage,
499 NULL);
500 MmUnlockAddressSpace(MmGetKernelAddressSpace());
501 }