- Create a memory area for the kpcr.
[reactos.git] / reactos / ntoskrnl / mm / mminit.c
1 /* $Id: mminit.c,v 1.56 2003/11/16 15:19:28 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* MiKernelMapDescriptor = NULL;
56 static MEMORY_AREA* MiPagedPoolDescriptor = NULL;
57
58 PHYSICAL_ADDRESS MmSharedDataPagePhysicalAddress;
59
60 PVOID MiNonPagedPoolStart;
61 ULONG MiNonPagedPoolLength;
62 PVOID MiKernelMapStart;
63 ULONG MiKernelMapLength;
64
65 /* FUNCTIONS ****************************************************************/
66
67 /*
68 * @implemented
69 */
70 BOOLEAN STDCALL MmIsThisAnNtAsSystem(VOID)
71 {
72 return(IsThisAnNtAsSystem);
73 }
74
75 /*
76 * @implemented
77 */
78 MM_SYSTEM_SIZE STDCALL MmQuerySystemSize(VOID)
79 {
80 return(MmSystemSize);
81 }
82
83 VOID MiShutdownMemoryManager(VOID)
84 {
85 }
86
87 VOID INIT_FUNCTION
88 MmInitVirtualMemory(ULONG LastKernelAddress,
89 ULONG KernelLength)
90 /*
91 * FUNCTION: Intialize the memory areas list
92 * ARGUMENTS:
93 * bp = Pointer to the boot parameters
94 * kernel_len = Length of the kernel
95 */
96 {
97 PVOID BaseAddress;
98 ULONG Length;
99 ULONG ParamLength = KernelLength;
100 NTSTATUS Status;
101 //ULONG i;
102
103 DPRINT("MmInitVirtualMemory(%x, %x)\n",LastKernelAddress, KernelLength);
104
105 LastKernelAddress = PAGE_ROUND_UP(LastKernelAddress);
106
107 MmInitMemoryAreas();
108
109 /* Don't change the start of kernel map. Pte's must always exist for this region. */
110 MiKernelMapStart = (PVOID)LastKernelAddress + PAGE_SIZE;
111 MiKernelMapLength = MM_KERNEL_MAP_SIZE;
112
113 MiNonPagedPoolStart = MiKernelMapStart + MiKernelMapLength + PAGE_SIZE;
114 MiNonPagedPoolLength = MM_NONPAGED_POOL_SIZE;
115
116 MmPagedPoolBase = MiNonPagedPoolStart + MiNonPagedPoolLength + PAGE_SIZE;
117 MmPagedPoolSize = MM_PAGED_POOL_SIZE;
118
119
120 MiInitKernelMap();
121 MiInitializeNonPagedPool();
122
123 /*
124 * Setup the system area descriptor list
125 */
126 BaseAddress = (PVOID)0xf0000000;
127 MmCreateMemoryArea(NULL,
128 MmGetKernelAddressSpace(),
129 MEMORY_AREA_SYSTEM,
130 &BaseAddress,
131 0x400000,
132 0,
133 &kernel_map_desc,
134 FALSE,
135 FALSE);
136
137 BaseAddress = (PVOID)KPCR_BASE;
138 MmCreateMemoryArea(NULL,
139 MmGetKernelAddressSpace(),
140 MEMORY_AREA_SYSTEM,
141 &BaseAddress,
142 PAGE_SIZE * MAXIMUM_PROCESSORS,
143 0,
144 &kernel_kpcr_desc,
145 FALSE,
146 FALSE);
147 BaseAddress = (PVOID)KERNEL_BASE;
148 Length = PAGE_ROUND_UP(((ULONG)&_text_end__)) - KERNEL_BASE;
149 ParamLength = ParamLength - Length;
150
151 /*
152 * No need to lock the address space at this point since no
153 * other threads are running.
154 */
155 MmCreateMemoryArea(NULL,
156 MmGetKernelAddressSpace(),
157 MEMORY_AREA_SYSTEM,
158 &BaseAddress,
159 Length,
160 0,
161 &kernel_text_desc,
162 FALSE,
163 FALSE);
164
165 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&_text_end__));
166 assert (BaseAddress == (PVOID)&_init_start__);
167 Length = PAGE_ROUND_UP(((ULONG)&_init_end__)) -
168 PAGE_ROUND_UP(((ULONG)&_text_end__));
169 ParamLength = ParamLength - Length;
170
171 MmCreateMemoryArea(NULL,
172 MmGetKernelAddressSpace(),
173 MEMORY_AREA_SYSTEM,
174 &BaseAddress,
175 Length,
176 0,
177 &kernel_init_desc,
178 FALSE,
179 FALSE);
180
181 Length = PAGE_ROUND_UP(((ULONG)&_bss_end__)) -
182 PAGE_ROUND_UP(((ULONG)&_init_end__));
183 ParamLength = ParamLength - Length;
184 DPRINT("Length %x\n",Length);
185 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&_init_end__));
186 DPRINT("BaseAddress %x\n",BaseAddress);
187
188 /*
189 * No need to lock the address space at this point since we are
190 * the only thread running.
191 */
192 MmCreateMemoryArea(NULL,
193 MmGetKernelAddressSpace(),
194 MEMORY_AREA_SYSTEM,
195 &BaseAddress,
196 Length,
197 0,
198 &kernel_data_desc,
199 FALSE,
200 FALSE);
201
202 BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&_bss_end__));
203 Length = LastKernelAddress - (ULONG)BaseAddress;
204 MmCreateMemoryArea(NULL,
205 MmGetKernelAddressSpace(),
206 MEMORY_AREA_SYSTEM,
207 &BaseAddress,
208 Length,
209 0,
210 &kernel_param_desc,
211 FALSE,
212 FALSE);
213
214 BaseAddress = MiNonPagedPoolStart;
215 MmCreateMemoryArea(NULL,
216 MmGetKernelAddressSpace(),
217 MEMORY_AREA_SYSTEM,
218 &BaseAddress,
219 MiNonPagedPoolLength,
220 0,
221 &kernel_pool_desc,
222 FALSE,
223 FALSE);
224
225 BaseAddress = MiKernelMapStart;
226 Status = MmCreateMemoryArea(NULL,
227 MmGetKernelAddressSpace(),
228 MEMORY_AREA_SYSTEM,
229 &BaseAddress,
230 MiKernelMapLength,
231 0,
232 &MiKernelMapDescriptor,
233 FALSE,
234 FALSE);
235
236 BaseAddress = MmPagedPoolBase;
237 Status = MmCreateMemoryArea(NULL,
238 MmGetKernelAddressSpace(),
239 MEMORY_AREA_PAGED_POOL,
240 &BaseAddress,
241 MmPagedPoolSize,
242 0,
243 &MiPagedPoolDescriptor,
244 FALSE,
245 FALSE);
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 FALSE,
262 FALSE);
263 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE,
264 &MmSharedDataPagePhysicalAddress);
265 Status = MmCreateVirtualMapping(NULL,
266 (PVOID)KI_USER_SHARED_DATA,
267 PAGE_READWRITE,
268 MmSharedDataPagePhysicalAddress,
269 TRUE);
270 if (!NT_SUCCESS(Status))
271 {
272 DbgPrint("Unable to create virtual mapping\n");
273 KEBUGCHECK(0);
274 }
275 RtlZeroMemory(BaseAddress, Length);
276
277 /*
278 *
279 */
280 MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory);
281 }
282
283 VOID INIT_FUNCTION
284 MmInit1(ULONG FirstKrnlPhysAddr,
285 ULONG LastKrnlPhysAddr,
286 ULONG LastKernelAddress,
287 PADDRESS_RANGE BIOSMemoryMap,
288 ULONG AddressRangeCount,
289 ULONG MaxMem)
290 /*
291 * FUNCTION: Initalize memory managment
292 */
293 {
294 ULONG i;
295 ULONG kernel_len;
296 #ifndef MP
297 extern unsigned int unmap_me, unmap_me2, unmap_me3;
298 #endif
299
300 DPRINT("MmInit1(FirstKrnlPhysAddr, %x, LastKrnlPhysAddr %x, LastKernelAddress %x)\n",
301 FirstKrnlPhysAddr,
302 LastKrnlPhysAddr,
303 LastKernelAddress);
304
305
306 if ((BIOSMemoryMap != NULL) && (AddressRangeCount > 0))
307 {
308 // If we have a bios memory map, recalulate the 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 /*
330 * FIXME: Set this based on the system command line
331 */
332 MmSystemRangeStart = (PVOID)KERNEL_BASE; // 0xC0000000
333 MmUserProbeAddress = (PVOID)0x7fff0000;
334 MmHighestUserAddress = (PVOID)0x7ffeffff;
335
336 MmInitGlobalKernelPageDirectory();
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 * Initialize the kernel address space
354 */
355 MmInitializeKernelAddressSpace();
356
357 /*
358 * Unmap low memory
359 */
360 #ifndef MP
361 /* In SMP mode we unmap the low memory in MmInit3.
362 The APIC needs the mapping of the first pages
363 while the processors are starting up. */
364 MmDeletePageTable(NULL, 0);
365 #endif
366 /*
367 * Free all pages not used for kernel memory
368 * (we assume the kernel occupies a continuous range of physical
369 * memory)
370 */
371 DPRINT("first krnl %x\nlast krnl %x\n",FirstKrnlPhysAddr,
372 LastKrnlPhysAddr);
373
374 /*
375 * Free physical memory not used by the kernel
376 */
377 MmStats.NrTotalPages = KeLoaderBlock.MemHigher/4;
378 if (!MmStats.NrTotalPages)
379 {
380 DbgPrint("Memory not detected, default to 8 MB\n");
381 MmStats.NrTotalPages = 2048;
382 }
383 else
384 {
385 /* add 1MB for standard memory (not extended) */
386 MmStats.NrTotalPages += 256;
387 }
388 #ifdef BIOS_MEM_FIX
389 MmStats.NrTotalPages += 16;
390 #endif
391 DbgPrint("Used memory %dKb\n", (MmStats.NrTotalPages * PAGE_SIZE) / 1024);
392
393 LastKernelAddress = (ULONG)MmInitializePageList((PVOID)FirstKrnlPhysAddr,
394 (PVOID)LastKrnlPhysAddr,
395 MmStats.NrTotalPages,
396 PAGE_ROUND_UP(LastKernelAddress),
397 BIOSMemoryMap,
398 AddressRangeCount);
399 kernel_len = LastKrnlPhysAddr - FirstKrnlPhysAddr;
400
401 /*
402 * Create a trap for null pointer references and protect text
403 * segment
404 */
405 CHECKPOINT;
406 DPRINT("_text_start__ %x _init_end__ %x\n",(int)&_text_start__,(int)&_init_end__);
407 for (i=PAGE_ROUND_DOWN(((int)&_text_start__));
408 i<PAGE_ROUND_UP(((int)&_init_end__));i=i+PAGE_SIZE)
409 {
410 MmSetPageProtect(NULL,
411 (PVOID)i,
412 PAGE_EXECUTE_READ);
413 }
414
415 DPRINT("Invalidating between %x and %x\n",
416 LastKernelAddress,
417 0xc0600000);
418 for (i=(LastKernelAddress); i<0xc0600000; i+=PAGE_SIZE)
419 {
420 MmRawDeleteVirtualMapping((PVOID)(i));
421 }
422 DPRINT("Almost done MmInit()\n");
423 #ifndef MP
424 /* FIXME: This is broken in SMP mode */
425 MmDeleteVirtualMapping(NULL, (PVOID)&unmap_me, TRUE, NULL, NULL);
426 MmDeleteVirtualMapping(NULL, (PVOID)&unmap_me2, TRUE, NULL, NULL);
427 MmDeleteVirtualMapping(NULL, (PVOID)&unmap_me3, TRUE, NULL, NULL);
428 #endif
429 /*
430 * Intialize memory areas
431 */
432 MmInitVirtualMemory(LastKernelAddress, kernel_len);
433
434 MmInitializeMdlImplementation();
435 }
436
437 VOID INIT_FUNCTION
438 MmInit2(VOID)
439 {
440 MmInitializeRmapList();
441 MmInitializePageOp();
442 MmInitSectionImplementation();
443 MmInitPagingFile();
444 }
445
446 VOID INIT_FUNCTION
447 MmInit3(VOID)
448 {
449 /*
450 * Unmap low memory
451 */
452 #ifdef MP
453 /* In SMP mode we can unmap the low memory
454 if all processors are started. */
455 MmDeletePageTable(NULL, 0);
456 #endif
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 PHYSICAL_ADDRESS PhysAddr, SWAPENTRY SwapEntry,
472 BOOLEAN Dirty)
473 {
474 assert(SwapEntry == 0);
475 if (PhysAddr.QuadPart != 0)
476 {
477 MmReleasePageMemoryConsumer(MC_NPPOOL, PhysAddr);
478 }
479 }
480
481 VOID
482 MiFreeInitMemory(VOID)
483 {
484 MmLockAddressSpace(MmGetKernelAddressSpace());
485 MmFreeMemoryArea(MmGetKernelAddressSpace(),
486 (PVOID)&_init_start__,
487 PAGE_ROUND_UP((ULONG)&_init_end__) - (ULONG)_init_start__,
488 MiFreeInitMemoryPage,
489 NULL);
490 MmUnlockAddressSpace(MmGetKernelAddressSpace());
491 }