2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/virtual.c
5 * PURPOSE: Implementing operations on virtual memory.
7 * PROGRAMMERS: David Welch
10 /* INCLUDE ********************************************************************/
16 #define MI_MAPPED_COPY_PAGES 16
17 #define MI_POOL_COPY_BYTES 512
18 #define MI_MAX_TRANSFER_SIZE 64 * 1024
19 #define TAG_VM TAG('V', 'm', 'R', 'w')
21 /* PRIVATE FUNCTIONS **********************************************************/
24 MiGetExceptionInfo(EXCEPTION_POINTERS
*ExceptionInfo
, BOOLEAN
* HaveBadAddress
, ULONG_PTR
* BadAddress
)
26 PEXCEPTION_RECORD ExceptionRecord
;
30 *HaveBadAddress
= FALSE
;
32 /* Get the exception record */
33 ExceptionRecord
= ExceptionInfo
->ExceptionRecord
;
35 /* Look at the exception code */
36 if ((ExceptionRecord
->ExceptionCode
== STATUS_ACCESS_VIOLATION
) ||
37 (ExceptionRecord
->ExceptionCode
== STATUS_GUARD_PAGE_VIOLATION
) ||
38 (ExceptionRecord
->ExceptionCode
== STATUS_IN_PAGE_ERROR
))
40 /* We can tell the address if we have more than one parameter */
41 if (ExceptionRecord
->NumberParameters
> 1)
43 /* Return the address */
44 *HaveBadAddress
= TRUE
;
45 *BadAddress
= ExceptionRecord
->ExceptionInformation
[1];
49 /* Continue executing the next handler */
50 return EXCEPTION_EXECUTE_HANDLER
;
55 MiDoMappedCopy(IN PEPROCESS SourceProcess
,
56 IN PVOID SourceAddress
,
57 IN PEPROCESS TargetProcess
,
58 OUT PVOID TargetAddress
,
60 IN KPROCESSOR_MODE PreviousMode
,
61 OUT PSIZE_T ReturnSize
)
63 PFN_NUMBER MdlBuffer
[(sizeof(MDL
) / sizeof(PFN_NUMBER
)) + MI_MAPPED_COPY_PAGES
+ 1];
64 PMDL Mdl
= (PMDL
)MdlBuffer
;
65 SIZE_T TotalSize
, CurrentSize
, RemainingSize
;
66 volatile BOOLEAN FailedInProbe
= FALSE
, FailedInMapping
= FALSE
, FailedInMoving
;
67 volatile BOOLEAN PagesLocked
;
68 PVOID CurrentAddress
= SourceAddress
, CurrentTargetAddress
= TargetAddress
;
69 volatile PVOID MdlAddress
;
71 BOOLEAN HaveBadAddress
;
73 NTSTATUS Status
= STATUS_SUCCESS
;
76 /* Calculate the maximum amount of data to move */
77 TotalSize
= (MI_MAPPED_COPY_PAGES
- 2) * PAGE_SIZE
;
78 if (BufferSize
<= TotalSize
) TotalSize
= BufferSize
;
79 CurrentSize
= TotalSize
;
80 RemainingSize
= BufferSize
;
82 /* Loop as long as there is still data */
83 while (RemainingSize
> 0)
85 /* Check if this transfer will finish everything off */
86 if (RemainingSize
< CurrentSize
) CurrentSize
= RemainingSize
;
88 /* Attach to the source address space */
89 KeStackAttachProcess(&SourceProcess
->Pcb
, &ApcState
);
91 /* Reset state for this pass */
94 FailedInMoving
= FALSE
;
95 ASSERT(FailedInProbe
== FALSE
);
97 /* Protect user-mode copy */
100 /* If this is our first time, probe the buffer */
101 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
103 /* Catch a failure here */
104 FailedInProbe
= TRUE
;
107 ProbeForRead(SourceAddress
, BufferSize
, sizeof(CHAR
));
110 FailedInProbe
= FALSE
;
113 /* Initialize and probe and lock the MDL */
114 MmInitializeMdl (Mdl
, CurrentAddress
, CurrentSize
);
115 MmProbeAndLockPages (Mdl
, PreviousMode
, IoReadAccess
);
118 /* Now map the pages */
119 MdlAddress
= MmMapLockedPagesSpecifyCache(Mdl
,
127 /* Use our SEH handler to pick this up */
128 FailedInMapping
= TRUE
;
129 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
132 /* Now let go of the source and grab to the target process */
133 KeUnstackDetachProcess(&ApcState
);
134 KeStackAttachProcess(&TargetProcess
->Pcb
, &ApcState
);
136 /* Check if this is our first time through */
137 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
139 /* Catch a failure here */
140 FailedInProbe
= TRUE
;
143 ProbeForWrite(TargetAddress
, BufferSize
, sizeof(CHAR
));
146 FailedInProbe
= FALSE
;
149 /* Now do the actual move */
150 FailedInMoving
= TRUE
;
151 RtlCopyMemory(CurrentTargetAddress
, MdlAddress
, CurrentSize
);
153 _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(), &HaveBadAddress
, &BadAddress
))
155 /* Detach from whoever we may be attached to */
156 KeUnstackDetachProcess(&ApcState
);
158 /* Check if we had mapped the pages */
159 if (MdlAddress
) MmUnmapLockedPages(MdlAddress
, Mdl
);
161 /* Check if we had locked the pages */
162 if (PagesLocked
) MmUnlockPages(Mdl
);
164 /* Check if we failed during the probe or mapping */
165 if ((FailedInProbe
) || (FailedInMapping
))
168 Status
= _SEH2_GetExceptionCode();
169 _SEH2_YIELD(return Status
);
172 /* Otherwise, we failed probably during the move */
173 *ReturnSize
= BufferSize
- RemainingSize
;
176 /* Check if we know exactly where we stopped copying */
179 /* Return the exact number of bytes copied */
180 *ReturnSize
= BadAddress
- (ULONG_PTR
)SourceAddress
;
184 /* Return partial copy */
185 Status
= STATUS_PARTIAL_COPY
;
189 /* Check for SEH status */
190 if (Status
!= STATUS_SUCCESS
) return Status
;
192 /* Detach from target */
193 KeUnstackDetachProcess(&ApcState
);
195 /* Unmap and unlock */
196 MmUnmapLockedPages(MdlAddress
, Mdl
);
199 /* Update location and size */
200 RemainingSize
-= CurrentSize
;
201 CurrentAddress
= (PVOID
)((ULONG_PTR
)CurrentAddress
+ CurrentSize
);
202 CurrentTargetAddress
= (PVOID
)((ULONG_PTR
)CurrentTargetAddress
+ CurrentSize
);
206 *ReturnSize
= BufferSize
;
207 return STATUS_SUCCESS
;
212 MiDoPoolCopy(IN PEPROCESS SourceProcess
,
213 IN PVOID SourceAddress
,
214 IN PEPROCESS TargetProcess
,
215 OUT PVOID TargetAddress
,
216 IN SIZE_T BufferSize
,
217 IN KPROCESSOR_MODE PreviousMode
,
218 OUT PSIZE_T ReturnSize
)
220 UCHAR StackBuffer
[MI_POOL_COPY_BYTES
];
221 SIZE_T TotalSize
, CurrentSize
, RemainingSize
;
222 volatile BOOLEAN FailedInProbe
= FALSE
, FailedInMoving
, HavePoolAddress
= FALSE
;
223 PVOID CurrentAddress
= SourceAddress
, CurrentTargetAddress
= TargetAddress
;
226 BOOLEAN HaveBadAddress
;
227 ULONG_PTR BadAddress
;
228 NTSTATUS Status
= STATUS_SUCCESS
;
231 /* Calculate the maximum amount of data to move */
232 TotalSize
= MI_MAX_TRANSFER_SIZE
;
233 if (BufferSize
<= MI_MAX_TRANSFER_SIZE
) TotalSize
= BufferSize
;
234 CurrentSize
= TotalSize
;
235 RemainingSize
= BufferSize
;
237 /* Check if we can use the stack */
238 if (BufferSize
<= MI_POOL_COPY_BYTES
)
241 PoolAddress
= (PVOID
)StackBuffer
;
246 PoolAddress
= ExAllocatePoolWithTag(NonPagedPool
, TotalSize
, TAG_VM
);
247 if (!PoolAddress
) ASSERT(FALSE
);
248 HavePoolAddress
= TRUE
;
251 /* Loop as long as there is still data */
252 while (RemainingSize
> 0)
254 /* Check if this transfer will finish everything off */
255 if (RemainingSize
< CurrentSize
) CurrentSize
= RemainingSize
;
257 /* Attach to the source address space */
258 KeStackAttachProcess(&SourceProcess
->Pcb
, &ApcState
);
260 /* Reset state for this pass */
261 FailedInMoving
= FALSE
;
262 ASSERT(FailedInProbe
== FALSE
);
264 /* Protect user-mode copy */
267 /* If this is our first time, probe the buffer */
268 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
270 /* Catch a failure here */
271 FailedInProbe
= TRUE
;
274 ProbeForRead(SourceAddress
, BufferSize
, sizeof(CHAR
));
277 FailedInProbe
= FALSE
;
281 RtlCopyMemory(PoolAddress
, CurrentAddress
, CurrentSize
);
283 /* Now let go of the source and grab to the target process */
284 KeUnstackDetachProcess(&ApcState
);
285 KeStackAttachProcess(&TargetProcess
->Pcb
, &ApcState
);
287 /* Check if this is our first time through */
288 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
290 /* Catch a failure here */
291 FailedInProbe
= TRUE
;
294 ProbeForWrite(TargetAddress
, BufferSize
, sizeof(CHAR
));
297 FailedInProbe
= FALSE
;
300 /* Now do the actual move */
301 FailedInMoving
= TRUE
;
302 RtlCopyMemory(CurrentTargetAddress
, PoolAddress
, CurrentSize
);
304 _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(), &HaveBadAddress
, &BadAddress
))
306 /* Detach from whoever we may be attached to */
307 KeUnstackDetachProcess(&ApcState
);
309 /* Check if we had allocated pool */
310 if (HavePoolAddress
) ExFreePool(PoolAddress
);
312 /* Check if we failed during the probe */
316 Status
= _SEH2_GetExceptionCode();
317 _SEH2_YIELD(return Status
);
320 /* Otherwise, we failed probably during the move */
321 *ReturnSize
= BufferSize
- RemainingSize
;
324 /* Check if we know exactly where we stopped copying */
327 /* Return the exact number of bytes copied */
328 *ReturnSize
= BadAddress
- (ULONG_PTR
)SourceAddress
;
332 /* Return partial copy */
333 Status
= STATUS_PARTIAL_COPY
;
337 /* Check for SEH status */
338 if (Status
!= STATUS_SUCCESS
) return Status
;
340 /* Detach from target */
341 KeUnstackDetachProcess(&ApcState
);
343 /* Update location and size */
344 RemainingSize
-= CurrentSize
;
345 CurrentAddress
= (PVOID
)((ULONG_PTR
)CurrentAddress
+ CurrentSize
);
346 CurrentTargetAddress
= (PVOID
)((ULONG_PTR
)CurrentTargetAddress
+ CurrentSize
);
349 /* Check if we had allocated pool */
350 if (HavePoolAddress
) ExFreePool(PoolAddress
);
353 *ReturnSize
= BufferSize
;
354 return STATUS_SUCCESS
;
359 MmCopyVirtualMemory(IN PEPROCESS SourceProcess
,
360 IN PVOID SourceAddress
,
361 IN PEPROCESS TargetProcess
,
362 OUT PVOID TargetAddress
,
363 IN SIZE_T BufferSize
,
364 IN KPROCESSOR_MODE PreviousMode
,
365 OUT PSIZE_T ReturnSize
)
368 PEPROCESS Process
= SourceProcess
;
370 /* Don't accept zero-sized buffers */
371 if (!BufferSize
) return STATUS_SUCCESS
;
373 /* If we are copying from ourselves, lock the target instead */
374 if (SourceProcess
== PsGetCurrentProcess()) Process
= TargetProcess
;
376 /* Acquire rundown protection */
377 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
380 return STATUS_PROCESS_IS_TERMINATING
;
383 /* See if we should use the pool copy */
384 if (BufferSize
> MI_POOL_COPY_BYTES
)
387 Status
= MiDoMappedCopy(SourceProcess
,
398 Status
= MiDoPoolCopy(SourceProcess
,
407 /* Release the lock */
408 ExReleaseRundownProtection(&Process
->RundownProtect
);
413 MiQueryVirtualMemory(IN HANDLE ProcessHandle
,
415 IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass
,
416 OUT PVOID VirtualMemoryInformation
,
418 OUT PSIZE_T ResultLength
)
422 MEMORY_AREA
* MemoryArea
;
423 PMMSUPPORT AddressSpace
;
425 Status
= ObReferenceObjectByHandle(ProcessHandle
,
426 PROCESS_QUERY_INFORMATION
,
432 if (!NT_SUCCESS(Status
))
434 DPRINT("NtQueryVirtualMemory() = %x\n",Status
);
438 AddressSpace
= &Process
->Vm
;
440 MmLockAddressSpace(AddressSpace
);
441 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
442 switch(VirtualMemoryInformationClass
)
444 case MemoryBasicInformation
:
446 PMEMORY_BASIC_INFORMATION Info
=
447 (PMEMORY_BASIC_INFORMATION
)VirtualMemoryInformation
;
448 if (Length
!= sizeof(MEMORY_BASIC_INFORMATION
))
450 MmUnlockAddressSpace(AddressSpace
);
451 ObDereferenceObject(Process
);
452 return(STATUS_INFO_LENGTH_MISMATCH
);
455 if (MemoryArea
== NULL
)
458 Info
->State
= MEM_FREE
;
459 Info
->Protect
= PAGE_NOACCESS
;
460 Info
->AllocationProtect
= 0;
461 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
462 Info
->AllocationBase
= NULL
;
463 Info
->RegionSize
= MmFindGapAtAddress(AddressSpace
, Info
->BaseAddress
);
464 Status
= STATUS_SUCCESS
;
465 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
469 switch(MemoryArea
->Type
)
471 case MEMORY_AREA_VIRTUAL_MEMORY
:
472 case MEMORY_AREA_PEB_OR_TEB
:
473 Status
= MmQueryAnonMem(MemoryArea
, Address
, Info
,
477 case MEMORY_AREA_SECTION_VIEW
:
478 Status
= MmQuerySectionView(MemoryArea
, Address
, Info
,
482 case MEMORY_AREA_NO_ACCESS
:
483 Info
->Type
= MEM_PRIVATE
;
484 Info
->State
= MEM_RESERVE
;
485 Info
->Protect
= MemoryArea
->Protect
;
486 Info
->AllocationProtect
= MemoryArea
->Protect
;
487 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
488 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
489 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
490 (ULONG_PTR
)MemoryArea
->StartingAddress
;
491 Status
= STATUS_SUCCESS
;
492 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
495 case MEMORY_AREA_SHARED_DATA
:
496 Info
->Type
= MEM_PRIVATE
;
497 Info
->State
= MEM_COMMIT
;
498 Info
->Protect
= MemoryArea
->Protect
;
499 Info
->AllocationProtect
= MemoryArea
->Protect
;
500 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
501 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
502 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
503 (ULONG_PTR
)MemoryArea
->StartingAddress
;
504 Status
= STATUS_SUCCESS
;
505 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
508 case MEMORY_AREA_SYSTEM
:
510 Info
->State
= MEM_COMMIT
;
511 Info
->Protect
= MemoryArea
->Protect
;
512 Info
->AllocationProtect
= MemoryArea
->Protect
;
513 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
514 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
515 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
516 (ULONG_PTR
)MemoryArea
->StartingAddress
;
517 Status
= STATUS_SUCCESS
;
518 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
521 case MEMORY_AREA_KERNEL_STACK
:
523 Info
->State
= MEM_COMMIT
;
524 Info
->Protect
= MemoryArea
->Protect
;
525 Info
->AllocationProtect
= MemoryArea
->Protect
;
526 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
527 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
528 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
529 (ULONG_PTR
)MemoryArea
->StartingAddress
;
530 Status
= STATUS_SUCCESS
;
531 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
534 case MEMORY_AREA_PAGED_POOL
:
536 Info
->State
= MEM_COMMIT
;
537 Info
->Protect
= MemoryArea
->Protect
;
538 Info
->AllocationProtect
= MemoryArea
->Protect
;
539 Info
->BaseAddress
= MemoryArea
->StartingAddress
;
540 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
541 Info
->RegionSize
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
542 (ULONG_PTR
)MemoryArea
->StartingAddress
;
543 Status
= STATUS_SUCCESS
;
544 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
548 DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea
->Type
);
549 Status
= STATUS_UNSUCCESSFUL
;
558 Status
= STATUS_INVALID_INFO_CLASS
;
564 MmUnlockAddressSpace(AddressSpace
);
565 ObDereferenceObject(Process
);
571 MiProtectVirtualMemory(IN PEPROCESS Process
,
572 IN OUT PVOID
*BaseAddress
,
573 IN OUT PSIZE_T NumberOfBytesToProtect
,
574 IN ULONG NewAccessProtection
,
575 OUT PULONG OldAccessProtection OPTIONAL
)
577 PMEMORY_AREA MemoryArea
;
578 PMMSUPPORT AddressSpace
;
579 ULONG OldAccessProtection_
;
582 *NumberOfBytesToProtect
=
583 PAGE_ROUND_UP((ULONG_PTR
)(*BaseAddress
) + (*NumberOfBytesToProtect
)) -
584 PAGE_ROUND_DOWN(*BaseAddress
);
585 *BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(*BaseAddress
);
587 AddressSpace
= &Process
->Vm
;
589 MmLockAddressSpace(AddressSpace
);
590 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, *BaseAddress
);
591 if (MemoryArea
== NULL
)
593 MmUnlockAddressSpace(AddressSpace
);
594 return STATUS_UNSUCCESSFUL
;
597 if (OldAccessProtection
== NULL
)
598 OldAccessProtection
= &OldAccessProtection_
;
600 if (MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
602 Status
= MmProtectAnonMem(AddressSpace
, MemoryArea
, *BaseAddress
,
603 *NumberOfBytesToProtect
, NewAccessProtection
,
604 OldAccessProtection
);
606 else if (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
)
608 Status
= MmProtectSectionView(AddressSpace
, MemoryArea
, *BaseAddress
,
609 *NumberOfBytesToProtect
,
611 OldAccessProtection
);
615 /* FIXME: Should we return failure or success in this case? */
616 Status
= STATUS_CONFLICTING_ADDRESSES
;
619 MmUnlockAddressSpace(AddressSpace
);
626 MiMapLockedPagesInUserSpace(IN PMDL Mdl
,
628 IN MEMORY_CACHING_TYPE CacheType
,
629 IN PVOID BaseAddress
)
632 PPFN_NUMBER MdlPages
;
634 PEPROCESS CurrentProcess
;
638 LARGE_INTEGER BoundaryAddressMultiple
;
640 /* Calculate the number of pages required. */
641 MdlPages
= (PPFN_NUMBER
)(Mdl
+ 1);
642 PageCount
= PAGE_ROUND_UP(Mdl
->ByteCount
+ Mdl
->ByteOffset
) / PAGE_SIZE
;
644 /* Set default page protection */
645 Protect
= PAGE_READWRITE
;
646 if (CacheType
== MmNonCached
) Protect
|= PAGE_NOCACHE
;
648 BoundaryAddressMultiple
.QuadPart
= 0;
651 CurrentProcess
= PsGetCurrentProcess();
653 MmLockAddressSpace(&CurrentProcess
->Vm
);
654 Status
= MmCreateMemoryArea(&CurrentProcess
->Vm
,
655 MEMORY_AREA_MDL_MAPPING
,
657 PageCount
* PAGE_SIZE
,
662 BoundaryAddressMultiple
);
663 MmUnlockAddressSpace(&CurrentProcess
->Vm
);
664 if (!NT_SUCCESS(Status
))
666 if (Mdl
->MdlFlags
& MDL_MAPPING_CAN_FAIL
)
671 /* Throw exception */
672 ExRaiseStatus(STATUS_ACCESS_VIOLATION
);
676 /* Set the virtual mappings for the MDL pages. */
677 if (Mdl
->MdlFlags
& MDL_IO_SPACE
)
680 Status
= MmCreateVirtualMappingUnsafe(CurrentProcess
,
689 Status
= MmCreateVirtualMapping(CurrentProcess
,
696 /* Check if the mapping suceeded */
697 if (!NT_SUCCESS(Status
))
699 /* If it can fail, return NULL */
700 if (Mdl
->MdlFlags
& MDL_MAPPING_CAN_FAIL
) return NULL
;
702 /* Throw exception */
703 ExRaiseStatus(STATUS_ACCESS_VIOLATION
);
706 /* Return the base */
707 Base
= (PVOID
)((ULONG_PTR
)Base
+ Mdl
->ByteOffset
);
713 MiUnmapLockedPagesInUserSpace(IN PVOID BaseAddress
,
716 PMEMORY_AREA MemoryArea
;
719 ASSERT(Mdl
->Process
== PsGetCurrentProcess());
721 /* Find the memory area */
722 MemoryArea
= MmLocateMemoryAreaByAddress(&Mdl
->Process
->Vm
,
727 MmFreeMemoryArea(&Mdl
->Process
->Vm
,
733 /* PUBLIC FUNCTIONS ***********************************************************/
740 MmGetVirtualForPhysical(IN PHYSICAL_ADDRESS PhysicalAddress
)
751 MmSecureVirtualMemory(IN PVOID Address
,
764 MmUnsecureVirtualMemory(IN PVOID SecureMem
)
769 /* SYSTEM CALLS ***************************************************************/
773 NtReadVirtualMemory(IN HANDLE ProcessHandle
,
774 IN PVOID BaseAddress
,
776 IN SIZE_T NumberOfBytesToRead
,
777 OUT PSIZE_T NumberOfBytesRead OPTIONAL
)
779 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
781 NTSTATUS Status
= STATUS_SUCCESS
;
782 SIZE_T BytesRead
= 0;
785 /* Check if we came from user mode */
786 if (PreviousMode
!= KernelMode
)
788 /* Validate the read addresses */
789 if ((((ULONG_PTR
)BaseAddress
+ NumberOfBytesToRead
) < (ULONG_PTR
)BaseAddress
) ||
790 (((ULONG_PTR
)Buffer
+ NumberOfBytesToRead
) < (ULONG_PTR
)Buffer
) ||
791 (((ULONG_PTR
)BaseAddress
+ NumberOfBytesToRead
) > MmUserProbeAddress
) ||
792 (((ULONG_PTR
)Buffer
+ NumberOfBytesToRead
) > MmUserProbeAddress
))
794 /* Don't allow to write into kernel space */
795 return STATUS_ACCESS_VIOLATION
;
798 /* Enter SEH for probe */
801 /* Probe the output value */
802 if (NumberOfBytesRead
) ProbeForWriteSize_t(NumberOfBytesRead
);
804 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
806 /* Get exception code */
807 Status
= _SEH2_GetExceptionCode();
811 /* Return if we failed */
812 if (!NT_SUCCESS(Status
)) return Status
;
815 /* Reference the process */
816 Status
= ObReferenceObjectByHandle(ProcessHandle
,
822 if (NT_SUCCESS(Status
))
825 Status
= MmCopyVirtualMemory(Process
,
827 PsGetCurrentProcess(),
833 /* Dereference the process */
834 ObDereferenceObject(Process
);
837 /* Check if the caller sent this parameter */
838 if (NumberOfBytesRead
)
840 /* Enter SEH to guard write */
843 /* Return the number of bytes read */
844 *NumberOfBytesRead
= BytesRead
;
846 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
848 /* Handle exception */
849 Status
= _SEH2_GetExceptionCode();
860 NtWriteVirtualMemory(IN HANDLE ProcessHandle
,
861 IN PVOID BaseAddress
,
863 IN SIZE_T NumberOfBytesToWrite
,
864 OUT PSIZE_T NumberOfBytesWritten OPTIONAL
)
866 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
868 NTSTATUS Status
= STATUS_SUCCESS
;
869 ULONG BytesWritten
= 0;
872 /* Check if we came from user mode */
873 if (PreviousMode
!= KernelMode
)
875 /* Validate the read addresses */
876 if ((((ULONG_PTR
)BaseAddress
+ NumberOfBytesToWrite
) < (ULONG_PTR
)BaseAddress
) ||
877 (((ULONG_PTR
)Buffer
+ NumberOfBytesToWrite
) < (ULONG_PTR
)Buffer
) ||
878 (((ULONG_PTR
)BaseAddress
+ NumberOfBytesToWrite
) > MmUserProbeAddress
) ||
879 (((ULONG_PTR
)Buffer
+ NumberOfBytesToWrite
) > MmUserProbeAddress
))
881 /* Don't allow to write into kernel space */
882 return STATUS_ACCESS_VIOLATION
;
885 /* Enter SEH for probe */
888 /* Probe the output value */
889 if (NumberOfBytesWritten
) ProbeForWriteSize_t(NumberOfBytesWritten
);
891 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
893 /* Get exception code */
894 Status
= _SEH2_GetExceptionCode();
898 /* Return if we failed */
899 if (!NT_SUCCESS(Status
)) return Status
;
902 /* Reference the process */
903 Status
= ObReferenceObjectByHandle(ProcessHandle
,
909 if (NT_SUCCESS(Status
))
912 Status
= MmCopyVirtualMemory(PsGetCurrentProcess(),
916 NumberOfBytesToWrite
,
920 /* Dereference the process */
921 ObDereferenceObject(Process
);
924 /* Check if the caller sent this parameter */
925 if (NumberOfBytesWritten
)
927 /* Enter SEH to guard write */
930 /* Return the number of bytes read */
931 *NumberOfBytesWritten
= BytesWritten
;
933 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
935 /* Handle exception */
936 Status
= _SEH2_GetExceptionCode();
947 NtProtectVirtualMemory(IN HANDLE ProcessHandle
,
948 IN OUT PVOID
*UnsafeBaseAddress
,
949 IN OUT SIZE_T
*UnsafeNumberOfBytesToProtect
,
950 IN ULONG NewAccessProtection
,
951 OUT PULONG UnsafeOldAccessProtection
)
954 ULONG OldAccessProtection
;
956 PVOID BaseAddress
= NULL
;
957 SIZE_T NumberOfBytesToProtect
= 0;
958 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
959 NTSTATUS Status
= STATUS_SUCCESS
;
962 /* Check for valid protection flags */
963 Protection
= NewAccessProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
964 if (Protection
!= PAGE_NOACCESS
&&
965 Protection
!= PAGE_READONLY
&&
966 Protection
!= PAGE_READWRITE
&&
967 Protection
!= PAGE_WRITECOPY
&&
968 Protection
!= PAGE_EXECUTE
&&
969 Protection
!= PAGE_EXECUTE_READ
&&
970 Protection
!= PAGE_EXECUTE_READWRITE
&&
971 Protection
!= PAGE_EXECUTE_WRITECOPY
)
973 return STATUS_INVALID_PAGE_PROTECTION
;
976 /* Check if we came from user mode */
977 if (PreviousMode
!= KernelMode
)
979 /* Enter SEH for probing */
982 /* Validate all outputs */
983 ProbeForWritePointer(UnsafeBaseAddress
);
984 ProbeForWriteSize_t(UnsafeNumberOfBytesToProtect
);
985 ProbeForWriteUlong(UnsafeOldAccessProtection
);
988 BaseAddress
= *UnsafeBaseAddress
;
989 NumberOfBytesToProtect
= *UnsafeNumberOfBytesToProtect
;
991 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
993 /* Get exception code */
994 Status
= _SEH2_GetExceptionCode();
998 /* Return on exception */
999 if (!NT_SUCCESS(Status
)) return Status
;
1003 /* Capture directly */
1004 BaseAddress
= *UnsafeBaseAddress
;
1005 NumberOfBytesToProtect
= *UnsafeNumberOfBytesToProtect
;
1008 /* Catch illegal base address */
1009 if (BaseAddress
> (PVOID
)MmUserProbeAddress
) return STATUS_INVALID_PARAMETER_2
;
1011 /* Catch illegal region size */
1012 if ((MmUserProbeAddress
- (ULONG_PTR
)BaseAddress
) < NumberOfBytesToProtect
)
1015 return STATUS_INVALID_PARAMETER_3
;
1018 /* 0 is also illegal */
1019 if (!NumberOfBytesToProtect
) return STATUS_INVALID_PARAMETER_3
;
1021 /* Get a reference to the process */
1022 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1023 PROCESS_VM_OPERATION
,
1028 if (!NT_SUCCESS(Status
)) return Status
;
1030 /* Do the actual work */
1031 Status
= MiProtectVirtualMemory(Process
,
1033 &NumberOfBytesToProtect
,
1034 NewAccessProtection
,
1035 &OldAccessProtection
);
1037 /* Release reference */
1038 ObDereferenceObject(Process
);
1040 /* Enter SEH to return data */
1043 /* Return data to user */
1044 *UnsafeOldAccessProtection
= OldAccessProtection
;
1045 *UnsafeBaseAddress
= BaseAddress
;
1046 *UnsafeNumberOfBytesToProtect
= NumberOfBytesToProtect
;
1048 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1050 /* Catch exception */
1051 Status
= _SEH2_GetExceptionCode();
1060 NtQueryVirtualMemory(IN HANDLE ProcessHandle
,
1062 IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass
,
1063 OUT PVOID VirtualMemoryInformation
,
1065 OUT PSIZE_T UnsafeResultLength
)
1067 NTSTATUS Status
= STATUS_SUCCESS
;
1068 SIZE_T ResultLength
= 0;
1069 KPROCESSOR_MODE PreviousMode
;
1070 WCHAR ModuleFileNameBuffer
[MAX_PATH
] = {0};
1071 UNICODE_STRING ModuleFileName
;
1072 PMEMORY_SECTION_NAME SectionName
= NULL
;
1076 MEMORY_BASIC_INFORMATION BasicInfo
;
1080 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
1081 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
1082 "Length %lu ResultLength %x)\n",ProcessHandle
,Address
,
1083 VirtualMemoryInformationClass
,VirtualMemoryInformation
,
1084 Length
,ResultLength
);
1086 PreviousMode
= ExGetPreviousMode();
1088 if (PreviousMode
!= KernelMode
)
1092 ProbeForWrite(VirtualMemoryInformation
,
1096 if (UnsafeResultLength
) ProbeForWriteSize_t(UnsafeResultLength
);
1098 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1100 Status
= _SEH2_GetExceptionCode();
1104 if (!NT_SUCCESS(Status
))
1110 if (Address
>= MmSystemRangeStart
)
1112 DPRINT1("Invalid parameter\n");
1113 return STATUS_INVALID_PARAMETER
;
1116 /* FIXME: Move this inside MiQueryVirtualMemory */
1117 if (VirtualMemoryInformationClass
== MemorySectionName
)
1119 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1120 PROCESS_QUERY_INFORMATION
,
1126 if (!NT_SUCCESS(Status
))
1128 DPRINT("NtQueryVirtualMemory() = %x\n",Status
);
1132 RtlInitEmptyUnicodeString(&ModuleFileName
, ModuleFileNameBuffer
, sizeof(ModuleFileNameBuffer
));
1133 Status
= MmGetFileNameForAddress(Address
, &ModuleFileName
);
1135 if (NT_SUCCESS(Status
))
1137 SectionName
= VirtualMemoryInformation
;
1138 if (PreviousMode
!= KernelMode
)
1142 RtlInitUnicodeString(&SectionName
->SectionFileName
, SectionName
->NameBuffer
);
1143 SectionName
->SectionFileName
.MaximumLength
= Length
;
1144 RtlCopyUnicodeString(&SectionName
->SectionFileName
, &ModuleFileName
);
1146 if (UnsafeResultLength
!= NULL
)
1148 *UnsafeResultLength
= ModuleFileName
.Length
;
1151 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1153 Status
= _SEH2_GetExceptionCode();
1159 RtlInitUnicodeString(&SectionName
->SectionFileName
, SectionName
->NameBuffer
);
1160 SectionName
->SectionFileName
.MaximumLength
= Length
;
1161 RtlCopyUnicodeString(&SectionName
->SectionFileName
, &ModuleFileName
);
1163 if (UnsafeResultLength
!= NULL
)
1165 *UnsafeResultLength
= ModuleFileName
.Length
;
1169 ObDereferenceObject(Process
);
1174 Status
= MiQueryVirtualMemory(ProcessHandle
,
1176 VirtualMemoryInformationClass
,
1182 if (NT_SUCCESS(Status
))
1184 if (PreviousMode
!= KernelMode
)
1188 if (ResultLength
> 0)
1190 ProbeForWrite(VirtualMemoryInformation
,
1193 RtlCopyMemory(VirtualMemoryInformation
,
1197 if (UnsafeResultLength
!= NULL
)
1199 *UnsafeResultLength
= ResultLength
;
1202 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1204 Status
= _SEH2_GetExceptionCode();
1210 if (ResultLength
> 0)
1212 RtlCopyMemory(VirtualMemoryInformation
,
1217 if (UnsafeResultLength
!= NULL
)
1219 *UnsafeResultLength
= ResultLength
;
1229 NtLockVirtualMemory(IN HANDLE ProcessHandle
,
1230 IN PVOID BaseAddress
,
1231 IN SIZE_T NumberOfBytesToLock
,
1232 OUT PSIZE_T NumberOfBytesLocked OPTIONAL
)
1235 if (NumberOfBytesLocked
) *NumberOfBytesLocked
= 0;
1236 return STATUS_SUCCESS
;
1241 NtUnlockVirtualMemory(IN HANDLE ProcessHandle
,
1242 IN PVOID BaseAddress
,
1243 IN SIZE_T NumberOfBytesToUnlock
,
1244 OUT PSIZE_T NumberOfBytesUnlocked OPTIONAL
)
1247 if (NumberOfBytesUnlocked
) *NumberOfBytesUnlocked
= 0;
1248 return STATUS_SUCCESS
;
1253 NtFlushVirtualMemory(IN HANDLE ProcessHandle
,
1254 IN OUT PVOID
*BaseAddress
,
1255 IN OUT PSIZE_T NumberOfBytesToFlush
,
1256 OUT PIO_STATUS_BLOCK IoStatusBlock
)
1259 return STATUS_SUCCESS
;
1267 NtGetWriteWatch(IN HANDLE ProcessHandle
,
1269 IN PVOID BaseAddress
,
1270 IN ULONG RegionSize
,
1271 IN PVOID
*UserAddressArray
,
1272 OUT PULONG EntriesInUserAddressArray
,
1273 OUT PULONG Granularity
)
1275 if (!EntriesInUserAddressArray
|| !Granularity
)
1277 return STATUS_ACCESS_VIOLATION
;
1280 if (!*EntriesInUserAddressArray
|| !RegionSize
)
1282 return STATUS_INVALID_PARAMETER
;
1285 if (!UserAddressArray
)
1287 return STATUS_ACCESS_VIOLATION
;
1290 /* HACK: Set granularity to PAGE_SIZE */
1291 *Granularity
= PAGE_SIZE
;
1294 return STATUS_NOT_IMPLEMENTED
;
1302 NtResetWriteWatch(IN HANDLE ProcessHandle
,
1303 IN PVOID BaseAddress
,
1304 IN ULONG RegionSize
)
1308 return STATUS_INVALID_PARAMETER
;
1312 return STATUS_NOT_IMPLEMENTED
;