mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 04:53:00 +00:00
320 lines
7.5 KiB
C
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);
|
|
}
|