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