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