- Changed all internal memory functions to use the page frame number instead of the...
[reactos.git] / reactos / ntoskrnl / mm / mminit.c
1 /* $Id: mminit.c,v 1.64 2004/08/01 07:24:58 hbirr Exp $
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 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * UPDATE HISTORY:
9 * Created 9/4/98
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <roscfg.h>
16 #include <internal/i386/segment.h>
17 #include <internal/mm.h>
18 #include <internal/ntoskrnl.h>
19 #include <internal/io.h>
20 #include <internal/ps.h>
21 #include <internal/pool.h>
22
23 #define NDEBUG
24 #include <internal/debug.h>
25
26 /* GLOBALS *****************************************************************/
27
28 /*
29 * Compiler defined symbols
30 */
31 extern unsigned int _text_start__;
32 extern unsigned int _text_end__;
33
34 extern unsigned int _init_start__;
35 extern unsigned int _init_end__;
36
37 extern unsigned int _bss_end__;
38
39
40 static BOOLEAN IsThisAnNtAsSystem = FALSE;
41 static MM_SYSTEM_SIZE MmSystemSize = MmSmallSystem;
42
43 static MEMORY_AREA* kernel_text_desc = NULL;
44 static MEMORY_AREA* kernel_init_desc = NULL;
45 static MEMORY_AREA* kernel_map_desc = NULL;
46 static MEMORY_AREA* kernel_kpcr_desc = NULL;
47 static MEMORY_AREA* kernel_data_desc = NULL;
48 static MEMORY_AREA* kernel_param_desc = NULL;
49 static MEMORY_AREA* kernel_pool_desc = NULL;
50 static MEMORY_AREA* kernel_shared_data_desc = NULL;
51 static MEMORY_AREA* kernel_mapped_vga_framebuffer_desc = NULL;
52 static MEMORY_AREA* MiKernelMapDescriptor = NULL;
53 static MEMORY_AREA* MiPagedPoolDescriptor = NULL;
54
55 PHYSICAL_ADDRESS MmSharedDataPagePhysicalAddress;
56
57 PVOID MiNonPagedPoolStart;
58 ULONG MiNonPagedPoolLength;
59 PVOID MiKernelMapStart;
60 ULONG MiKernelMapLength;
61
62 /* FUNCTIONS ****************************************************************/
63
64 /*
65 * @implemented
66 */
67 BOOLEAN STDCALL MmIsThisAnNtAsSystem(VOID)
68 {
69 return(IsThisAnNtAsSystem);
70 }
71
72 /*
73 * @implemented
74 */
75 MM_SYSTEM_SIZE STDCALL MmQuerySystemSize(VOID)
76 {
77 return(MmSystemSize);
78 }
79
80 VOID MiShutdownMemoryManager(VOID)
81 {}
82
83 VOID INIT_FUNCTION
84 MmInitVirtualMemory(ULONG LastKernelAddress,
85 ULONG KernelLength)
86 /*
87 * FUNCTION: Intialize the memory areas list
88 * ARGUMENTS:
89 * bp = Pointer to the boot parameters
90 * kernel_len = Length of the kernel
91 */
92 {
93 PVOID BaseAddress;
94 ULONG Length;
95 ULONG ParamLength = KernelLength;
96 NTSTATUS Status;
97 PHYSICAL_ADDRESS BoundaryAddressMultiple;
98 PFN_TYPE Pfn;
99
100 DPRINT("MmInitVirtualMemory(%x, %x)\n",LastKernelAddress, KernelLength);
101
102 BoundaryAddressMultiple.QuadPart = 0;
103 LastKernelAddress = PAGE_ROUND_UP(LastKernelAddress);
104
105 MmInitMemoryAreas();
106
107 /* Don't change the start of kernel map. Pte's must always exist for this region. */
108 MiKernelMapStart = (char*)LastKernelAddress + PAGE_SIZE;
109 MiKernelMapLength = MM_KERNEL_MAP_SIZE;
110
111 MiNonPagedPoolStart = (char*)MiKernelMapStart + MiKernelMapLength + PAGE_SIZE;
112 MiNonPagedPoolLength = MM_NONPAGED_POOL_SIZE;
113
114 MmPagedPoolBase = (char*)MiNonPagedPoolStart + MiNonPagedPoolLength + PAGE_SIZE;
115 MmPagedPoolSize = MM_PAGED_POOL_SIZE;
116
117
118 MiInitKernelMap();
119 MiInitializeNonPagedPool();
120
121 /*
122 * Setup the system area descriptor list
123 */
124 BaseAddress = (PVOID)0xf0000000;
125 MmCreateMemoryArea(NULL,
126 MmGetKernelAddressSpace(),
127 MEMORY_AREA_SYSTEM,
128 &BaseAddress,
129 0x400000,
130 0,
131 &kernel_map_desc,
132 FALSE,
133 FALSE,
134 BoundaryAddressMultiple);
135
136 BaseAddress = (PVOID)KPCR_BASE;
137 MmCreateMemoryArea(NULL,
138 MmGetKernelAddressSpace(),
139 MEMORY_AREA_SYSTEM,
140 &BaseAddress,
141 PAGE_SIZE * MAXIMUM_PROCESSORS,
142 0,
143 &kernel_kpcr_desc,
144 FALSE,
145 FALSE,
146 BoundaryAddressMultiple);
147
148 BaseAddress = (PVOID)0xFF3A0000;
149 MmCreateMemoryArea(NULL,
150 MmGetKernelAddressSpace(),
151 MEMORY_AREA_SYSTEM,
152 &BaseAddress,
153 0x20000,
154 0,
155 &kernel_mapped_vga_framebuffer_desc,
156 FALSE,
157 FALSE,
158 BoundaryAddressMultiple);
159
160 BaseAddress = (PVOID)KERNEL_BASE;
161 Length = PAGE_ROUND_UP(((ULONG)&_text_end__)) - KERNEL_BASE;
162 ParamLength = ParamLength - Length;
163
164 /*
165 * No need to lock the address space at this point since no
166 * other threads are running.
167 */
168 MmCreateMemoryArea(NULL,
169 MmGetKernelAddressSpace(),
170 MEMORY_AREA_SYSTEM,
171 &BaseAddress,
172 Length,
173 0,
174 &kernel_text_desc,
175 FALSE,
176 FALSE,
177 BoundaryAddressMultiple);
178
179 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&_text_end__));
180 assert (BaseAddress == (PVOID)&_init_start__);
181 Length = PAGE_ROUND_UP(((ULONG)&_init_end__)) -
182 PAGE_ROUND_UP(((ULONG)&_text_end__));
183 ParamLength = ParamLength - Length;
184
185 MmCreateMemoryArea(NULL,
186 MmGetKernelAddressSpace(),
187 MEMORY_AREA_SYSTEM,
188 &BaseAddress,
189 Length,
190 0,
191 &kernel_init_desc,
192 FALSE,
193 FALSE,
194 BoundaryAddressMultiple);
195
196 Length = PAGE_ROUND_UP(((ULONG)&_bss_end__)) -
197 PAGE_ROUND_UP(((ULONG)&_init_end__));
198 ParamLength = ParamLength - Length;
199 DPRINT("Length %x\n",Length);
200 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&_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(NULL,
208 MmGetKernelAddressSpace(),
209 MEMORY_AREA_SYSTEM,
210 &BaseAddress,
211 Length,
212 0,
213 &kernel_data_desc,
214 FALSE,
215 FALSE,
216 BoundaryAddressMultiple);
217
218 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&_bss_end__));
219 Length = LastKernelAddress - (ULONG)BaseAddress;
220 MmCreateMemoryArea(NULL,
221 MmGetKernelAddressSpace(),
222 MEMORY_AREA_SYSTEM,
223 &BaseAddress,
224 Length,
225 0,
226 &kernel_param_desc,
227 FALSE,
228 FALSE,
229 BoundaryAddressMultiple);
230
231 BaseAddress = MiNonPagedPoolStart;
232 MmCreateMemoryArea(NULL,
233 MmGetKernelAddressSpace(),
234 MEMORY_AREA_SYSTEM,
235 &BaseAddress,
236 MiNonPagedPoolLength,
237 0,
238 &kernel_pool_desc,
239 FALSE,
240 FALSE,
241 BoundaryAddressMultiple);
242
243 BaseAddress = MiKernelMapStart;
244 Status = MmCreateMemoryArea(NULL,
245 MmGetKernelAddressSpace(),
246 MEMORY_AREA_SYSTEM,
247 &BaseAddress,
248 MiKernelMapLength,
249 0,
250 &MiKernelMapDescriptor,
251 FALSE,
252 FALSE,
253 BoundaryAddressMultiple);
254
255 BaseAddress = MmPagedPoolBase;
256 Status = MmCreateMemoryArea(NULL,
257 MmGetKernelAddressSpace(),
258 MEMORY_AREA_PAGED_POOL,
259 &BaseAddress,
260 MmPagedPoolSize,
261 0,
262 &MiPagedPoolDescriptor,
263 FALSE,
264 FALSE,
265 BoundaryAddressMultiple);
266
267 MmInitializePagedPool();
268
269 /*
270 * Create the kernel mapping of the user/kernel shared memory.
271 */
272 BaseAddress = (PVOID)KI_USER_SHARED_DATA;
273 Length = PAGE_SIZE;
274 MmCreateMemoryArea(NULL,
275 MmGetKernelAddressSpace(),
276 MEMORY_AREA_SYSTEM,
277 &BaseAddress,
278 Length,
279 0,
280 &kernel_shared_data_desc,
281 FALSE,
282 FALSE,
283 BoundaryAddressMultiple);
284 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Pfn);
285 MmSharedDataPagePhysicalAddress.QuadPart = Pfn << PAGE_SHIFT;
286 Status = MmCreateVirtualMapping(NULL,
287 (PVOID)KI_USER_SHARED_DATA,
288 PAGE_READWRITE,
289 &Pfn,
290 1);
291 if (!NT_SUCCESS(Status))
292 {
293 DbgPrint("Unable to create virtual mapping\n");
294 KEBUGCHECK(0);
295 }
296 RtlZeroMemory(BaseAddress, Length);
297
298 /*
299 *
300 */
301 MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory);
302 }
303
304 VOID INIT_FUNCTION
305 MmInit1(ULONG FirstKrnlPhysAddr,
306 ULONG LastKrnlPhysAddr,
307 ULONG LastKernelAddress,
308 PADDRESS_RANGE BIOSMemoryMap,
309 ULONG AddressRangeCount,
310 ULONG MaxMem)
311 /*
312 * FUNCTION: Initalize memory managment
313 */
314 {
315 ULONG i;
316 ULONG kernel_len;
317 #ifndef MP
318
319 extern unsigned int unmap_me, unmap_me2, unmap_me3;
320 #endif
321
322 DPRINT("MmInit1(FirstKrnlPhysAddr, %x, LastKrnlPhysAddr %x, LastKernelAddress %x)\n",
323 FirstKrnlPhysAddr,
324 LastKrnlPhysAddr,
325 LastKernelAddress);
326
327
328 if ((BIOSMemoryMap != NULL) && (AddressRangeCount > 0))
329 {
330 // If we have a bios memory map, recalulate the memory size
331 ULONG last = 0;
332 for (i = 0; i < AddressRangeCount; i++)
333 {
334 if (BIOSMemoryMap[i].Type == 1
335 && (BIOSMemoryMap[i].BaseAddrLow + BIOSMemoryMap[i].LengthLow + PAGE_SIZE -1) / PAGE_SIZE > last)
336 {
337 last = (BIOSMemoryMap[i].BaseAddrLow + BIOSMemoryMap[i].LengthLow + PAGE_SIZE -1) / PAGE_SIZE;
338 }
339 }
340 if ((last - 256) * 4 > KeLoaderBlock.MemHigher)
341 {
342 KeLoaderBlock.MemHigher = (last - 256) * 4;
343 }
344 }
345
346 if (KeLoaderBlock.MemHigher >= (MaxMem - 1) * 1024)
347 {
348 KeLoaderBlock.MemHigher = (MaxMem - 1) * 1024;
349 }
350
351 /*
352 * FIXME: Set this based on the system command line
353 */
354 MmSystemRangeStart = (PVOID)KERNEL_BASE; // 0xC0000000
355 MmUserProbeAddress = (PVOID)0x7fff0000;
356 MmHighestUserAddress = (PVOID)0x7ffeffff;
357
358 MmInitGlobalKernelPageDirectory();
359
360 /*
361 * Initialize memory managment statistics
362 */
363 MmStats.NrTotalPages = 0;
364 MmStats.NrSystemPages = 0;
365 MmStats.NrUserPages = 0;
366 MmStats.NrReservedPages = 0;
367 MmStats.NrUserPages = 0;
368 MmStats.NrFreePages = 0;
369 MmStats.NrLockedPages = 0;
370 MmStats.PagingRequestsInLastMinute = 0;
371 MmStats.PagingRequestsInLastFiveMinutes = 0;
372 MmStats.PagingRequestsInLastFifteenMinutes = 0;
373
374 /*
375 * Initialize the kernel address space
376 */
377 MmInitializeKernelAddressSpace();
378
379 /*
380 * Unmap low memory
381 */
382 #ifndef MP
383 /* In SMP mode we unmap the low memory in MmInit3.
384 The APIC needs the mapping of the first pages
385 while the processors are starting up. */
386 MmDeletePageTable(NULL, 0);
387 #endif
388 /*
389 * Free all pages not used for kernel memory
390 * (we assume the kernel occupies a continuous range of physical
391 * memory)
392 */
393 DPRINT("first krnl %x\nlast krnl %x\n",FirstKrnlPhysAddr,
394 LastKrnlPhysAddr);
395
396 /*
397 * Free physical memory not used by the kernel
398 */
399 MmStats.NrTotalPages = KeLoaderBlock.MemHigher/4;
400 if (!MmStats.NrTotalPages)
401 {
402 DbgPrint("Memory not detected, default to 8 MB\n");
403 MmStats.NrTotalPages = 2048;
404 }
405 else
406 {
407 /* add 1MB for standard memory (not extended) */
408 MmStats.NrTotalPages += 256;
409 }
410 #ifdef BIOS_MEM_FIX
411 MmStats.NrTotalPages += 16;
412 #endif
413
414 DbgPrint("Used memory %dKb\n", (MmStats.NrTotalPages * PAGE_SIZE) / 1024);
415
416 LastKernelAddress = (ULONG)MmInitializePageList((PVOID)FirstKrnlPhysAddr,
417 (PVOID)LastKrnlPhysAddr,
418 MmStats.NrTotalPages,
419 PAGE_ROUND_UP(LastKernelAddress),
420 BIOSMemoryMap,
421 AddressRangeCount);
422 kernel_len = LastKrnlPhysAddr - FirstKrnlPhysAddr;
423
424 /*
425 * Create a trap for null pointer references and protect text
426 * segment
427 */
428 CHECKPOINT;
429 DPRINT("_text_start__ %x _init_end__ %x\n",(int)&_text_start__,(int)&_init_end__);
430 for (i=PAGE_ROUND_DOWN(((int)&_text_start__));
431 i<PAGE_ROUND_UP(((int)&_init_end__));i=i+PAGE_SIZE)
432 {
433 MmSetPageProtect(NULL,
434 (PVOID)i,
435 PAGE_EXECUTE_READ);
436 }
437
438 DPRINT("Invalidating between %x and %x\n",
439 LastKernelAddress, 0xc0600000);
440 for (i=(LastKernelAddress); i<0xc0600000; i+=PAGE_SIZE)
441 {
442 MmRawDeleteVirtualMapping((PVOID)(i));
443 }
444
445 DPRINT("Invalidating between %x and %x\n",
446 0xd0100000, 0xd0400000);
447 for (i=0xd0100000; i<0xd0400000; i+=PAGE_SIZE)
448 {
449 MmRawDeleteVirtualMapping((PVOID)(i));
450 }
451
452 DPRINT("Almost done MmInit()\n");
453 #ifndef MP
454 /* FIXME: This is broken in SMP mode */
455 MmDeleteVirtualMapping(NULL, (PVOID)&unmap_me, TRUE, NULL, NULL);
456 MmDeleteVirtualMapping(NULL, (PVOID)&unmap_me2, TRUE, NULL, NULL);
457 MmDeleteVirtualMapping(NULL, (PVOID)&unmap_me3, TRUE, NULL, NULL);
458 #endif
459 /*
460 * Intialize memory areas
461 */
462 MmInitVirtualMemory(LastKernelAddress, kernel_len);
463
464 MmInitializeMdlImplementation();
465 }
466
467 VOID INIT_FUNCTION
468 MmInit2(VOID)
469 {
470 MmInitializeRmapList();
471 MmInitializePageOp();
472 MmInitSectionImplementation();
473 MmInitPagingFile();
474 }
475
476 VOID INIT_FUNCTION
477 MmInit3(VOID)
478 {
479 /*
480 * Unmap low memory
481 */
482 #ifdef MP
483 /* In SMP mode we can unmap the low memory
484 if all processors are started. */
485 MmDeletePageTable(NULL, 0);
486 #endif
487
488 MmInitZeroPageThread();
489 MmCreatePhysicalMemorySection();
490 MiInitBalancerThread();
491
492 /*
493 * Initialise the modified page writer.
494 */
495 MmInitMpwThread();
496
497 /* FIXME: Read parameters from memory */
498 }
499
500 VOID STATIC
501 MiFreeInitMemoryPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
502 PFN_TYPE Page, SWAPENTRY SwapEntry,
503 BOOLEAN Dirty)
504 {
505 assert(SwapEntry == 0);
506 if (Page != 0)
507 {
508 MmReleasePageMemoryConsumer(MC_NPPOOL, Page);
509 }
510 }
511
512 VOID
513 MiFreeInitMemory(VOID)
514 {
515 MmLockAddressSpace(MmGetKernelAddressSpace());
516 MmFreeMemoryArea(MmGetKernelAddressSpace(),
517 (PVOID)&_init_start__,
518 PAGE_ROUND_UP((ULONG)&_init_end__) - (ULONG)_init_start__,
519 MiFreeInitMemoryPage,
520 NULL);
521 MmUnlockAddressSpace(MmGetKernelAddressSpace());
522 }