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