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