3 * COPYRIGHT: See COPYING in the top directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/mm.c
6 * PURPOSE: Kernel memory managment functions
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
10 /* INCLUDES *****************************************************************/
14 #include <internal/debug.h>
16 /* GLOBALS *****************************************************************/
18 extern MODULE_OBJECT NtoskrnlModuleObject
;
19 extern MODULE_OBJECT HalModuleObject
;
21 ULONG EXPORTED MmUserProbeAddress
= 0;
22 PVOID EXPORTED MmHighestUserAddress
= NULL
;
23 PBOOLEAN EXPORTED Mm64BitPhysicalAddress
= FALSE
;
24 PVOID EXPORTED MmSystemRangeStart
= NULL
;
28 /* FUNCTIONS ****************************************************************/
32 MmCopyToCaller(PVOID Dest
, const VOID
*Src
, ULONG NumberOfBytes
)
36 if (ExGetPreviousMode() == UserMode
)
38 if ((ULONG_PTR
)Dest
>= KERNEL_BASE
)
40 return(STATUS_ACCESS_VIOLATION
);
42 Status
= MmSafeCopyToUser(Dest
, Src
, NumberOfBytes
);
47 memcpy(Dest
, Src
, NumberOfBytes
);
48 return(STATUS_SUCCESS
);
53 MmCopyFromCaller(PVOID Dest
, const VOID
*Src
, ULONG NumberOfBytes
)
57 if (ExGetPreviousMode() == UserMode
)
59 if ((ULONG_PTR
)Src
>= KERNEL_BASE
)
61 return(STATUS_ACCESS_VIOLATION
);
63 Status
= MmSafeCopyFromUser(Dest
, Src
, NumberOfBytes
);
68 memcpy(Dest
, Src
, NumberOfBytes
);
69 return(STATUS_SUCCESS
);
75 NTSTATUS
MmReleaseMemoryArea(PEPROCESS Process
, PMEMORY_AREA Marea
)
79 DPRINT("MmReleaseMemoryArea(Process %x, Marea %x)\n",Process
,Marea
);
81 DPRINT("Releasing %x between %x %x (type %d)\n",
82 Marea
, Marea
->StartingAddress
, Marea
->EndingAddress
,
87 case MEMORY_AREA_SECTION_VIEW
:
88 Status
= MmUnmapViewOfSection(Process
, (PVOID
)Marea
->StartingAddress
);
89 ASSERT(Status
== STATUS_SUCCESS
);
90 return(STATUS_SUCCESS
);
92 case MEMORY_AREA_VIRTUAL_MEMORY
:
93 case MEMORY_AREA_PEB_OR_TEB
:
94 MmFreeVirtualMemory(Process
, Marea
);
97 case MEMORY_AREA_SHARED_DATA
:
98 case MEMORY_AREA_NO_ACCESS
:
99 Status
= MmFreeMemoryArea(&Process
->AddressSpace
,
105 case MEMORY_AREA_MDL_MAPPING
:
106 KEBUGCHECK(PROCESS_HAS_LOCKED_PAGES
);
113 return(STATUS_SUCCESS
);
116 NTSTATUS
MmReleaseMmInfo(PEPROCESS Process
)
118 DPRINT("MmReleaseMmInfo(Process %x (%s))\n", Process
,
119 Process
->ImageFileName
);
121 MmLockAddressSpace(&Process
->AddressSpace
);
123 while (Process
->AddressSpace
.MemoryAreaRoot
!= NULL
)
124 MmReleaseMemoryArea(Process
, Process
->AddressSpace
.MemoryAreaRoot
);
126 Mmi386ReleaseMmInfo(Process
);
128 MmUnlockAddressSpace(&Process
->AddressSpace
);
129 MmDestroyAddressSpace(&Process
->AddressSpace
);
131 DPRINT("Finished MmReleaseMmInfo()\n");
132 return(STATUS_SUCCESS
);
138 BOOLEAN STDCALL
MmIsNonPagedSystemAddressValid(PVOID VirtualAddress
)
140 return MmIsAddressValid(VirtualAddress
);
146 BOOLEAN STDCALL
MmIsAddressValid(PVOID VirtualAddress
)
148 * FUNCTION: Checks whether the given address is valid for a read or write
150 * VirtualAddress = address to check
151 * RETURNS: True if the access would be valid
152 * False if the access would cause a page fault
153 * NOTES: This function checks whether a byte access to the page would
154 * succeed. Is this realistic for RISC processors which don't
155 * allow byte granular access?
158 MEMORY_AREA
* MemoryArea
;
159 PMADDRESS_SPACE AddressSpace
;
161 if ((ULONG_PTR
)VirtualAddress
>= KERNEL_BASE
)
163 AddressSpace
= MmGetKernelAddressSpace();
167 AddressSpace
= &PsGetCurrentProcess()->AddressSpace
;
170 MmLockAddressSpace(AddressSpace
);
171 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
174 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
176 MmUnlockAddressSpace(AddressSpace
);
179 MmUnlockAddressSpace(AddressSpace
);
183 NTSTATUS
MmAccessFault(KPROCESSOR_MODE Mode
,
187 PMADDRESS_SPACE AddressSpace
;
188 MEMORY_AREA
* MemoryArea
;
190 BOOLEAN Locked
= FromMdl
;
192 DPRINT("MmAccessFault(Mode %d, Address %x)\n", Mode
, Address
);
194 if (KeGetCurrentIrql() >= DISPATCH_LEVEL
)
196 CPRINT("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
197 return(STATUS_UNSUCCESSFUL
);
199 if (PsGetCurrentProcess() == NULL
)
201 CPRINT("No current process\n");
202 return(STATUS_UNSUCCESSFUL
);
206 * Find the memory area for the faulting address
208 if (Address
>= KERNEL_BASE
)
213 if (Mode
!= KernelMode
)
215 DbgPrint("%s:%d\n",__FILE__
,__LINE__
);
216 return(STATUS_UNSUCCESSFUL
);
218 AddressSpace
= MmGetKernelAddressSpace();
222 AddressSpace
= &PsGetCurrentProcess()->AddressSpace
;
227 MmLockAddressSpace(AddressSpace
);
231 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, (PVOID
)Address
);
232 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
236 MmUnlockAddressSpace(AddressSpace
);
238 return (STATUS_UNSUCCESSFUL
);
241 switch (MemoryArea
->Type
)
243 case MEMORY_AREA_SYSTEM
:
244 Status
= STATUS_UNSUCCESSFUL
;
247 case MEMORY_AREA_PAGED_POOL
:
248 Status
= STATUS_SUCCESS
;
251 case MEMORY_AREA_SECTION_VIEW
:
252 Status
= MmAccessFaultSectionView(AddressSpace
,
258 case MEMORY_AREA_VIRTUAL_MEMORY
:
259 Status
= STATUS_UNSUCCESSFUL
;
262 case MEMORY_AREA_SHARED_DATA
:
263 Status
= STATUS_UNSUCCESSFUL
;
267 Status
= STATUS_UNSUCCESSFUL
;
271 while (Status
== STATUS_MM_RESTART_OPERATION
);
273 DPRINT("Completed page fault handling\n");
276 MmUnlockAddressSpace(AddressSpace
);
281 NTSTATUS
MmCommitPagedPoolAddress(PVOID Address
, BOOLEAN Locked
)
284 PFN_TYPE AllocatedPage
;
285 Status
= MmRequestPageMemoryConsumer(MC_PPOOL
, FALSE
, &AllocatedPage
);
286 if (!NT_SUCCESS(Status
))
288 MmUnlockAddressSpace(MmGetKernelAddressSpace());
289 Status
= MmRequestPageMemoryConsumer(MC_PPOOL
, TRUE
, &AllocatedPage
);
290 MmLockAddressSpace(MmGetKernelAddressSpace());
293 MmCreateVirtualMapping(NULL
,
294 (PVOID
)PAGE_ROUND_DOWN(Address
),
300 MmLockPage(AllocatedPage
);
305 NTSTATUS
MmNotPresentFault(KPROCESSOR_MODE Mode
,
309 PMADDRESS_SPACE AddressSpace
;
310 MEMORY_AREA
* MemoryArea
;
312 BOOLEAN Locked
= FromMdl
;
315 DPRINT("MmNotPresentFault(Mode %d, Address %x)\n", Mode
, Address
);
317 if (KeGetCurrentIrql() >= DISPATCH_LEVEL
)
319 CPRINT("Page fault at high IRQL was %d, address %x\n", KeGetCurrentIrql(), Address
);
320 return(STATUS_UNSUCCESSFUL
);
322 if (PsGetCurrentProcess() == NULL
)
324 /* Allow this! It lets us page alloc much earlier! It won't be needed
325 * after my init patch anyways
327 CPRINT("No current process\n");
328 if (Address
< KERNEL_BASE
)
330 return(STATUS_UNSUCCESSFUL
);
335 * Find the memory area for the faulting address
337 if (Address
>= KERNEL_BASE
)
342 if (Mode
!= KernelMode
)
344 CPRINT("Address: %x\n", Address
);
345 return(STATUS_UNSUCCESSFUL
);
347 AddressSpace
= MmGetKernelAddressSpace();
351 AddressSpace
= &PsGetCurrentProcess()->AddressSpace
;
356 MmLockAddressSpace(AddressSpace
);
360 * Call the memory area specific fault handler
364 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, (PVOID
)Address
);
365 if (MemoryArea
== NULL
|| MemoryArea
->DeleteInProgress
)
369 MmUnlockAddressSpace(AddressSpace
);
371 return (STATUS_UNSUCCESSFUL
);
374 switch (MemoryArea
->Type
)
376 case MEMORY_AREA_PAGED_POOL
:
378 Status
= MmCommitPagedPoolAddress((PVOID
)Address
, Locked
);
382 case MEMORY_AREA_SYSTEM
:
383 Status
= STATUS_UNSUCCESSFUL
;
386 case MEMORY_AREA_SECTION_VIEW
:
387 Status
= MmNotPresentFaultSectionView(AddressSpace
,
393 case MEMORY_AREA_VIRTUAL_MEMORY
:
394 case MEMORY_AREA_PEB_OR_TEB
:
395 Status
= MmNotPresentFaultVirtualMemory(AddressSpace
,
401 case MEMORY_AREA_SHARED_DATA
:
402 Pfn
= MmSharedDataPagePhysicalAddress
.QuadPart
>> PAGE_SHIFT
;
404 MmCreateVirtualMapping(PsGetCurrentProcess(),
405 (PVOID
)PAGE_ROUND_DOWN(Address
),
412 Status
= STATUS_UNSUCCESSFUL
;
416 while (Status
== STATUS_MM_RESTART_OPERATION
);
418 DPRINT("Completed page fault handling\n");
421 MmUnlockAddressSpace(AddressSpace
);
426 /* Miscellanea functions: they may fit somewhere else */
432 MmAdjustWorkingSetSize (DWORD Unknown0
,
443 MmDbgTranslatePhysicalAddress (
463 return (STATUS_NOT_IMPLEMENTED
);
472 MmSetAddressRangeModified (
486 MmGetSystemRoutineAddress (
487 IN PUNICODE_STRING SystemRoutineName
491 ANSI_STRING AnsiRoutineName
;
494 if(!NT_SUCCESS(RtlUnicodeStringToAnsiString(&AnsiRoutineName
,
501 Status
= LdrGetProcedureAddress(NtoskrnlModuleObject
.Base
,
506 if(!NT_SUCCESS(Status
))
508 Status
= LdrGetProcedureAddress(HalModuleObject
.Base
,
514 RtlFreeAnsiString(&AnsiRoutineName
);
516 return (NT_SUCCESS(Status
) ? ProcAddress
: NULL
);