update for HEAD-2003091401
[reactos.git] / 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  * 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