3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/virtual.c
6 * PURPOSE: Implementing operations on virtual memory.
8 * PROGRAMMERS: David Welch
11 /* INCLUDE *****************************************************************/
16 #include <internal/debug.h>
18 /* FUNCTIONS *****************************************************************/
21 NtFlushVirtualMemory(IN HANDLE ProcessHandle
,
23 IN ULONG NumberOfBytesToFlush
,
24 OUT PULONG NumberOfBytesFlushed OPTIONAL
)
26 * FUNCTION: Flushes virtual memory to file
28 * ProcessHandle = Points to the process that allocated the virtual
30 * BaseAddress = Points to the memory address
31 * NumberOfBytesToFlush = Limits the range to flush,
32 * NumberOfBytesFlushed = Actual number of bytes flushed
36 /* This should be implemented once we support network filesystems */
37 DPRINT("NtFlushVirtualMemory is UNIMPLEMENTED\n");
38 return(STATUS_SUCCESS
);
43 MiLockVirtualMemory(HANDLE ProcessHandle
,
45 ULONG NumberOfBytesToLock
,
46 PULONG NumberOfBytesLocked
,
47 PObReferenceObjectByHandle pObReferenceObjectByHandle
,
48 PMmCreateMdl pMmCreateMdl
,
49 PObDereferenceObject pObDereferenceObject
,
50 PMmProbeAndLockPages pMmProbeAndLockPages
,
51 PExFreePool pExFreePool
)
57 Status
= pObReferenceObjectByHandle(ProcessHandle
,
63 if (!NT_SUCCESS(Status
))
66 Mdl
= pMmCreateMdl(NULL
,
71 pObDereferenceObject(Process
);
72 return(STATUS_NO_MEMORY
);
75 pMmProbeAndLockPages(Mdl
,
81 pObDereferenceObject(Process
);
83 *NumberOfBytesLocked
= NumberOfBytesToLock
;
84 return(STATUS_SUCCESS
);
89 NtLockVirtualMemory(HANDLE ProcessHandle
,
91 ULONG NumberOfBytesToLock
,
92 PULONG NumberOfBytesLocked
)
94 DPRINT("NtLockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
95 "NumberOfBytesToLock %d, NumberOfBytesLocked %x)\n",
101 return MiLockVirtualMemory(ProcessHandle
,
105 ObReferenceObjectByHandle
,
107 ObfDereferenceObject
,
114 MiQueryVirtualMemory (IN HANDLE ProcessHandle
,
116 IN CINT VirtualMemoryInformationClass
,
117 OUT PVOID VirtualMemoryInformation
,
119 OUT PULONG ResultLength
)
123 MEMORY_AREA
* MemoryArea
;
124 PMADDRESS_SPACE AddressSpace
;
126 if (Address
< (PVOID
)KERNEL_BASE
)
128 Status
= ObReferenceObjectByHandle(ProcessHandle
,
129 PROCESS_QUERY_INFORMATION
,
135 if (!NT_SUCCESS(Status
))
137 DPRINT("NtQueryVirtualMemory() = %x\n",Status
);
140 AddressSpace
= &Process
->AddressSpace
;
144 AddressSpace
= MmGetKernelAddressSpace();
146 MmLockAddressSpace(AddressSpace
);
147 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
148 switch(VirtualMemoryInformationClass
)
150 case MemoryBasicInformation
:
152 PMEMORY_BASIC_INFORMATION Info
=
153 (PMEMORY_BASIC_INFORMATION
)VirtualMemoryInformation
;
154 if (Length
!= sizeof(MEMORY_BASIC_INFORMATION
))
156 MmUnlockAddressSpace(AddressSpace
);
157 ObDereferenceObject(Process
);
158 return(STATUS_INFO_LENGTH_MISMATCH
);
161 if (MemoryArea
== NULL
)
164 Info
->State
= MEM_FREE
;
165 Info
->Protect
= PAGE_NOACCESS
;
166 Info
->AllocationProtect
= 0;
167 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
168 Info
->AllocationBase
= NULL
;
169 Info
->RegionSize
= MmFindGapAtAddress(AddressSpace
, Info
->BaseAddress
);
170 Status
= STATUS_SUCCESS
;
171 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
175 switch(MemoryArea
->Type
)
177 case MEMORY_AREA_VIRTUAL_MEMORY
:
178 Status
= MmQueryAnonMem(MemoryArea
, Address
, Info
,
181 case MEMORY_AREA_SECTION_VIEW
:
182 Status
= MmQuerySectionView(MemoryArea
, Address
, Info
,
185 case MEMORY_AREA_NO_ACCESS
:
187 Info
->State
= MEM_FREE
;
188 Info
->Protect
= MemoryArea
->Attributes
;
189 Info
->AllocationProtect
= MemoryArea
->Attributes
;
190 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
191 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
192 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
193 (ULONG_PTR
)MemoryArea
->StartingAddress
;
194 Status
= STATUS_SUCCESS
;
195 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
197 case MEMORY_AREA_SHARED_DATA
:
199 Info
->State
= MEM_COMMIT
;
200 Info
->Protect
= MemoryArea
->Attributes
;
201 Info
->AllocationProtect
= MemoryArea
->Attributes
;
202 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
203 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
204 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
205 (ULONG_PTR
)MemoryArea
->StartingAddress
;
206 Status
= STATUS_SUCCESS
;
207 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
209 case MEMORY_AREA_SYSTEM
:
211 Info
->State
= MEM_COMMIT
;
212 Info
->Protect
= MemoryArea
->Attributes
;
213 Info
->AllocationProtect
= MemoryArea
->Attributes
;
214 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
215 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
216 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
217 (ULONG_PTR
)MemoryArea
->StartingAddress
;
218 Status
= STATUS_SUCCESS
;
219 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
221 case MEMORY_AREA_KERNEL_STACK
:
223 Info
->State
= MEM_COMMIT
;
224 Info
->Protect
= MemoryArea
->Attributes
;
225 Info
->AllocationProtect
= MemoryArea
->Attributes
;
226 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
227 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
228 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
229 (ULONG_PTR
)MemoryArea
->StartingAddress
;
230 Status
= STATUS_SUCCESS
;
231 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
234 DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea
->Type
);
235 Status
= STATUS_UNSUCCESSFUL
;
244 Status
= STATUS_INVALID_INFO_CLASS
;
250 MmUnlockAddressSpace(AddressSpace
);
251 if (Address
< (PVOID
)KERNEL_BASE
)
253 ObDereferenceObject(Process
);
261 * Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
265 NtQueryVirtualMemory (IN HANDLE ProcessHandle
,
267 IN CINT VirtualMemoryInformationClass
,
268 OUT PVOID VirtualMemoryInformation
,
270 OUT PULONG UnsafeResultLength
)
273 ULONG ResultLength
= 0;
274 KPROCESSOR_MODE PrevMode
;
277 MEMORY_BASIC_INFORMATION BasicInfo
;
281 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
282 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
283 "Length %lu ResultLength %x)\n",ProcessHandle
,Address
,
284 VirtualMemoryInformationClass
,VirtualMemoryInformation
,
285 Length
,ResultLength
);
287 PrevMode
= ExGetPreviousMode();
289 if (Address
>= (PVOID
)KERNEL_BASE
)
291 DPRINT1("Invalid parameter\n");
292 return STATUS_INVALID_PARAMETER
;
295 Status
= MiQueryVirtualMemory ( ProcessHandle
,
297 VirtualMemoryInformationClass
,
302 if (NT_SUCCESS(Status
) && ResultLength
> 0)
304 Status
= MmCopyToCaller(VirtualMemoryInformation
, &VirtualMemoryInfo
, ResultLength
);
305 if (!NT_SUCCESS(Status
))
311 if (UnsafeResultLength
!= NULL
)
313 MmCopyToCaller(UnsafeResultLength
, &ResultLength
, sizeof(ULONG
));
320 MiProtectVirtualMemory(IN PEPROCESS Process
,
321 IN OUT PVOID
*BaseAddress
,
322 IN OUT PULONG NumberOfBytesToProtect
,
323 IN ULONG NewAccessProtection
,
324 OUT PULONG OldAccessProtection OPTIONAL
)
326 PMEMORY_AREA MemoryArea
;
327 PMADDRESS_SPACE AddressSpace
;
328 ULONG OldAccessProtection_
;
331 *NumberOfBytesToProtect
=
332 PAGE_ROUND_UP((*BaseAddress
) + (*NumberOfBytesToProtect
)) -
333 PAGE_ROUND_DOWN(*BaseAddress
);
334 *BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(*BaseAddress
);
336 AddressSpace
= &Process
->AddressSpace
;
338 MmLockAddressSpace(AddressSpace
);
339 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, *BaseAddress
);
340 if (MemoryArea
== NULL
)
342 MmUnlockAddressSpace(AddressSpace
);
343 return STATUS_UNSUCCESSFUL
;
346 if (OldAccessProtection
== NULL
)
347 OldAccessProtection
= &OldAccessProtection_
;
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
);
364 /* FIXME: Should we return failure or success in this case? */
365 Status
= STATUS_SUCCESS
;
368 MmUnlockAddressSpace(AddressSpace
);
376 * Called from VirtualProtectEx (lib\kernel32\mem\virtual.c)
380 NtProtectVirtualMemory(IN HANDLE ProcessHandle
,
381 IN OUT PVOID
*UnsafeBaseAddress
,
382 IN OUT ULONG
*UnsafeNumberOfBytesToProtect
,
383 IN ULONG NewAccessProtection
,
384 OUT PULONG UnsafeOldAccessProtection
)
388 ULONG OldAccessProtection
;
390 ULONG NumberOfBytesToProtect
;
392 Status
= MmCopyFromCaller(&BaseAddress
, UnsafeBaseAddress
, sizeof(PVOID
));
393 if (!NT_SUCCESS(Status
))
395 Status
= MmCopyFromCaller(&NumberOfBytesToProtect
, UnsafeNumberOfBytesToProtect
, sizeof(ULONG
));
396 if (!NT_SUCCESS(Status
))
399 /* (tMk 2004.II.5) in Microsoft SDK I read:
400 * 'if this parameter is NULL or does not point to a valid variable, the function fails'
402 if(UnsafeOldAccessProtection
== NULL
)
404 return(STATUS_INVALID_PARAMETER
);
407 Status
= ObReferenceObjectByHandle(ProcessHandle
,
408 PROCESS_VM_OPERATION
,
413 if (!NT_SUCCESS(Status
))
415 DPRINT("NtProtectVirtualMemory() = %x\n",Status
);
419 Status
= MiProtectVirtualMemory(Process
,
421 &NumberOfBytesToProtect
,
423 &OldAccessProtection
);
425 ObDereferenceObject(Process
);
427 MmCopyToCaller(UnsafeOldAccessProtection
, &OldAccessProtection
, sizeof(ULONG
));
428 MmCopyToCaller(UnsafeBaseAddress
, &BaseAddress
, sizeof(PVOID
));
429 MmCopyToCaller(UnsafeNumberOfBytesToProtect
, &NumberOfBytesToProtect
, sizeof(ULONG
));
437 * Called from ReadProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
439 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
442 NtReadVirtualMemory(IN HANDLE ProcessHandle
,
443 IN PVOID BaseAddress
,
445 IN ULONG NumberOfBytesToRead
,
446 OUT PULONG NumberOfBytesRead OPTIONAL
)
450 KPROCESSOR_MODE PreviousMode
;
451 PEPROCESS Process
, CurrentProcess
;
452 NTSTATUS Status
= STATUS_SUCCESS
;
456 PreviousMode
= ExGetPreviousMode();
458 if(PreviousMode
!= KernelMode
)
462 ProbeForWrite(Buffer
,
465 if(NumberOfBytesRead
!= NULL
)
467 ProbeForWrite(NumberOfBytesRead
,
474 Status
= _SEH_GetExceptionCode();
478 if(!NT_SUCCESS(Status
))
484 DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
485 "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle
,BaseAddress
,
486 Buffer
,NumberOfBytesToRead
);
488 Status
= ObReferenceObjectByHandle(ProcessHandle
,
494 if (!NT_SUCCESS(Status
))
499 CurrentProcess
= PsGetCurrentProcess();
501 if (Process
== CurrentProcess
)
505 RtlCopyMemory(Buffer
, BaseAddress
, NumberOfBytesToRead
);
509 Status
= _SEH_GetExceptionCode();
515 Mdl
= MmCreateMdl(NULL
,
517 NumberOfBytesToRead
);
520 ObDereferenceObject(Process
);
521 return(STATUS_NO_MEMORY
);
525 MmProbeAndLockPages(Mdl
,
531 Status
= _SEH_GetExceptionCode();
535 if(NT_SUCCESS(Status
))
537 KeAttachProcess(&Process
->Pcb
);
539 SystemAddress
= MmGetSystemAddressForMdl(Mdl
);
541 Status
= STATUS_SUCCESS
;
543 ProbeForRead(BaseAddress
, NumberOfBytesToRead
, 1);
544 Status
= STATUS_PARTIAL_COPY
;
545 RtlCopyMemory(SystemAddress
, BaseAddress
, NumberOfBytesToRead
);
546 Status
= STATUS_SUCCESS
;
548 if(Status
!= STATUS_PARTIAL_COPY
)
549 Status
= _SEH_GetExceptionCode();
554 if (Mdl
->MappedSystemVa
!= NULL
)
556 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
563 ObDereferenceObject(Process
);
565 if((NT_SUCCESS(Status
) || Status
== STATUS_PARTIAL_COPY
) &&
566 NumberOfBytesRead
!= NULL
)
570 *NumberOfBytesRead
= NumberOfBytesToRead
;
574 Status
= _SEH_GetExceptionCode();
583 * FUNCTION: THIS function doesn't make a sense...
584 * Called from VirtualUnlock (lib\kernel32\mem\virtual.c)
587 NtUnlockVirtualMemory(HANDLE ProcessHandle
,
589 ULONG NumberOfBytesToUnlock
,
590 PULONG NumberOfBytesUnlocked OPTIONAL
)
592 // AG [08-20-03] : I have *no* idea if this is correct, I just used the
593 // other functions as a template and made a few intelligent guesses...
599 DPRINT("NtUnlockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
600 "NumberOfBytesToUnlock %d), NumberOfBytesUnlocked %x\n",ProcessHandle
,BaseAddress
,
601 NumberOfBytesToUnlock
, NumberOfBytesUnlocked
);
603 Status
= ObReferenceObjectByHandle(ProcessHandle
,
609 if (!NT_SUCCESS(Status
))
614 Mdl
= MmCreateMdl(NULL
,
616 NumberOfBytesToUnlock
);
619 ObDereferenceObject(Process
);
620 return(STATUS_NO_MEMORY
);
623 ObDereferenceObject(Process
);
625 if (Mdl
->MappedSystemVa
!= NULL
)
627 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
632 *NumberOfBytesUnlocked
= NumberOfBytesToUnlock
;
634 return(STATUS_SUCCESS
);
640 * Called from WriteProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
642 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
645 NtWriteVirtualMemory(IN HANDLE ProcessHandle
,
646 IN PVOID BaseAddress
,
648 IN ULONG NumberOfBytesToWrite
,
649 OUT PULONG NumberOfBytesWritten OPTIONAL
)
655 ULONG OldProtection
= 0;
656 PVOID ProtectBaseAddress
;
657 ULONG ProtectNumberOfBytes
;
659 DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
660 "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle
,BaseAddress
,
661 Buffer
,NumberOfBytesToWrite
);
663 Status
= ObReferenceObjectByHandle(ProcessHandle
,
669 if (!NT_SUCCESS(Status
))
674 /* We have to make sure the target memory is writable.
676 * I am not sure if it is correct to do this in any case, but it has to be
677 * done at least in some cases because you can use WriteProcessMemory to
678 * write into the .text section of a module where memcpy() would crash.
679 * -blight (2005/01/09)
681 ProtectBaseAddress
= BaseAddress
;
682 ProtectNumberOfBytes
= NumberOfBytesToWrite
;
685 if (Process
== PsGetCurrentProcess())
687 Status
= MiProtectVirtualMemory(Process
,
689 &ProtectNumberOfBytes
,
692 if (!NT_SUCCESS(Status
))
694 ObDereferenceObject(Process
);
697 memcpy(BaseAddress
, Buffer
, NumberOfBytesToWrite
);
701 /* Create MDL describing the source buffer. */
702 Mdl
= MmCreateMdl(NULL
,
704 NumberOfBytesToWrite
);
707 ObDereferenceObject(Process
);
708 return(STATUS_NO_MEMORY
);
711 /* Make the target area writable. */
712 Status
= MiProtectVirtualMemory(Process
,
714 &ProtectNumberOfBytes
,
717 if (!NT_SUCCESS(Status
))
719 ObDereferenceObject(Process
);
725 MmProbeAndLockPages(Mdl
,
729 /* Copy memory from the mapped MDL into the target buffer. */
730 KeAttachProcess(&Process
->Pcb
);
732 SystemAddress
= MmGetSystemAddressForMdl(Mdl
);
733 memcpy(BaseAddress
, SystemAddress
, NumberOfBytesToWrite
);
738 if (Mdl
->MappedSystemVa
!= NULL
)
740 MmUnmapLockedPages(Mdl
->MappedSystemVa
, Mdl
);
746 /* Reset the protection of the target memory. */
747 Status
= MiProtectVirtualMemory(Process
,
749 &ProtectNumberOfBytes
,
752 if (!NT_SUCCESS(Status
))
754 DPRINT1("Failed to reset protection of the target memory! (Status 0x%x)\n", Status
);
755 /* FIXME: Should we bugcheck here? */
758 ObDereferenceObject(Process
);
760 if (NumberOfBytesWritten
!= NULL
)
761 MmCopyToCaller(NumberOfBytesWritten
, &NumberOfBytesToWrite
, sizeof(ULONG
));
763 return(STATUS_SUCCESS
);
772 MmGetVirtualForPhysical (
773 IN PHYSICAL_ADDRESS PhysicalAddress
781 * Called from EngSecureMem (subsys\win32k\eng\mem.c)
785 MmSecureVirtualMemory (PVOID Address
,
789 /* Only works for user space */
790 if (MmHighestUserAddress
< Address
)
802 * Called from EngUnsecureMem (subsys\win32k\eng\mem.c)
806 MmUnsecureVirtualMemory(PVOID SecureMem
)
808 if (NULL
== SecureMem
)
821 ProbeForRead (IN CONST VOID
*Address
,
825 ASSERT(Alignment
== 1 || Alignment
== 2 || Alignment
== 4 || Alignment
== 8);
830 if (((ULONG_PTR
)Address
& (Alignment
- 1)) != 0)
832 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT
);
834 else if ((ULONG_PTR
)Address
+ Length
- 1 < (ULONG_PTR
)Address
||
835 (ULONG_PTR
)Address
+ Length
- 1 > (ULONG_PTR
)MmUserProbeAddress
)
837 ExRaiseStatus (STATUS_ACCESS_VIOLATION
);
846 ProbeForWrite (IN CONST VOID
*Address
,
850 volatile CHAR
*Current
;
853 ASSERT(Alignment
== 1 || Alignment
== 2 || Alignment
== 4 || Alignment
== 8);
858 if (((ULONG_PTR
)Address
& (Alignment
- 1)) != 0)
860 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT
);
863 Last
= (PCHAR
)((ULONG_PTR
)Address
+ Length
- 1);
864 if ((ULONG_PTR
)Last
< (ULONG_PTR
)Address
||
865 (ULONG_PTR
)Last
> (ULONG_PTR
)MmUserProbeAddress
)
867 ExRaiseStatus (STATUS_ACCESS_VIOLATION
);
870 /* Check for accessible pages */
871 Current
= (CHAR
*)Address
;
875 Current
= (CHAR
*)((ULONG_PTR
)Current
+ PAGE_SIZE
);
876 } while (Current
<= Last
);