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