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