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