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.80 2004/08/31 20:17:18 hbirr Exp $
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/virtual.c
23 * PURPOSE: Implementing operations on virtual memory.
24 * PROGRAMMER: David Welch
27 /* INCLUDE *****************************************************************/
29 #include <ddk/ntddk.h>
30 #include <internal/mm.h>
31 #include <internal/ob.h>
32 #include <internal/io.h>
33 #include <internal/ps.h>
34 #include <internal/pool.h>
35 #include <internal/safe.h>
38 #include <internal/debug.h>
40 /* FUNCTIONS *****************************************************************/
43 NtFlushVirtualMemory(IN HANDLE ProcessHandle
,
45 IN ULONG NumberOfBytesToFlush
,
46 OUT PULONG NumberOfBytesFlushed OPTIONAL
)
48 * FUNCTION: Flushes virtual memory to file
50 * ProcessHandle = Points to the process that allocated the virtual
52 * BaseAddress = Points to the memory address
53 * NumberOfBytesToFlush = Limits the range to flush,
54 * NumberOfBytesFlushed = Actual number of bytes flushed
59 return(STATUS_NOT_IMPLEMENTED
);
63 * FUNCTION: Locks range of process virtual memory.
64 * Called from VirtualLock (lib\kernel32\mem\virtual.c)
66 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
69 NtLockVirtualMemory(HANDLE ProcessHandle
,
71 ULONG NumberOfBytesToLock
,
72 PULONG NumberOfBytesLocked
) // ULONG LockOption?
74 // AG [08-20-03] : I have *no* idea if this is correct, I just used the
75 // other functions as a template and made a few intelligent guesses...
81 DPRINT("NtLockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
82 "NumberOfBytesToLock %d), NumberOfBytesLocked %x\n",ProcessHandle
,BaseAddress
,
83 NumberOfBytesToLock
, NumberOfBytesLocked
);
85 Status
= ObReferenceObjectByHandle(ProcessHandle
,
91 if (!NT_SUCCESS(Status
))
96 Mdl
= MmCreateMdl(NULL
,
101 ObDereferenceObject(Process
);
102 return(STATUS_NO_MEMORY
);
104 MmProbeAndLockPages(Mdl
,
108 ExFreePool(Mdl
); // Are we supposed to do this here?
110 ObDereferenceObject(Process
);
112 *NumberOfBytesLocked
= NumberOfBytesToLock
;
113 return(STATUS_SUCCESS
);
119 * Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
123 NtQueryVirtualMemory (IN HANDLE ProcessHandle
,
125 IN CINT VirtualMemoryInformationClass
,
126 OUT PVOID VirtualMemoryInformation
,
128 OUT PULONG UnsafeResultLength
)
132 MEMORY_AREA
* MemoryArea
;
133 ULONG ResultLength
= 0;
134 PMADDRESS_SPACE AddressSpace
;
135 KPROCESSOR_MODE PrevMode
;
138 MEMORY_BASIC_INFORMATION BasicInfo
;
142 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
143 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
144 "Length %lu ResultLength %x)\n",ProcessHandle
,Address
,
145 VirtualMemoryInformationClass
,VirtualMemoryInformation
,
146 Length
,ResultLength
);
148 PrevMode
= ExGetPreviousMode();
150 if (PrevMode
== UserMode
&& Address
>= (PVOID
)KERNEL_BASE
)
152 return STATUS_INVALID_PARAMETER
;
155 if (Address
< (PVOID
)KERNEL_BASE
)
157 Status
= ObReferenceObjectByHandle(ProcessHandle
,
158 PROCESS_QUERY_INFORMATION
,
164 if (!NT_SUCCESS(Status
))
166 DPRINT("NtQueryVirtualMemory() = %x\n",Status
);
169 AddressSpace
= &Process
->AddressSpace
;
173 AddressSpace
= MmGetKernelAddressSpace();
175 MmLockAddressSpace(AddressSpace
);
176 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
178 switch(VirtualMemoryInformationClass
)
180 case MemoryBasicInformation
:
182 PMEMORY_BASIC_INFORMATION Info
= &VirtualMemoryInfo
.BasicInfo
;
183 if (Length
!= sizeof(MEMORY_BASIC_INFORMATION
))
185 MmUnlockAddressSpace(AddressSpace
);
186 ObDereferenceObject(Process
);
187 return(STATUS_INFO_LENGTH_MISMATCH
);
190 if (MemoryArea
== NULL
)
193 Info
->State
= MEM_FREE
;
194 Info
->Protect
= PAGE_NOACCESS
;
195 Info
->AllocationProtect
= 0;
196 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
197 Info
->AllocationBase
= NULL
;
198 Info
->RegionSize
= MmFindGapAtAddress(AddressSpace
, Info
->BaseAddress
);
199 Status
= STATUS_SUCCESS
;
200 ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
204 switch(MemoryArea
->Type
)
206 case MEMORY_AREA_VIRTUAL_MEMORY
:
207 Status
= MmQueryAnonMem(MemoryArea
, Address
, Info
,
210 case MEMORY_AREA_SECTION_VIEW
:
211 Status
= MmQuerySectionView(MemoryArea
, Address
, Info
,
214 case MEMORY_AREA_NO_ACCESS
:
216 Info
->State
= MEM_FREE
;
217 Info
->Protect
= MemoryArea
->Attributes
;
218 Info
->AllocationProtect
= MemoryArea
->Attributes
;
219 Info
->BaseAddress
= MemoryArea
->BaseAddress
;
220 Info
->AllocationBase
= MemoryArea
->BaseAddress
;
221 Info
->RegionSize
= MemoryArea
->Length
;
222 Status
= STATUS_SUCCESS
;
223 ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
225 case MEMORY_AREA_SHARED_DATA
:
227 Info
->State
= MEM_COMMIT
;
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
);
237 Status
= STATUS_UNSUCCESSFUL
;
246 Status
= STATUS_INVALID_INFO_CLASS
;
252 MmUnlockAddressSpace(AddressSpace
);
253 if (Address
< (PVOID
)KERNEL_BASE
)
255 ObDereferenceObject(Process
);
258 if (NT_SUCCESS(Status
) && ResultLength
> 0)
260 Status
= MmCopyToCaller(VirtualMemoryInformation
, &VirtualMemoryInfo
, ResultLength
);
261 if (!NT_SUCCESS(Status
))
267 if (UnsafeResultLength
!= NULL
)
269 MmCopyToCaller(UnsafeResultLength
, &ResultLength
, sizeof(ULONG
));
277 * Called from VirtualProtectEx (lib\kernel32\mem\virtual.c)
281 NtProtectVirtualMemory(IN HANDLE ProcessHandle
,
282 IN PVOID
*UnsafeBaseAddress
,
283 IN ULONG
*UnsafeNumberOfBytesToProtect
,
284 IN ULONG NewAccessProtection
,
285 OUT PULONG UnsafeOldAccessProtection
)
287 PMEMORY_AREA MemoryArea
;
290 PMADDRESS_SPACE AddressSpace
;
291 ULONG OldAccessProtection
;
293 ULONG NumberOfBytesToProtect
;
295 Status
= MmCopyFromCaller(&BaseAddress
, UnsafeBaseAddress
, sizeof(PVOID
));
296 if (!NT_SUCCESS(Status
))
298 Status
= MmCopyFromCaller(&NumberOfBytesToProtect
, UnsafeNumberOfBytesToProtect
, sizeof(ULONG
));
299 if (!NT_SUCCESS(Status
))
302 // (tMk 2004.II.5) in Microsoft SDK I read:
303 // 'if this parameter is NULL or does not point to a valid variable, the function fails'
304 if(UnsafeOldAccessProtection
== NULL
)
306 return(STATUS_INVALID_PARAMETER
);
309 NumberOfBytesToProtect
=
310 PAGE_ROUND_UP(BaseAddress
+ NumberOfBytesToProtect
) -
311 PAGE_ROUND_DOWN(BaseAddress
);
312 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(BaseAddress
);
314 Status
= ObReferenceObjectByHandle(ProcessHandle
,
315 PROCESS_VM_OPERATION
,
320 if (!NT_SUCCESS(Status
))
322 DPRINT("NtProtectVirtualMemory() = %x\n",Status
);
326 AddressSpace
= &Process
->AddressSpace
;
328 MmLockAddressSpace(AddressSpace
);
329 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
331 if (MemoryArea
== NULL
)
333 MmUnlockAddressSpace(AddressSpace
);
334 ObDereferenceObject(Process
);
335 return(STATUS_UNSUCCESSFUL
);
338 if (MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
340 Status
= MmProtectAnonMem(AddressSpace
, MemoryArea
, BaseAddress
,
341 NumberOfBytesToProtect
, NewAccessProtection
,
342 &OldAccessProtection
);
344 else if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
346 Status
= MmProtectSectionView(AddressSpace
, MemoryArea
, BaseAddress
,
347 NumberOfBytesToProtect
,
349 &OldAccessProtection
);
352 MmUnlockAddressSpace(AddressSpace
);
353 ObDereferenceObject(Process
);
355 MmCopyToCaller(UnsafeOldAccessProtection
, &OldAccessProtection
, sizeof(ULONG
));
356 MmCopyToCaller(UnsafeBaseAddress
, &BaseAddress
, sizeof(PVOID
));
357 MmCopyToCaller(UnsafeNumberOfBytesToProtect
, &NumberOfBytesToProtect
, sizeof(ULONG
));
365 * Called from ReadProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
367 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
370 NtReadVirtualMemory(IN HANDLE ProcessHandle
,
371 IN PVOID BaseAddress
,
373 IN ULONG NumberOfBytesToRead
,
374 OUT PULONG NumberOfBytesRead OPTIONAL
)
379 PEPROCESS Process
, CurrentProcess
;
382 DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
383 "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle
,BaseAddress
,
384 Buffer
,NumberOfBytesToRead
);
386 Status
= ObReferenceObjectByHandle(ProcessHandle
,
392 if (!NT_SUCCESS(Status
))
397 CurrentProcess
= PsGetCurrentProcess();
399 if (Process
== CurrentProcess
)
401 memcpy(Buffer
, BaseAddress
, NumberOfBytesToRead
);
405 Mdl
= MmCreateMdl(NULL
,
407 NumberOfBytesToRead
);
410 ObDereferenceObject(Process
);
411 return(STATUS_NO_MEMORY
);
413 MmProbeAndLockPages(Mdl
,
417 KeAttachProcess(Process
);
419 SystemAddress
= MmGetSystemAddressForMdl(Mdl
);
420 memcpy(SystemAddress
, BaseAddress
, NumberOfBytesToRead
);
424 if (Mdl
->MappedSystemVa
!= NULL
)
426 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
432 ObDereferenceObject(Process
);
434 if (NumberOfBytesRead
)
435 *NumberOfBytesRead
= NumberOfBytesToRead
;
436 return(STATUS_SUCCESS
);
440 * FUNCTION: THIS function doesn't make a sense...
441 * Called from VirtualUnlock (lib\kernel32\mem\virtual.c)
444 NtUnlockVirtualMemory(HANDLE ProcessHandle
,
446 ULONG NumberOfBytesToUnlock
,
447 PULONG NumberOfBytesUnlocked OPTIONAL
)
449 // AG [08-20-03] : I have *no* idea if this is correct, I just used the
450 // other functions as a template and made a few intelligent guesses...
456 DPRINT("NtUnlockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
457 "NumberOfBytesToUnlock %d), NumberOfBytesUnlocked %x\n",ProcessHandle
,BaseAddress
,
458 NumberOfBytesToUnlock
, NumberOfBytesUnlocked
);
460 Status
= ObReferenceObjectByHandle(ProcessHandle
,
466 if (!NT_SUCCESS(Status
))
471 Mdl
= MmCreateMdl(NULL
,
473 NumberOfBytesToUnlock
);
476 ObDereferenceObject(Process
);
477 return(STATUS_NO_MEMORY
);
480 ObDereferenceObject(Process
);
482 if (Mdl
->MappedSystemVa
!= NULL
)
484 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
489 *NumberOfBytesUnlocked
= NumberOfBytesToUnlock
;
491 return(STATUS_SUCCESS
);
497 * Called from WriteProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
499 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
502 NtWriteVirtualMemory(IN HANDLE ProcessHandle
,
503 IN PVOID BaseAddress
,
505 IN ULONG NumberOfBytesToWrite
,
506 OUT PULONG NumberOfBytesWritten
)
513 DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
514 "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle
,BaseAddress
,
515 Buffer
,NumberOfBytesToWrite
);
517 Status
= ObReferenceObjectByHandle(ProcessHandle
,
523 if (!NT_SUCCESS(Status
))
528 if (Process
== PsGetCurrentProcess())
530 memcpy(BaseAddress
, Buffer
, NumberOfBytesToWrite
);
534 Mdl
= MmCreateMdl(NULL
,
536 NumberOfBytesToWrite
);
537 MmProbeAndLockPages(Mdl
,
542 ObDereferenceObject(Process
);
543 return(STATUS_NO_MEMORY
);
545 KeAttachProcess(Process
);
547 SystemAddress
= MmGetSystemAddressForMdl(Mdl
);
548 memcpy(BaseAddress
, SystemAddress
, NumberOfBytesToWrite
);
552 if (Mdl
->MappedSystemVa
!= NULL
)
554 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
560 ObDereferenceObject(Process
);
562 *NumberOfBytesWritten
= NumberOfBytesToWrite
;
564 return(STATUS_SUCCESS
);
573 MmGetVirtualForPhysical (
574 IN PHYSICAL_ADDRESS PhysicalAddress
582 * Called from EngSecureMem (subsys\win32k\eng\mem.c)
586 MmSecureVirtualMemory (PVOID Address
,
590 /* Only works for user space */
591 if (MmHighestUserAddress
< Address
)
603 * Called from EngUnsecureMem (subsys\win32k\eng\mem.c)
607 MmUnsecureVirtualMemory(PVOID SecureMem
)
609 if (NULL
== SecureMem
)
622 ProbeForRead (IN PVOID Address
,
626 assert (Alignment
==1 || Alignment
== 2 || Alignment
== 4 || Alignment
== 8);
631 if (((ULONG_PTR
)Address
& (Alignment
- 1)) != 0)
633 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT
);
635 else if ((ULONG_PTR
)Address
+ Length
< (ULONG_PTR
)Address
||
636 (ULONG_PTR
)Address
+ Length
> (ULONG_PTR
)MmUserProbeAddress
)
638 ExRaiseStatus (STATUS_ACCESS_VIOLATION
);
647 ProbeForWrite (IN PVOID Address
,
655 assert (Alignment
==1 || Alignment
== 2 || Alignment
== 4 || Alignment
== 8);
660 if (((ULONG_PTR
)Address
& (Alignment
- 1)) != 0)
662 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT
);
664 else if ((ULONG_PTR
)Address
+ Length
< (ULONG_PTR
)Address
||
665 (ULONG_PTR
)Address
+ Length
> (ULONG_PTR
)MmUserProbeAddress
)
667 ExRaiseStatus (STATUS_ACCESS_VIOLATION
);
670 /* Check for accessible pages */
671 for (i
= 0; i
< Length
; i
+= PAGE_SIZE
)
673 Ptr
= (PULONG
)(((ULONG_PTR
)Address
& ~(PAGE_SIZE
- 1)) + i
);