-/* $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:
* 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
*/
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());
+}