reactos/reactos/ntoskrnl/mm/mm.c
David Welch d837d19fac *** empty log message ***
svn path=/trunk/; revision=375
1999-04-14 00:52:19 +00:00

320 lines
7.5 KiB
C

/*
* COPYRIGHT: See COPYING in the top directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/mm.c
* PURPOSE: kernel memory managment functions
* PROGRAMMER: David Welch (welch@cwcom.net)
* UPDATE HISTORY:
* Created 9/4/98
*/
/* INCLUDES *****************************************************************/
#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/mmhal.h>
#define NDEBUG
#include <internal/debug.h>
/* GLOBALS *****************************************************************/
/*
* Size of extended memory (kb) (fixed for now)
*/
#define EXTENDED_MEMORY_SIZE (3*1024*1024)
/*
* Compiler defined symbol
*/
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 end;
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;
/* FUNCTIONS ****************************************************************/
void VirtualInit(boot_param* bp)
/*
* FUNCTION: Intialize the memory areas list
* ARGUMENTS:
* bp = Pointer to the boot parameters
* kernel_len = Length of the kernel
*/
{
unsigned int kernel_len = bp->end_mem - bp->start_mem;
PVOID BaseAddress;
ULONG Length;
ULONG ParamLength = kernel_len;
DPRINT("VirtualInit() %x\n",bp);
MmInitMemoryAreas();
ExInitNonPagedPool(KERNEL_BASE+ PAGE_ROUND_UP(kernel_len) + PAGESIZE);
/*
* Setup the system area descriptor list
*/
BaseAddress = (PVOID)KERNEL_BASE;
Length = PAGE_ROUND_UP(((ULONG)&etext)) - KERNEL_BASE;
ParamLength = ParamLength - Length;
MmCreateMemoryArea(KernelMode,NULL,MEMORY_AREA_SYSTEM,&BaseAddress,
Length,0,&kernel_text_desc);
Length = PAGE_ROUND_UP(((ULONG)&end)) - PAGE_ROUND_UP(((ULONG)&etext));
ParamLength = ParamLength - Length;
DPRINT("Length %x\n",Length);
BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&etext));
MmCreateMemoryArea(KernelMode,
NULL,
MEMORY_AREA_SYSTEM,
&BaseAddress,
Length,
0,
&kernel_data_desc);
BaseAddress = (PVOID)PAGE_ROUND_UP(((ULONG)&end));
Length = ParamLength;
MmCreateMemoryArea(KernelMode,NULL,MEMORY_AREA_SYSTEM,&BaseAddress,
Length,0,&kernel_param_desc);
BaseAddress = (PVOID)(KERNEL_BASE + PAGE_ROUND_UP(kernel_len) + PAGESIZE);
Length = NONPAGED_POOL_SIZE;
MmCreateMemoryArea(KernelMode,NULL,MEMORY_AREA_SYSTEM,&BaseAddress,
Length,0,&kernel_pool_desc);
// MmDumpMemoryAreas();
CHECKPOINT;
MmInitSectionImplementation();
}
ULONG MmCommitedSectionHandleFault(MEMORY_AREA* MemoryArea, PVOID Address)
{
MmSetPage(PsGetCurrentProcess(),
Address,
MemoryArea->Attributes,
(ULONG)MmAllocPage());
return(TRUE);
}
NTSTATUS MmSectionHandleFault(MEMORY_AREA* MemoryArea, PVOID Address)
{
LARGE_INTEGER Offset;
IO_STATUS_BLOCK IoStatus;
DPRINT("MmSectionHandleFault(MemoryArea %x, Address %x)\n",
MemoryArea,Address);
MmSetPage(NULL,
Address,
MemoryArea->Attributes,
(ULONG)MmAllocPage());
LARGE_INTEGER_QUAD_PART(Offset) = (Address - MemoryArea->BaseAddress) +
MemoryArea->Data.SectionData.ViewOffset;
DPRINT("MemoryArea->Data.SectionData.Section->FileObject %x\n",
MemoryArea->Data.SectionData.Section->FileObject);
if (MemoryArea->Data.SectionData.Section->FileObject == NULL)
{
return(STATUS_UNSUCCESSFUL);
}
IoPageRead(MemoryArea->Data.SectionData.Section->FileObject,
(PVOID)Address,
&Offset,
&IoStatus);
DPRINT("Returning from MmSectionHandleFault()\n");
return(STATUS_SUCCESS);
}
asmlinkage int page_fault_handler(unsigned int cs,
unsigned int eip)
/*
* FUNCTION: Handle a page fault
*/
{
KPROCESSOR_MODE FaultMode;
MEMORY_AREA* MemoryArea;
KIRQL oldlvl;
ULONG stat;
/*
* Get the address for the page fault
*/
unsigned int cr2;
__asm__("movl %%cr2,%0\n\t" : "=d" (cr2));
DPRINT("Page fault at address %x with eip %x in process %x\n",cr2,eip,
PsGetCurrentProcess());
cr2 = PAGE_ROUND_DOWN(cr2);
if (KeGetCurrentIrql() != PASSIVE_LEVEL)
{
DbgPrint("Page fault at high IRQL\n");
return(0);
// KeBugCheck(0);
}
KeRaiseIrql(DISPATCH_LEVEL, &oldlvl);
/*
* Find the memory area for the faulting address
*/
if (cr2>=KERNEL_BASE)
{
/*
* Check permissions
*/
if (cs != KERNEL_CS)
{
printk("%s:%d\n",__FILE__,__LINE__);
return(0);
}
FaultMode = UserMode;
}
else
{
FaultMode = KernelMode;
}
MemoryArea = MmOpenMemoryAreaByAddress(PsGetCurrentProcess(),(PVOID)cr2);
if (MemoryArea == NULL)
{
printk("%s:%d\n",__FILE__,__LINE__);
return(0);
}
switch (MemoryArea->Type)
{
case MEMORY_AREA_SYSTEM:
stat = 0;
break;
case MEMORY_AREA_SECTION_VIEW_COMMIT:
if (MmSectionHandleFault(MemoryArea, (PVOID)cr2)==STATUS_SUCCESS)
{
stat = 1;
}
else
{
stat = 0;
}
break;
case MEMORY_AREA_COMMIT:
stat = MmCommitedSectionHandleFault(MemoryArea,(PVOID)cr2);
break;
default:
stat = 0;
break;
}
DPRINT("Completed page fault handling\n");
if (stat)
{
KeLowerIrql(oldlvl);
}
return(stat);
}
BOOLEAN MmIsThisAnNtAsSystem(VOID)
{
return(IsThisAnNtAsSystem);
}
MM_SYSTEM_SIZE MmQuerySystemSize(VOID)
{
return(MmSystemSize);
}
void MmInitialize(boot_param* bp, ULONG LastKernelAddress)
/*
* FUNCTION: Initalize memory managment
*/
{
unsigned int first_krnl_phys_addr;
unsigned int last_krnl_phys_addr;
int i;
unsigned int kernel_len;
DPRINT("MmInitialize(bp %x, LastKernelAddress %x)\n", bp,
LastKernelAddress);
/*
* 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);
/*
* 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;
/*
* Create a trap for null pointer references and protect text
* segment
*/
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);
}
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)
{
MmSetPage(NULL, (PVOID)(i), PAGE_NOACCESS, 0);
}
DPRINT("Almost done MmInit()\n");
/*
* Intialize memory areas
*/
VirtualInit(bp);
}