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.86 2004/12/22 05:17:44 royce 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 MiLockVirtualMemory(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 MiLockVirtualMemory(ProcessHandle
,
120 ObReferenceObjectByHandle
,
122 ObfDereferenceObject
,
129 MiQueryVirtualMemory (IN HANDLE ProcessHandle
,
131 IN CINT VirtualMemoryInformationClass
,
132 OUT PVOID VirtualMemoryInformation
,
134 OUT PULONG ResultLength
)
138 MEMORY_AREA
* MemoryArea
;
139 PMADDRESS_SPACE AddressSpace
;
141 if (Address
< (PVOID
)KERNEL_BASE
)
143 Status
= ObReferenceObjectByHandle(ProcessHandle
,
144 PROCESS_QUERY_INFORMATION
,
150 if (!NT_SUCCESS(Status
))
152 DPRINT("NtQueryVirtualMemory() = %x\n",Status
);
155 AddressSpace
= &Process
->AddressSpace
;
159 AddressSpace
= MmGetKernelAddressSpace();
161 MmLockAddressSpace(AddressSpace
);
162 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
164 switch(VirtualMemoryInformationClass
)
166 case MemoryBasicInformation
:
168 PMEMORY_BASIC_INFORMATION Info
=
169 (PMEMORY_BASIC_INFORMATION
)VirtualMemoryInformation
;
170 if (Length
!= sizeof(MEMORY_BASIC_INFORMATION
))
172 MmUnlockAddressSpace(AddressSpace
);
173 ObDereferenceObject(Process
);
174 return(STATUS_INFO_LENGTH_MISMATCH
);
177 if (MemoryArea
== NULL
)
180 Info
->State
= MEM_FREE
;
181 Info
->Protect
= PAGE_NOACCESS
;
182 Info
->AllocationProtect
= 0;
183 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
184 Info
->AllocationBase
= NULL
;
185 Info
->RegionSize
= MmFindGapAtAddress(AddressSpace
, Info
->BaseAddress
);
186 Status
= STATUS_SUCCESS
;
187 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
191 switch(MemoryArea
->Type
)
193 case MEMORY_AREA_VIRTUAL_MEMORY
:
194 Status
= MmQueryAnonMem(MemoryArea
, Address
, Info
,
197 case MEMORY_AREA_SECTION_VIEW
:
198 Status
= MmQuerySectionView(MemoryArea
, Address
, Info
,
201 case MEMORY_AREA_NO_ACCESS
:
203 Info
->State
= MEM_FREE
;
204 Info
->Protect
= MemoryArea
->Attributes
;
205 Info
->AllocationProtect
= MemoryArea
->Attributes
;
206 Info
->BaseAddress
= MemoryArea
->BaseAddress
;
207 Info
->AllocationBase
= MemoryArea
->BaseAddress
;
208 Info
->RegionSize
= MemoryArea
->Length
;
209 Status
= STATUS_SUCCESS
;
210 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
212 case MEMORY_AREA_SHARED_DATA
:
214 Info
->State
= MEM_COMMIT
;
215 Info
->Protect
= MemoryArea
->Attributes
;
216 Info
->AllocationProtect
= MemoryArea
->Attributes
;
217 Info
->BaseAddress
= MemoryArea
->BaseAddress
;
218 Info
->AllocationBase
= MemoryArea
->BaseAddress
;
219 Info
->RegionSize
= MemoryArea
->Length
;
220 Status
= STATUS_SUCCESS
;
221 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
223 case MEMORY_AREA_SYSTEM
:
225 static int warned
= 0;
228 DPRINT1("FIXME: MEMORY_AREA_SYSTEM case incomplete (or possibly wrong) for NtQueryVirtualMemory()\n");
232 /* FIXME - don't have a clue if this is right, but it's better than nothing */
234 Info
->State
= MEM_COMMIT
;
235 Info
->Protect
= MemoryArea
->Attributes
;
236 Info
->AllocationProtect
= MemoryArea
->Attributes
;
237 Info
->BaseAddress
= MemoryArea
->BaseAddress
;
238 Info
->AllocationBase
= MemoryArea
->BaseAddress
;
239 Info
->RegionSize
= MemoryArea
->Length
;
240 Status
= STATUS_SUCCESS
;
241 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
243 case MEMORY_AREA_KERNEL_STACK
:
245 static int warned
= 0;
248 DPRINT1("FIXME: MEMORY_AREA_KERNEL_STACK case incomplete (or possibly wrong) for NtQueryVirtualMemory()\n");
252 /* FIXME - don't have a clue if this is right, but it's better than nothing */
254 Info
->State
= MEM_COMMIT
;
255 Info
->Protect
= MemoryArea
->Attributes
;
256 Info
->AllocationProtect
= MemoryArea
->Attributes
;
257 Info
->BaseAddress
= MemoryArea
->BaseAddress
;
258 Info
->AllocationBase
= MemoryArea
->BaseAddress
;
259 Info
->RegionSize
= MemoryArea
->Length
;
260 Status
= STATUS_SUCCESS
;
261 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
264 DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea
->Type
);
265 Status
= STATUS_UNSUCCESSFUL
;
274 Status
= STATUS_INVALID_INFO_CLASS
;
280 MmUnlockAddressSpace(AddressSpace
);
281 if (Address
< (PVOID
)KERNEL_BASE
)
283 ObDereferenceObject(Process
);
291 * Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
295 NtQueryVirtualMemory (IN HANDLE ProcessHandle
,
297 IN CINT VirtualMemoryInformationClass
,
298 OUT PVOID VirtualMemoryInformation
,
300 OUT PULONG UnsafeResultLength
)
303 ULONG ResultLength
= 0;
304 KPROCESSOR_MODE PrevMode
;
307 MEMORY_BASIC_INFORMATION BasicInfo
;
311 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
312 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
313 "Length %lu ResultLength %x)\n",ProcessHandle
,Address
,
314 VirtualMemoryInformationClass
,VirtualMemoryInformation
,
315 Length
,ResultLength
);
317 PrevMode
= ExGetPreviousMode();
319 if (PrevMode
== UserMode
&& Address
>= (PVOID
)KERNEL_BASE
)
321 DPRINT1("Invalid parameter\n");
322 return STATUS_INVALID_PARAMETER
;
325 Status
= MiQueryVirtualMemory ( ProcessHandle
,
327 VirtualMemoryInformationClass
,
332 if (NT_SUCCESS(Status
) && ResultLength
> 0)
334 Status
= MmCopyToCaller(VirtualMemoryInformation
, &VirtualMemoryInfo
, ResultLength
);
335 if (!NT_SUCCESS(Status
))
341 if (UnsafeResultLength
!= NULL
)
343 MmCopyToCaller(UnsafeResultLength
, &ResultLength
, sizeof(ULONG
));
351 * Called from VirtualProtectEx (lib\kernel32\mem\virtual.c)
355 NtProtectVirtualMemory(IN HANDLE ProcessHandle
,
356 IN PVOID
*UnsafeBaseAddress
,
357 IN ULONG
*UnsafeNumberOfBytesToProtect
,
358 IN ULONG NewAccessProtection
,
359 OUT PULONG UnsafeOldAccessProtection
)
361 PMEMORY_AREA MemoryArea
;
364 PMADDRESS_SPACE AddressSpace
;
365 ULONG OldAccessProtection
;
367 ULONG NumberOfBytesToProtect
;
369 Status
= MmCopyFromCaller(&BaseAddress
, UnsafeBaseAddress
, sizeof(PVOID
));
370 if (!NT_SUCCESS(Status
))
372 Status
= MmCopyFromCaller(&NumberOfBytesToProtect
, UnsafeNumberOfBytesToProtect
, sizeof(ULONG
));
373 if (!NT_SUCCESS(Status
))
376 // (tMk 2004.II.5) in Microsoft SDK I read:
377 // 'if this parameter is NULL or does not point to a valid variable, the function fails'
378 if(UnsafeOldAccessProtection
== NULL
)
380 return(STATUS_INVALID_PARAMETER
);
383 NumberOfBytesToProtect
=
384 PAGE_ROUND_UP(BaseAddress
+ NumberOfBytesToProtect
) -
385 PAGE_ROUND_DOWN(BaseAddress
);
386 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(BaseAddress
);
388 Status
= ObReferenceObjectByHandle(ProcessHandle
,
389 PROCESS_VM_OPERATION
,
394 if (!NT_SUCCESS(Status
))
396 DPRINT("NtProtectVirtualMemory() = %x\n",Status
);
400 AddressSpace
= &Process
->AddressSpace
;
402 MmLockAddressSpace(AddressSpace
);
403 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
405 if (MemoryArea
== NULL
)
407 MmUnlockAddressSpace(AddressSpace
);
408 ObDereferenceObject(Process
);
409 return(STATUS_UNSUCCESSFUL
);
412 if (MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
414 Status
= MmProtectAnonMem(AddressSpace
, MemoryArea
, BaseAddress
,
415 NumberOfBytesToProtect
, NewAccessProtection
,
416 &OldAccessProtection
);
418 else if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
420 Status
= MmProtectSectionView(AddressSpace
, MemoryArea
, BaseAddress
,
421 NumberOfBytesToProtect
,
423 &OldAccessProtection
);
426 MmUnlockAddressSpace(AddressSpace
);
427 ObDereferenceObject(Process
);
429 MmCopyToCaller(UnsafeOldAccessProtection
, &OldAccessProtection
, sizeof(ULONG
));
430 MmCopyToCaller(UnsafeBaseAddress
, &BaseAddress
, sizeof(PVOID
));
431 MmCopyToCaller(UnsafeNumberOfBytesToProtect
, &NumberOfBytesToProtect
, sizeof(ULONG
));
439 * Called from ReadProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
441 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
444 NtReadVirtualMemory(IN HANDLE ProcessHandle
,
445 IN PVOID BaseAddress
,
447 IN ULONG NumberOfBytesToRead
,
448 OUT PULONG NumberOfBytesRead OPTIONAL
)
453 PEPROCESS Process
, CurrentProcess
;
456 DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
457 "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle
,BaseAddress
,
458 Buffer
,NumberOfBytesToRead
);
460 Status
= ObReferenceObjectByHandle(ProcessHandle
,
466 if (!NT_SUCCESS(Status
))
471 CurrentProcess
= PsGetCurrentProcess();
473 if (Process
== CurrentProcess
)
475 memcpy(Buffer
, BaseAddress
, NumberOfBytesToRead
);
479 Mdl
= MmCreateMdl(NULL
,
481 NumberOfBytesToRead
);
484 ObDereferenceObject(Process
);
485 return(STATUS_NO_MEMORY
);
487 MmProbeAndLockPages(Mdl
,
491 KeAttachProcess(&Process
->Pcb
);
493 SystemAddress
= MmGetSystemAddressForMdl(Mdl
);
494 memcpy(SystemAddress
, BaseAddress
, NumberOfBytesToRead
);
498 if (Mdl
->MappedSystemVa
!= NULL
)
500 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
506 ObDereferenceObject(Process
);
508 if (NumberOfBytesRead
)
509 *NumberOfBytesRead
= NumberOfBytesToRead
;
510 return(STATUS_SUCCESS
);
514 * FUNCTION: THIS function doesn't make a sense...
515 * Called from VirtualUnlock (lib\kernel32\mem\virtual.c)
518 NtUnlockVirtualMemory(HANDLE ProcessHandle
,
520 ULONG NumberOfBytesToUnlock
,
521 PULONG NumberOfBytesUnlocked OPTIONAL
)
523 // AG [08-20-03] : I have *no* idea if this is correct, I just used the
524 // other functions as a template and made a few intelligent guesses...
530 DPRINT("NtUnlockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
531 "NumberOfBytesToUnlock %d), NumberOfBytesUnlocked %x\n",ProcessHandle
,BaseAddress
,
532 NumberOfBytesToUnlock
, NumberOfBytesUnlocked
);
534 Status
= ObReferenceObjectByHandle(ProcessHandle
,
540 if (!NT_SUCCESS(Status
))
545 Mdl
= MmCreateMdl(NULL
,
547 NumberOfBytesToUnlock
);
550 ObDereferenceObject(Process
);
551 return(STATUS_NO_MEMORY
);
554 ObDereferenceObject(Process
);
556 if (Mdl
->MappedSystemVa
!= NULL
)
558 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
563 *NumberOfBytesUnlocked
= NumberOfBytesToUnlock
;
565 return(STATUS_SUCCESS
);
571 * Called from WriteProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
573 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
576 NtWriteVirtualMemory(IN HANDLE ProcessHandle
,
577 IN PVOID BaseAddress
,
579 IN ULONG NumberOfBytesToWrite
,
580 OUT PULONG NumberOfBytesWritten
)
587 DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
588 "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle
,BaseAddress
,
589 Buffer
,NumberOfBytesToWrite
);
591 Status
= ObReferenceObjectByHandle(ProcessHandle
,
597 if (!NT_SUCCESS(Status
))
602 if (Process
== PsGetCurrentProcess())
604 memcpy(BaseAddress
, Buffer
, NumberOfBytesToWrite
);
608 Mdl
= MmCreateMdl(NULL
,
610 NumberOfBytesToWrite
);
611 MmProbeAndLockPages(Mdl
,
616 ObDereferenceObject(Process
);
617 return(STATUS_NO_MEMORY
);
619 KeAttachProcess(&Process
->Pcb
);
621 SystemAddress
= MmGetSystemAddressForMdl(Mdl
);
622 memcpy(BaseAddress
, SystemAddress
, NumberOfBytesToWrite
);
626 if (Mdl
->MappedSystemVa
!= NULL
)
628 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
634 ObDereferenceObject(Process
);
636 *NumberOfBytesWritten
= NumberOfBytesToWrite
;
638 return(STATUS_SUCCESS
);
647 MmGetVirtualForPhysical (
648 IN PHYSICAL_ADDRESS PhysicalAddress
656 * Called from EngSecureMem (subsys\win32k\eng\mem.c)
660 MmSecureVirtualMemory (PVOID Address
,
664 /* Only works for user space */
665 if (MmHighestUserAddress
< Address
)
677 * Called from EngUnsecureMem (subsys\win32k\eng\mem.c)
681 MmUnsecureVirtualMemory(PVOID SecureMem
)
683 if (NULL
== SecureMem
)
696 ProbeForRead (IN PVOID Address
,
700 ASSERT(Alignment
==1 || Alignment
== 2 || Alignment
== 4 || Alignment
== 8);
705 if (((ULONG_PTR
)Address
& (Alignment
- 1)) != 0)
707 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT
);
709 else if ((ULONG_PTR
)Address
+ Length
< (ULONG_PTR
)Address
||
710 (ULONG_PTR
)Address
+ Length
> (ULONG_PTR
)MmUserProbeAddress
)
712 ExRaiseStatus (STATUS_ACCESS_VIOLATION
);
721 ProbeForWrite (IN PVOID Address
,
729 ASSERT(Alignment
==1 || Alignment
== 2 || Alignment
== 4 || Alignment
== 8);
734 if (((ULONG_PTR
)Address
& (Alignment
- 1)) != 0)
736 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT
);
738 else if ((ULONG_PTR
)Address
+ Length
< (ULONG_PTR
)Address
||
739 (ULONG_PTR
)Address
+ Length
> (ULONG_PTR
)MmUserProbeAddress
)
741 ExRaiseStatus (STATUS_ACCESS_VIOLATION
);
744 /* Check for accessible pages */
745 for (i
= 0; i
< Length
; i
+= PAGE_SIZE
)
747 Ptr
= (PULONG
)(((ULONG_PTR
)Address
& ~(PAGE_SIZE
- 1)) + i
);