- Removed the initialisation of the kernel map area.
[reactos.git] / reactos / ntoskrnl / mm / mminit.c
index fd3433c..c06a57e 100644 (file)
@@ -1,79 +1,72 @@
-/* $Id: mminit.c,v 1.6 2000/08/20 17:02:08 dwelch Exp $
+/* $Id$
  *
- * COPYRIGHT:   See COPYING in the top directory
- * PROJECT:     ReactOS kernel 
- * FILE:        ntoskrnl/mm/mminit.c
- * PURPOSE:     kernel memory managment initialization functions
- * PROGRAMMER:  David Welch (welch@cwcom.net)
- * UPDATE HISTORY:
- *              Created 9/4/98
+ * COPYRIGHT:       See COPYING in the top directory
+ * PROJECT:         ReactOS kernel
+ * FILE:            ntoskrnl/mm/mminit.c
+ * PURPOSE:         Kernel memory managment initialization functions
+ *
+ * PROGRAMMERS:     David Welch (welch@cwcom.net)
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
-#include <internal/hal/io.h>
-#include <internal/i386/segment.h>
-#include <internal/stddef.h>
-#include <internal/mm.h>
-#include <string.h>
-#include <internal/string.h>
-#include <internal/ntoskrnl.h>
-#include <internal/bitops.h>
-#include <internal/string.h>
-#include <internal/io.h>
-#include <internal/ps.h>
-#include <internal/mmhal.h>
-#include <napi/shared_data.h>
-
+#include <ntoskrnl.h>
 #define NDEBUG
 #include <internal/debug.h>
 
 /* GLOBALS *****************************************************************/
 
 /*
- * Size of extended memory (kb) (fixed for now)
+ * Compiler defined symbols
  */
-#define EXTENDED_MEMORY_SIZE  (3*1024*1024)
+extern unsigned int _text_start__;
+extern unsigned int _text_end__;
+
+extern unsigned int _init_start__;
+extern unsigned int _init_end__;
+
+extern unsigned int _bss_end__;
 
-/*
- * Compiler defined symbol s
- */
-extern unsigned int stext;
-extern unsigned int etext;
-extern unsigned int end;
 
 static BOOLEAN IsThisAnNtAsSystem = FALSE;
 static MM_SYSTEM_SIZE MmSystemSize = MmSmallSystem;
 
-extern unsigned int etext;
-extern unsigned int _bss_end__;
+PHYSICAL_ADDRESS MmSharedDataPagePhysicalAddress;
 
-static MEMORY_AREA* kernel_text_desc = NULL;
-static MEMORY_AREA* kernel_data_desc = NULL;
-static MEMORY_AREA* kernel_param_desc = NULL;
-static MEMORY_AREA* kernel_pool_desc = NULL;
-static MEMORY_AREA* kernel_shared_data_desc = NULL;
+PVOID MiNonPagedPoolStart;
+ULONG MiNonPagedPoolLength;
 
-PVOID MmSharedDataPagePhysicalAddress = NULL;
+extern ULONG init_stack;
+extern ULONG init_stack_top;
 
 /* FUNCTIONS ****************************************************************/
 
+/*
+ * @implemented
+ */
 BOOLEAN STDCALL MmIsThisAnNtAsSystem(VOID)
 {
    return(IsThisAnNtAsSystem);
 }
 
+/*
+ * @implemented
+ */
 MM_SYSTEM_SIZE STDCALL MmQuerySystemSize(VOID)
 {
    return(MmSystemSize);
 }
 
-VOID MiShutdownMemoryManager(VOID)
-{
-}
+VOID
+NTAPI
+MiShutdownMemoryManager(VOID)
+{}
 
-VOID MmInitVirtualMemory(PLOADER_PARAMETER_BLOCK bp, ULONG LastKernelAddress)
+VOID
+INIT_FUNCTION
+NTAPI
+MmInitVirtualMemory(ULONG_PTR LastKernelAddress,
+                    ULONG KernelLength)
 /*
  * FUNCTION: Intialize the memory areas list
  * ARGUMENTS:
@@ -81,116 +74,269 @@ VOID MmInitVirtualMemory(PLOADER_PARAMETER_BLOCK bp, ULONG LastKernelAddress)
  *           kernel_len = Length of the kernel
  */
 {
-   unsigned int kernel_len = bp->end_mem - bp->start_mem;
    PVOID BaseAddress;
    ULONG Length;
-   ULONG ParamLength = kernel_len;
+   ULONG ParamLength = KernelLength;
    NTSTATUS Status;
-   
-   DPRINT("MmInitVirtualMemory(%x)\n",bp);
-   
+   PHYSICAL_ADDRESS BoundaryAddressMultiple;
+   PFN_TYPE Pfn;
+   PMEMORY_AREA MArea;
+
+   DPRINT("MmInitVirtualMemory(%x, %x)\n",LastKernelAddress, KernelLength);
+
+   BoundaryAddressMultiple.QuadPart = 0;
    LastKernelAddress = PAGE_ROUND_UP(LastKernelAddress);
-   
+
    MmInitMemoryAreas();
-//   ExInitNonPagedPool(KERNEL_BASE + PAGE_ROUND_UP(kernel_len) + PAGESIZE);
-   ExInitNonPagedPool(LastKernelAddress + PAGESIZE);
-   
-   
+
+   /* Start the paged and nonpaged pool at a 4MB boundary. */ 
+   MiNonPagedPoolStart = (PVOID)ROUND_UP((ULONG_PTR)LastKernelAddress + PAGE_SIZE, 0x400000);
+   MiNonPagedPoolLength = MM_NONPAGED_POOL_SIZE;
+
+   MmPagedPoolBase = (PVOID)ROUND_UP((ULONG_PTR)MiNonPagedPoolStart + MiNonPagedPoolLength + PAGE_SIZE, 0x400000);
+   MmPagedPoolSize = MM_PAGED_POOL_SIZE;
+
+   DPRINT("NonPagedPool %x - %x, PagedPool %x - %x\n", MiNonPagedPoolStart, (ULONG_PTR)MiNonPagedPoolStart + MiNonPagedPoolLength - 1, 
+           MmPagedPoolBase, (ULONG_PTR)MmPagedPoolBase + MmPagedPoolSize - 1);
+
+   MiInitializeNonPagedPool();
+
    /*
     * Setup the system area descriptor list
     */
+   MiInitPageDirectoryMap();
+
+   BaseAddress = (PVOID)KPCR_BASE;
+   MmCreateMemoryArea(NULL,
+                      MmGetKernelAddressSpace(),
+                      MEMORY_AREA_SYSTEM,
+                      &BaseAddress,
+                      PAGE_SIZE * MAXIMUM_PROCESSORS,
+                      0,
+                      &MArea,
+                      TRUE,
+                      FALSE,
+                      BoundaryAddressMultiple);
+
+   /* Local APIC base */
+   BaseAddress = (PVOID)0xFEE00000;
+   MmCreateMemoryArea(NULL,
+                      MmGetKernelAddressSpace(),
+                      MEMORY_AREA_SYSTEM,
+                      &BaseAddress,
+                      PAGE_SIZE,
+                      0,
+                      &MArea,
+                      TRUE,
+                      FALSE,
+                      BoundaryAddressMultiple);
+
+   /* i/o APIC base */
+   BaseAddress = (PVOID)0xFEC00000;
+   MmCreateMemoryArea(NULL,
+                      MmGetKernelAddressSpace(),
+                      MEMORY_AREA_SYSTEM,
+                      &BaseAddress,
+                      PAGE_SIZE,
+                      0,
+                      &MArea,
+                      TRUE,
+                      FALSE,
+                      BoundaryAddressMultiple);
+
+   BaseAddress = (PVOID)0xFF3A0000;
+   MmCreateMemoryArea(NULL,
+                      MmGetKernelAddressSpace(),
+                      MEMORY_AREA_SYSTEM,
+                      &BaseAddress,
+                      0x20000,
+                      0,
+                      &MArea,
+                      TRUE,
+                      FALSE,
+                      BoundaryAddressMultiple);
+
    BaseAddress = (PVOID)KERNEL_BASE;
-   Length = PAGE_ROUND_UP(((ULONG)&etext)) - KERNEL_BASE;
+   Length = PAGE_ROUND_UP(((ULONG_PTR)&_text_end__)) - KERNEL_BASE;
+   ParamLength = ParamLength - Length;
+
+   /*
+    * No need to lock the address space at this point since no
+    * other threads are running.
+    */
+   MmCreateMemoryArea(NULL,
+                      MmGetKernelAddressSpace(),
+                      MEMORY_AREA_SYSTEM,
+                      &BaseAddress,
+                      Length,
+                      0,
+                      &MArea,
+                      TRUE,
+                      FALSE,
+                      BoundaryAddressMultiple);
+
+   BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG_PTR)&_text_end__));
+   ASSERT(BaseAddress == (PVOID)&_init_start__);
+   Length = PAGE_ROUND_UP(((ULONG_PTR)&_init_end__)) -
+            PAGE_ROUND_UP(((ULONG_PTR)&_text_end__));
    ParamLength = ParamLength - Length;
+
    MmCreateMemoryArea(NULL,
-                     MmGetKernelAddressSpace(),
-                     MEMORY_AREA_SYSTEM,
-                     &BaseAddress,
-                     Length,
-                     0,
-                     &kernel_text_desc);
-   
-   Length = PAGE_ROUND_UP(((ULONG)&_bss_end__)) - 
-            PAGE_ROUND_UP(((ULONG)&etext));
+                      MmGetKernelAddressSpace(),
+                      MEMORY_AREA_SYSTEM,
+                      &BaseAddress,
+                      Length,
+                      0,
+                      &MArea,
+                      TRUE,
+                      FALSE,
+                      BoundaryAddressMultiple);
+
+   Length = PAGE_ROUND_UP(((ULONG_PTR)&_bss_end__)) -
+            PAGE_ROUND_UP(((ULONG_PTR)&_init_end__));
    ParamLength = ParamLength - Length;
    DPRINT("Length %x\n",Length);
-   BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&etext));
+   BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG_PTR)&_init_end__));
    DPRINT("BaseAddress %x\n",BaseAddress);
+
+   /*
+    * No need to lock the address space at this point since we are
+    * the only thread running.
+    */
    MmCreateMemoryArea(NULL,
-                     MmGetKernelAddressSpace(),                      
-                     MEMORY_AREA_SYSTEM,
-                     &BaseAddress,
-                     Length,
-                     0,
-                     &kernel_data_desc);
-   
-   BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&end));
-//   Length = ParamLength;
-   Length = LastKernelAddress - (ULONG)BaseAddress;
+                      MmGetKernelAddressSpace(),
+                      MEMORY_AREA_SYSTEM,
+                      &BaseAddress,
+                      Length,
+                      0,
+                      &MArea,
+                      TRUE,
+                      FALSE,
+                      BoundaryAddressMultiple);
+
+   BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG_PTR)&_bss_end__));
+   Length = LastKernelAddress - (ULONG_PTR)BaseAddress;
    MmCreateMemoryArea(NULL,
-                     MmGetKernelAddressSpace(),                      
-                     MEMORY_AREA_SYSTEM,
-                     &BaseAddress,
-                     Length,
-                     0,
-                     &kernel_param_desc);
-
-   BaseAddress = (PVOID)(LastKernelAddress + PAGESIZE);
-   Length = NONPAGED_POOL_SIZE;
+                      MmGetKernelAddressSpace(),
+                      MEMORY_AREA_SYSTEM,
+                      &BaseAddress,
+                      Length,
+                      0,
+                      &MArea,
+                      TRUE,
+                      FALSE,
+                      BoundaryAddressMultiple);
+
+   BaseAddress = MiNonPagedPoolStart;
    MmCreateMemoryArea(NULL,
-                     MmGetKernelAddressSpace(),
-                     MEMORY_AREA_SYSTEM,
-                     &BaseAddress,
-                     Length,
-                     0,
-                     &kernel_pool_desc);
-   
-   DPRINT1("Creating shared data page\n");
-   BaseAddress = (PVOID)KERNEL_SHARED_DATA_BASE;
-   Length = PAGESIZE;
+                      MmGetKernelAddressSpace(),
+                      MEMORY_AREA_SYSTEM,
+                      &BaseAddress,
+                      MiNonPagedPoolLength,
+                      0,
+                      &MArea,
+                      TRUE,
+                      FALSE,
+                      BoundaryAddressMultiple);
+
+   BaseAddress = MmPagedPoolBase;
+   Status = MmCreateMemoryArea(NULL,
+                               MmGetKernelAddressSpace(),
+                               MEMORY_AREA_PAGED_POOL,
+                               &BaseAddress,
+                               MmPagedPoolSize,
+                               0,
+                               &MArea,
+                               TRUE,
+                               FALSE,
+                               BoundaryAddressMultiple);
+
+   MmInitializePagedPool();
+
+   /*
+    * Create the kernel mapping of the user/kernel shared memory.
+    */
+   BaseAddress = (PVOID)KI_USER_SHARED_DATA;
+   Length = PAGE_SIZE;
    MmCreateMemoryArea(NULL,
-                     MmGetKernelAddressSpace(),
-                     MEMORY_AREA_SYSTEM,
-                     &BaseAddress,
-                     Length,
-                     0,
-                     &kernel_shared_data_desc);
-   MmSharedDataPagePhysicalAddress = MmAllocPage(0);
+                      MmGetKernelAddressSpace(),
+                      MEMORY_AREA_SYSTEM,
+                      &BaseAddress,
+                      Length,
+                      0,
+                      &MArea,
+                      TRUE,
+                      FALSE,
+                      BoundaryAddressMultiple);
+   Status = MmRequestPageMemoryConsumer(MC_NPPOOL, TRUE, &Pfn);
+   MmSharedDataPagePhysicalAddress.QuadPart = Pfn << PAGE_SHIFT;
    Status = MmCreateVirtualMapping(NULL,
-                                  (PVOID)KERNEL_SHARED_DATA_BASE,
-                                  PAGE_READWRITE,
-                                  (ULONG)MmSharedDataPagePhysicalAddress);
+                                   (PVOID)KI_USER_SHARED_DATA,
+                                   PAGE_READWRITE,
+                                   &Pfn,
+                                   1);
    if (!NT_SUCCESS(Status))
-     {
-       DbgPrint("Unable to create virtual mapping\n");
-       KeBugCheck(0);
-     }
-   ((PKUSER_SHARED_DATA)KERNEL_SHARED_DATA_BASE)->TickCountLow = 0xdeadbeef;
-   DPRINT1("Finished creating shared data page\n");
-   
-//   MmDumpMemoryAreas();
-   DPRINT("MmInitVirtualMemory() done\n");
+   {
+      DbgPrint("Unable to create virtual mapping\n");
+      KEBUGCHECK(0);
+   }
+   RtlZeroMemory(BaseAddress, Length);
+
+   /*
+    *
+    */
+   MmInitializeMemoryConsumer(MC_USER, MmTrimUserMemory);
 }
 
-VOID MmInit1(PLOADER_PARAMETER_BLOCK bp, ULONG LastKernelAddress)
+VOID
+INIT_FUNCTION
+NTAPI
+MmInit1(ULONG_PTR FirstKrnlPhysAddr,
+        ULONG_PTR LastKrnlPhysAddr,
+        ULONG_PTR LastKernelAddress,
+        PADDRESS_RANGE BIOSMemoryMap,
+        ULONG AddressRangeCount,
+        ULONG MaxMem)
 /*
  * FUNCTION: Initalize memory managment
  */
 {
-   ULONG first_krnl_phys_addr;
-   ULONG last_krnl_phys_addr;
    ULONG i;
    ULONG kernel_len;
-   
-   DPRINT("MmInit1(bp %x, LastKernelAddress %x)\n", bp, 
-         LastKernelAddress);
-   
-   /*
-    * FIXME: Set this based on the system command line
-    */
-   MmUserProbeAddress = (PVOID)0x7fff0000;
-   MmHighestUserAddress = (PVOID)0x7ffeffff;
-   
+   ULONG_PTR MappingAddress;
+
+   DPRINT("MmInit1(FirstKrnlPhysAddr, %p, LastKrnlPhysAddr %p, LastKernelAddress %p)\n",
+          FirstKrnlPhysAddr,
+          LastKrnlPhysAddr,
+          LastKernelAddress);
+
+   if ((BIOSMemoryMap != NULL) && (AddressRangeCount > 0))
+   {
+      // If we have a bios memory map, recalulate the memory size
+      ULONG last = 0;
+      for (i = 0; i < AddressRangeCount; i++)
+      {
+         if (BIOSMemoryMap[i].Type == 1
+               && (BIOSMemoryMap[i].BaseAddrLow + BIOSMemoryMap[i].LengthLow + PAGE_SIZE -1) / PAGE_SIZE > last)
+         {
+            last = (BIOSMemoryMap[i].BaseAddrLow + BIOSMemoryMap[i].LengthLow + PAGE_SIZE -1) / PAGE_SIZE;
+         }
+      }
+      if ((last - 256) * 4 > KeLoaderBlock.MemHigher)
+      {
+         KeLoaderBlock.MemHigher = (last - 256) * 4;
+      }
+   }
+
+   if (KeLoaderBlock.MemHigher >= (MaxMem - 1) * 1024)
+   {
+      KeLoaderBlock.MemHigher = (MaxMem - 1) * 1024;
+   }
+
+   /* Set memory limits */
+   MmUserProbeAddress = (ULONG_PTR)MmSystemRangeStart - 0x10000;
+   MmHighestUserAddress = (PVOID)(MmUserProbeAddress - 1);
+
    /*
     * Initialize memory managment statistics
     */
@@ -204,77 +350,149 @@ VOID MmInit1(PLOADER_PARAMETER_BLOCK bp, ULONG LastKernelAddress)
    MmStats.PagingRequestsInLastMinute = 0;
    MmStats.PagingRequestsInLastFiveMinutes = 0;
    MmStats.PagingRequestsInLastFifteenMinutes = 0;
-   
-   /*
-    * Initialize the kernel address space
-    */
-   MmInitializeKernelAddressSpace();
-   
-   /*
-    * Unmap low memory
-    */
-   MmDeletePageTable(NULL, 0);
-   
+
    /*
     * Free all pages not used for kernel memory
     * (we assume the kernel occupies a continuous range of physical
     * memory)
     */
-   first_krnl_phys_addr = bp->start_mem;
-   last_krnl_phys_addr = bp->end_mem;
-   DPRINT("first krnl %x\nlast krnl %x\n",first_krnl_phys_addr,
-         last_krnl_phys_addr);
-   
+   DPRINT("first krnl %x\nlast krnl %x\n",FirstKrnlPhysAddr,
+          LastKrnlPhysAddr);
+
    /*
     * Free physical memory not used by the kernel
     */
-   LastKernelAddress = (ULONG)MmInitializePageList(
-                                          (PVOID)first_krnl_phys_addr,
-                                          (PVOID)last_krnl_phys_addr,
-                                          1024,
-                                          PAGE_ROUND_UP(LastKernelAddress));
-   kernel_len = last_krnl_phys_addr - first_krnl_phys_addr;
-   
+   MmStats.NrTotalPages = KeLoaderBlock.MemHigher/4;
+   if (!MmStats.NrTotalPages)
+   {
+      DbgPrint("Memory not detected, default to 8 MB\n");
+      MmStats.NrTotalPages = 2048;
+   }
+   else
+   {
+      /* add 1MB for standard memory (not extended) */
+      MmStats.NrTotalPages += 256;
+   }
+#ifdef BIOS_MEM_FIX
+   MmStats.NrTotalPages += 16;
+#endif
+
+   /*
+    * Initialize the kernel address space
+    */
+   MmInitializeKernelAddressSpace();
+
+   MmInitGlobalKernelPageDirectory();
+
+   DbgPrint("Used memory %dKb\n", (MmStats.NrTotalPages * PAGE_SIZE) / 1024);
+   DPRINT1("Kernel Stack Limits. InitTop = 0x%x, Init = 0x%x\n", init_stack_top, init_stack);
+
+   LastKernelAddress = (ULONG_PTR)MmInitializePageList(
+                       FirstKrnlPhysAddr,
+                       LastKrnlPhysAddr,
+                       MmStats.NrTotalPages,
+                       PAGE_ROUND_UP(LastKernelAddress),
+                       BIOSMemoryMap,
+                       AddressRangeCount);
+   kernel_len = LastKrnlPhysAddr - FirstKrnlPhysAddr;
+
    /*
-    * Create a trap for null pointer references and protect text
-    * segment
+    * Unmap low memory
     */
-   CHECKPOINT;
-   DPRINT("stext %x etext %x\n",(int)&stext,(int)&etext);
-   for (i=PAGE_ROUND_UP(((int)&stext));
-       i<PAGE_ROUND_DOWN(((int)&etext));i=i+PAGESIZE)
-     {
-       MmSetPageProtect(NULL,
-                        (PVOID)i,
-                        PAGE_EXECUTE_READ);
-     }
-   
+#ifdef CONFIG_SMP
+   /* In SMP mode we unmap the low memory pagetable in MmInit3.
+      The APIC needs the mapping of the first pages
+      while the processors are starting up.
+      We unmap all pages except page 2 and 3. */
+   for (MappingAddress = 0;
+        MappingAddress < 1024 * PAGE_SIZE;
+        MappingAddress += PAGE_SIZE)
+   {
+      if (MappingAddress != 2 * PAGE_SIZE &&
+          MappingAddress != 3 * PAGE_SIZE)
+      {
+         MmRawDeleteVirtualMapping((PVOID)MappingAddress);
+      }
+   }
+#else
+   MmDeletePageTable(NULL, 0);
+#endif
+
    DPRINT("Invalidating between %x and %x\n",
-         LastKernelAddress,
-         KERNEL_BASE + PAGE_TABLE_SIZE);
-   for (i=(LastKernelAddress); 
-       i<(KERNEL_BASE + PAGE_TABLE_SIZE); 
-       i=i+PAGESIZE)
-     {
-       MmDeleteVirtualMapping(NULL, (PVOID)(i), FALSE);
-     }
+          LastKernelAddress, KERNEL_BASE + 0x00600000);
+   for (MappingAddress = LastKernelAddress;
+        MappingAddress < KERNEL_BASE + 0x00600000;
+        MappingAddress += PAGE_SIZE)
+   {
+      MmRawDeleteVirtualMapping((PVOID)MappingAddress);
+   }
+
    DPRINT("Almost done MmInit()\n");
-   
    /*
     * Intialize memory areas
     */
-   MmInitVirtualMemory(bp, LastKernelAddress);
+   MmInitVirtualMemory(LastKernelAddress, kernel_len);
+
+   MmInitializeMdlImplementation();
 }
 
-VOID MmInit2(VOID)
+VOID
+NTAPI
+INIT_FUNCTION
+MmInit2(VOID)
 {
+   MmInitializeRmapList();
+   MmInitializePageOp();
    MmInitSectionImplementation();
    MmInitPagingFile();
 }
 
-VOID MmInit3(VOID)
+VOID
+INIT_FUNCTION
+NTAPI
+MmInit3(VOID)
 {
-   MmInitPagerThread();
+   /*
+    * Unmap low memory
+    */
+#ifdef CONFIG_SMP
+   /* In SMP mode we can unmap the low memory
+      if all processors are started. */
+   MmDeletePageTable(NULL, 0);
+#endif
+
+   MmInitZeroPageThread();
+   MmCreatePhysicalMemorySection();
+   MiInitBalancerThread();
+
+   /*
+    * Initialise the modified page writer.
+    */
+   MmInitMpwThread();
+
    /* FIXME: Read parameters from memory */
 }
 
+VOID STATIC
+MiFreeInitMemoryPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
+                     PFN_TYPE Page, SWAPENTRY SwapEntry,
+                     BOOLEAN Dirty)
+{
+   ASSERT(SwapEntry == 0);
+   if (Page != 0)
+   {
+      MmReleasePageMemoryConsumer(MC_NPPOOL, Page);
+   }
+}
+
+VOID
+NTAPI
+MiFreeInitMemory(VOID)
+{
+   MmLockAddressSpace(MmGetKernelAddressSpace());
+   MmFreeMemoryAreaByPtr(MmGetKernelAddressSpace(),
+                         (PVOID)&_init_start__,
+                         MiFreeInitMemoryPage,
+                         NULL);
+   MmUnlockAddressSpace(MmGetKernelAddressSpace());
+}