c06a57e8a3a5eee46be08e3884a3c0e39c35be0c
[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
42 /* FUNCTIONS ****************************************************************/
43
44 /*
45 * @implemented
46 */
47 BOOLEAN STDCALL MmIsThisAnNtAsSystem(VOID)
48 {
49 return(IsThisAnNtAsSystem);
50 }
51
52 /*
53 * @implemented
54 */
55 MM_SYSTEM_SIZE STDCALL MmQuerySystemSize(VOID)
56 {
57 return(MmSystemSize);
58 }
59
60 VOID
61 NTAPI
62 MiShutdownMemoryManager(VOID)
63 {}
64
65 VOID
66 INIT_FUNCTION
67 NTAPI
68 MmInitVirtualMemory(ULONG_PTR LastKernelAddress,
69 ULONG KernelLength)
70 /*
71 * FUNCTION: Intialize the memory areas list
72 * ARGUMENTS:
73 * bp = Pointer to the boot parameters
74 * kernel_len = Length of the kernel
75 */
76 {
77 PVOID BaseAddress;
78 ULONG Length;
79 ULONG ParamLength = KernelLength;
80 NTSTATUS Status;
81 PHYSICAL_ADDRESS BoundaryAddressMultiple;
82 PFN_TYPE Pfn;
83 PMEMORY_AREA MArea;
84
85 DPRINT("MmInitVirtualMemory(%x, %x)\n",LastKernelAddress, KernelLength);
86
87 BoundaryAddressMultiple.QuadPart = 0;
88 LastKernelAddress = PAGE_ROUND_UP(LastKernelAddress);
89
90 MmInitMemoryAreas();
91
92 /* Start the paged and nonpaged pool at a 4MB boundary. */
93 MiNonPagedPoolStart = (PVOID)ROUND_UP((ULONG_PTR)LastKernelAddress + PAGE_SIZE, 0x400000);
94 MiNonPagedPoolLength = MM_NONPAGED_POOL_SIZE;
95
96 MmPagedPoolBase = (PVOID)ROUND_UP((ULONG_PTR)MiNonPagedPoolStart + MiNonPagedPoolLength + PAGE_SIZE, 0x400000);
97 MmPagedPoolSize = MM_PAGED_POOL_SIZE;
98
99 DPRINT("NonPagedPool %x - %x, PagedPool %x - %x\n", MiNonPagedPoolStart, (ULONG_PTR)MiNonPagedPoolStart + MiNonPagedPoolLength - 1,
100 MmPagedPoolBase, (ULONG_PTR)MmPagedPoolBase + MmPagedPoolSize - 1);
101
102 MiInitializeNonPagedPool();
103
104 /*
105 * Setup the system area descriptor list
106 */
107 MiInitPageDirectoryMap();
108
109 BaseAddress = (PVOID)KPCR_BASE;
110 MmCreateMemoryArea(NULL,
111 MmGetKernelAddressSpace(),
112 MEMORY_AREA_SYSTEM,
113 &BaseAddress,
114 PAGE_SIZE * MAXIMUM_PROCESSORS,
115 0,
116 &MArea,
117 TRUE,
118 FALSE,
119 BoundaryAddressMultiple);
120
121 /* Local APIC base */
122 BaseAddress = (PVOID)0xFEE00000;
123 MmCreateMemoryArea(NULL,
124 MmGetKernelAddressSpace(),
125 MEMORY_AREA_SYSTEM,
126 &BaseAddress,
127 PAGE_SIZE,
128 0,
129 &MArea,
130 TRUE,
131 FALSE,
132 BoundaryAddressMultiple);
133
134 /* i/o APIC base */
135 BaseAddress = (PVOID)0xFEC00000;
136 MmCreateMemoryArea(NULL,
137 MmGetKernelAddressSpace(),
138 MEMORY_AREA_SYSTEM,
139 &BaseAddress,
140 PAGE_SIZE,
141 0,
142 &MArea,
143 TRUE,
144 FALSE,
145 BoundaryAddressMultiple);
146
147 BaseAddress = (PVOID)0xFF3A0000;
148 MmCreateMemoryArea(NULL,
149 MmGetKernelAddressSpace(),
150 MEMORY_AREA_SYSTEM,
151 &BaseAddress,
152 0x20000,
153 0,
154 &MArea,
155 TRUE,
156 FALSE,
157 BoundaryAddressMultiple);
158
159 BaseAddress = (PVOID)KERNEL_BASE;
160 Length = PAGE_ROUND_UP(((ULONG_PTR)&_text_end__)) - KERNEL_BASE;
161 ParamLength = ParamLength - Length;
162
163 /*
164 * No need to lock the address space at this point since no
165 * other threads are running.
166 */
167 MmCreateMemoryArea(NULL,
168 MmGetKernelAddressSpace(),
169 MEMORY_AREA_SYSTEM,
170 &BaseAddress,
171 Length,
172 0,
173 &MArea,
174 TRUE,
175 FALSE,
176 BoundaryAddressMultiple);
177
178 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG_PTR)&_text_end__));
179 ASSERT(BaseAddress == (PVOID)&_init_start__);
180 Length = PAGE_ROUND_UP(((ULONG_PTR)&_init_end__)) -
181 PAGE_ROUND_UP(((ULONG_PTR)&_text_end__));
182 ParamLength = ParamLength - Length;
183
184 MmCreateMemoryArea(NULL,
185 MmGetKernelAddressSpace(),
186 MEMORY_AREA_SYSTEM,
187 &BaseAddress,
188 Length,
189 0,
190 &MArea,
191 TRUE,
192 FALSE,
193 BoundaryAddressMultiple);
194
195 Length = PAGE_ROUND_UP(((ULONG_PTR)&_bss_end__)) -
196 PAGE_ROUND_UP(((ULONG_PTR)&_init_end__));
197 ParamLength = ParamLength - Length;
198 DPRINT("Length %x\n",Length);
199 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG_PTR)&_init_end__));
200 DPRINT("BaseAddress %x\n",BaseAddress);
201
202 /*
203 * No need to lock the address space at this point since we are
204 * the only thread running.
205 */
206 MmCreateMemoryArea(NULL,
207 MmGetKernelAddressSpace(),
208 MEMORY_AREA_SYSTEM,
209 &BaseAddress,
210 Length,
211 0,
212 &MArea,
213 TRUE,
214 FALSE,
215 BoundaryAddressMultiple);
216
217 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG_PTR)&_bss_end__));
218 Length = LastKernelAddress - (ULONG_PTR)BaseAddress;
219 MmCreateMemoryArea(NULL,
220 MmGetKernelAddressSpace(),
221 MEMORY_AREA_SYSTEM,
222 &BaseAddress,
223 Length,
224 0,
225 &MArea,
226 TRUE,
227 FALSE,
228 BoundaryAddressMultiple);
229
230 BaseAddress = MiNonPagedPoolStart;
231 MmCreateMemoryArea(NULL,
232 MmGetKernelAddressSpace(),
233 MEMORY_AREA_SYSTEM,
234 &BaseAddress,
235 MiNonPagedPoolLength,
236 0,
237 &MArea,
238 TRUE,
239 FALSE,
240 BoundaryAddressMultiple);
241
242 BaseAddress = MmPagedPoolBase;
243 Status = MmCreateMemoryArea(NULL,
244 MmGetKernelAddressSpace(),
245 MEMORY_AREA_PAGED_POOL,
246 &BaseAddress,
247 MmPagedPoolSize,
248 0,
249 &MArea,
250 TRUE,
251 FALSE,
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(NULL,
262 MmGetKernelAddressSpace(),
263 MEMORY_AREA_SYSTEM,
264 &BaseAddress,
265 Length,
266 0,
267 &MArea,
268 TRUE,
269 FALSE,
270 BoundaryAddressMultiple);
271 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Pfn);
272 MmSharedDataPagePhysicalAddress.QuadPart = Pfn << PAGE_SHIFT;
273 Status = MmCreateVirtualMapping(NULL,
274 (PVOID)KI_USER_SHARED_DATA,
275 PAGE_READWRITE,
276 &Pfn,
277 1);
278 if (!NT_SUCCESS(Status))
279 {
280 DbgPrint("Unable to create virtual mapping\n");
281 KEBUGCHECK(0);
282 }
283 RtlZeroMemory(BaseAddress, Length);
284
285 /*
286 *
287 */
288 MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory);
289 }
290
291 VOID
292 INIT_FUNCTION
293 NTAPI
294 MmInit1(ULONG_PTR FirstKrnlPhysAddr,
295 ULONG_PTR LastKrnlPhysAddr,
296 ULONG_PTR LastKernelAddress,
297 PADDRESS_RANGE BIOSMemoryMap,
298 ULONG AddressRangeCount,
299 ULONG MaxMem)
300 /*
301 * FUNCTION: Initalize memory managment
302 */
303 {
304 ULONG i;
305 ULONG kernel_len;
306 ULONG_PTR MappingAddress;
307
308 DPRINT("MmInit1(FirstKrnlPhysAddr, %p, LastKrnlPhysAddr %p, LastKernelAddress %p)\n",
309 FirstKrnlPhysAddr,
310 LastKrnlPhysAddr,
311 LastKernelAddress);
312
313 if ((BIOSMemoryMap != NULL) && (AddressRangeCount > 0))
314 {
315 // If we have a bios memory map, recalulate the memory size
316 ULONG last = 0;
317 for (i = 0; i < AddressRangeCount; i++)
318 {
319 if (BIOSMemoryMap[i].Type == 1
320 && (BIOSMemoryMap[i].BaseAddrLow + BIOSMemoryMap[i].LengthLow + PAGE_SIZE -1) / PAGE_SIZE > last)
321 {
322 last = (BIOSMemoryMap[i].BaseAddrLow + BIOSMemoryMap[i].LengthLow + PAGE_SIZE -1) / PAGE_SIZE;
323 }
324 }
325 if ((last - 256) * 4 > KeLoaderBlock.MemHigher)
326 {
327 KeLoaderBlock.MemHigher = (last - 256) * 4;
328 }
329 }
330
331 if (KeLoaderBlock.MemHigher >= (MaxMem - 1) * 1024)
332 {
333 KeLoaderBlock.MemHigher = (MaxMem - 1) * 1024;
334 }
335
336 /* Set memory limits */
337 MmUserProbeAddress = (ULONG_PTR)MmSystemRangeStart - 0x10000;
338 MmHighestUserAddress = (PVOID)(MmUserProbeAddress - 1);
339
340 /*
341 * Initialize memory managment statistics
342 */
343 MmStats.NrTotalPages = 0;
344 MmStats.NrSystemPages = 0;
345 MmStats.NrUserPages = 0;
346 MmStats.NrReservedPages = 0;
347 MmStats.NrUserPages = 0;
348 MmStats.NrFreePages = 0;
349 MmStats.NrLockedPages = 0;
350 MmStats.PagingRequestsInLastMinute = 0;
351 MmStats.PagingRequestsInLastFiveMinutes = 0;
352 MmStats.PagingRequestsInLastFifteenMinutes = 0;
353
354 /*
355 * Free all pages not used for kernel memory
356 * (we assume the kernel occupies a continuous range of physical
357 * memory)
358 */
359 DPRINT("first krnl %x\nlast krnl %x\n",FirstKrnlPhysAddr,
360 LastKrnlPhysAddr);
361
362 /*
363 * Free physical memory not used by the kernel
364 */
365 MmStats.NrTotalPages = KeLoaderBlock.MemHigher/4;
366 if (!MmStats.NrTotalPages)
367 {
368 DbgPrint("Memory not detected, default to 8 MB\n");
369 MmStats.NrTotalPages = 2048;
370 }
371 else
372 {
373 /* add 1MB for standard memory (not extended) */
374 MmStats.NrTotalPages += 256;
375 }
376 #ifdef BIOS_MEM_FIX
377 MmStats.NrTotalPages += 16;
378 #endif
379
380 /*
381 * Initialize the kernel address space
382 */
383 MmInitializeKernelAddressSpace();
384
385 MmInitGlobalKernelPageDirectory();
386
387 DbgPrint("Used memory %dKb\n", (MmStats.NrTotalPages * PAGE_SIZE) / 1024);
388 DPRINT1("Kernel Stack Limits. InitTop = 0x%x, Init = 0x%x\n", init_stack_top, init_stack);
389
390 LastKernelAddress = (ULONG_PTR)MmInitializePageList(
391 FirstKrnlPhysAddr,
392 LastKrnlPhysAddr,
393 MmStats.NrTotalPages,
394 PAGE_ROUND_UP(LastKernelAddress),
395 BIOSMemoryMap,
396 AddressRangeCount);
397 kernel_len = LastKrnlPhysAddr - FirstKrnlPhysAddr;
398
399 /*
400 * Unmap low memory
401 */
402 #ifdef CONFIG_SMP
403 /* In SMP mode we unmap the low memory pagetable in MmInit3.
404 The APIC needs the mapping of the first pages
405 while the processors are starting up.
406 We unmap all pages except page 2 and 3. */
407 for (MappingAddress = 0;
408 MappingAddress < 1024 * PAGE_SIZE;
409 MappingAddress += PAGE_SIZE)
410 {
411 if (MappingAddress != 2 * PAGE_SIZE &&
412 MappingAddress != 3 * PAGE_SIZE)
413 {
414 MmRawDeleteVirtualMapping((PVOID)MappingAddress);
415 }
416 }
417 #else
418 MmDeletePageTable(NULL, 0);
419 #endif
420
421 DPRINT("Invalidating between %x and %x\n",
422 LastKernelAddress, KERNEL_BASE + 0x00600000);
423 for (MappingAddress = LastKernelAddress;
424 MappingAddress < KERNEL_BASE + 0x00600000;
425 MappingAddress += PAGE_SIZE)
426 {
427 MmRawDeleteVirtualMapping((PVOID)MappingAddress);
428 }
429
430 DPRINT("Almost done MmInit()\n");
431 /*
432 * Intialize memory areas
433 */
434 MmInitVirtualMemory(LastKernelAddress, kernel_len);
435
436 MmInitializeMdlImplementation();
437 }
438
439 VOID
440 NTAPI
441 INIT_FUNCTION
442 MmInit2(VOID)
443 {
444 MmInitializeRmapList();
445 MmInitializePageOp();
446 MmInitSectionImplementation();
447 MmInitPagingFile();
448 }
449
450 VOID
451 INIT_FUNCTION
452 NTAPI
453 MmInit3(VOID)
454 {
455 /*
456 * Unmap low memory
457 */
458 #ifdef CONFIG_SMP
459 /* In SMP mode we can unmap the low memory
460 if all processors are started. */
461 MmDeletePageTable(NULL, 0);
462 #endif
463
464 MmInitZeroPageThread();
465 MmCreatePhysicalMemorySection();
466 MiInitBalancerThread();
467
468 /*
469 * Initialise the modified page writer.
470 */
471 MmInitMpwThread();
472
473 /* FIXME: Read parameters from memory */
474 }
475
476 VOID STATIC
477 MiFreeInitMemoryPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
478 PFN_TYPE Page, SWAPENTRY SwapEntry,
479 BOOLEAN Dirty)
480 {
481 ASSERT(SwapEntry == 0);
482 if (Page != 0)
483 {
484 MmReleasePageMemoryConsumer(MC_NPPOOL, Page);
485 }
486 }
487
488 VOID
489 NTAPI
490 MiFreeInitMemory(VOID)
491 {
492 MmLockAddressSpace(MmGetKernelAddressSpace());
493 MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
494 (PVOID)&_init_start__,
495 MiFreeInitMemoryPage,
496 NULL);
497 MmUnlockAddressSpace(MmGetKernelAddressSpace());
498 }