2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/virtual.c
5 * PURPOSE: ARM Memory Manager Virtual Memory Management
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 #line 15 "ARMĀ³::VIRTUAL"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
19 #define MI_MAPPED_COPY_PAGES 14
20 #define MI_POOL_COPY_BYTES 512
21 #define MI_MAX_TRANSFER_SIZE 64 * 1024
24 MiProtectVirtualMemory(IN PEPROCESS Process
,
25 IN OUT PVOID
*BaseAddress
,
26 IN OUT PSIZE_T NumberOfBytesToProtect
,
27 IN ULONG NewAccessProtection
,
28 OUT PULONG OldAccessProtection OPTIONAL
);
30 /* PRIVATE FUNCTIONS **********************************************************/
33 MiGetExceptionInfo(IN PEXCEPTION_POINTERS ExceptionInfo
,
34 OUT PBOOLEAN HaveBadAddress
,
35 OUT PULONG_PTR BadAddress
)
37 PEXCEPTION_RECORD ExceptionRecord
;
43 *HaveBadAddress
= FALSE
;
46 // Get the exception record
48 ExceptionRecord
= ExceptionInfo
->ExceptionRecord
;
51 // Look at the exception code
53 if ((ExceptionRecord
->ExceptionCode
== STATUS_ACCESS_VIOLATION
) ||
54 (ExceptionRecord
->ExceptionCode
== STATUS_GUARD_PAGE_VIOLATION
) ||
55 (ExceptionRecord
->ExceptionCode
== STATUS_IN_PAGE_ERROR
))
58 // We can tell the address if we have more than one parameter
60 if (ExceptionRecord
->NumberParameters
> 1)
65 *HaveBadAddress
= TRUE
;
66 *BadAddress
= ExceptionRecord
->ExceptionInformation
[1];
71 // Continue executing the next handler
73 return EXCEPTION_EXECUTE_HANDLER
;
78 MiDoMappedCopy(IN PEPROCESS SourceProcess
,
79 IN PVOID SourceAddress
,
80 IN PEPROCESS TargetProcess
,
81 OUT PVOID TargetAddress
,
83 IN KPROCESSOR_MODE PreviousMode
,
84 OUT PSIZE_T ReturnSize
)
86 PFN_NUMBER MdlBuffer
[(sizeof(MDL
) / sizeof(PFN_NUMBER
)) + MI_MAPPED_COPY_PAGES
+ 1];
87 PMDL Mdl
= (PMDL
)MdlBuffer
;
88 SIZE_T TotalSize
, CurrentSize
, RemainingSize
;
89 volatile BOOLEAN FailedInProbe
= FALSE
, FailedInMapping
= FALSE
, FailedInMoving
;
90 volatile BOOLEAN PagesLocked
;
91 PVOID CurrentAddress
= SourceAddress
, CurrentTargetAddress
= TargetAddress
;
92 volatile PVOID MdlAddress
;
94 BOOLEAN HaveBadAddress
;
96 NTSTATUS Status
= STATUS_SUCCESS
;
100 // Calculate the maximum amount of data to move
102 TotalSize
= MI_MAPPED_COPY_PAGES
* PAGE_SIZE
;
103 if (BufferSize
<= TotalSize
) TotalSize
= BufferSize
;
104 CurrentSize
= TotalSize
;
105 RemainingSize
= BufferSize
;
108 // Loop as long as there is still data
110 while (RemainingSize
> 0)
113 // Check if this transfer will finish everything off
115 if (RemainingSize
< CurrentSize
) CurrentSize
= RemainingSize
;
118 // Attach to the source address space
120 KeStackAttachProcess(&SourceProcess
->Pcb
, &ApcState
);
123 // Reset state for this pass
127 FailedInMoving
= FALSE
;
128 ASSERT(FailedInProbe
== FALSE
);
131 // Protect user-mode copy
136 // If this is our first time, probe the buffer
138 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
141 // Catch a failure here
143 FailedInProbe
= TRUE
;
148 ProbeForRead(SourceAddress
, BufferSize
, sizeof(CHAR
));
153 FailedInProbe
= FALSE
;
157 // Initialize and probe and lock the MDL
159 MmInitializeMdl(Mdl
, CurrentAddress
, CurrentSize
);
160 MmProbeAndLockPages(Mdl
, PreviousMode
, IoReadAccess
);
166 MdlAddress
= MmMapLockedPagesSpecifyCache(Mdl
,
175 // Use our SEH handler to pick this up
177 FailedInMapping
= TRUE
;
178 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
182 // Now let go of the source and grab to the target process
184 KeUnstackDetachProcess(&ApcState
);
185 KeStackAttachProcess(&TargetProcess
->Pcb
, &ApcState
);
188 // Check if this is our first time through
190 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
193 // Catch a failure here
195 FailedInProbe
= TRUE
;
200 ProbeForWrite(TargetAddress
, BufferSize
, sizeof(CHAR
));
205 FailedInProbe
= FALSE
;
209 // Now do the actual move
211 FailedInMoving
= TRUE
;
212 RtlCopyMemory(CurrentTargetAddress
, MdlAddress
, CurrentSize
);
214 _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(),
219 // Detach from whoever we may be attached to
221 KeUnstackDetachProcess(&ApcState
);
224 // Check if we had mapped the pages
226 if (MdlAddress
) MmUnmapLockedPages(MdlAddress
, Mdl
);
229 // Check if we had locked the pages
231 if (PagesLocked
) MmUnlockPages(Mdl
);
234 // Check if we hit working set quota
236 if (_SEH2_GetExceptionCode() == STATUS_WORKING_SET_QUOTA
)
241 return STATUS_WORKING_SET_QUOTA
;
245 // Check if we failed during the probe or mapping
247 if ((FailedInProbe
) || (FailedInMapping
))
252 Status
= _SEH2_GetExceptionCode();
253 _SEH2_YIELD(return Status
);
257 // Otherwise, we failed probably during the move
259 *ReturnSize
= BufferSize
- RemainingSize
;
263 // Check if we know exactly where we stopped copying
268 // Return the exact number of bytes copied
270 *ReturnSize
= BadAddress
- (ULONG_PTR
)SourceAddress
;
275 // Return partial copy
277 Status
= STATUS_PARTIAL_COPY
;
282 // Check for SEH status
284 if (Status
!= STATUS_SUCCESS
) return Status
;
287 // Detach from target
289 KeUnstackDetachProcess(&ApcState
);
294 MmUnmapLockedPages(MdlAddress
, Mdl
);
298 // Update location and size
300 RemainingSize
-= CurrentSize
;
301 CurrentAddress
= (PVOID
)((ULONG_PTR
)CurrentAddress
+ CurrentSize
);
302 CurrentTargetAddress
= (PVOID
)((ULONG_PTR
)CurrentTargetAddress
+ CurrentSize
);
308 *ReturnSize
= BufferSize
;
309 return STATUS_SUCCESS
;
314 MiDoPoolCopy(IN PEPROCESS SourceProcess
,
315 IN PVOID SourceAddress
,
316 IN PEPROCESS TargetProcess
,
317 OUT PVOID TargetAddress
,
318 IN SIZE_T BufferSize
,
319 IN KPROCESSOR_MODE PreviousMode
,
320 OUT PSIZE_T ReturnSize
)
322 UCHAR StackBuffer
[MI_POOL_COPY_BYTES
];
323 SIZE_T TotalSize
, CurrentSize
, RemainingSize
;
324 volatile BOOLEAN FailedInProbe
= FALSE
, FailedInMoving
, HavePoolAddress
= FALSE
;
325 PVOID CurrentAddress
= SourceAddress
, CurrentTargetAddress
= TargetAddress
;
328 BOOLEAN HaveBadAddress
;
329 ULONG_PTR BadAddress
;
330 NTSTATUS Status
= STATUS_SUCCESS
;
334 // Calculate the maximum amount of data to move
336 TotalSize
= MI_MAX_TRANSFER_SIZE
;
337 if (BufferSize
<= MI_MAX_TRANSFER_SIZE
) TotalSize
= BufferSize
;
338 CurrentSize
= TotalSize
;
339 RemainingSize
= BufferSize
;
342 // Check if we can use the stack
344 if (BufferSize
<= MI_POOL_COPY_BYTES
)
349 PoolAddress
= (PVOID
)StackBuffer
;
356 PoolAddress
= ExAllocatePoolWithTag(NonPagedPool
, TotalSize
, 'VmRw');
357 if (!PoolAddress
) ASSERT(FALSE
);
358 HavePoolAddress
= TRUE
;
362 // Loop as long as there is still data
364 while (RemainingSize
> 0)
367 // Check if this transfer will finish everything off
369 if (RemainingSize
< CurrentSize
) CurrentSize
= RemainingSize
;
372 // Attach to the source address space
374 KeStackAttachProcess(&SourceProcess
->Pcb
, &ApcState
);
377 // Reset state for this pass
379 FailedInMoving
= FALSE
;
380 ASSERT(FailedInProbe
== FALSE
);
383 // Protect user-mode copy
388 // If this is our first time, probe the buffer
390 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
393 // Catch a failure here
395 FailedInProbe
= TRUE
;
400 ProbeForRead(SourceAddress
, BufferSize
, sizeof(CHAR
));
405 FailedInProbe
= FALSE
;
411 RtlCopyMemory(PoolAddress
, CurrentAddress
, CurrentSize
);
414 // Now let go of the source and grab to the target process
416 KeUnstackDetachProcess(&ApcState
);
417 KeStackAttachProcess(&TargetProcess
->Pcb
, &ApcState
);
420 // Check if this is our first time through
422 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
425 // Catch a failure here
427 FailedInProbe
= TRUE
;
432 ProbeForWrite(TargetAddress
, BufferSize
, sizeof(CHAR
));
437 FailedInProbe
= FALSE
;
441 // Now do the actual move
443 FailedInMoving
= TRUE
;
444 RtlCopyMemory(CurrentTargetAddress
, PoolAddress
, CurrentSize
);
446 _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(),
451 // Detach from whoever we may be attached to
453 KeUnstackDetachProcess(&ApcState
);
456 // Check if we had allocated pool
458 if (HavePoolAddress
) ExFreePool(PoolAddress
);
461 // Check if we failed during the probe
468 Status
= _SEH2_GetExceptionCode();
469 _SEH2_YIELD(return Status
);
473 // Otherwise, we failed, probably during the move
475 *ReturnSize
= BufferSize
- RemainingSize
;
479 // Check if we know exactly where we stopped copying
484 // Return the exact number of bytes copied
486 *ReturnSize
= BadAddress
- (ULONG_PTR
)SourceAddress
;
491 // Return partial copy
493 Status
= STATUS_PARTIAL_COPY
;
498 // Check for SEH status
500 if (Status
!= STATUS_SUCCESS
) return Status
;
503 // Detach from target
505 KeUnstackDetachProcess(&ApcState
);
508 // Update location and size
510 RemainingSize
-= CurrentSize
;
511 CurrentAddress
= (PVOID
)((ULONG_PTR
)CurrentAddress
+ CurrentSize
);
512 CurrentTargetAddress
= (PVOID
)((ULONG_PTR
)CurrentTargetAddress
+
517 // Check if we had allocated pool
519 if (HavePoolAddress
) ExFreePool(PoolAddress
);
524 *ReturnSize
= BufferSize
;
525 return STATUS_SUCCESS
;
530 MmCopyVirtualMemory(IN PEPROCESS SourceProcess
,
531 IN PVOID SourceAddress
,
532 IN PEPROCESS TargetProcess
,
533 OUT PVOID TargetAddress
,
534 IN SIZE_T BufferSize
,
535 IN KPROCESSOR_MODE PreviousMode
,
536 OUT PSIZE_T ReturnSize
)
539 PEPROCESS Process
= SourceProcess
;
542 // Don't accept zero-sized buffers
544 if (!BufferSize
) return STATUS_SUCCESS
;
547 // If we are copying from ourselves, lock the target instead
549 if (SourceProcess
== PsGetCurrentProcess()) Process
= TargetProcess
;
552 // Acquire rundown protection
554 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
559 return STATUS_PROCESS_IS_TERMINATING
;
563 // See if we should use the pool copy
565 if (BufferSize
> MI_POOL_COPY_BYTES
)
570 Status
= MiDoMappedCopy(SourceProcess
,
583 Status
= MiDoPoolCopy(SourceProcess
,
595 ExReleaseRundownProtection(&Process
->RundownProtect
);
601 MmFlushVirtualMemory(IN PEPROCESS Process
,
602 IN OUT PVOID
*BaseAddress
,
603 IN OUT PSIZE_T RegionSize
,
604 OUT PIO_STATUS_BLOCK IoStatusBlock
)
612 return STATUS_SUCCESS
;
615 /* PUBLIC FUNCTIONS ***********************************************************/
622 MmGetVirtualForPhysical(IN PHYSICAL_ADDRESS PhysicalAddress
)
633 MmSecureVirtualMemory(IN PVOID Address
,
646 MmUnsecureVirtualMemory(IN PVOID SecureMem
)
651 /* SYSTEM CALLS ***************************************************************/
655 NtReadVirtualMemory(IN HANDLE ProcessHandle
,
656 IN PVOID BaseAddress
,
658 IN SIZE_T NumberOfBytesToRead
,
659 OUT PSIZE_T NumberOfBytesRead OPTIONAL
)
661 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
663 NTSTATUS Status
= STATUS_SUCCESS
;
664 SIZE_T BytesRead
= 0;
668 // Check if we came from user mode
670 if (PreviousMode
!= KernelMode
)
673 // Validate the read addresses
675 if ((((ULONG_PTR
)BaseAddress
+ NumberOfBytesToRead
) < (ULONG_PTR
)BaseAddress
) ||
676 (((ULONG_PTR
)Buffer
+ NumberOfBytesToRead
) < (ULONG_PTR
)Buffer
) ||
677 (((ULONG_PTR
)BaseAddress
+ NumberOfBytesToRead
) > MmUserProbeAddress
) ||
678 (((ULONG_PTR
)Buffer
+ NumberOfBytesToRead
) > MmUserProbeAddress
))
681 // Don't allow to write into kernel space
683 return STATUS_ACCESS_VIOLATION
;
687 // Enter SEH for probe
692 // Probe the output value
694 if (NumberOfBytesRead
) ProbeForWriteSize_t(NumberOfBytesRead
);
696 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
699 // Get exception code
701 _SEH2_YIELD(return _SEH2_GetExceptionCode());
707 // Don't do zero-byte transfers
709 if (NumberOfBytesToRead
)
712 // Reference the process
714 Status
= ObReferenceObjectByHandle(ProcessHandle
,
720 if (NT_SUCCESS(Status
))
725 Status
= MmCopyVirtualMemory(Process
,
727 PsGetCurrentProcess(),
734 // Dereference the process
736 ObDereferenceObject(Process
);
741 // Check if the caller sent this parameter
743 if (NumberOfBytesRead
)
746 // Enter SEH to guard write
751 // Return the number of bytes read
753 *NumberOfBytesRead
= BytesRead
;
755 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
769 NtWriteVirtualMemory(IN HANDLE ProcessHandle
,
770 IN PVOID BaseAddress
,
772 IN SIZE_T NumberOfBytesToWrite
,
773 OUT PSIZE_T NumberOfBytesWritten OPTIONAL
)
775 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
777 NTSTATUS Status
= STATUS_SUCCESS
;
778 ULONG BytesWritten
= 0;
782 // Check if we came from user mode
784 if (PreviousMode
!= KernelMode
)
787 // Validate the read addresses
789 if ((((ULONG_PTR
)BaseAddress
+ NumberOfBytesToWrite
) < (ULONG_PTR
)BaseAddress
) ||
790 (((ULONG_PTR
)Buffer
+ NumberOfBytesToWrite
) < (ULONG_PTR
)Buffer
) ||
791 (((ULONG_PTR
)BaseAddress
+ NumberOfBytesToWrite
) > MmUserProbeAddress
) ||
792 (((ULONG_PTR
)Buffer
+ NumberOfBytesToWrite
) > MmUserProbeAddress
))
795 // Don't allow to write into kernel space
797 return STATUS_ACCESS_VIOLATION
;
801 // Enter SEH for probe
806 // Probe the output value
808 if (NumberOfBytesWritten
) ProbeForWriteSize_t(NumberOfBytesWritten
);
810 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
813 // Get exception code
815 _SEH2_YIELD(return _SEH2_GetExceptionCode());
821 // Don't do zero-byte transfers
823 if (NumberOfBytesToWrite
)
826 // Reference the process
828 Status
= ObReferenceObjectByHandle(ProcessHandle
,
834 if (NT_SUCCESS(Status
))
839 Status
= MmCopyVirtualMemory(PsGetCurrentProcess(),
843 NumberOfBytesToWrite
,
848 // Dereference the process
850 ObDereferenceObject(Process
);
855 // Check if the caller sent this parameter
857 if (NumberOfBytesWritten
)
860 // Enter SEH to guard write
865 // Return the number of bytes written
867 *NumberOfBytesWritten
= BytesWritten
;
869 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
883 NtProtectVirtualMemory(IN HANDLE ProcessHandle
,
884 IN OUT PVOID
*UnsafeBaseAddress
,
885 IN OUT SIZE_T
*UnsafeNumberOfBytesToProtect
,
886 IN ULONG NewAccessProtection
,
887 OUT PULONG UnsafeOldAccessProtection
)
890 ULONG OldAccessProtection
;
892 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
893 PVOID BaseAddress
= NULL
;
894 SIZE_T NumberOfBytesToProtect
= 0;
895 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
897 BOOLEAN Attached
= FALSE
;
902 // Check for valid protection flags
904 Protection
= NewAccessProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
905 if (Protection
!= PAGE_NOACCESS
&&
906 Protection
!= PAGE_READONLY
&&
907 Protection
!= PAGE_READWRITE
&&
908 Protection
!= PAGE_WRITECOPY
&&
909 Protection
!= PAGE_EXECUTE
&&
910 Protection
!= PAGE_EXECUTE_READ
&&
911 Protection
!= PAGE_EXECUTE_READWRITE
&&
912 Protection
!= PAGE_EXECUTE_WRITECOPY
)
917 return STATUS_INVALID_PAGE_PROTECTION
;
921 // Check if we came from user mode
923 if (PreviousMode
!= KernelMode
)
926 // Enter SEH for probing
931 // Validate all outputs
933 ProbeForWritePointer(UnsafeBaseAddress
);
934 ProbeForWriteSize_t(UnsafeNumberOfBytesToProtect
);
935 ProbeForWriteUlong(UnsafeOldAccessProtection
);
940 BaseAddress
= *UnsafeBaseAddress
;
941 NumberOfBytesToProtect
= *UnsafeNumberOfBytesToProtect
;
943 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
946 // Get exception code
948 _SEH2_YIELD(return _SEH2_GetExceptionCode());
957 BaseAddress
= *UnsafeBaseAddress
;
958 NumberOfBytesToProtect
= *UnsafeNumberOfBytesToProtect
;
962 // Catch illegal base address
964 if (BaseAddress
> MM_HIGHEST_USER_ADDRESS
) return STATUS_INVALID_PARAMETER_2
;
967 // Catch illegal region size
969 if ((MmUserProbeAddress
- (ULONG_PTR
)BaseAddress
) < NumberOfBytesToProtect
)
974 return STATUS_INVALID_PARAMETER_3
;
980 if (!NumberOfBytesToProtect
) return STATUS_INVALID_PARAMETER_3
;
983 // Get a reference to the process
985 Status
= ObReferenceObjectByHandle(ProcessHandle
,
986 PROCESS_VM_OPERATION
,
991 if (!NT_SUCCESS(Status
)) return Status
;
994 // Check if we should attach
996 if (CurrentProcess
!= Process
)
1001 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
1006 // Do the actual work
1008 Status
= MiProtectVirtualMemory(Process
,
1010 &NumberOfBytesToProtect
,
1011 NewAccessProtection
,
1012 &OldAccessProtection
);
1017 if (Attached
) KeUnstackDetachProcess(&ApcState
);
1020 // Release reference
1022 ObDereferenceObject(Process
);
1025 // Enter SEH to return data
1030 // Return data to user
1032 *UnsafeOldAccessProtection
= OldAccessProtection
;
1033 *UnsafeBaseAddress
= BaseAddress
;
1034 *UnsafeNumberOfBytesToProtect
= NumberOfBytesToProtect
;
1036 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1049 NtLockVirtualMemory(IN HANDLE ProcessHandle
,
1050 IN OUT PVOID
*BaseAddress
,
1051 IN OUT PSIZE_T NumberOfBytesToLock
,
1055 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
1057 BOOLEAN Attached
= FALSE
;
1058 KAPC_STATE ApcState
;
1059 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1060 PVOID CapturedBaseAddress
;
1061 SIZE_T CapturedBytesToLock
;
1067 if ((MapType
& ~(MAP_PROCESS
| MAP_SYSTEM
)))
1070 // Invalid set of flags
1072 return STATUS_INVALID_PARAMETER
;
1076 // At least one flag must be specified
1078 if (!(MapType
& (MAP_PROCESS
| MAP_SYSTEM
)))
1083 return STATUS_INVALID_PARAMETER
;
1087 // Enter SEH for probing
1092 // Validate output data
1094 ProbeForWritePointer(BaseAddress
);
1095 ProbeForWriteSize_t(NumberOfBytesToLock
);
1100 CapturedBaseAddress
= *BaseAddress
;
1101 CapturedBytesToLock
= *NumberOfBytesToLock
;
1103 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1106 // Get exception code
1108 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1113 // Catch illegal base address
1115 if (CapturedBaseAddress
> MM_HIGHEST_USER_ADDRESS
) return STATUS_INVALID_PARAMETER
;
1118 // Catch illegal region size
1120 if ((MmUserProbeAddress
- (ULONG_PTR
)CapturedBaseAddress
) < CapturedBytesToLock
)
1125 return STATUS_INVALID_PARAMETER
;
1129 // 0 is also illegal
1131 if (!CapturedBytesToLock
) return STATUS_INVALID_PARAMETER
;
1134 // Get a reference to the process
1136 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1137 PROCESS_VM_OPERATION
,
1142 if (!NT_SUCCESS(Status
)) return Status
;
1145 // Check if this is is system-mapped
1147 if (MapType
& MAP_SYSTEM
)
1150 // Check for required privilege
1152 if (!SeSinglePrivilegeCheck(SeLockMemoryPrivilege
, PreviousMode
))
1155 // Fail: Don't have it
1157 ObDereferenceObject(Process
);
1158 return STATUS_PRIVILEGE_NOT_HELD
;
1163 // Check if we should attach
1165 if (CurrentProcess
!= Process
)
1170 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
1182 if (Attached
) KeUnstackDetachProcess(&ApcState
);
1185 // Release reference
1187 ObDereferenceObject(Process
);
1190 // Enter SEH to return data
1195 // Return data to user
1197 *BaseAddress
= CapturedBaseAddress
;
1198 *NumberOfBytesToLock
= 0;
1200 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1203 // Get exception code
1205 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1212 return STATUS_SUCCESS
;
1217 NtUnlockVirtualMemory(IN HANDLE ProcessHandle
,
1218 IN OUT PVOID
*BaseAddress
,
1219 IN OUT PSIZE_T NumberOfBytesToUnlock
,
1223 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
1225 BOOLEAN Attached
= FALSE
;
1226 KAPC_STATE ApcState
;
1227 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1228 PVOID CapturedBaseAddress
;
1229 SIZE_T CapturedBytesToUnlock
;
1235 if ((MapType
& ~(MAP_PROCESS
| MAP_SYSTEM
)))
1238 // Invalid set of flags
1240 return STATUS_INVALID_PARAMETER
;
1244 // At least one flag must be specified
1246 if (!(MapType
& (MAP_PROCESS
| MAP_SYSTEM
)))
1251 return STATUS_INVALID_PARAMETER
;
1255 // Enter SEH for probing
1260 // Validate output data
1262 ProbeForWritePointer(BaseAddress
);
1263 ProbeForWriteSize_t(NumberOfBytesToUnlock
);
1268 CapturedBaseAddress
= *BaseAddress
;
1269 CapturedBytesToUnlock
= *NumberOfBytesToUnlock
;
1271 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1274 // Get exception code
1276 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1281 // Catch illegal base address
1283 if (CapturedBaseAddress
> MM_HIGHEST_USER_ADDRESS
) return STATUS_INVALID_PARAMETER
;
1286 // Catch illegal region size
1288 if ((MmUserProbeAddress
- (ULONG_PTR
)CapturedBaseAddress
) < CapturedBytesToUnlock
)
1293 return STATUS_INVALID_PARAMETER
;
1297 // 0 is also illegal
1299 if (!CapturedBytesToUnlock
) return STATUS_INVALID_PARAMETER
;
1302 // Get a reference to the process
1304 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1305 PROCESS_VM_OPERATION
,
1310 if (!NT_SUCCESS(Status
)) return Status
;
1313 // Check if this is is system-mapped
1315 if (MapType
& MAP_SYSTEM
)
1318 // Check for required privilege
1320 if (!SeSinglePrivilegeCheck(SeLockMemoryPrivilege
, PreviousMode
))
1323 // Fail: Don't have it
1325 ObDereferenceObject(Process
);
1326 return STATUS_PRIVILEGE_NOT_HELD
;
1331 // Check if we should attach
1333 if (CurrentProcess
!= Process
)
1338 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
1350 if (Attached
) KeUnstackDetachProcess(&ApcState
);
1353 // Release reference
1355 ObDereferenceObject(Process
);
1358 // Enter SEH to return data
1363 // Return data to user
1365 *BaseAddress
= PAGE_ALIGN(CapturedBaseAddress
);
1366 *NumberOfBytesToUnlock
= 0;
1368 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1371 // Get exception code
1373 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1380 return STATUS_SUCCESS
;
1385 NtFlushVirtualMemory(IN HANDLE ProcessHandle
,
1386 IN OUT PVOID
*BaseAddress
,
1387 IN OUT PSIZE_T NumberOfBytesToFlush
,
1388 OUT PIO_STATUS_BLOCK IoStatusBlock
)
1392 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1393 PVOID CapturedBaseAddress
;
1394 SIZE_T CapturedBytesToFlush
;
1395 IO_STATUS_BLOCK LocalStatusBlock
;
1399 // Check if we came from user mode
1401 if (PreviousMode
!= KernelMode
)
1404 // Enter SEH for probing
1409 // Validate all outputs
1411 ProbeForWritePointer(BaseAddress
);
1412 ProbeForWriteSize_t(NumberOfBytesToFlush
);
1413 ProbeForWriteIoStatusBlock(IoStatusBlock
);
1418 CapturedBaseAddress
= *BaseAddress
;
1419 CapturedBytesToFlush
= *NumberOfBytesToFlush
;
1421 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1424 // Get exception code
1426 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1435 CapturedBaseAddress
= *BaseAddress
;
1436 CapturedBytesToFlush
= *NumberOfBytesToFlush
;
1440 // Catch illegal base address
1442 if (CapturedBaseAddress
> MM_HIGHEST_USER_ADDRESS
) return STATUS_INVALID_PARAMETER
;
1445 // Catch illegal region size
1447 if ((MmUserProbeAddress
- (ULONG_PTR
)CapturedBaseAddress
) < CapturedBytesToFlush
)
1452 return STATUS_INVALID_PARAMETER
;
1456 // Get a reference to the process
1458 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1459 PROCESS_VM_OPERATION
,
1464 if (!NT_SUCCESS(Status
)) return Status
;
1469 Status
= MmFlushVirtualMemory(Process
,
1470 &CapturedBaseAddress
,
1471 &CapturedBytesToFlush
,
1475 // Release reference
1477 ObDereferenceObject(Process
);
1480 // Enter SEH to return data
1485 // Return data to user
1487 *BaseAddress
= PAGE_ALIGN(CapturedBaseAddress
);
1488 *NumberOfBytesToFlush
= 0;
1489 *IoStatusBlock
= LocalStatusBlock
;
1491 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1507 NtGetWriteWatch(IN HANDLE ProcessHandle
,
1509 IN PVOID BaseAddress
,
1510 IN SIZE_T RegionSize
,
1511 IN PVOID
*UserAddressArray
,
1512 OUT PULONG_PTR EntriesInUserAddressArray
,
1513 OUT PULONG Granularity
)
1518 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1519 ULONG_PTR CapturedEntryCount
;
1523 // Check if we came from user mode
1525 if (PreviousMode
!= KernelMode
)
1528 // Enter SEH for probing
1533 // Catch illegal base address
1535 if (BaseAddress
> MM_HIGHEST_USER_ADDRESS
) return STATUS_INVALID_PARAMETER_2
;
1538 // Catch illegal region size
1540 if ((MmUserProbeAddress
- (ULONG_PTR
)BaseAddress
) < RegionSize
)
1545 return STATUS_INVALID_PARAMETER_3
;
1549 // Validate all data
1551 ProbeForWriteSize_t(EntriesInUserAddressArray
);
1552 ProbeForWriteUlong(Granularity
);
1557 CapturedEntryCount
= *EntriesInUserAddressArray
;
1560 // Must have a count
1562 if (CapturedEntryCount
== 0) return STATUS_INVALID_PARAMETER_5
;
1565 // Can't be larger than the maximum
1567 if (CapturedEntryCount
> (MAXULONG_PTR
/ sizeof(ULONG_PTR
)))
1572 return STATUS_INVALID_PARAMETER_5
;
1576 // Probe the actual array
1578 ProbeForWrite(UserAddressArray
,
1579 CapturedEntryCount
* sizeof(PVOID
),
1582 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1585 // Get exception code
1587 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1596 CapturedEntryCount
= *EntriesInUserAddressArray
;
1597 ASSERT(CapturedEntryCount
!= 0);
1601 // Check if this is a local request
1603 if (ProcessHandle
== NtCurrentProcess())
1606 // No need to reference the process
1608 Process
= PsGetCurrentProcess();
1613 // Reference the target
1615 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1616 PROCESS_VM_OPERATION
,
1621 if (!NT_SUCCESS(Status
)) return Status
;
1625 // Compute the last address and validate it
1627 EndAddress
= (PVOID
)((ULONG_PTR
)BaseAddress
+ RegionSize
- 1);
1628 if (BaseAddress
> EndAddress
)
1633 if (ProcessHandle
!= NtCurrentProcess()) ObDereferenceObject(Process
);
1634 return STATUS_INVALID_PARAMETER_4
;
1643 // Dereference if needed
1645 if (ProcessHandle
!= NtCurrentProcess()) ObDereferenceObject(Process
);
1648 // Enter SEH to return data
1653 // Return data to user
1655 *EntriesInUserAddressArray
= 0;
1656 *Granularity
= PAGE_SIZE
;
1658 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1661 // Get exception code
1663 Status
= _SEH2_GetExceptionCode();
1670 return STATUS_SUCCESS
;
1678 NtResetWriteWatch(IN HANDLE ProcessHandle
,
1679 IN PVOID BaseAddress
,
1680 IN SIZE_T RegionSize
)
1685 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1686 ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL
);
1689 // Catch illegal base address
1691 if (BaseAddress
> MM_HIGHEST_USER_ADDRESS
) return STATUS_INVALID_PARAMETER_2
;
1694 // Catch illegal region size
1696 if ((MmUserProbeAddress
- (ULONG_PTR
)BaseAddress
) < RegionSize
)
1701 return STATUS_INVALID_PARAMETER_3
;
1705 // Check if this is a local request
1707 if (ProcessHandle
== NtCurrentProcess())
1710 // No need to reference the process
1712 Process
= PsGetCurrentProcess();
1717 // Reference the target
1719 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1720 PROCESS_VM_OPERATION
,
1725 if (!NT_SUCCESS(Status
)) return Status
;
1729 // Compute the last address and validate it
1731 EndAddress
= (PVOID
)((ULONG_PTR
)BaseAddress
+ RegionSize
- 1);
1732 if (BaseAddress
> EndAddress
)
1737 if (ProcessHandle
!= NtCurrentProcess()) ObDereferenceObject(Process
);
1738 return STATUS_INVALID_PARAMETER_3
;
1747 // Dereference if needed
1749 if (ProcessHandle
!= NtCurrentProcess()) ObDereferenceObject(Process
);
1754 return STATUS_SUCCESS
;