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