fixing the build for gcc 3.4.5
[reactos.git] / reactos / ntoskrnl / mm / virtual.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/virtual.c
6 * PURPOSE: Implementing operations on virtual memory.
7 *
8 * PROGRAMMERS: David Welch
9 */
10
11 /* INCLUDE *****************************************************************/
12
13 #include <ntoskrnl.h>
14
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* FUNCTIONS *****************************************************************/
19
20 NTSTATUS STDCALL
21 NtFlushVirtualMemory(IN HANDLE ProcessHandle,
22 IN PVOID BaseAddress,
23 IN ULONG NumberOfBytesToFlush,
24 OUT PULONG NumberOfBytesFlushed OPTIONAL)
25 /*
26 * FUNCTION: Flushes virtual memory to file
27 * ARGUMENTS:
28 * ProcessHandle = Points to the process that allocated the virtual
29 * memory
30 * BaseAddress = Points to the memory address
31 * NumberOfBytesToFlush = Limits the range to flush,
32 * NumberOfBytesFlushed = Actual number of bytes flushed
33 * RETURNS: Status
34 */
35 {
36 /* This should be implemented once we support network filesystems */
37 DPRINT("NtFlushVirtualMemory is UNIMPLEMENTED\n");
38 return(STATUS_SUCCESS);
39 }
40
41
42 NTSTATUS STDCALL
43 MiLockVirtualMemory(HANDLE ProcessHandle,
44 PVOID BaseAddress,
45 ULONG NumberOfBytesToLock,
46 PULONG NumberOfBytesLocked,
47 PObReferenceObjectByHandle pObReferenceObjectByHandle,
48 PMmCreateMdl pMmCreateMdl,
49 PObDereferenceObject pObDereferenceObject,
50 PMmProbeAndLockPages pMmProbeAndLockPages,
51 PExFreePool pExFreePool)
52 {
53 PEPROCESS Process;
54 NTSTATUS Status;
55 PMDL Mdl;
56
57 Status = pObReferenceObjectByHandle(ProcessHandle,
58 PROCESS_VM_WRITE,
59 NULL,
60 UserMode,
61 (PVOID*)(&Process),
62 NULL);
63 if (!NT_SUCCESS(Status))
64 return(Status);
65
66 Mdl = pMmCreateMdl(NULL,
67 BaseAddress,
68 NumberOfBytesToLock);
69 if (Mdl == NULL)
70 {
71 pObDereferenceObject(Process);
72 return(STATUS_NO_MEMORY);
73 }
74
75 pMmProbeAndLockPages(Mdl,
76 UserMode,
77 IoWriteAccess);
78
79 pExFreePool(Mdl);
80
81 pObDereferenceObject(Process);
82
83 *NumberOfBytesLocked = NumberOfBytesToLock;
84 return(STATUS_SUCCESS);
85 }
86
87
88 NTSTATUS STDCALL
89 NtLockVirtualMemory(HANDLE ProcessHandle,
90 PVOID BaseAddress,
91 ULONG NumberOfBytesToLock,
92 PULONG NumberOfBytesLocked)
93 {
94 DPRINT("NtLockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
95 "NumberOfBytesToLock %d, NumberOfBytesLocked %x)\n",
96 ProcessHandle,
97 BaseAddress,
98 NumberOfBytesToLock,
99 NumberOfBytesLocked);
100
101 return MiLockVirtualMemory(ProcessHandle,
102 BaseAddress,
103 NumberOfBytesToLock,
104 NumberOfBytesLocked,
105 ObReferenceObjectByHandle,
106 MmCreateMdl,
107 (PVOID)ObfDereferenceObject,
108 MmProbeAndLockPages,
109 ExFreePool);
110 }
111
112
113 NTSTATUS FASTCALL
114 MiQueryVirtualMemory (IN HANDLE ProcessHandle,
115 IN PVOID Address,
116 IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass,
117 OUT PVOID VirtualMemoryInformation,
118 IN ULONG Length,
119 OUT PULONG ResultLength)
120 {
121 NTSTATUS Status;
122 PEPROCESS Process;
123 MEMORY_AREA* MemoryArea;
124 PMADDRESS_SPACE AddressSpace;
125
126 if (Address < MmSystemRangeStart)
127 {
128 Status = ObReferenceObjectByHandle(ProcessHandle,
129 PROCESS_QUERY_INFORMATION,
130 NULL,
131 UserMode,
132 (PVOID*)(&Process),
133 NULL);
134
135 if (!NT_SUCCESS(Status))
136 {
137 DPRINT("NtQueryVirtualMemory() = %x\n",Status);
138 return(Status);
139 }
140 AddressSpace = (PMADDRESS_SPACE)&Process->VadRoot;
141 }
142 else
143 {
144 AddressSpace = MmGetKernelAddressSpace();
145 }
146 MmLockAddressSpace(AddressSpace);
147 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
148 switch(VirtualMemoryInformationClass)
149 {
150 case MemoryBasicInformation:
151 {
152 PMEMORY_BASIC_INFORMATION Info =
153 (PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation;
154 if (Length != sizeof(MEMORY_BASIC_INFORMATION))
155 {
156 MmUnlockAddressSpace(AddressSpace);
157 ObDereferenceObject(Process);
158 return(STATUS_INFO_LENGTH_MISMATCH);
159 }
160
161 if (MemoryArea == NULL)
162 {
163 Info->Type = 0;
164 Info->State = MEM_FREE;
165 Info->Protect = PAGE_NOACCESS;
166 Info->AllocationProtect = 0;
167 Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
168 Info->AllocationBase = NULL;
169 Info->RegionSize = MmFindGapAtAddress(AddressSpace, Info->BaseAddress);
170 Status = STATUS_SUCCESS;
171 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
172 }
173 else
174 {
175 switch(MemoryArea->Type)
176 {
177 case MEMORY_AREA_VIRTUAL_MEMORY:
178 case MEMORY_AREA_PEB_OR_TEB:
179 Status = MmQueryAnonMem(MemoryArea, Address, Info,
180 ResultLength);
181 break;
182 case MEMORY_AREA_SECTION_VIEW:
183 Status = MmQuerySectionView(MemoryArea, Address, Info,
184 ResultLength);
185 break;
186 case MEMORY_AREA_NO_ACCESS:
187 Info->Type = MEM_PRIVATE;
188 Info->State = MEM_RESERVE;
189 Info->Protect = MemoryArea->Protect;
190 Info->AllocationProtect = MemoryArea->Protect;
191 Info->BaseAddress = MemoryArea->StartingAddress;
192 Info->AllocationBase = MemoryArea->StartingAddress;
193 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
194 (ULONG_PTR)MemoryArea->StartingAddress;
195 Status = STATUS_SUCCESS;
196 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
197 break;
198 case MEMORY_AREA_SHARED_DATA:
199 Info->Type = MEM_PRIVATE;
200 Info->State = MEM_COMMIT;
201 Info->Protect = MemoryArea->Protect;
202 Info->AllocationProtect = MemoryArea->Protect;
203 Info->BaseAddress = MemoryArea->StartingAddress;
204 Info->AllocationBase = MemoryArea->StartingAddress;
205 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
206 (ULONG_PTR)MemoryArea->StartingAddress;
207 Status = STATUS_SUCCESS;
208 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
209 break;
210 case MEMORY_AREA_SYSTEM:
211 Info->Type = 0;
212 Info->State = MEM_COMMIT;
213 Info->Protect = MemoryArea->Protect;
214 Info->AllocationProtect = MemoryArea->Protect;
215 Info->BaseAddress = MemoryArea->StartingAddress;
216 Info->AllocationBase = MemoryArea->StartingAddress;
217 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
218 (ULONG_PTR)MemoryArea->StartingAddress;
219 Status = STATUS_SUCCESS;
220 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
221 break;
222 case MEMORY_AREA_KERNEL_STACK:
223 Info->Type = 0;
224 Info->State = MEM_COMMIT;
225 Info->Protect = MemoryArea->Protect;
226 Info->AllocationProtect = MemoryArea->Protect;
227 Info->BaseAddress = MemoryArea->StartingAddress;
228 Info->AllocationBase = MemoryArea->StartingAddress;
229 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
230 (ULONG_PTR)MemoryArea->StartingAddress;
231 Status = STATUS_SUCCESS;
232 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
233 break;
234 case MEMORY_AREA_PAGED_POOL:
235 Info->Type = 0;
236 Info->State = MEM_COMMIT;
237 Info->Protect = MemoryArea->Protect;
238 Info->AllocationProtect = MemoryArea->Protect;
239 Info->BaseAddress = MemoryArea->StartingAddress;
240 Info->AllocationBase = MemoryArea->StartingAddress;
241 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
242 (ULONG_PTR)MemoryArea->StartingAddress;
243 Status = STATUS_SUCCESS;
244 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
245 break;
246 default:
247 DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea->Type);
248 Status = STATUS_UNSUCCESSFUL;
249 *ResultLength = 0;
250 }
251 }
252 break;
253 }
254
255 default:
256 {
257 Status = STATUS_INVALID_INFO_CLASS;
258 *ResultLength = 0;
259 break;
260 }
261 }
262
263 MmUnlockAddressSpace(AddressSpace);
264 if (Address < MmSystemRangeStart)
265 {
266 ASSERT(Process);
267 ObDereferenceObject(Process);
268 }
269
270 return Status;
271 }
272
273 /* (tMk 2004.II.4)
274 * FUNCTION:
275 * Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
276 *
277 */
278 NTSTATUS STDCALL
279 NtQueryVirtualMemory (IN HANDLE ProcessHandle,
280 IN PVOID Address,
281 IN MEMORY_INFORMATION_CLASS VirtualMemoryInformationClass,
282 OUT PVOID VirtualMemoryInformation,
283 IN ULONG Length,
284 OUT PULONG UnsafeResultLength)
285 {
286 NTSTATUS Status = STATUS_SUCCESS;
287 ULONG ResultLength = 0;
288 KPROCESSOR_MODE PreviousMode;
289 union
290 {
291 MEMORY_BASIC_INFORMATION BasicInfo;
292 }
293 VirtualMemoryInfo;
294
295 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
296 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
297 "Length %lu ResultLength %x)\n",ProcessHandle,Address,
298 VirtualMemoryInformationClass,VirtualMemoryInformation,
299 Length,ResultLength);
300
301 PreviousMode = ExGetPreviousMode();
302
303 if (PreviousMode != KernelMode && UnsafeResultLength != NULL)
304 {
305 _SEH_TRY
306 {
307 ProbeForWriteUlong(UnsafeResultLength);
308 }
309 _SEH_HANDLE
310 {
311 Status = _SEH_GetExceptionCode();
312 }
313 _SEH_END;
314
315 if (!NT_SUCCESS(Status))
316 {
317 return Status;
318 }
319 }
320
321 if (Address >= MmSystemRangeStart)
322 {
323 DPRINT1("Invalid parameter\n");
324 return STATUS_INVALID_PARAMETER;
325 }
326
327 Status = MiQueryVirtualMemory ( ProcessHandle,
328 Address,
329 VirtualMemoryInformationClass,
330 &VirtualMemoryInfo,
331 Length,
332 &ResultLength );
333
334 if (NT_SUCCESS(Status))
335 {
336 if (PreviousMode != KernelMode)
337 {
338 _SEH_TRY
339 {
340 if (ResultLength > 0)
341 {
342 ProbeForWrite(VirtualMemoryInformation,
343 ResultLength,
344 1);
345 RtlCopyMemory(VirtualMemoryInformation,
346 &VirtualMemoryInfo,
347 ResultLength);
348 }
349 if (UnsafeResultLength != NULL)
350 {
351 *UnsafeResultLength = ResultLength;
352 }
353 }
354 _SEH_HANDLE
355 {
356 Status = _SEH_GetExceptionCode();
357 }
358 _SEH_END;
359 }
360 else
361 {
362 if (ResultLength > 0)
363 {
364 RtlCopyMemory(VirtualMemoryInformation,
365 &VirtualMemoryInfo,
366 ResultLength);
367 }
368
369 if (UnsafeResultLength != NULL)
370 {
371 *UnsafeResultLength = ResultLength;
372 }
373 }
374 }
375
376 return(Status);
377 }
378
379
380 NTSTATUS STDCALL
381 MiProtectVirtualMemory(IN PEPROCESS Process,
382 IN OUT PVOID *BaseAddress,
383 IN OUT PULONG NumberOfBytesToProtect,
384 IN ULONG NewAccessProtection,
385 OUT PULONG OldAccessProtection OPTIONAL)
386 {
387 PMEMORY_AREA MemoryArea;
388 PMADDRESS_SPACE AddressSpace;
389 ULONG OldAccessProtection_;
390 NTSTATUS Status;
391
392 *NumberOfBytesToProtect =
393 PAGE_ROUND_UP((*BaseAddress) + (*NumberOfBytesToProtect)) -
394 PAGE_ROUND_DOWN(*BaseAddress);
395 *BaseAddress = (PVOID)PAGE_ROUND_DOWN(*BaseAddress);
396
397 AddressSpace = (PMADDRESS_SPACE)&(Process)->VadRoot;
398
399 MmLockAddressSpace(AddressSpace);
400 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *BaseAddress);
401 if (MemoryArea == NULL)
402 {
403 MmUnlockAddressSpace(AddressSpace);
404 return STATUS_UNSUCCESSFUL;
405 }
406
407 if (OldAccessProtection == NULL)
408 OldAccessProtection = &OldAccessProtection_;
409
410 if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
411 {
412 Status = MmProtectAnonMem(AddressSpace, MemoryArea, *BaseAddress,
413 *NumberOfBytesToProtect, NewAccessProtection,
414 OldAccessProtection);
415 }
416 else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
417 {
418 Status = MmProtectSectionView(AddressSpace, MemoryArea, *BaseAddress,
419 *NumberOfBytesToProtect,
420 NewAccessProtection,
421 OldAccessProtection);
422 }
423 else
424 {
425 /* FIXME: Should we return failure or success in this case? */
426 Status = STATUS_CONFLICTING_ADDRESSES;
427 }
428
429 MmUnlockAddressSpace(AddressSpace);
430
431 return Status;
432 }
433
434
435 /* (tMk 2004.II.5)
436 * FUNCTION:
437 * Called from VirtualProtectEx (lib\kernel32\mem\virtual.c)
438 *
439 */
440 NTSTATUS STDCALL
441 NtProtectVirtualMemory(IN HANDLE ProcessHandle,
442 IN OUT PVOID *UnsafeBaseAddress,
443 IN OUT ULONG *UnsafeNumberOfBytesToProtect,
444 IN ULONG NewAccessProtection,
445 OUT PULONG UnsafeOldAccessProtection)
446 {
447 PEPROCESS Process;
448 ULONG OldAccessProtection;
449 PVOID BaseAddress = NULL;
450 ULONG NumberOfBytesToProtect = 0;
451 KPROCESSOR_MODE PreviousMode;
452 NTSTATUS Status = STATUS_SUCCESS;
453
454 PreviousMode = ExGetPreviousMode();
455
456 if (PreviousMode != KernelMode)
457 {
458 _SEH_TRY
459 {
460 ProbeForWritePointer(UnsafeBaseAddress);
461 ProbeForWriteUlong(UnsafeNumberOfBytesToProtect);
462 ProbeForWriteUlong(UnsafeOldAccessProtection);
463
464 BaseAddress = *UnsafeBaseAddress;
465 NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
466 }
467 _SEH_HANDLE
468 {
469 Status = _SEH_GetExceptionCode();
470 }
471 _SEH_END;
472
473 if (!NT_SUCCESS(Status))
474 {
475 return Status;
476 }
477 }
478 else
479 {
480 BaseAddress = *UnsafeBaseAddress;
481 NumberOfBytesToProtect = *UnsafeNumberOfBytesToProtect;
482 }
483
484 if ((ULONG_PTR)BaseAddress + NumberOfBytesToProtect - 1 < (ULONG_PTR)BaseAddress ||
485 (ULONG_PTR)BaseAddress + NumberOfBytesToProtect - 1 >= MmUserProbeAddress)
486 {
487 /* Don't allow to change the protection of a kernel mode address */
488 return STATUS_INVALID_PARAMETER_2;
489 }
490
491 /* (tMk 2004.II.5) in Microsoft SDK I read:
492 * 'if this parameter is NULL or does not point to a valid variable, the function fails'
493 */
494 if(UnsafeOldAccessProtection == NULL)
495 {
496 return(STATUS_INVALID_PARAMETER);
497 }
498
499 Status = ObReferenceObjectByHandle(ProcessHandle,
500 PROCESS_VM_OPERATION,
501 PsProcessType,
502 UserMode,
503 (PVOID*)(&Process),
504 NULL);
505 if (!NT_SUCCESS(Status))
506 {
507 DPRINT("NtProtectVirtualMemory() = %x\n",Status);
508 return(Status);
509 }
510
511 Status = MiProtectVirtualMemory(Process,
512 &BaseAddress,
513 &NumberOfBytesToProtect,
514 NewAccessProtection,
515 &OldAccessProtection);
516
517 ObDereferenceObject(Process);
518
519 if (PreviousMode != KernelMode)
520 {
521 _SEH_TRY
522 {
523 *UnsafeOldAccessProtection = OldAccessProtection;
524 *UnsafeBaseAddress = BaseAddress;
525 *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
526 }
527 _SEH_HANDLE
528 {
529 Status = _SEH_GetExceptionCode();
530 }
531 _SEH_END;
532 }
533 else
534 {
535 *UnsafeOldAccessProtection = OldAccessProtection;
536 *UnsafeBaseAddress = BaseAddress;
537 *UnsafeNumberOfBytesToProtect = NumberOfBytesToProtect;
538 }
539
540 return(Status);
541 }
542
543
544 /* (tMk 2004.II.05)
545 * FUNCTION:
546 * Called from ReadProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
547 *
548 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
549 */
550 NTSTATUS STDCALL
551 NtReadVirtualMemory(IN HANDLE ProcessHandle,
552 IN PVOID BaseAddress,
553 OUT PVOID Buffer,
554 IN ULONG NumberOfBytesToRead,
555 OUT PULONG NumberOfBytesRead OPTIONAL)
556 {
557 PMDL Mdl = NULL;
558 PVOID SystemAddress;
559 KPROCESSOR_MODE PreviousMode = {0};
560 PEPROCESS Process, CurrentProcess = NULL;
561 NTSTATUS Status = STATUS_SUCCESS;
562
563 PAGED_CODE();
564
565 DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
566 "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress,
567 Buffer,NumberOfBytesToRead);
568
569 if ((ULONG_PTR)BaseAddress + NumberOfBytesToRead - 1 < (ULONG_PTR)BaseAddress ||
570 (ULONG_PTR)BaseAddress + NumberOfBytesToRead - 1 >= MmUserProbeAddress)
571 {
572 /* Don't allow to read from kernel space */
573 return STATUS_ACCESS_VIOLATION;
574 }
575
576 PreviousMode = ExGetPreviousMode();
577
578 if (PreviousMode != KernelMode)
579 {
580 if ((ULONG_PTR)Buffer + NumberOfBytesToRead - 1 < (ULONG_PTR)Buffer ||
581 (ULONG_PTR)Buffer + NumberOfBytesToRead - 1 >= MmUserProbeAddress)
582 {
583 /* Don't allow to write into kernel space */
584 return STATUS_ACCESS_VIOLATION;
585 }
586 }
587
588 Status = ObReferenceObjectByHandle(ProcessHandle,
589 PROCESS_VM_READ,
590 NULL,
591 PreviousMode,
592 (PVOID*)(&Process),
593 NULL);
594 if (!NT_SUCCESS(Status))
595 {
596 return(Status);
597 }
598
599 CurrentProcess = PsGetCurrentProcess();
600
601 if(PreviousMode != KernelMode)
602 {
603 _SEH_TRY
604 {
605 if(NumberOfBytesRead != NULL)
606 {
607 ProbeForWriteUlong(NumberOfBytesRead);
608 }
609 }
610 _SEH_HANDLE
611 {
612 Status = _SEH_GetExceptionCode();
613 }
614 _SEH_END;
615
616 if(!NT_SUCCESS(Status))
617 {
618 return Status;
619 }
620 }
621
622
623 if (Process == CurrentProcess)
624 {
625 _SEH_TRY
626 {
627 RtlCopyMemory(Buffer, BaseAddress, NumberOfBytesToRead);
628 }
629 _SEH_HANDLE
630 {
631 Status = _SEH_GetExceptionCode();
632 }
633 _SEH_END;
634 }
635 else
636 {
637 Mdl = MmCreateMdl(NULL,
638 Buffer,
639 NumberOfBytesToRead);
640 if(Mdl == NULL)
641 {
642 ObDereferenceObject(Process);
643 return(STATUS_NO_MEMORY);
644 }
645 _SEH_TRY
646 {
647 MmProbeAndLockPages(Mdl,
648 PreviousMode,
649 IoWriteAccess);
650 }
651 _SEH_HANDLE
652 {
653 Status = _SEH_GetExceptionCode();
654 }
655 _SEH_END;
656
657 if(NT_SUCCESS(Status))
658 {
659 KeAttachProcess(&Process->Pcb);
660
661 SystemAddress = MmGetSystemAddressForMdl(Mdl);
662
663 Status = STATUS_SUCCESS;
664 _SEH_TRY {
665 Status = STATUS_PARTIAL_COPY;
666 RtlCopyMemory(SystemAddress, BaseAddress, NumberOfBytesToRead);
667 Status = STATUS_SUCCESS;
668 } _SEH_HANDLE {
669 if(Status != STATUS_PARTIAL_COPY)
670 Status = _SEH_GetExceptionCode();
671 } _SEH_END;
672
673 KeDetachProcess();
674
675 if (Mdl->MappedSystemVa != NULL)
676 {
677 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
678 }
679 MmUnlockPages(Mdl);
680 }
681 ExFreePool(Mdl);
682 }
683
684 ObDereferenceObject(Process);
685
686 if((NT_SUCCESS(Status) || Status == STATUS_PARTIAL_COPY) &&
687 NumberOfBytesRead != NULL)
688 {
689 _SEH_TRY
690 {
691 *NumberOfBytesRead = NumberOfBytesToRead;
692 }
693 _SEH_HANDLE
694 {
695 Status = _SEH_GetExceptionCode();
696 }
697 _SEH_END;
698 }
699
700 return(Status);
701 }
702
703 /* (tMk 2004.II.05)
704 * FUNCTION: THIS function doesn't make a sense...
705 * Called from VirtualUnlock (lib\kernel32\mem\virtual.c)
706 */
707 NTSTATUS STDCALL
708 NtUnlockVirtualMemory(HANDLE ProcessHandle,
709 PVOID BaseAddress,
710 ULONG NumberOfBytesToUnlock,
711 PULONG NumberOfBytesUnlocked OPTIONAL)
712 {
713 // AG [08-20-03] : I have *no* idea if this is correct, I just used the
714 // other functions as a template and made a few intelligent guesses...
715
716 NTSTATUS Status;
717 PMDL Mdl;
718 PEPROCESS Process;
719
720 DPRINT("NtUnlockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
721 "NumberOfBytesToUnlock %d), NumberOfBytesUnlocked %x\n",ProcessHandle,BaseAddress,
722 NumberOfBytesToUnlock, NumberOfBytesUnlocked);
723
724 Status = ObReferenceObjectByHandle(ProcessHandle,
725 PROCESS_VM_WRITE,
726 NULL,
727 UserMode,
728 (PVOID*)(&Process),
729 NULL);
730 if (!NT_SUCCESS(Status))
731 {
732 return(Status);
733 }
734
735 Mdl = MmCreateMdl(NULL,
736 BaseAddress,
737 NumberOfBytesToUnlock);
738 if(Mdl == NULL)
739 {
740 ObDereferenceObject(Process);
741 return(STATUS_NO_MEMORY);
742 }
743
744 ObDereferenceObject(Process);
745
746 if (Mdl->MappedSystemVa != NULL)
747 {
748 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
749 }
750 MmUnlockPages(Mdl);
751 ExFreePool(Mdl);
752
753 *NumberOfBytesUnlocked = NumberOfBytesToUnlock;
754
755 return(STATUS_SUCCESS);
756 }
757
758
759 /* (tMk 2004.II.05)
760 * FUNCTION:
761 * Called from WriteProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
762 *
763 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
764 */
765 NTSTATUS STDCALL
766 NtWriteVirtualMemory(IN HANDLE ProcessHandle,
767 IN PVOID BaseAddress,
768 IN PVOID Buffer,
769 IN ULONG NumberOfBytesToWrite,
770 OUT PULONG NumberOfBytesWritten OPTIONAL)
771 {
772 PMDL Mdl = NULL;
773 PVOID SystemAddress = NULL;
774 PEPROCESS Process;
775 KPROCESSOR_MODE PreviousMode = {0};
776 NTSTATUS CopyStatus = STATUS_SUCCESS, Status = STATUS_SUCCESS;
777
778 DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
779 "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle,BaseAddress,
780 Buffer,NumberOfBytesToWrite);
781
782 if ((ULONG_PTR)BaseAddress + NumberOfBytesToWrite - 1 < (ULONG_PTR)BaseAddress ||
783 (ULONG_PTR)BaseAddress + NumberOfBytesToWrite - 1 >= MmUserProbeAddress)
784 {
785 /* Don't allow to write into kernel space */
786 return STATUS_ACCESS_VIOLATION;
787 }
788
789 PreviousMode = ExGetPreviousMode();
790
791 if (PreviousMode != KernelMode)
792 {
793 if ((ULONG_PTR)Buffer + NumberOfBytesToWrite - 1 < (ULONG_PTR)Buffer ||
794 (ULONG_PTR)Buffer + NumberOfBytesToWrite - 1 >= MmUserProbeAddress)
795 {
796 /* Don't allow to read from kernel space */
797 return STATUS_ACCESS_VIOLATION;
798 }
799 if (NumberOfBytesWritten != NULL)
800 {
801 _SEH_TRY
802 {
803 ProbeForWriteUlong(NumberOfBytesWritten);
804 }
805 _SEH_HANDLE
806 {
807 Status = _SEH_GetExceptionCode();
808 }
809 _SEH_END;
810
811 if (!NT_SUCCESS(Status))
812 {
813 return Status;
814 }
815 }
816 }
817
818 Status = ObReferenceObjectByHandle(ProcessHandle,
819 PROCESS_VM_WRITE,
820 NULL,
821 UserMode,
822 (PVOID*)(&Process),
823 NULL);
824 if (!NT_SUCCESS(Status))
825 {
826 return(Status);
827 }
828
829 CopyStatus = STATUS_SUCCESS;
830
831 /* Write memory */
832 if (Process == PsGetCurrentProcess())
833 {
834 if (PreviousMode != KernelMode)
835 {
836 _SEH_TRY
837 {
838 memcpy(BaseAddress, Buffer, NumberOfBytesToWrite);
839 }
840 _SEH_HANDLE
841 {
842 CopyStatus = _SEH_GetExceptionCode();
843 }
844 _SEH_END;
845 }
846 else
847 {
848 memcpy(BaseAddress, Buffer, NumberOfBytesToWrite);
849 }
850 }
851 else
852 {
853 /* Create MDL describing the source buffer. */
854 Mdl = MmCreateMdl(NULL,
855 Buffer,
856 NumberOfBytesToWrite);
857 if(Mdl == NULL)
858 {
859 ObDereferenceObject(Process);
860 return(STATUS_NO_MEMORY);
861 }
862 _SEH_TRY
863 {
864 /* Map the MDL. */
865 MmProbeAndLockPages(Mdl,
866 UserMode,
867 IoReadAccess);
868 }
869 _SEH_HANDLE
870 {
871 CopyStatus = _SEH_GetExceptionCode();
872 }
873 _SEH_END;
874
875 if (NT_SUCCESS(CopyStatus))
876 {
877 /* Copy memory from the mapped MDL into the target buffer. */
878 KeAttachProcess(&Process->Pcb);
879
880 SystemAddress = MmGetSystemAddressForMdl(Mdl);
881 if (PreviousMode != KernelMode)
882 {
883 _SEH_TRY
884 {
885 memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
886 }
887 _SEH_HANDLE
888 {
889 CopyStatus = _SEH_GetExceptionCode();
890 }
891 _SEH_END;
892 }
893 else
894 {
895 memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
896 }
897
898 KeDetachProcess();
899 }
900
901 /* Free the MDL. */
902 if (Mdl->MappedSystemVa != NULL)
903 {
904 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
905 }
906 MmUnlockPages(Mdl);
907 ExFreePool(Mdl);
908 }
909 ObDereferenceObject(Process);
910
911 if (NT_SUCCESS(CopyStatus) && NumberOfBytesWritten != NULL)
912 {
913 if (PreviousMode != KernelMode)
914 {
915 _SEH_TRY
916 {
917 *NumberOfBytesWritten = NumberOfBytesToWrite;
918 }
919 _SEH_HANDLE
920 {
921 Status = _SEH_GetExceptionCode();
922 }
923 _SEH_END;
924 }
925 else
926 {
927 *NumberOfBytesWritten = NumberOfBytesToWrite;
928 }
929 }
930
931 return(NT_SUCCESS(CopyStatus) ? Status : CopyStatus);
932 }
933
934 /*
935 * @unimplemented
936 */
937
938 PVOID
939 STDCALL
940 MmGetVirtualForPhysical (
941 IN PHYSICAL_ADDRESS PhysicalAddress
942 )
943 {
944 UNIMPLEMENTED;
945 return 0;
946 }
947
948 /* FUNCTION:
949 * Called from EngSecureMem (subsys\win32k\eng\mem.c)
950 * @unimplemented
951 */
952 PVOID STDCALL
953 MmSecureVirtualMemory (PVOID Address,
954 SIZE_T Length,
955 ULONG Mode)
956 {
957 /* Only works for user space */
958 if (MmHighestUserAddress < Address)
959 {
960 return NULL;
961 }
962
963 UNIMPLEMENTED;
964
965 return 0;
966 }
967
968
969 /* FUNCTION:
970 * Called from EngUnsecureMem (subsys\win32k\eng\mem.c)
971 * @unimplemented
972 */
973 VOID STDCALL
974 MmUnsecureVirtualMemory(PVOID SecureMem)
975 {
976 if (NULL == SecureMem)
977 {
978 return;
979 }
980
981 UNIMPLEMENTED;
982 }
983
984
985 /*
986 * @implemented
987 */
988 VOID STDCALL
989 ProbeForRead (IN CONST VOID *Address,
990 IN ULONG Length,
991 IN ULONG Alignment)
992 {
993 if (Length != 0)
994 {
995 ASSERT(Alignment == 1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
996
997 if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
998 {
999 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
1000 }
1001 else if ((ULONG_PTR)Address + Length - 1 < (ULONG_PTR)Address ||
1002 (ULONG_PTR)Address + Length - 1 >= (ULONG_PTR)MmUserProbeAddress)
1003 {
1004 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
1005 }
1006 }
1007 }
1008
1009
1010 /*
1011 * @implemented
1012 */
1013 VOID STDCALL
1014 ProbeForWrite (IN PVOID Address,
1015 IN ULONG Length,
1016 IN ULONG Alignment)
1017 {
1018 volatile CHAR *Current;
1019 PCHAR Last;
1020
1021 if (Length != 0)
1022 {
1023 ASSERT(Alignment == 1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
1024
1025 if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
1026 {
1027 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
1028 }
1029
1030 Last = (PCHAR)((ULONG_PTR)Address + Length - 1);
1031 if ((ULONG_PTR)Last < (ULONG_PTR)Address ||
1032 (ULONG_PTR)Last >= (ULONG_PTR)MmUserProbeAddress)
1033 {
1034 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
1035 }
1036
1037 /* Check for accessible pages, do *not* touch any memory outside of the
1038 range!*/
1039 Current = (volatile CHAR*)Address;
1040 Last = (PCHAR)(PAGE_ROUND_DOWN(Last));
1041 do
1042 {
1043 *Current = *Current;
1044 Current = (volatile CHAR*)(PAGE_ROUND_DOWN(Current) + PAGE_SIZE);
1045 } while (Current <= Last);
1046 }
1047 }
1048
1049 /* EOF */