3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: virtual.c,v 1.82 2004/10/28 19:01:58 chorns Exp $
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/virtual.c
23 * PURPOSE: Implementing operations on virtual memory.
24 * PROGRAMMER: David Welch
27 /* INCLUDE *****************************************************************/
32 #include <internal/debug.h>
34 /* FUNCTIONS *****************************************************************/
37 NtFlushVirtualMemory(IN HANDLE ProcessHandle
,
39 IN ULONG NumberOfBytesToFlush
,
40 OUT PULONG NumberOfBytesFlushed OPTIONAL
)
42 * FUNCTION: Flushes virtual memory to file
44 * ProcessHandle = Points to the process that allocated the virtual
46 * BaseAddress = Points to the memory address
47 * NumberOfBytesToFlush = Limits the range to flush,
48 * NumberOfBytesFlushed = Actual number of bytes flushed
53 return(STATUS_NOT_IMPLEMENTED
);
58 NtLockVirtualMemoryInternal(HANDLE ProcessHandle
,
60 ULONG NumberOfBytesToLock
,
61 PULONG NumberOfBytesLocked
,
62 PObReferenceObjectByHandle pObReferenceObjectByHandle
,
63 PMmCreateMdl pMmCreateMdl
,
64 PObDereferenceObject pObDereferenceObject
,
65 PMmProbeAndLockPages pMmProbeAndLockPages
,
66 PExFreePool pExFreePool
)
72 Status
= pObReferenceObjectByHandle(ProcessHandle
,
78 if (!NT_SUCCESS(Status
))
81 Mdl
= pMmCreateMdl(NULL
,
86 pObDereferenceObject(Process
);
87 return(STATUS_NO_MEMORY
);
90 pMmProbeAndLockPages(Mdl
,
96 pObDereferenceObject(Process
);
98 *NumberOfBytesLocked
= NumberOfBytesToLock
;
99 return(STATUS_SUCCESS
);
104 NtLockVirtualMemory(HANDLE ProcessHandle
,
106 ULONG NumberOfBytesToLock
,
107 PULONG NumberOfBytesLocked
)
109 DPRINT("NtLockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
110 "NumberOfBytesToLock %d, NumberOfBytesLocked %x)\n",
114 NumberOfBytesLocked
);
116 return NtLockVirtualMemoryInternal(ProcessHandle
,
120 ObReferenceObjectByHandle
,
122 ObfDereferenceObject
,
130 * Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
134 NtQueryVirtualMemory (IN HANDLE ProcessHandle
,
136 IN CINT VirtualMemoryInformationClass
,
137 OUT PVOID VirtualMemoryInformation
,
139 OUT PULONG UnsafeResultLength
)
143 MEMORY_AREA
* MemoryArea
;
144 ULONG ResultLength
= 0;
145 PMADDRESS_SPACE AddressSpace
;
146 KPROCESSOR_MODE PrevMode
;
149 MEMORY_BASIC_INFORMATION BasicInfo
;
153 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
154 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
155 "Length %lu ResultLength %x)\n",ProcessHandle
,Address
,
156 VirtualMemoryInformationClass
,VirtualMemoryInformation
,
157 Length
,ResultLength
);
159 PrevMode
= ExGetPreviousMode();
161 if (PrevMode
== UserMode
&& Address
>= (PVOID
)KERNEL_BASE
)
163 return STATUS_INVALID_PARAMETER
;
166 if (Address
< (PVOID
)KERNEL_BASE
)
168 Status
= ObReferenceObjectByHandle(ProcessHandle
,
169 PROCESS_QUERY_INFORMATION
,
175 if (!NT_SUCCESS(Status
))
177 DPRINT("NtQueryVirtualMemory() = %x\n",Status
);
180 AddressSpace
= &Process
->AddressSpace
;
184 AddressSpace
= MmGetKernelAddressSpace();
186 MmLockAddressSpace(AddressSpace
);
187 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
189 switch(VirtualMemoryInformationClass
)
191 case MemoryBasicInformation
:
193 PMEMORY_BASIC_INFORMATION Info
= &VirtualMemoryInfo
.BasicInfo
;
194 if (Length
!= sizeof(MEMORY_BASIC_INFORMATION
))
196 MmUnlockAddressSpace(AddressSpace
);
197 ObDereferenceObject(Process
);
198 return(STATUS_INFO_LENGTH_MISMATCH
);
201 if (MemoryArea
== NULL
)
204 Info
->State
= MEM_FREE
;
205 Info
->Protect
= PAGE_NOACCESS
;
206 Info
->AllocationProtect
= 0;
207 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
208 Info
->AllocationBase
= NULL
;
209 Info
->RegionSize
= MmFindGapAtAddress(AddressSpace
, Info
->BaseAddress
);
210 Status
= STATUS_SUCCESS
;
211 ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
215 switch(MemoryArea
->Type
)
217 case MEMORY_AREA_VIRTUAL_MEMORY
:
218 Status
= MmQueryAnonMem(MemoryArea
, Address
, Info
,
221 case MEMORY_AREA_SECTION_VIEW
:
222 Status
= MmQuerySectionView(MemoryArea
, Address
, Info
,
225 case MEMORY_AREA_NO_ACCESS
:
227 Info
->State
= MEM_FREE
;
228 Info
->Protect
= MemoryArea
->Attributes
;
229 Info
->AllocationProtect
= MemoryArea
->Attributes
;
230 Info
->BaseAddress
= MemoryArea
->BaseAddress
;
231 Info
->AllocationBase
= MemoryArea
->BaseAddress
;
232 Info
->RegionSize
= MemoryArea
->Length
;
233 Status
= STATUS_SUCCESS
;
234 ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
236 case MEMORY_AREA_SHARED_DATA
:
238 Info
->State
= MEM_COMMIT
;
239 Info
->Protect
= MemoryArea
->Attributes
;
240 Info
->AllocationProtect
= MemoryArea
->Attributes
;
241 Info
->BaseAddress
= MemoryArea
->BaseAddress
;
242 Info
->AllocationBase
= MemoryArea
->BaseAddress
;
243 Info
->RegionSize
= MemoryArea
->Length
;
244 Status
= STATUS_SUCCESS
;
245 ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
248 Status
= STATUS_UNSUCCESSFUL
;
257 Status
= STATUS_INVALID_INFO_CLASS
;
263 MmUnlockAddressSpace(AddressSpace
);
264 if (Address
< (PVOID
)KERNEL_BASE
)
266 ObDereferenceObject(Process
);
269 if (NT_SUCCESS(Status
) && ResultLength
> 0)
271 Status
= MmCopyToCaller(VirtualMemoryInformation
, &VirtualMemoryInfo
, ResultLength
);
272 if (!NT_SUCCESS(Status
))
278 if (UnsafeResultLength
!= NULL
)
280 MmCopyToCaller(UnsafeResultLength
, &ResultLength
, sizeof(ULONG
));
288 * Called from VirtualProtectEx (lib\kernel32\mem\virtual.c)
292 NtProtectVirtualMemory(IN HANDLE ProcessHandle
,
293 IN PVOID
*UnsafeBaseAddress
,
294 IN ULONG
*UnsafeNumberOfBytesToProtect
,
295 IN ULONG NewAccessProtection
,
296 OUT PULONG UnsafeOldAccessProtection
)
298 PMEMORY_AREA MemoryArea
;
301 PMADDRESS_SPACE AddressSpace
;
302 ULONG OldAccessProtection
;
304 ULONG NumberOfBytesToProtect
;
306 Status
= MmCopyFromCaller(&BaseAddress
, UnsafeBaseAddress
, sizeof(PVOID
));
307 if (!NT_SUCCESS(Status
))
309 Status
= MmCopyFromCaller(&NumberOfBytesToProtect
, UnsafeNumberOfBytesToProtect
, sizeof(ULONG
));
310 if (!NT_SUCCESS(Status
))
313 // (tMk 2004.II.5) in Microsoft SDK I read:
314 // 'if this parameter is NULL or does not point to a valid variable, the function fails'
315 if(UnsafeOldAccessProtection
== NULL
)
317 return(STATUS_INVALID_PARAMETER
);
320 NumberOfBytesToProtect
=
321 PAGE_ROUND_UP(BaseAddress
+ NumberOfBytesToProtect
) -
322 PAGE_ROUND_DOWN(BaseAddress
);
323 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(BaseAddress
);
325 Status
= ObReferenceObjectByHandle(ProcessHandle
,
326 PROCESS_VM_OPERATION
,
331 if (!NT_SUCCESS(Status
))
333 DPRINT("NtProtectVirtualMemory() = %x\n",Status
);
337 AddressSpace
= &Process
->AddressSpace
;
339 MmLockAddressSpace(AddressSpace
);
340 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
342 if (MemoryArea
== NULL
)
344 MmUnlockAddressSpace(AddressSpace
);
345 ObDereferenceObject(Process
);
346 return(STATUS_UNSUCCESSFUL
);
349 if (MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
351 Status
= MmProtectAnonMem(AddressSpace
, MemoryArea
, BaseAddress
,
352 NumberOfBytesToProtect
, NewAccessProtection
,
353 &OldAccessProtection
);
355 else if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
357 Status
= MmProtectSectionView(AddressSpace
, MemoryArea
, BaseAddress
,
358 NumberOfBytesToProtect
,
360 &OldAccessProtection
);
363 MmUnlockAddressSpace(AddressSpace
);
364 ObDereferenceObject(Process
);
366 MmCopyToCaller(UnsafeOldAccessProtection
, &OldAccessProtection
, sizeof(ULONG
));
367 MmCopyToCaller(UnsafeBaseAddress
, &BaseAddress
, sizeof(PVOID
));
368 MmCopyToCaller(UnsafeNumberOfBytesToProtect
, &NumberOfBytesToProtect
, sizeof(ULONG
));
376 * Called from ReadProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
378 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
381 NtReadVirtualMemory(IN HANDLE ProcessHandle
,
382 IN PVOID BaseAddress
,
384 IN ULONG NumberOfBytesToRead
,
385 OUT PULONG NumberOfBytesRead OPTIONAL
)
390 PEPROCESS Process
, CurrentProcess
;
393 DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
394 "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle
,BaseAddress
,
395 Buffer
,NumberOfBytesToRead
);
397 Status
= ObReferenceObjectByHandle(ProcessHandle
,
403 if (!NT_SUCCESS(Status
))
408 CurrentProcess
= PsGetCurrentProcess();
410 if (Process
== CurrentProcess
)
412 memcpy(Buffer
, BaseAddress
, NumberOfBytesToRead
);
416 Mdl
= MmCreateMdl(NULL
,
418 NumberOfBytesToRead
);
421 ObDereferenceObject(Process
);
422 return(STATUS_NO_MEMORY
);
424 MmProbeAndLockPages(Mdl
,
428 KeAttachProcess(Process
);
430 SystemAddress
= MmGetSystemAddressForMdl(Mdl
);
431 memcpy(SystemAddress
, BaseAddress
, NumberOfBytesToRead
);
435 if (Mdl
->MappedSystemVa
!= NULL
)
437 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
443 ObDereferenceObject(Process
);
445 if (NumberOfBytesRead
)
446 *NumberOfBytesRead
= NumberOfBytesToRead
;
447 return(STATUS_SUCCESS
);
451 * FUNCTION: THIS function doesn't make a sense...
452 * Called from VirtualUnlock (lib\kernel32\mem\virtual.c)
455 NtUnlockVirtualMemory(HANDLE ProcessHandle
,
457 ULONG NumberOfBytesToUnlock
,
458 PULONG NumberOfBytesUnlocked OPTIONAL
)
460 // AG [08-20-03] : I have *no* idea if this is correct, I just used the
461 // other functions as a template and made a few intelligent guesses...
467 DPRINT("NtUnlockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
468 "NumberOfBytesToUnlock %d), NumberOfBytesUnlocked %x\n",ProcessHandle
,BaseAddress
,
469 NumberOfBytesToUnlock
, NumberOfBytesUnlocked
);
471 Status
= ObReferenceObjectByHandle(ProcessHandle
,
477 if (!NT_SUCCESS(Status
))
482 Mdl
= MmCreateMdl(NULL
,
484 NumberOfBytesToUnlock
);
487 ObDereferenceObject(Process
);
488 return(STATUS_NO_MEMORY
);
491 ObDereferenceObject(Process
);
493 if (Mdl
->MappedSystemVa
!= NULL
)
495 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
500 *NumberOfBytesUnlocked
= NumberOfBytesToUnlock
;
502 return(STATUS_SUCCESS
);
508 * Called from WriteProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
510 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
513 NtWriteVirtualMemory(IN HANDLE ProcessHandle
,
514 IN PVOID BaseAddress
,
516 IN ULONG NumberOfBytesToWrite
,
517 OUT PULONG NumberOfBytesWritten
)
524 DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
525 "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle
,BaseAddress
,
526 Buffer
,NumberOfBytesToWrite
);
528 Status
= ObReferenceObjectByHandle(ProcessHandle
,
534 if (!NT_SUCCESS(Status
))
539 if (Process
== PsGetCurrentProcess())
541 memcpy(BaseAddress
, Buffer
, NumberOfBytesToWrite
);
545 Mdl
= MmCreateMdl(NULL
,
547 NumberOfBytesToWrite
);
548 MmProbeAndLockPages(Mdl
,
553 ObDereferenceObject(Process
);
554 return(STATUS_NO_MEMORY
);
556 KeAttachProcess(Process
);
558 SystemAddress
= MmGetSystemAddressForMdl(Mdl
);
559 memcpy(BaseAddress
, SystemAddress
, NumberOfBytesToWrite
);
563 if (Mdl
->MappedSystemVa
!= NULL
)
565 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
571 ObDereferenceObject(Process
);
573 *NumberOfBytesWritten
= NumberOfBytesToWrite
;
575 return(STATUS_SUCCESS
);
584 MmGetVirtualForPhysical (
585 IN PHYSICAL_ADDRESS PhysicalAddress
593 * Called from EngSecureMem (subsys\win32k\eng\mem.c)
597 MmSecureVirtualMemory (PVOID Address
,
601 /* Only works for user space */
602 if (MmHighestUserAddress
< Address
)
614 * Called from EngUnsecureMem (subsys\win32k\eng\mem.c)
618 MmUnsecureVirtualMemory(PVOID SecureMem
)
620 if (NULL
== SecureMem
)
633 ProbeForRead (IN PVOID Address
,
637 ASSERT(Alignment
==1 || Alignment
== 2 || Alignment
== 4 || Alignment
== 8);
642 if (((ULONG_PTR
)Address
& (Alignment
- 1)) != 0)
644 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT
);
646 else if ((ULONG_PTR
)Address
+ Length
< (ULONG_PTR
)Address
||
647 (ULONG_PTR
)Address
+ Length
> (ULONG_PTR
)MmUserProbeAddress
)
649 ExRaiseStatus (STATUS_ACCESS_VIOLATION
);
658 ProbeForWrite (IN PVOID Address
,
666 ASSERT(Alignment
==1 || Alignment
== 2 || Alignment
== 4 || Alignment
== 8);
671 if (((ULONG_PTR
)Address
& (Alignment
- 1)) != 0)
673 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT
);
675 else if ((ULONG_PTR
)Address
+ Length
< (ULONG_PTR
)Address
||
676 (ULONG_PTR
)Address
+ Length
> (ULONG_PTR
)MmUserProbeAddress
)
678 ExRaiseStatus (STATUS_ACCESS_VIOLATION
);
681 /* Check for accessible pages */
682 for (i
= 0; i
< Length
; i
+= PAGE_SIZE
)
684 Ptr
= (PULONG
)(((ULONG_PTR
)Address
& ~(PAGE_SIZE
- 1)) + i
);