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 **********************************************************/
34 MiDeleteSystemPageableVm(IN PMMPTE PointerPte
,
35 IN PFN_NUMBER PageCount
,
37 OUT PPFN_NUMBER ValidPages
)
39 PFN_NUMBER ActualPages
= 0;
40 PETHREAD CurrentThread
= PsGetCurrentThread();
42 PFN_NUMBER PageFrameIndex
, PageTableIndex
;
44 ASSERT(KeGetCurrentIrql() <= APC_LEVEL
);
46 /* Lock the system working set */
47 MiLockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
52 /* Make sure there's some data about the page */
53 if (PointerPte
->u
.Long
)
55 /* As always, only handle current ARM3 scenarios */
56 ASSERT(PointerPte
->u
.Soft
.Prototype
== 0);
57 ASSERT(PointerPte
->u
.Soft
.Transition
== 0);
59 /* Normally this is one possibility -- freeing a valid page */
60 if (PointerPte
->u
.Hard
.Valid
)
62 /* Get the page PFN */
63 PageFrameIndex
= PFN_FROM_PTE(PointerPte
);
64 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
66 /* Should not have any working set data yet */
67 ASSERT(Pfn1
->u1
.WsIndex
== 0);
69 /* Actual valid, legitimate, pages */
70 if (ValidPages
) *ValidPages
++;
72 /* Get the page table entry */
73 PageTableIndex
= Pfn1
->u4
.PteFrame
;
74 Pfn2
= MiGetPfnEntry(PageTableIndex
);
76 /* Lock the PFN database */
77 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
79 /* Delete it the page */
80 MI_SET_PFN_DELETED(Pfn1
);
81 MiDecrementShareCount(Pfn1
, PageFrameIndex
);
83 /* Decrement the page table too */
84 #if 0 // ARM3: Dont't trust this yet
85 MiDecrementShareCount(Pfn2
, PageTableIndex
);
88 /* Release the PFN database */
89 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
92 PointerPte
->u
.Long
= 0;
95 /* Actual legitimate pages */
101 * The only other ARM3 possibility is a demand zero page, which would
102 * mean freeing some of the paged pool pages that haven't even been
103 * touched yet, as part of a larger allocation.
105 * Right now, we shouldn't expect any page file information in the PTE
107 ASSERT(PointerPte
->u
.Soft
.PageFileHigh
== 0);
109 /* Destroy the PTE */
110 PointerPte
->u
.Long
= 0;
118 /* Release the working set */
119 MiUnlockWorkingSet(CurrentThread
, &MmSystemCacheWs
);
121 /* Flush the entire TLB */
122 KeFlushEntireTb(TRUE
, TRUE
);
129 MiGetExceptionInfo(IN PEXCEPTION_POINTERS ExceptionInfo
,
130 OUT PBOOLEAN HaveBadAddress
,
131 OUT PULONG_PTR BadAddress
)
133 PEXCEPTION_RECORD ExceptionRecord
;
139 *HaveBadAddress
= FALSE
;
142 // Get the exception record
144 ExceptionRecord
= ExceptionInfo
->ExceptionRecord
;
147 // Look at the exception code
149 if ((ExceptionRecord
->ExceptionCode
== STATUS_ACCESS_VIOLATION
) ||
150 (ExceptionRecord
->ExceptionCode
== STATUS_GUARD_PAGE_VIOLATION
) ||
151 (ExceptionRecord
->ExceptionCode
== STATUS_IN_PAGE_ERROR
))
154 // We can tell the address if we have more than one parameter
156 if (ExceptionRecord
->NumberParameters
> 1)
159 // Return the address
161 *HaveBadAddress
= TRUE
;
162 *BadAddress
= ExceptionRecord
->ExceptionInformation
[1];
167 // Continue executing the next handler
169 return EXCEPTION_EXECUTE_HANDLER
;
174 MiDoMappedCopy(IN PEPROCESS SourceProcess
,
175 IN PVOID SourceAddress
,
176 IN PEPROCESS TargetProcess
,
177 OUT PVOID TargetAddress
,
178 IN SIZE_T BufferSize
,
179 IN KPROCESSOR_MODE PreviousMode
,
180 OUT PSIZE_T ReturnSize
)
182 PFN_NUMBER MdlBuffer
[(sizeof(MDL
) / sizeof(PFN_NUMBER
)) + MI_MAPPED_COPY_PAGES
+ 1];
183 PMDL Mdl
= (PMDL
)MdlBuffer
;
184 SIZE_T TotalSize
, CurrentSize
, RemainingSize
;
185 volatile BOOLEAN FailedInProbe
= FALSE
, FailedInMapping
= FALSE
, FailedInMoving
;
186 volatile BOOLEAN PagesLocked
;
187 PVOID CurrentAddress
= SourceAddress
, CurrentTargetAddress
= TargetAddress
;
188 volatile PVOID MdlAddress
;
190 BOOLEAN HaveBadAddress
;
191 ULONG_PTR BadAddress
;
192 NTSTATUS Status
= STATUS_SUCCESS
;
196 // Calculate the maximum amount of data to move
198 TotalSize
= MI_MAPPED_COPY_PAGES
* PAGE_SIZE
;
199 if (BufferSize
<= TotalSize
) TotalSize
= BufferSize
;
200 CurrentSize
= TotalSize
;
201 RemainingSize
= BufferSize
;
204 // Loop as long as there is still data
206 while (RemainingSize
> 0)
209 // Check if this transfer will finish everything off
211 if (RemainingSize
< CurrentSize
) CurrentSize
= RemainingSize
;
214 // Attach to the source address space
216 KeStackAttachProcess(&SourceProcess
->Pcb
, &ApcState
);
219 // Reset state for this pass
223 FailedInMoving
= FALSE
;
224 ASSERT(FailedInProbe
== FALSE
);
227 // Protect user-mode copy
232 // If this is our first time, probe the buffer
234 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
237 // Catch a failure here
239 FailedInProbe
= TRUE
;
244 ProbeForRead(SourceAddress
, BufferSize
, sizeof(CHAR
));
249 FailedInProbe
= FALSE
;
253 // Initialize and probe and lock the MDL
255 MmInitializeMdl(Mdl
, CurrentAddress
, CurrentSize
);
256 MmProbeAndLockPages(Mdl
, PreviousMode
, IoReadAccess
);
262 MdlAddress
= MmMapLockedPagesSpecifyCache(Mdl
,
271 // Use our SEH handler to pick this up
273 FailedInMapping
= TRUE
;
274 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES
);
278 // Now let go of the source and grab to the target process
280 KeUnstackDetachProcess(&ApcState
);
281 KeStackAttachProcess(&TargetProcess
->Pcb
, &ApcState
);
284 // Check if this is our first time through
286 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
289 // Catch a failure here
291 FailedInProbe
= TRUE
;
296 ProbeForWrite(TargetAddress
, BufferSize
, sizeof(CHAR
));
301 FailedInProbe
= FALSE
;
305 // Now do the actual move
307 FailedInMoving
= TRUE
;
308 RtlCopyMemory(CurrentTargetAddress
, MdlAddress
, CurrentSize
);
310 _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(),
315 // Detach from whoever we may be attached to
317 KeUnstackDetachProcess(&ApcState
);
320 // Check if we had mapped the pages
322 if (MdlAddress
) MmUnmapLockedPages(MdlAddress
, Mdl
);
325 // Check if we had locked the pages
327 if (PagesLocked
) MmUnlockPages(Mdl
);
330 // Check if we hit working set quota
332 if (_SEH2_GetExceptionCode() == STATUS_WORKING_SET_QUOTA
)
337 return STATUS_WORKING_SET_QUOTA
;
341 // Check if we failed during the probe or mapping
343 if ((FailedInProbe
) || (FailedInMapping
))
348 Status
= _SEH2_GetExceptionCode();
349 _SEH2_YIELD(return Status
);
353 // Otherwise, we failed probably during the move
355 *ReturnSize
= BufferSize
- RemainingSize
;
359 // Check if we know exactly where we stopped copying
364 // Return the exact number of bytes copied
366 *ReturnSize
= BadAddress
- (ULONG_PTR
)SourceAddress
;
371 // Return partial copy
373 Status
= STATUS_PARTIAL_COPY
;
378 // Check for SEH status
380 if (Status
!= STATUS_SUCCESS
) return Status
;
383 // Detach from target
385 KeUnstackDetachProcess(&ApcState
);
390 MmUnmapLockedPages(MdlAddress
, Mdl
);
394 // Update location and size
396 RemainingSize
-= CurrentSize
;
397 CurrentAddress
= (PVOID
)((ULONG_PTR
)CurrentAddress
+ CurrentSize
);
398 CurrentTargetAddress
= (PVOID
)((ULONG_PTR
)CurrentTargetAddress
+ CurrentSize
);
404 *ReturnSize
= BufferSize
;
405 return STATUS_SUCCESS
;
410 MiDoPoolCopy(IN PEPROCESS SourceProcess
,
411 IN PVOID SourceAddress
,
412 IN PEPROCESS TargetProcess
,
413 OUT PVOID TargetAddress
,
414 IN SIZE_T BufferSize
,
415 IN KPROCESSOR_MODE PreviousMode
,
416 OUT PSIZE_T ReturnSize
)
418 UCHAR StackBuffer
[MI_POOL_COPY_BYTES
];
419 SIZE_T TotalSize
, CurrentSize
, RemainingSize
;
420 volatile BOOLEAN FailedInProbe
= FALSE
, FailedInMoving
, HavePoolAddress
= FALSE
;
421 PVOID CurrentAddress
= SourceAddress
, CurrentTargetAddress
= TargetAddress
;
424 BOOLEAN HaveBadAddress
;
425 ULONG_PTR BadAddress
;
426 NTSTATUS Status
= STATUS_SUCCESS
;
430 // Calculate the maximum amount of data to move
432 TotalSize
= MI_MAX_TRANSFER_SIZE
;
433 if (BufferSize
<= MI_MAX_TRANSFER_SIZE
) TotalSize
= BufferSize
;
434 CurrentSize
= TotalSize
;
435 RemainingSize
= BufferSize
;
438 // Check if we can use the stack
440 if (BufferSize
<= MI_POOL_COPY_BYTES
)
445 PoolAddress
= (PVOID
)StackBuffer
;
452 PoolAddress
= ExAllocatePoolWithTag(NonPagedPool
, TotalSize
, 'VmRw');
453 if (!PoolAddress
) ASSERT(FALSE
);
454 HavePoolAddress
= TRUE
;
458 // Loop as long as there is still data
460 while (RemainingSize
> 0)
463 // Check if this transfer will finish everything off
465 if (RemainingSize
< CurrentSize
) CurrentSize
= RemainingSize
;
468 // Attach to the source address space
470 KeStackAttachProcess(&SourceProcess
->Pcb
, &ApcState
);
473 // Reset state for this pass
475 FailedInMoving
= FALSE
;
476 ASSERT(FailedInProbe
== FALSE
);
479 // Protect user-mode copy
484 // If this is our first time, probe the buffer
486 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
489 // Catch a failure here
491 FailedInProbe
= TRUE
;
496 ProbeForRead(SourceAddress
, BufferSize
, sizeof(CHAR
));
501 FailedInProbe
= FALSE
;
507 RtlCopyMemory(PoolAddress
, CurrentAddress
, CurrentSize
);
510 // Now let go of the source and grab to the target process
512 KeUnstackDetachProcess(&ApcState
);
513 KeStackAttachProcess(&TargetProcess
->Pcb
, &ApcState
);
516 // Check if this is our first time through
518 if ((CurrentAddress
== SourceAddress
) && (PreviousMode
!= KernelMode
))
521 // Catch a failure here
523 FailedInProbe
= TRUE
;
528 ProbeForWrite(TargetAddress
, BufferSize
, sizeof(CHAR
));
533 FailedInProbe
= FALSE
;
537 // Now do the actual move
539 FailedInMoving
= TRUE
;
540 RtlCopyMemory(CurrentTargetAddress
, PoolAddress
, CurrentSize
);
542 _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(),
547 // Detach from whoever we may be attached to
549 KeUnstackDetachProcess(&ApcState
);
552 // Check if we had allocated pool
554 if (HavePoolAddress
) ExFreePool(PoolAddress
);
557 // Check if we failed during the probe
564 Status
= _SEH2_GetExceptionCode();
565 _SEH2_YIELD(return Status
);
569 // Otherwise, we failed, probably during the move
571 *ReturnSize
= BufferSize
- RemainingSize
;
575 // Check if we know exactly where we stopped copying
580 // Return the exact number of bytes copied
582 *ReturnSize
= BadAddress
- (ULONG_PTR
)SourceAddress
;
587 // Return partial copy
589 Status
= STATUS_PARTIAL_COPY
;
594 // Check for SEH status
596 if (Status
!= STATUS_SUCCESS
) return Status
;
599 // Detach from target
601 KeUnstackDetachProcess(&ApcState
);
604 // Update location and size
606 RemainingSize
-= CurrentSize
;
607 CurrentAddress
= (PVOID
)((ULONG_PTR
)CurrentAddress
+ CurrentSize
);
608 CurrentTargetAddress
= (PVOID
)((ULONG_PTR
)CurrentTargetAddress
+
613 // Check if we had allocated pool
615 if (HavePoolAddress
) ExFreePool(PoolAddress
);
620 *ReturnSize
= BufferSize
;
621 return STATUS_SUCCESS
;
626 MmCopyVirtualMemory(IN PEPROCESS SourceProcess
,
627 IN PVOID SourceAddress
,
628 IN PEPROCESS TargetProcess
,
629 OUT PVOID TargetAddress
,
630 IN SIZE_T BufferSize
,
631 IN KPROCESSOR_MODE PreviousMode
,
632 OUT PSIZE_T ReturnSize
)
635 PEPROCESS Process
= SourceProcess
;
638 // Don't accept zero-sized buffers
640 if (!BufferSize
) return STATUS_SUCCESS
;
643 // If we are copying from ourselves, lock the target instead
645 if (SourceProcess
== PsGetCurrentProcess()) Process
= TargetProcess
;
648 // Acquire rundown protection
650 if (!ExAcquireRundownProtection(&Process
->RundownProtect
))
655 return STATUS_PROCESS_IS_TERMINATING
;
659 // See if we should use the pool copy
661 if (BufferSize
> MI_POOL_COPY_BYTES
)
666 Status
= MiDoMappedCopy(SourceProcess
,
679 Status
= MiDoPoolCopy(SourceProcess
,
691 ExReleaseRundownProtection(&Process
->RundownProtect
);
697 MmFlushVirtualMemory(IN PEPROCESS Process
,
698 IN OUT PVOID
*BaseAddress
,
699 IN OUT PSIZE_T RegionSize
,
700 OUT PIO_STATUS_BLOCK IoStatusBlock
)
708 return STATUS_SUCCESS
;
711 /* PUBLIC FUNCTIONS ***********************************************************/
718 MmGetVirtualForPhysical(IN PHYSICAL_ADDRESS PhysicalAddress
)
729 MmSecureVirtualMemory(IN PVOID Address
,
733 static BOOLEAN Warn
; if (!Warn
++) UNIMPLEMENTED
;
742 MmUnsecureVirtualMemory(IN PVOID SecureMem
)
744 static BOOLEAN Warn
; if (!Warn
++) UNIMPLEMENTED
;
747 /* SYSTEM CALLS ***************************************************************/
751 NtReadVirtualMemory(IN HANDLE ProcessHandle
,
752 IN PVOID BaseAddress
,
754 IN SIZE_T NumberOfBytesToRead
,
755 OUT PSIZE_T NumberOfBytesRead OPTIONAL
)
757 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
759 NTSTATUS Status
= STATUS_SUCCESS
;
760 SIZE_T BytesRead
= 0;
764 // Check if we came from user mode
766 if (PreviousMode
!= KernelMode
)
769 // Validate the read addresses
771 if ((((ULONG_PTR
)BaseAddress
+ NumberOfBytesToRead
) < (ULONG_PTR
)BaseAddress
) ||
772 (((ULONG_PTR
)Buffer
+ NumberOfBytesToRead
) < (ULONG_PTR
)Buffer
) ||
773 (((ULONG_PTR
)BaseAddress
+ NumberOfBytesToRead
) > MmUserProbeAddress
) ||
774 (((ULONG_PTR
)Buffer
+ NumberOfBytesToRead
) > MmUserProbeAddress
))
777 // Don't allow to write into kernel space
779 return STATUS_ACCESS_VIOLATION
;
783 // Enter SEH for probe
788 // Probe the output value
790 if (NumberOfBytesRead
) ProbeForWriteSize_t(NumberOfBytesRead
);
792 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
795 // Get exception code
797 _SEH2_YIELD(return _SEH2_GetExceptionCode());
803 // Don't do zero-byte transfers
805 if (NumberOfBytesToRead
)
808 // Reference the process
810 Status
= ObReferenceObjectByHandle(ProcessHandle
,
816 if (NT_SUCCESS(Status
))
821 Status
= MmCopyVirtualMemory(Process
,
823 PsGetCurrentProcess(),
830 // Dereference the process
832 ObDereferenceObject(Process
);
837 // Check if the caller sent this parameter
839 if (NumberOfBytesRead
)
842 // Enter SEH to guard write
847 // Return the number of bytes read
849 *NumberOfBytesRead
= BytesRead
;
851 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
865 NtWriteVirtualMemory(IN HANDLE ProcessHandle
,
866 IN PVOID BaseAddress
,
868 IN SIZE_T NumberOfBytesToWrite
,
869 OUT PSIZE_T NumberOfBytesWritten OPTIONAL
)
871 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
873 NTSTATUS Status
= STATUS_SUCCESS
;
874 SIZE_T BytesWritten
= 0;
878 // Check if we came from user mode
880 if (PreviousMode
!= KernelMode
)
883 // Validate the read addresses
885 if ((((ULONG_PTR
)BaseAddress
+ NumberOfBytesToWrite
) < (ULONG_PTR
)BaseAddress
) ||
886 (((ULONG_PTR
)Buffer
+ NumberOfBytesToWrite
) < (ULONG_PTR
)Buffer
) ||
887 (((ULONG_PTR
)BaseAddress
+ NumberOfBytesToWrite
) > MmUserProbeAddress
) ||
888 (((ULONG_PTR
)Buffer
+ NumberOfBytesToWrite
) > MmUserProbeAddress
))
891 // Don't allow to write into kernel space
893 return STATUS_ACCESS_VIOLATION
;
897 // Enter SEH for probe
902 // Probe the output value
904 if (NumberOfBytesWritten
) ProbeForWriteSize_t(NumberOfBytesWritten
);
906 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
909 // Get exception code
911 _SEH2_YIELD(return _SEH2_GetExceptionCode());
917 // Don't do zero-byte transfers
919 if (NumberOfBytesToWrite
)
922 // Reference the process
924 Status
= ObReferenceObjectByHandle(ProcessHandle
,
930 if (NT_SUCCESS(Status
))
935 Status
= MmCopyVirtualMemory(PsGetCurrentProcess(),
939 NumberOfBytesToWrite
,
944 // Dereference the process
946 ObDereferenceObject(Process
);
951 // Check if the caller sent this parameter
953 if (NumberOfBytesWritten
)
956 // Enter SEH to guard write
961 // Return the number of bytes written
963 *NumberOfBytesWritten
= BytesWritten
;
965 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
979 NtProtectVirtualMemory(IN HANDLE ProcessHandle
,
980 IN OUT PVOID
*UnsafeBaseAddress
,
981 IN OUT SIZE_T
*UnsafeNumberOfBytesToProtect
,
982 IN ULONG NewAccessProtection
,
983 OUT PULONG UnsafeOldAccessProtection
)
986 ULONG OldAccessProtection
;
988 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
989 PVOID BaseAddress
= NULL
;
990 SIZE_T NumberOfBytesToProtect
= 0;
991 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
993 BOOLEAN Attached
= FALSE
;
998 // Check for valid protection flags
1000 Protection
= NewAccessProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
1001 if (Protection
!= PAGE_NOACCESS
&&
1002 Protection
!= PAGE_READONLY
&&
1003 Protection
!= PAGE_READWRITE
&&
1004 Protection
!= PAGE_WRITECOPY
&&
1005 Protection
!= PAGE_EXECUTE
&&
1006 Protection
!= PAGE_EXECUTE_READ
&&
1007 Protection
!= PAGE_EXECUTE_READWRITE
&&
1008 Protection
!= PAGE_EXECUTE_WRITECOPY
)
1013 return STATUS_INVALID_PAGE_PROTECTION
;
1017 // Check if we came from user mode
1019 if (PreviousMode
!= KernelMode
)
1022 // Enter SEH for probing
1027 // Validate all outputs
1029 ProbeForWritePointer(UnsafeBaseAddress
);
1030 ProbeForWriteSize_t(UnsafeNumberOfBytesToProtect
);
1031 ProbeForWriteUlong(UnsafeOldAccessProtection
);
1036 BaseAddress
= *UnsafeBaseAddress
;
1037 NumberOfBytesToProtect
= *UnsafeNumberOfBytesToProtect
;
1039 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1042 // Get exception code
1044 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1053 BaseAddress
= *UnsafeBaseAddress
;
1054 NumberOfBytesToProtect
= *UnsafeNumberOfBytesToProtect
;
1058 // Catch illegal base address
1060 if (BaseAddress
> MM_HIGHEST_USER_ADDRESS
) return STATUS_INVALID_PARAMETER_2
;
1063 // Catch illegal region size
1065 if ((MmUserProbeAddress
- (ULONG_PTR
)BaseAddress
) < NumberOfBytesToProtect
)
1070 return STATUS_INVALID_PARAMETER_3
;
1074 // 0 is also illegal
1076 if (!NumberOfBytesToProtect
) return STATUS_INVALID_PARAMETER_3
;
1079 // Get a reference to the process
1081 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1082 PROCESS_VM_OPERATION
,
1087 if (!NT_SUCCESS(Status
)) return Status
;
1090 // Check if we should attach
1092 if (CurrentProcess
!= Process
)
1097 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
1102 // Do the actual work
1104 Status
= MiProtectVirtualMemory(Process
,
1106 &NumberOfBytesToProtect
,
1107 NewAccessProtection
,
1108 &OldAccessProtection
);
1113 if (Attached
) KeUnstackDetachProcess(&ApcState
);
1116 // Release reference
1118 ObDereferenceObject(Process
);
1121 // Enter SEH to return data
1126 // Return data to user
1128 *UnsafeOldAccessProtection
= OldAccessProtection
;
1129 *UnsafeBaseAddress
= BaseAddress
;
1130 *UnsafeNumberOfBytesToProtect
= NumberOfBytesToProtect
;
1132 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1145 NtLockVirtualMemory(IN HANDLE ProcessHandle
,
1146 IN OUT PVOID
*BaseAddress
,
1147 IN OUT PSIZE_T NumberOfBytesToLock
,
1151 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
1153 BOOLEAN Attached
= FALSE
;
1154 KAPC_STATE ApcState
;
1155 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1156 PVOID CapturedBaseAddress
;
1157 SIZE_T CapturedBytesToLock
;
1163 if ((MapType
& ~(MAP_PROCESS
| MAP_SYSTEM
)))
1166 // Invalid set of flags
1168 return STATUS_INVALID_PARAMETER
;
1172 // At least one flag must be specified
1174 if (!(MapType
& (MAP_PROCESS
| MAP_SYSTEM
)))
1179 return STATUS_INVALID_PARAMETER
;
1183 // Enter SEH for probing
1188 // Validate output data
1190 ProbeForWritePointer(BaseAddress
);
1191 ProbeForWriteSize_t(NumberOfBytesToLock
);
1196 CapturedBaseAddress
= *BaseAddress
;
1197 CapturedBytesToLock
= *NumberOfBytesToLock
;
1199 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1202 // Get exception code
1204 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1209 // Catch illegal base address
1211 if (CapturedBaseAddress
> MM_HIGHEST_USER_ADDRESS
) return STATUS_INVALID_PARAMETER
;
1214 // Catch illegal region size
1216 if ((MmUserProbeAddress
- (ULONG_PTR
)CapturedBaseAddress
) < CapturedBytesToLock
)
1221 return STATUS_INVALID_PARAMETER
;
1225 // 0 is also illegal
1227 if (!CapturedBytesToLock
) return STATUS_INVALID_PARAMETER
;
1230 // Get a reference to the process
1232 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1233 PROCESS_VM_OPERATION
,
1238 if (!NT_SUCCESS(Status
)) return Status
;
1241 // Check if this is is system-mapped
1243 if (MapType
& MAP_SYSTEM
)
1246 // Check for required privilege
1248 if (!SeSinglePrivilegeCheck(SeLockMemoryPrivilege
, PreviousMode
))
1251 // Fail: Don't have it
1253 ObDereferenceObject(Process
);
1254 return STATUS_PRIVILEGE_NOT_HELD
;
1259 // Check if we should attach
1261 if (CurrentProcess
!= Process
)
1266 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
1278 if (Attached
) KeUnstackDetachProcess(&ApcState
);
1281 // Release reference
1283 ObDereferenceObject(Process
);
1286 // Enter SEH to return data
1291 // Return data to user
1293 *BaseAddress
= CapturedBaseAddress
;
1294 *NumberOfBytesToLock
= 0;
1296 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1299 // Get exception code
1301 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1308 return STATUS_SUCCESS
;
1313 NtUnlockVirtualMemory(IN HANDLE ProcessHandle
,
1314 IN OUT PVOID
*BaseAddress
,
1315 IN OUT PSIZE_T NumberOfBytesToUnlock
,
1319 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
1321 BOOLEAN Attached
= FALSE
;
1322 KAPC_STATE ApcState
;
1323 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1324 PVOID CapturedBaseAddress
;
1325 SIZE_T CapturedBytesToUnlock
;
1331 if ((MapType
& ~(MAP_PROCESS
| MAP_SYSTEM
)))
1334 // Invalid set of flags
1336 return STATUS_INVALID_PARAMETER
;
1340 // At least one flag must be specified
1342 if (!(MapType
& (MAP_PROCESS
| MAP_SYSTEM
)))
1347 return STATUS_INVALID_PARAMETER
;
1351 // Enter SEH for probing
1356 // Validate output data
1358 ProbeForWritePointer(BaseAddress
);
1359 ProbeForWriteSize_t(NumberOfBytesToUnlock
);
1364 CapturedBaseAddress
= *BaseAddress
;
1365 CapturedBytesToUnlock
= *NumberOfBytesToUnlock
;
1367 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1370 // Get exception code
1372 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1377 // Catch illegal base address
1379 if (CapturedBaseAddress
> MM_HIGHEST_USER_ADDRESS
) return STATUS_INVALID_PARAMETER
;
1382 // Catch illegal region size
1384 if ((MmUserProbeAddress
- (ULONG_PTR
)CapturedBaseAddress
) < CapturedBytesToUnlock
)
1389 return STATUS_INVALID_PARAMETER
;
1393 // 0 is also illegal
1395 if (!CapturedBytesToUnlock
) return STATUS_INVALID_PARAMETER
;
1398 // Get a reference to the process
1400 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1401 PROCESS_VM_OPERATION
,
1406 if (!NT_SUCCESS(Status
)) return Status
;
1409 // Check if this is is system-mapped
1411 if (MapType
& MAP_SYSTEM
)
1414 // Check for required privilege
1416 if (!SeSinglePrivilegeCheck(SeLockMemoryPrivilege
, PreviousMode
))
1419 // Fail: Don't have it
1421 ObDereferenceObject(Process
);
1422 return STATUS_PRIVILEGE_NOT_HELD
;
1427 // Check if we should attach
1429 if (CurrentProcess
!= Process
)
1434 KeStackAttachProcess(&Process
->Pcb
, &ApcState
);
1446 if (Attached
) KeUnstackDetachProcess(&ApcState
);
1449 // Release reference
1451 ObDereferenceObject(Process
);
1454 // Enter SEH to return data
1459 // Return data to user
1461 *BaseAddress
= PAGE_ALIGN(CapturedBaseAddress
);
1462 *NumberOfBytesToUnlock
= 0;
1464 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1467 // Get exception code
1469 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1476 return STATUS_SUCCESS
;
1481 NtFlushVirtualMemory(IN HANDLE ProcessHandle
,
1482 IN OUT PVOID
*BaseAddress
,
1483 IN OUT PSIZE_T NumberOfBytesToFlush
,
1484 OUT PIO_STATUS_BLOCK IoStatusBlock
)
1488 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1489 PVOID CapturedBaseAddress
;
1490 SIZE_T CapturedBytesToFlush
;
1491 IO_STATUS_BLOCK LocalStatusBlock
;
1495 // Check if we came from user mode
1497 if (PreviousMode
!= KernelMode
)
1500 // Enter SEH for probing
1505 // Validate all outputs
1507 ProbeForWritePointer(BaseAddress
);
1508 ProbeForWriteSize_t(NumberOfBytesToFlush
);
1509 ProbeForWriteIoStatusBlock(IoStatusBlock
);
1514 CapturedBaseAddress
= *BaseAddress
;
1515 CapturedBytesToFlush
= *NumberOfBytesToFlush
;
1517 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1520 // Get exception code
1522 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1531 CapturedBaseAddress
= *BaseAddress
;
1532 CapturedBytesToFlush
= *NumberOfBytesToFlush
;
1536 // Catch illegal base address
1538 if (CapturedBaseAddress
> MM_HIGHEST_USER_ADDRESS
) return STATUS_INVALID_PARAMETER
;
1541 // Catch illegal region size
1543 if ((MmUserProbeAddress
- (ULONG_PTR
)CapturedBaseAddress
) < CapturedBytesToFlush
)
1548 return STATUS_INVALID_PARAMETER
;
1552 // Get a reference to the process
1554 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1555 PROCESS_VM_OPERATION
,
1560 if (!NT_SUCCESS(Status
)) return Status
;
1565 Status
= MmFlushVirtualMemory(Process
,
1566 &CapturedBaseAddress
,
1567 &CapturedBytesToFlush
,
1571 // Release reference
1573 ObDereferenceObject(Process
);
1576 // Enter SEH to return data
1581 // Return data to user
1583 *BaseAddress
= PAGE_ALIGN(CapturedBaseAddress
);
1584 *NumberOfBytesToFlush
= 0;
1585 *IoStatusBlock
= LocalStatusBlock
;
1587 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1603 NtGetWriteWatch(IN HANDLE ProcessHandle
,
1605 IN PVOID BaseAddress
,
1606 IN SIZE_T RegionSize
,
1607 IN PVOID
*UserAddressArray
,
1608 OUT PULONG_PTR EntriesInUserAddressArray
,
1609 OUT PULONG Granularity
)
1614 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1615 ULONG_PTR CapturedEntryCount
;
1619 // Check if we came from user mode
1621 if (PreviousMode
!= KernelMode
)
1624 // Enter SEH for probing
1629 // Catch illegal base address
1631 if (BaseAddress
> MM_HIGHEST_USER_ADDRESS
) return STATUS_INVALID_PARAMETER_2
;
1634 // Catch illegal region size
1636 if ((MmUserProbeAddress
- (ULONG_PTR
)BaseAddress
) < RegionSize
)
1641 return STATUS_INVALID_PARAMETER_3
;
1645 // Validate all data
1647 ProbeForWriteSize_t(EntriesInUserAddressArray
);
1648 ProbeForWriteUlong(Granularity
);
1653 CapturedEntryCount
= *EntriesInUserAddressArray
;
1656 // Must have a count
1658 if (CapturedEntryCount
== 0) return STATUS_INVALID_PARAMETER_5
;
1661 // Can't be larger than the maximum
1663 if (CapturedEntryCount
> (MAXULONG_PTR
/ sizeof(ULONG_PTR
)))
1668 return STATUS_INVALID_PARAMETER_5
;
1672 // Probe the actual array
1674 ProbeForWrite(UserAddressArray
,
1675 CapturedEntryCount
* sizeof(PVOID
),
1678 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1681 // Get exception code
1683 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1692 CapturedEntryCount
= *EntriesInUserAddressArray
;
1693 ASSERT(CapturedEntryCount
!= 0);
1697 // Check if this is a local request
1699 if (ProcessHandle
== NtCurrentProcess())
1702 // No need to reference the process
1704 Process
= PsGetCurrentProcess();
1709 // Reference the target
1711 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1712 PROCESS_VM_OPERATION
,
1717 if (!NT_SUCCESS(Status
)) return Status
;
1721 // Compute the last address and validate it
1723 EndAddress
= (PVOID
)((ULONG_PTR
)BaseAddress
+ RegionSize
- 1);
1724 if (BaseAddress
> EndAddress
)
1729 if (ProcessHandle
!= NtCurrentProcess()) ObDereferenceObject(Process
);
1730 return STATUS_INVALID_PARAMETER_4
;
1739 // Dereference if needed
1741 if (ProcessHandle
!= NtCurrentProcess()) ObDereferenceObject(Process
);
1744 // Enter SEH to return data
1749 // Return data to user
1751 *EntriesInUserAddressArray
= 0;
1752 *Granularity
= PAGE_SIZE
;
1754 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1757 // Get exception code
1759 Status
= _SEH2_GetExceptionCode();
1766 return STATUS_SUCCESS
;
1774 NtResetWriteWatch(IN HANDLE ProcessHandle
,
1775 IN PVOID BaseAddress
,
1776 IN SIZE_T RegionSize
)
1781 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1782 ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL
);
1785 // Catch illegal base address
1787 if (BaseAddress
> MM_HIGHEST_USER_ADDRESS
) return STATUS_INVALID_PARAMETER_2
;
1790 // Catch illegal region size
1792 if ((MmUserProbeAddress
- (ULONG_PTR
)BaseAddress
) < RegionSize
)
1797 return STATUS_INVALID_PARAMETER_3
;
1801 // Check if this is a local request
1803 if (ProcessHandle
== NtCurrentProcess())
1806 // No need to reference the process
1808 Process
= PsGetCurrentProcess();
1813 // Reference the target
1815 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1816 PROCESS_VM_OPERATION
,
1821 if (!NT_SUCCESS(Status
)) return Status
;
1825 // Compute the last address and validate it
1827 EndAddress
= (PVOID
)((ULONG_PTR
)BaseAddress
+ RegionSize
- 1);
1828 if (BaseAddress
> EndAddress
)
1833 if (ProcessHandle
!= NtCurrentProcess()) ObDereferenceObject(Process
);
1834 return STATUS_INVALID_PARAMETER_3
;
1843 // Dereference if needed
1845 if (ProcessHandle
!= NtCurrentProcess()) ObDereferenceObject(Process
);
1850 return STATUS_SUCCESS
;