Sync with trunk (48237)
[reactos.git] / ntoskrnl / mm / ARM3 / virtual.c
1 /*
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
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 #line 15 "ARMĀ³::VIRTUAL"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
18
19 #define MI_MAPPED_COPY_PAGES 14
20 #define MI_POOL_COPY_BYTES 512
21 #define MI_MAX_TRANSFER_SIZE 64 * 1024
22
23 NTSTATUS NTAPI
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);
29
30 /* PRIVATE FUNCTIONS **********************************************************/
31
32 PFN_NUMBER
33 NTAPI
34 MiDeleteSystemPageableVm(IN PMMPTE PointerPte,
35 IN PFN_NUMBER PageCount,
36 IN ULONG Flags,
37 OUT PPFN_NUMBER ValidPages)
38 {
39 PFN_NUMBER ActualPages = 0;
40 PETHREAD CurrentThread = PsGetCurrentThread();
41 PMMPFN Pfn1, Pfn2;
42 PFN_NUMBER PageFrameIndex, PageTableIndex;
43 KIRQL OldIrql;
44 ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
45
46 /* Lock the system working set */
47 MiLockWorkingSet(CurrentThread, &MmSystemCacheWs);
48
49 /* Loop all pages */
50 while (PageCount)
51 {
52 /* Make sure there's some data about the page */
53 if (PointerPte->u.Long)
54 {
55 /* As always, only handle current ARM3 scenarios */
56 ASSERT(PointerPte->u.Soft.Prototype == 0);
57 ASSERT(PointerPte->u.Soft.Transition == 0);
58
59 /* Normally this is one possibility -- freeing a valid page */
60 if (PointerPte->u.Hard.Valid)
61 {
62 /* Get the page PFN */
63 PageFrameIndex = PFN_FROM_PTE(PointerPte);
64 Pfn1 = MiGetPfnEntry(PageFrameIndex);
65
66 /* Should not have any working set data yet */
67 ASSERT(Pfn1->u1.WsIndex == 0);
68
69 /* Actual valid, legitimate, pages */
70 if (ValidPages) *ValidPages++;
71
72 /* Get the page table entry */
73 PageTableIndex = Pfn1->u4.PteFrame;
74 Pfn2 = MiGetPfnEntry(PageTableIndex);
75
76 /* Lock the PFN database */
77 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
78
79 /* Delete it the page */
80 MI_SET_PFN_DELETED(Pfn1);
81 MiDecrementShareCount(Pfn1, PageFrameIndex);
82
83 /* Decrement the page table too */
84 #if 0 // ARM3: Dont't trust this yet
85 MiDecrementShareCount(Pfn2, PageTableIndex);
86 #endif
87
88 /* Release the PFN database */
89 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
90
91 /* Destroy the PTE */
92 PointerPte->u.Long = 0;
93 }
94
95 /* Actual legitimate pages */
96 ActualPages++;
97 }
98 else
99 {
100 /*
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.
104 *
105 * Right now, we shouldn't expect any page file information in the PTE
106 */
107 ASSERT(PointerPte->u.Soft.PageFileHigh == 0);
108
109 /* Destroy the PTE */
110 PointerPte->u.Long = 0;
111 }
112
113 /* Keep going */
114 PointerPte++;
115 PageCount--;
116 }
117
118 /* Release the working set */
119 MiUnlockWorkingSet(CurrentThread, &MmSystemCacheWs);
120
121 /* Flush the entire TLB */
122 KeFlushEntireTb(TRUE, TRUE);
123
124 /* Done */
125 return ActualPages;
126 }
127
128 LONG
129 MiGetExceptionInfo(IN PEXCEPTION_POINTERS ExceptionInfo,
130 OUT PBOOLEAN HaveBadAddress,
131 OUT PULONG_PTR BadAddress)
132 {
133 PEXCEPTION_RECORD ExceptionRecord;
134 PAGED_CODE();
135
136 //
137 // Assume default
138 //
139 *HaveBadAddress = FALSE;
140
141 //
142 // Get the exception record
143 //
144 ExceptionRecord = ExceptionInfo->ExceptionRecord;
145
146 //
147 // Look at the exception code
148 //
149 if ((ExceptionRecord->ExceptionCode == STATUS_ACCESS_VIOLATION) ||
150 (ExceptionRecord->ExceptionCode == STATUS_GUARD_PAGE_VIOLATION) ||
151 (ExceptionRecord->ExceptionCode == STATUS_IN_PAGE_ERROR))
152 {
153 //
154 // We can tell the address if we have more than one parameter
155 //
156 if (ExceptionRecord->NumberParameters > 1)
157 {
158 //
159 // Return the address
160 //
161 *HaveBadAddress = TRUE;
162 *BadAddress = ExceptionRecord->ExceptionInformation[1];
163 }
164 }
165
166 //
167 // Continue executing the next handler
168 //
169 return EXCEPTION_EXECUTE_HANDLER;
170 }
171
172 NTSTATUS
173 NTAPI
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)
181 {
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;
189 KAPC_STATE ApcState;
190 BOOLEAN HaveBadAddress;
191 ULONG_PTR BadAddress;
192 NTSTATUS Status = STATUS_SUCCESS;
193 PAGED_CODE();
194
195 //
196 // Calculate the maximum amount of data to move
197 //
198 TotalSize = MI_MAPPED_COPY_PAGES * PAGE_SIZE;
199 if (BufferSize <= TotalSize) TotalSize = BufferSize;
200 CurrentSize = TotalSize;
201 RemainingSize = BufferSize;
202
203 //
204 // Loop as long as there is still data
205 //
206 while (RemainingSize > 0)
207 {
208 //
209 // Check if this transfer will finish everything off
210 //
211 if (RemainingSize < CurrentSize) CurrentSize = RemainingSize;
212
213 //
214 // Attach to the source address space
215 //
216 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
217
218 //
219 // Reset state for this pass
220 //
221 MdlAddress = NULL;
222 PagesLocked = FALSE;
223 FailedInMoving = FALSE;
224 ASSERT(FailedInProbe == FALSE);
225
226 //
227 // Protect user-mode copy
228 //
229 _SEH2_TRY
230 {
231 //
232 // If this is our first time, probe the buffer
233 //
234 if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
235 {
236 //
237 // Catch a failure here
238 //
239 FailedInProbe = TRUE;
240
241 //
242 // Do the probe
243 //
244 ProbeForRead(SourceAddress, BufferSize, sizeof(CHAR));
245
246 //
247 // Passed
248 //
249 FailedInProbe = FALSE;
250 }
251
252 //
253 // Initialize and probe and lock the MDL
254 //
255 MmInitializeMdl(Mdl, CurrentAddress, CurrentSize);
256 MmProbeAndLockPages(Mdl, PreviousMode, IoReadAccess);
257 PagesLocked = TRUE;
258
259 //
260 // Now map the pages
261 //
262 MdlAddress = MmMapLockedPagesSpecifyCache(Mdl,
263 KernelMode,
264 MmCached,
265 NULL,
266 FALSE,
267 HighPagePriority);
268 if (!MdlAddress)
269 {
270 //
271 // Use our SEH handler to pick this up
272 //
273 FailedInMapping = TRUE;
274 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
275 }
276
277 //
278 // Now let go of the source and grab to the target process
279 //
280 KeUnstackDetachProcess(&ApcState);
281 KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
282
283 //
284 // Check if this is our first time through
285 //
286 if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
287 {
288 //
289 // Catch a failure here
290 //
291 FailedInProbe = TRUE;
292
293 //
294 // Do the probe
295 //
296 ProbeForWrite(TargetAddress, BufferSize, sizeof(CHAR));
297
298 //
299 // Passed
300 //
301 FailedInProbe = FALSE;
302 }
303
304 //
305 // Now do the actual move
306 //
307 FailedInMoving = TRUE;
308 RtlCopyMemory(CurrentTargetAddress, MdlAddress, CurrentSize);
309 }
310 _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(),
311 &HaveBadAddress,
312 &BadAddress))
313 {
314 //
315 // Detach from whoever we may be attached to
316 //
317 KeUnstackDetachProcess(&ApcState);
318
319 //
320 // Check if we had mapped the pages
321 //
322 if (MdlAddress) MmUnmapLockedPages(MdlAddress, Mdl);
323
324 //
325 // Check if we had locked the pages
326 //
327 if (PagesLocked) MmUnlockPages(Mdl);
328
329 //
330 // Check if we hit working set quota
331 //
332 if (_SEH2_GetExceptionCode() == STATUS_WORKING_SET_QUOTA)
333 {
334 //
335 // Return the error
336 //
337 return STATUS_WORKING_SET_QUOTA;
338 }
339
340 //
341 // Check if we failed during the probe or mapping
342 //
343 if ((FailedInProbe) || (FailedInMapping))
344 {
345 //
346 // Exit
347 //
348 Status = _SEH2_GetExceptionCode();
349 _SEH2_YIELD(return Status);
350 }
351
352 //
353 // Otherwise, we failed probably during the move
354 //
355 *ReturnSize = BufferSize - RemainingSize;
356 if (FailedInMoving)
357 {
358 //
359 // Check if we know exactly where we stopped copying
360 //
361 if (HaveBadAddress)
362 {
363 //
364 // Return the exact number of bytes copied
365 //
366 *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
367 }
368 }
369
370 //
371 // Return partial copy
372 //
373 Status = STATUS_PARTIAL_COPY;
374 }
375 _SEH2_END;
376
377 //
378 // Check for SEH status
379 //
380 if (Status != STATUS_SUCCESS) return Status;
381
382 //
383 // Detach from target
384 //
385 KeUnstackDetachProcess(&ApcState);
386
387 //
388 // Unmap and unlock
389 //
390 MmUnmapLockedPages(MdlAddress, Mdl);
391 MmUnlockPages(Mdl);
392
393 //
394 // Update location and size
395 //
396 RemainingSize -= CurrentSize;
397 CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize);
398 CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress + CurrentSize);
399 }
400
401 //
402 // All bytes read
403 //
404 *ReturnSize = BufferSize;
405 return STATUS_SUCCESS;
406 }
407
408 NTSTATUS
409 NTAPI
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)
417 {
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;
422 PVOID PoolAddress;
423 KAPC_STATE ApcState;
424 BOOLEAN HaveBadAddress;
425 ULONG_PTR BadAddress;
426 NTSTATUS Status = STATUS_SUCCESS;
427 PAGED_CODE();
428
429 //
430 // Calculate the maximum amount of data to move
431 //
432 TotalSize = MI_MAX_TRANSFER_SIZE;
433 if (BufferSize <= MI_MAX_TRANSFER_SIZE) TotalSize = BufferSize;
434 CurrentSize = TotalSize;
435 RemainingSize = BufferSize;
436
437 //
438 // Check if we can use the stack
439 //
440 if (BufferSize <= MI_POOL_COPY_BYTES)
441 {
442 //
443 // Use it
444 //
445 PoolAddress = (PVOID)StackBuffer;
446 }
447 else
448 {
449 //
450 // Allocate pool
451 //
452 PoolAddress = ExAllocatePoolWithTag(NonPagedPool, TotalSize, 'VmRw');
453 if (!PoolAddress) ASSERT(FALSE);
454 HavePoolAddress = TRUE;
455 }
456
457 //
458 // Loop as long as there is still data
459 //
460 while (RemainingSize > 0)
461 {
462 //
463 // Check if this transfer will finish everything off
464 //
465 if (RemainingSize < CurrentSize) CurrentSize = RemainingSize;
466
467 //
468 // Attach to the source address space
469 //
470 KeStackAttachProcess(&SourceProcess->Pcb, &ApcState);
471
472 //
473 // Reset state for this pass
474 //
475 FailedInMoving = FALSE;
476 ASSERT(FailedInProbe == FALSE);
477
478 //
479 // Protect user-mode copy
480 //
481 _SEH2_TRY
482 {
483 //
484 // If this is our first time, probe the buffer
485 //
486 if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
487 {
488 //
489 // Catch a failure here
490 //
491 FailedInProbe = TRUE;
492
493 //
494 // Do the probe
495 //
496 ProbeForRead(SourceAddress, BufferSize, sizeof(CHAR));
497
498 //
499 // Passed
500 //
501 FailedInProbe = FALSE;
502 }
503
504 //
505 // Do the copy
506 //
507 RtlCopyMemory(PoolAddress, CurrentAddress, CurrentSize);
508
509 //
510 // Now let go of the source and grab to the target process
511 //
512 KeUnstackDetachProcess(&ApcState);
513 KeStackAttachProcess(&TargetProcess->Pcb, &ApcState);
514
515 //
516 // Check if this is our first time through
517 //
518 if ((CurrentAddress == SourceAddress) && (PreviousMode != KernelMode))
519 {
520 //
521 // Catch a failure here
522 //
523 FailedInProbe = TRUE;
524
525 //
526 // Do the probe
527 //
528 ProbeForWrite(TargetAddress, BufferSize, sizeof(CHAR));
529
530 //
531 // Passed
532 //
533 FailedInProbe = FALSE;
534 }
535
536 //
537 // Now do the actual move
538 //
539 FailedInMoving = TRUE;
540 RtlCopyMemory(CurrentTargetAddress, PoolAddress, CurrentSize);
541 }
542 _SEH2_EXCEPT(MiGetExceptionInfo(_SEH2_GetExceptionInformation(),
543 &HaveBadAddress,
544 &BadAddress))
545 {
546 //
547 // Detach from whoever we may be attached to
548 //
549 KeUnstackDetachProcess(&ApcState);
550
551 //
552 // Check if we had allocated pool
553 //
554 if (HavePoolAddress) ExFreePool(PoolAddress);
555
556 //
557 // Check if we failed during the probe
558 //
559 if (FailedInProbe)
560 {
561 //
562 // Exit
563 //
564 Status = _SEH2_GetExceptionCode();
565 _SEH2_YIELD(return Status);
566 }
567
568 //
569 // Otherwise, we failed, probably during the move
570 //
571 *ReturnSize = BufferSize - RemainingSize;
572 if (FailedInMoving)
573 {
574 //
575 // Check if we know exactly where we stopped copying
576 //
577 if (HaveBadAddress)
578 {
579 //
580 // Return the exact number of bytes copied
581 //
582 *ReturnSize = BadAddress - (ULONG_PTR)SourceAddress;
583 }
584 }
585
586 //
587 // Return partial copy
588 //
589 Status = STATUS_PARTIAL_COPY;
590 }
591 _SEH2_END;
592
593 //
594 // Check for SEH status
595 //
596 if (Status != STATUS_SUCCESS) return Status;
597
598 //
599 // Detach from target
600 //
601 KeUnstackDetachProcess(&ApcState);
602
603 //
604 // Update location and size
605 //
606 RemainingSize -= CurrentSize;
607 CurrentAddress = (PVOID)((ULONG_PTR)CurrentAddress + CurrentSize);
608 CurrentTargetAddress = (PVOID)((ULONG_PTR)CurrentTargetAddress +
609 CurrentSize);
610 }
611
612 //
613 // Check if we had allocated pool
614 //
615 if (HavePoolAddress) ExFreePool(PoolAddress);
616
617 //
618 // All bytes read
619 //
620 *ReturnSize = BufferSize;
621 return STATUS_SUCCESS;
622 }
623
624 NTSTATUS
625 NTAPI
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)
633 {
634 NTSTATUS Status;
635 PEPROCESS Process = SourceProcess;
636
637 //
638 // Don't accept zero-sized buffers
639 //
640 if (!BufferSize) return STATUS_SUCCESS;
641
642 //
643 // If we are copying from ourselves, lock the target instead
644 //
645 if (SourceProcess == PsGetCurrentProcess()) Process = TargetProcess;
646
647 //
648 // Acquire rundown protection
649 //
650 if (!ExAcquireRundownProtection(&Process->RundownProtect))
651 {
652 //
653 // Fail
654 //
655 return STATUS_PROCESS_IS_TERMINATING;
656 }
657
658 //
659 // See if we should use the pool copy
660 //
661 if (BufferSize > MI_POOL_COPY_BYTES)
662 {
663 //
664 // Use MDL-copy
665 //
666 Status = MiDoMappedCopy(SourceProcess,
667 SourceAddress,
668 TargetProcess,
669 TargetAddress,
670 BufferSize,
671 PreviousMode,
672 ReturnSize);
673 }
674 else
675 {
676 //
677 // Do pool copy
678 //
679 Status = MiDoPoolCopy(SourceProcess,
680 SourceAddress,
681 TargetProcess,
682 TargetAddress,
683 BufferSize,
684 PreviousMode,
685 ReturnSize);
686 }
687
688 //
689 // Release the lock
690 //
691 ExReleaseRundownProtection(&Process->RundownProtect);
692 return Status;
693 }
694
695 NTSTATUS
696 NTAPI
697 MmFlushVirtualMemory(IN PEPROCESS Process,
698 IN OUT PVOID *BaseAddress,
699 IN OUT PSIZE_T RegionSize,
700 OUT PIO_STATUS_BLOCK IoStatusBlock)
701 {
702 PAGED_CODE();
703 UNIMPLEMENTED;
704
705 //
706 // Fake success
707 //
708 return STATUS_SUCCESS;
709 }
710
711 /* PUBLIC FUNCTIONS ***********************************************************/
712
713 /*
714 * @unimplemented
715 */
716 PVOID
717 NTAPI
718 MmGetVirtualForPhysical(IN PHYSICAL_ADDRESS PhysicalAddress)
719 {
720 UNIMPLEMENTED;
721 return 0;
722 }
723
724 /*
725 * @unimplemented
726 */
727 PVOID
728 NTAPI
729 MmSecureVirtualMemory(IN PVOID Address,
730 IN SIZE_T Length,
731 IN ULONG Mode)
732 {
733 static BOOLEAN Warn; if (!Warn++) UNIMPLEMENTED;
734 return Address;
735 }
736
737 /*
738 * @unimplemented
739 */
740 VOID
741 NTAPI
742 MmUnsecureVirtualMemory(IN PVOID SecureMem)
743 {
744 static BOOLEAN Warn; if (!Warn++) UNIMPLEMENTED;
745 }
746
747 /* SYSTEM CALLS ***************************************************************/
748
749 NTSTATUS
750 NTAPI
751 NtReadVirtualMemory(IN HANDLE ProcessHandle,
752 IN PVOID BaseAddress,
753 OUT PVOID Buffer,
754 IN SIZE_T NumberOfBytesToRead,
755 OUT PSIZE_T NumberOfBytesRead OPTIONAL)
756 {
757 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
758 PEPROCESS Process;
759 NTSTATUS Status = STATUS_SUCCESS;
760 SIZE_T BytesRead = 0;
761 PAGED_CODE();
762
763 //
764 // Check if we came from user mode
765 //
766 if (PreviousMode != KernelMode)
767 {
768 //
769 // Validate the read addresses
770 //
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))
775 {
776 //
777 // Don't allow to write into kernel space
778 //
779 return STATUS_ACCESS_VIOLATION;
780 }
781
782 //
783 // Enter SEH for probe
784 //
785 _SEH2_TRY
786 {
787 //
788 // Probe the output value
789 //
790 if (NumberOfBytesRead) ProbeForWriteSize_t(NumberOfBytesRead);
791 }
792 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
793 {
794 //
795 // Get exception code
796 //
797 _SEH2_YIELD(return _SEH2_GetExceptionCode());
798 }
799 _SEH2_END;
800 }
801
802 //
803 // Don't do zero-byte transfers
804 //
805 if (NumberOfBytesToRead)
806 {
807 //
808 // Reference the process
809 //
810 Status = ObReferenceObjectByHandle(ProcessHandle,
811 PROCESS_VM_READ,
812 PsProcessType,
813 PreviousMode,
814 (PVOID*)(&Process),
815 NULL);
816 if (NT_SUCCESS(Status))
817 {
818 //
819 // Do the copy
820 //
821 Status = MmCopyVirtualMemory(Process,
822 BaseAddress,
823 PsGetCurrentProcess(),
824 Buffer,
825 NumberOfBytesToRead,
826 PreviousMode,
827 &BytesRead);
828
829 //
830 // Dereference the process
831 //
832 ObDereferenceObject(Process);
833 }
834 }
835
836 //
837 // Check if the caller sent this parameter
838 //
839 if (NumberOfBytesRead)
840 {
841 //
842 // Enter SEH to guard write
843 //
844 _SEH2_TRY
845 {
846 //
847 // Return the number of bytes read
848 //
849 *NumberOfBytesRead = BytesRead;
850 }
851 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
852 {
853 }
854 _SEH2_END;
855 }
856
857 //
858 // Return status
859 //
860 return Status;
861 }
862
863 NTSTATUS
864 NTAPI
865 NtWriteVirtualMemory(IN HANDLE ProcessHandle,
866 IN PVOID BaseAddress,
867 IN PVOID Buffer,
868 IN SIZE_T NumberOfBytesToWrite,
869 OUT PSIZE_T NumberOfBytesWritten OPTIONAL)
870 {
871 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
872 PEPROCESS Process;
873 NTSTATUS Status = STATUS_SUCCESS;
874 SIZE_T BytesWritten = 0;
875 PAGED_CODE();
876
877 //
878 // Check if we came from user mode
879 //
880 if (PreviousMode != KernelMode)
881 {
882 //
883 // Validate the read addresses
884 //
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))
889 {
890 //
891 // Don't allow to write into kernel space
892 //
893 return STATUS_ACCESS_VIOLATION;
894 }
895
896 //
897 // Enter SEH for probe
898 //
899 _SEH2_TRY
900 {
901 //
902 // Probe the output value
903 //
904 if (NumberOfBytesWritten) ProbeForWriteSize_t(NumberOfBytesWritten);
905 }
906 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
907 {
908 //
909 // Get exception code
910 //
911 _SEH2_YIELD(return _SEH2_GetExceptionCode());
912 }
913 _SEH2_END;
914 }
915
916 //
917 // Don't do zero-byte transfers
918 //
919 if (NumberOfBytesToWrite)
920 {
921 //
922 // Reference the process
923 //
924 Status = ObReferenceObjectByHandle(ProcessHandle,
925 PROCESS_VM_WRITE,
926 PsProcessType,
927 PreviousMode,
928 (PVOID*)&Process,
929 NULL);
930 if (NT_SUCCESS(Status))
931 {
932 //
933 // Do the copy
934 //
935 Status = MmCopyVirtualMemory(PsGetCurrentProcess(),
936 Buffer,
937 Process,
938 BaseAddress,
939 NumberOfBytesToWrite,
940 PreviousMode,
941 &BytesWritten);
942
943 //
944 // Dereference the process
945 //
946 ObDereferenceObject(Process);
947 }
948 }
949
950 //
951 // Check if the caller sent this parameter
952 //
953 if (NumberOfBytesWritten)
954 {
955 //
956 // Enter SEH to guard write
957 //
958 _SEH2_TRY
959 {
960 //
961 // Return the number of bytes written
962 //
963 *NumberOfBytesWritten = BytesWritten;
964 }
965 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
966 {
967 }
968 _SEH2_END;
969 }
970
971 //
972 // Return status
973 //
974 return Status;
975 }
976
977 NTSTATUS
978 NTAPI
979 NtProtectVirtualMemory(IN HANDLE ProcessHandle,
980 IN OUT PVOID *UnsafeBaseAddress,
981 IN OUT SIZE_T *UnsafeNumberOfBytesToProtect,
982 IN ULONG NewAccessProtection,
983 OUT PULONG UnsafeOldAccessProtection)
984 {
985 PEPROCESS Process;
986 ULONG OldAccessProtection;
987 ULONG Protection;
988 PEPROCESS CurrentProcess = PsGetCurrentProcess();
989 PVOID BaseAddress = NULL;
990 SIZE_T NumberOfBytesToProtect = 0;
991 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
992 NTSTATUS Status;
993 BOOLEAN Attached = FALSE;
994 KAPC_STATE ApcState;
995 PAGED_CODE();
996
997 //
998 // Check for valid protection flags
999 //
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)
1009 {
1010 //
1011 // Fail
1012 //
1013 return STATUS_INVALID_PAGE_PROTECTION;
1014 }
1015
1016 //
1017 // Check if we came from user mode
1018 //
1019 if (PreviousMode != KernelMode)
1020 {
1021 //
1022 // Enter SEH for probing
1023 //
1024 _SEH2_TRY
1025 {
1026 //
1027 // Validate all outputs
1028 //
1029 ProbeForWritePointer(UnsafeBaseAddress);
1030 ProbeForWriteSize_t(UnsafeNumberOfBytesToProtect);
1031 ProbeForWriteUlong(UnsafeOldAccessProtection);
1032
1033 //
1034 // Capture them
1035 //
1036 BaseAddress = *UnsafeBaseAddress;
1037 NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
1038 }
1039 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1040 {
1041 //
1042 // Get exception code
1043 //
1044 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1045 }
1046 _SEH2_END;
1047 }
1048 else
1049 {
1050 //
1051 // Capture directly
1052 //
1053 BaseAddress = *UnsafeBaseAddress;
1054 NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
1055 }
1056
1057 //
1058 // Catch illegal base address
1059 //
1060 if (BaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER_2;
1061
1062 //
1063 // Catch illegal region size
1064 //
1065 if ((MmUserProbeAddress - (ULONG_PTR)BaseAddress) < NumberOfBytesToProtect)
1066 {
1067 //
1068 // Fail
1069 //
1070 return STATUS_INVALID_PARAMETER_3;
1071 }
1072
1073 //
1074 // 0 is also illegal
1075 //
1076 if (!NumberOfBytesToProtect) return STATUS_INVALID_PARAMETER_3;
1077
1078 //
1079 // Get a reference to the process
1080 //
1081 Status = ObReferenceObjectByHandle(ProcessHandle,
1082 PROCESS_VM_OPERATION,
1083 PsProcessType,
1084 PreviousMode,
1085 (PVOID*)(&Process),
1086 NULL);
1087 if (!NT_SUCCESS(Status)) return Status;
1088
1089 //
1090 // Check if we should attach
1091 //
1092 if (CurrentProcess != Process)
1093 {
1094 //
1095 // Do it
1096 //
1097 KeStackAttachProcess(&Process->Pcb, &ApcState);
1098 Attached = TRUE;
1099 }
1100
1101 //
1102 // Do the actual work
1103 //
1104 Status = MiProtectVirtualMemory(Process,
1105 &BaseAddress,
1106 &NumberOfBytesToProtect,
1107 NewAccessProtection,
1108 &OldAccessProtection);
1109
1110 //
1111 // Detach if needed
1112 //
1113 if (Attached) KeUnstackDetachProcess(&ApcState);
1114
1115 //
1116 // Release reference
1117 //
1118 ObDereferenceObject(Process);
1119
1120 //
1121 // Enter SEH to return data
1122 //
1123 _SEH2_TRY
1124 {
1125 //
1126 // Return data to user
1127 //
1128 *UnsafeOldAccessProtection = OldAccessProtection;
1129 *UnsafeBaseAddress = BaseAddress;
1130 *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
1131 }
1132 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1133 {
1134 }
1135 _SEH2_END;
1136
1137 //
1138 // Return status
1139 //
1140 return Status;
1141 }
1142
1143 NTSTATUS
1144 NTAPI
1145 NtLockVirtualMemory(IN HANDLE ProcessHandle,
1146 IN OUT PVOID *BaseAddress,
1147 IN OUT PSIZE_T NumberOfBytesToLock,
1148 IN ULONG MapType)
1149 {
1150 PEPROCESS Process;
1151 PEPROCESS CurrentProcess = PsGetCurrentProcess();
1152 NTSTATUS Status;
1153 BOOLEAN Attached = FALSE;
1154 KAPC_STATE ApcState;
1155 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1156 PVOID CapturedBaseAddress;
1157 SIZE_T CapturedBytesToLock;
1158 PAGED_CODE();
1159
1160 //
1161 // Validate flags
1162 //
1163 if ((MapType & ~(MAP_PROCESS | MAP_SYSTEM)))
1164 {
1165 //
1166 // Invalid set of flags
1167 //
1168 return STATUS_INVALID_PARAMETER;
1169 }
1170
1171 //
1172 // At least one flag must be specified
1173 //
1174 if (!(MapType & (MAP_PROCESS | MAP_SYSTEM)))
1175 {
1176 //
1177 // No flag given
1178 //
1179 return STATUS_INVALID_PARAMETER;
1180 }
1181
1182 //
1183 // Enter SEH for probing
1184 //
1185 _SEH2_TRY
1186 {
1187 //
1188 // Validate output data
1189 //
1190 ProbeForWritePointer(BaseAddress);
1191 ProbeForWriteSize_t(NumberOfBytesToLock);
1192
1193 //
1194 // Capture it
1195 //
1196 CapturedBaseAddress = *BaseAddress;
1197 CapturedBytesToLock = *NumberOfBytesToLock;
1198 }
1199 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1200 {
1201 //
1202 // Get exception code
1203 //
1204 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1205 }
1206 _SEH2_END;
1207
1208 //
1209 // Catch illegal base address
1210 //
1211 if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
1212
1213 //
1214 // Catch illegal region size
1215 //
1216 if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToLock)
1217 {
1218 //
1219 // Fail
1220 //
1221 return STATUS_INVALID_PARAMETER;
1222 }
1223
1224 //
1225 // 0 is also illegal
1226 //
1227 if (!CapturedBytesToLock) return STATUS_INVALID_PARAMETER;
1228
1229 //
1230 // Get a reference to the process
1231 //
1232 Status = ObReferenceObjectByHandle(ProcessHandle,
1233 PROCESS_VM_OPERATION,
1234 PsProcessType,
1235 PreviousMode,
1236 (PVOID*)(&Process),
1237 NULL);
1238 if (!NT_SUCCESS(Status)) return Status;
1239
1240 //
1241 // Check if this is is system-mapped
1242 //
1243 if (MapType & MAP_SYSTEM)
1244 {
1245 //
1246 // Check for required privilege
1247 //
1248 if (!SeSinglePrivilegeCheck(SeLockMemoryPrivilege, PreviousMode))
1249 {
1250 //
1251 // Fail: Don't have it
1252 //
1253 ObDereferenceObject(Process);
1254 return STATUS_PRIVILEGE_NOT_HELD;
1255 }
1256 }
1257
1258 //
1259 // Check if we should attach
1260 //
1261 if (CurrentProcess != Process)
1262 {
1263 //
1264 // Do it
1265 //
1266 KeStackAttachProcess(&Process->Pcb, &ApcState);
1267 Attached = TRUE;
1268 }
1269
1270 //
1271 // Oops :(
1272 //
1273 UNIMPLEMENTED;
1274
1275 //
1276 // Detach if needed
1277 //
1278 if (Attached) KeUnstackDetachProcess(&ApcState);
1279
1280 //
1281 // Release reference
1282 //
1283 ObDereferenceObject(Process);
1284
1285 //
1286 // Enter SEH to return data
1287 //
1288 _SEH2_TRY
1289 {
1290 //
1291 // Return data to user
1292 //
1293 *BaseAddress = CapturedBaseAddress;
1294 *NumberOfBytesToLock = 0;
1295 }
1296 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1297 {
1298 //
1299 // Get exception code
1300 //
1301 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1302 }
1303 _SEH2_END;
1304
1305 //
1306 // Return status
1307 //
1308 return STATUS_SUCCESS;
1309 }
1310
1311 NTSTATUS
1312 NTAPI
1313 NtUnlockVirtualMemory(IN HANDLE ProcessHandle,
1314 IN OUT PVOID *BaseAddress,
1315 IN OUT PSIZE_T NumberOfBytesToUnlock,
1316 IN ULONG MapType)
1317 {
1318 PEPROCESS Process;
1319 PEPROCESS CurrentProcess = PsGetCurrentProcess();
1320 NTSTATUS Status;
1321 BOOLEAN Attached = FALSE;
1322 KAPC_STATE ApcState;
1323 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1324 PVOID CapturedBaseAddress;
1325 SIZE_T CapturedBytesToUnlock;
1326 PAGED_CODE();
1327
1328 //
1329 // Validate flags
1330 //
1331 if ((MapType & ~(MAP_PROCESS | MAP_SYSTEM)))
1332 {
1333 //
1334 // Invalid set of flags
1335 //
1336 return STATUS_INVALID_PARAMETER;
1337 }
1338
1339 //
1340 // At least one flag must be specified
1341 //
1342 if (!(MapType & (MAP_PROCESS | MAP_SYSTEM)))
1343 {
1344 //
1345 // No flag given
1346 //
1347 return STATUS_INVALID_PARAMETER;
1348 }
1349
1350 //
1351 // Enter SEH for probing
1352 //
1353 _SEH2_TRY
1354 {
1355 //
1356 // Validate output data
1357 //
1358 ProbeForWritePointer(BaseAddress);
1359 ProbeForWriteSize_t(NumberOfBytesToUnlock);
1360
1361 //
1362 // Capture it
1363 //
1364 CapturedBaseAddress = *BaseAddress;
1365 CapturedBytesToUnlock = *NumberOfBytesToUnlock;
1366 }
1367 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1368 {
1369 //
1370 // Get exception code
1371 //
1372 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1373 }
1374 _SEH2_END;
1375
1376 //
1377 // Catch illegal base address
1378 //
1379 if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
1380
1381 //
1382 // Catch illegal region size
1383 //
1384 if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToUnlock)
1385 {
1386 //
1387 // Fail
1388 //
1389 return STATUS_INVALID_PARAMETER;
1390 }
1391
1392 //
1393 // 0 is also illegal
1394 //
1395 if (!CapturedBytesToUnlock) return STATUS_INVALID_PARAMETER;
1396
1397 //
1398 // Get a reference to the process
1399 //
1400 Status = ObReferenceObjectByHandle(ProcessHandle,
1401 PROCESS_VM_OPERATION,
1402 PsProcessType,
1403 PreviousMode,
1404 (PVOID*)(&Process),
1405 NULL);
1406 if (!NT_SUCCESS(Status)) return Status;
1407
1408 //
1409 // Check if this is is system-mapped
1410 //
1411 if (MapType & MAP_SYSTEM)
1412 {
1413 //
1414 // Check for required privilege
1415 //
1416 if (!SeSinglePrivilegeCheck(SeLockMemoryPrivilege, PreviousMode))
1417 {
1418 //
1419 // Fail: Don't have it
1420 //
1421 ObDereferenceObject(Process);
1422 return STATUS_PRIVILEGE_NOT_HELD;
1423 }
1424 }
1425
1426 //
1427 // Check if we should attach
1428 //
1429 if (CurrentProcess != Process)
1430 {
1431 //
1432 // Do it
1433 //
1434 KeStackAttachProcess(&Process->Pcb, &ApcState);
1435 Attached = TRUE;
1436 }
1437
1438 //
1439 // Oops :(
1440 //
1441 UNIMPLEMENTED;
1442
1443 //
1444 // Detach if needed
1445 //
1446 if (Attached) KeUnstackDetachProcess(&ApcState);
1447
1448 //
1449 // Release reference
1450 //
1451 ObDereferenceObject(Process);
1452
1453 //
1454 // Enter SEH to return data
1455 //
1456 _SEH2_TRY
1457 {
1458 //
1459 // Return data to user
1460 //
1461 *BaseAddress = PAGE_ALIGN(CapturedBaseAddress);
1462 *NumberOfBytesToUnlock = 0;
1463 }
1464 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1465 {
1466 //
1467 // Get exception code
1468 //
1469 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1470 }
1471 _SEH2_END;
1472
1473 //
1474 // Return status
1475 //
1476 return STATUS_SUCCESS;
1477 }
1478
1479 NTSTATUS
1480 NTAPI
1481 NtFlushVirtualMemory(IN HANDLE ProcessHandle,
1482 IN OUT PVOID *BaseAddress,
1483 IN OUT PSIZE_T NumberOfBytesToFlush,
1484 OUT PIO_STATUS_BLOCK IoStatusBlock)
1485 {
1486 PEPROCESS Process;
1487 NTSTATUS Status;
1488 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1489 PVOID CapturedBaseAddress;
1490 SIZE_T CapturedBytesToFlush;
1491 IO_STATUS_BLOCK LocalStatusBlock;
1492 PAGED_CODE();
1493
1494 //
1495 // Check if we came from user mode
1496 //
1497 if (PreviousMode != KernelMode)
1498 {
1499 //
1500 // Enter SEH for probing
1501 //
1502 _SEH2_TRY
1503 {
1504 //
1505 // Validate all outputs
1506 //
1507 ProbeForWritePointer(BaseAddress);
1508 ProbeForWriteSize_t(NumberOfBytesToFlush);
1509 ProbeForWriteIoStatusBlock(IoStatusBlock);
1510
1511 //
1512 // Capture them
1513 //
1514 CapturedBaseAddress = *BaseAddress;
1515 CapturedBytesToFlush = *NumberOfBytesToFlush;
1516 }
1517 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1518 {
1519 //
1520 // Get exception code
1521 //
1522 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1523 }
1524 _SEH2_END;
1525 }
1526 else
1527 {
1528 //
1529 // Capture directly
1530 //
1531 CapturedBaseAddress = *BaseAddress;
1532 CapturedBytesToFlush = *NumberOfBytesToFlush;
1533 }
1534
1535 //
1536 // Catch illegal base address
1537 //
1538 if (CapturedBaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER;
1539
1540 //
1541 // Catch illegal region size
1542 //
1543 if ((MmUserProbeAddress - (ULONG_PTR)CapturedBaseAddress) < CapturedBytesToFlush)
1544 {
1545 //
1546 // Fail
1547 //
1548 return STATUS_INVALID_PARAMETER;
1549 }
1550
1551 //
1552 // Get a reference to the process
1553 //
1554 Status = ObReferenceObjectByHandle(ProcessHandle,
1555 PROCESS_VM_OPERATION,
1556 PsProcessType,
1557 PreviousMode,
1558 (PVOID*)(&Process),
1559 NULL);
1560 if (!NT_SUCCESS(Status)) return Status;
1561
1562 //
1563 // Do it
1564 //
1565 Status = MmFlushVirtualMemory(Process,
1566 &CapturedBaseAddress,
1567 &CapturedBytesToFlush,
1568 &LocalStatusBlock);
1569
1570 //
1571 // Release reference
1572 //
1573 ObDereferenceObject(Process);
1574
1575 //
1576 // Enter SEH to return data
1577 //
1578 _SEH2_TRY
1579 {
1580 //
1581 // Return data to user
1582 //
1583 *BaseAddress = PAGE_ALIGN(CapturedBaseAddress);
1584 *NumberOfBytesToFlush = 0;
1585 *IoStatusBlock = LocalStatusBlock;
1586 }
1587 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1588 {
1589 }
1590 _SEH2_END;
1591
1592 //
1593 // Return status
1594 //
1595 return Status;
1596 }
1597
1598 /*
1599 * @unimplemented
1600 */
1601 NTSTATUS
1602 NTAPI
1603 NtGetWriteWatch(IN HANDLE ProcessHandle,
1604 IN ULONG Flags,
1605 IN PVOID BaseAddress,
1606 IN SIZE_T RegionSize,
1607 IN PVOID *UserAddressArray,
1608 OUT PULONG_PTR EntriesInUserAddressArray,
1609 OUT PULONG Granularity)
1610 {
1611 PEPROCESS Process;
1612 NTSTATUS Status;
1613 PVOID EndAddress;
1614 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1615 ULONG_PTR CapturedEntryCount;
1616 PAGED_CODE();
1617
1618 //
1619 // Check if we came from user mode
1620 //
1621 if (PreviousMode != KernelMode)
1622 {
1623 //
1624 // Enter SEH for probing
1625 //
1626 _SEH2_TRY
1627 {
1628 //
1629 // Catch illegal base address
1630 //
1631 if (BaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER_2;
1632
1633 //
1634 // Catch illegal region size
1635 //
1636 if ((MmUserProbeAddress - (ULONG_PTR)BaseAddress) < RegionSize)
1637 {
1638 //
1639 // Fail
1640 //
1641 return STATUS_INVALID_PARAMETER_3;
1642 }
1643
1644 //
1645 // Validate all data
1646 //
1647 ProbeForWriteSize_t(EntriesInUserAddressArray);
1648 ProbeForWriteUlong(Granularity);
1649
1650 //
1651 // Capture them
1652 //
1653 CapturedEntryCount = *EntriesInUserAddressArray;
1654
1655 //
1656 // Must have a count
1657 //
1658 if (CapturedEntryCount == 0) return STATUS_INVALID_PARAMETER_5;
1659
1660 //
1661 // Can't be larger than the maximum
1662 //
1663 if (CapturedEntryCount > (MAXULONG_PTR / sizeof(ULONG_PTR)))
1664 {
1665 //
1666 // Fail
1667 //
1668 return STATUS_INVALID_PARAMETER_5;
1669 }
1670
1671 //
1672 // Probe the actual array
1673 //
1674 ProbeForWrite(UserAddressArray,
1675 CapturedEntryCount * sizeof(PVOID),
1676 sizeof(PVOID));
1677 }
1678 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1679 {
1680 //
1681 // Get exception code
1682 //
1683 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1684 }
1685 _SEH2_END;
1686 }
1687 else
1688 {
1689 //
1690 // Capture directly
1691 //
1692 CapturedEntryCount = *EntriesInUserAddressArray;
1693 ASSERT(CapturedEntryCount != 0);
1694 }
1695
1696 //
1697 // Check if this is a local request
1698 //
1699 if (ProcessHandle == NtCurrentProcess())
1700 {
1701 //
1702 // No need to reference the process
1703 //
1704 Process = PsGetCurrentProcess();
1705 }
1706 else
1707 {
1708 //
1709 // Reference the target
1710 //
1711 Status = ObReferenceObjectByHandle(ProcessHandle,
1712 PROCESS_VM_OPERATION,
1713 PsProcessType,
1714 PreviousMode,
1715 (PVOID *)&Process,
1716 NULL);
1717 if (!NT_SUCCESS(Status)) return Status;
1718 }
1719
1720 //
1721 // Compute the last address and validate it
1722 //
1723 EndAddress = (PVOID)((ULONG_PTR)BaseAddress + RegionSize - 1);
1724 if (BaseAddress > EndAddress)
1725 {
1726 //
1727 // Fail
1728 //
1729 if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
1730 return STATUS_INVALID_PARAMETER_4;
1731 }
1732
1733 //
1734 // Oops :(
1735 //
1736 UNIMPLEMENTED;
1737
1738 //
1739 // Dereference if needed
1740 //
1741 if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
1742
1743 //
1744 // Enter SEH to return data
1745 //
1746 _SEH2_TRY
1747 {
1748 //
1749 // Return data to user
1750 //
1751 *EntriesInUserAddressArray = 0;
1752 *Granularity = PAGE_SIZE;
1753 }
1754 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1755 {
1756 //
1757 // Get exception code
1758 //
1759 Status = _SEH2_GetExceptionCode();
1760 }
1761 _SEH2_END;
1762
1763 //
1764 // Return success
1765 //
1766 return STATUS_SUCCESS;
1767 }
1768
1769 /*
1770 * @unimplemented
1771 */
1772 NTSTATUS
1773 NTAPI
1774 NtResetWriteWatch(IN HANDLE ProcessHandle,
1775 IN PVOID BaseAddress,
1776 IN SIZE_T RegionSize)
1777 {
1778 PVOID EndAddress;
1779 PEPROCESS Process;
1780 NTSTATUS Status;
1781 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1782 ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
1783
1784 //
1785 // Catch illegal base address
1786 //
1787 if (BaseAddress > MM_HIGHEST_USER_ADDRESS) return STATUS_INVALID_PARAMETER_2;
1788
1789 //
1790 // Catch illegal region size
1791 //
1792 if ((MmUserProbeAddress - (ULONG_PTR)BaseAddress) < RegionSize)
1793 {
1794 //
1795 // Fail
1796 //
1797 return STATUS_INVALID_PARAMETER_3;
1798 }
1799
1800 //
1801 // Check if this is a local request
1802 //
1803 if (ProcessHandle == NtCurrentProcess())
1804 {
1805 //
1806 // No need to reference the process
1807 //
1808 Process = PsGetCurrentProcess();
1809 }
1810 else
1811 {
1812 //
1813 // Reference the target
1814 //
1815 Status = ObReferenceObjectByHandle(ProcessHandle,
1816 PROCESS_VM_OPERATION,
1817 PsProcessType,
1818 PreviousMode,
1819 (PVOID *)&Process,
1820 NULL);
1821 if (!NT_SUCCESS(Status)) return Status;
1822 }
1823
1824 //
1825 // Compute the last address and validate it
1826 //
1827 EndAddress = (PVOID)((ULONG_PTR)BaseAddress + RegionSize - 1);
1828 if (BaseAddress > EndAddress)
1829 {
1830 //
1831 // Fail
1832 //
1833 if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
1834 return STATUS_INVALID_PARAMETER_3;
1835 }
1836
1837 //
1838 // Oops :(
1839 //
1840 UNIMPLEMENTED;
1841
1842 //
1843 // Dereference if needed
1844 //
1845 if (ProcessHandle != NtCurrentProcess()) ObDereferenceObject(Process);
1846
1847 //
1848 // Return success
1849 //
1850 return STATUS_SUCCESS;
1851 }
1852
1853 /* EOF */