Merge 15329:15546 from trunk
[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 ObfDereferenceObject,
108 MmProbeAndLockPages,
109 ExFreePool);
110 }
111
112
113 NTSTATUS FASTCALL
114 MiQueryVirtualMemory (IN HANDLE ProcessHandle,
115 IN PVOID Address,
116 IN CINT 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 < (PVOID)KERNEL_BASE)
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 = &Process->AddressSpace;
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 Status = MmQueryAnonMem(MemoryArea, Address, Info,
179 ResultLength);
180 break;
181 case MEMORY_AREA_SECTION_VIEW:
182 Status = MmQuerySectionView(MemoryArea, Address, Info,
183 ResultLength);
184 break;
185 case MEMORY_AREA_NO_ACCESS:
186 Info->Type = 0;
187 Info->State = MEM_FREE;
188 Info->Protect = MemoryArea->Attributes;
189 Info->AllocationProtect = MemoryArea->Attributes;
190 Info->BaseAddress = MemoryArea->StartingAddress;
191 Info->AllocationBase = MemoryArea->StartingAddress;
192 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
193 (ULONG_PTR)MemoryArea->StartingAddress;
194 Status = STATUS_SUCCESS;
195 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
196 break;
197 case MEMORY_AREA_SHARED_DATA:
198 Info->Type = 0;
199 Info->State = MEM_COMMIT;
200 Info->Protect = MemoryArea->Attributes;
201 Info->AllocationProtect = MemoryArea->Attributes;
202 Info->BaseAddress = MemoryArea->StartingAddress;
203 Info->AllocationBase = MemoryArea->StartingAddress;
204 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
205 (ULONG_PTR)MemoryArea->StartingAddress;
206 Status = STATUS_SUCCESS;
207 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
208 break;
209 case MEMORY_AREA_SYSTEM:
210 Info->Type = 0;
211 Info->State = MEM_COMMIT;
212 Info->Protect = MemoryArea->Attributes;
213 Info->AllocationProtect = MemoryArea->Attributes;
214 Info->BaseAddress = MemoryArea->StartingAddress;
215 Info->AllocationBase = MemoryArea->StartingAddress;
216 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
217 (ULONG_PTR)MemoryArea->StartingAddress;
218 Status = STATUS_SUCCESS;
219 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
220 break;
221 case MEMORY_AREA_KERNEL_STACK:
222 Info->Type = 0;
223 Info->State = MEM_COMMIT;
224 Info->Protect = MemoryArea->Attributes;
225 Info->AllocationProtect = MemoryArea->Attributes;
226 Info->BaseAddress = MemoryArea->StartingAddress;
227 Info->AllocationBase = MemoryArea->StartingAddress;
228 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
229 (ULONG_PTR)MemoryArea->StartingAddress;
230 Status = STATUS_SUCCESS;
231 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
232 break;
233 default:
234 DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea->Type);
235 Status = STATUS_UNSUCCESSFUL;
236 *ResultLength = 0;
237 }
238 }
239 break;
240 }
241
242 default:
243 {
244 Status = STATUS_INVALID_INFO_CLASS;
245 *ResultLength = 0;
246 break;
247 }
248 }
249
250 MmUnlockAddressSpace(AddressSpace);
251 if (Address < (PVOID)KERNEL_BASE)
252 {
253 ObDereferenceObject(Process);
254 }
255
256 return Status;
257 }
258
259 /* (tMk 2004.II.4)
260 * FUNCTION:
261 * Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
262 *
263 */
264 NTSTATUS STDCALL
265 NtQueryVirtualMemory (IN HANDLE ProcessHandle,
266 IN PVOID Address,
267 IN CINT VirtualMemoryInformationClass,
268 OUT PVOID VirtualMemoryInformation,
269 IN ULONG Length,
270 OUT PULONG UnsafeResultLength)
271 {
272 NTSTATUS Status;
273 ULONG ResultLength = 0;
274 KPROCESSOR_MODE PrevMode;
275 union
276 {
277 MEMORY_BASIC_INFORMATION BasicInfo;
278 }
279 VirtualMemoryInfo;
280
281 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
282 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
283 "Length %lu ResultLength %x)\n",ProcessHandle,Address,
284 VirtualMemoryInformationClass,VirtualMemoryInformation,
285 Length,ResultLength);
286
287 PrevMode = ExGetPreviousMode();
288
289 if (Address >= (PVOID)KERNEL_BASE)
290 {
291 DPRINT1("Invalid parameter\n");
292 return STATUS_INVALID_PARAMETER;
293 }
294
295 Status = MiQueryVirtualMemory ( ProcessHandle,
296 Address,
297 VirtualMemoryInformationClass,
298 &VirtualMemoryInfo,
299 Length,
300 &ResultLength );
301
302 if (NT_SUCCESS(Status) && ResultLength > 0)
303 {
304 Status = MmCopyToCaller(VirtualMemoryInformation, &VirtualMemoryInfo, ResultLength);
305 if (!NT_SUCCESS(Status))
306 {
307 ResultLength = 0;
308 }
309 }
310
311 if (UnsafeResultLength != NULL)
312 {
313 MmCopyToCaller(UnsafeResultLength, &ResultLength, sizeof(ULONG));
314 }
315 return(Status);
316 }
317
318
319 NTSTATUS STDCALL
320 MiProtectVirtualMemory(IN PEPROCESS Process,
321 IN OUT PVOID *BaseAddress,
322 IN OUT PULONG NumberOfBytesToProtect,
323 IN ULONG NewAccessProtection,
324 OUT PULONG OldAccessProtection OPTIONAL)
325 {
326 PMEMORY_AREA MemoryArea;
327 PMADDRESS_SPACE AddressSpace;
328 ULONG OldAccessProtection_;
329 NTSTATUS Status;
330
331 *NumberOfBytesToProtect =
332 PAGE_ROUND_UP((*BaseAddress) + (*NumberOfBytesToProtect)) -
333 PAGE_ROUND_DOWN(*BaseAddress);
334 *BaseAddress = (PVOID)PAGE_ROUND_DOWN(*BaseAddress);
335
336 AddressSpace = &Process->AddressSpace;
337
338 MmLockAddressSpace(AddressSpace);
339 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *BaseAddress);
340 if (MemoryArea == NULL)
341 {
342 MmUnlockAddressSpace(AddressSpace);
343 return STATUS_UNSUCCESSFUL;
344 }
345
346 if (OldAccessProtection == NULL)
347 OldAccessProtection = &OldAccessProtection_;
348
349 if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
350 {
351 Status = MmProtectAnonMem(AddressSpace, MemoryArea, *BaseAddress,
352 *NumberOfBytesToProtect, NewAccessProtection,
353 OldAccessProtection);
354 }
355 else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
356 {
357 Status = MmProtectSectionView(AddressSpace, MemoryArea, *BaseAddress,
358 *NumberOfBytesToProtect,
359 NewAccessProtection,
360 OldAccessProtection);
361 }
362 else
363 {
364 /* FIXME: Should we return failure or success in this case? */
365 Status = STATUS_SUCCESS;
366 }
367
368 MmUnlockAddressSpace(AddressSpace);
369
370 return Status;
371 }
372
373
374 /* (tMk 2004.II.5)
375 * FUNCTION:
376 * Called from VirtualProtectEx (lib\kernel32\mem\virtual.c)
377 *
378 */
379 NTSTATUS STDCALL
380 NtProtectVirtualMemory(IN HANDLE ProcessHandle,
381 IN OUT PVOID *UnsafeBaseAddress,
382 IN OUT ULONG *UnsafeNumberOfBytesToProtect,
383 IN ULONG NewAccessProtection,
384 OUT PULONG UnsafeOldAccessProtection)
385 {
386 PEPROCESS Process;
387 NTSTATUS Status;
388 ULONG OldAccessProtection;
389 PVOID BaseAddress;
390 ULONG NumberOfBytesToProtect;
391
392 Status = MmCopyFromCaller(&BaseAddress, UnsafeBaseAddress, sizeof(PVOID));
393 if (!NT_SUCCESS(Status))
394 return Status;
395 Status = MmCopyFromCaller(&NumberOfBytesToProtect, UnsafeNumberOfBytesToProtect, sizeof(ULONG));
396 if (!NT_SUCCESS(Status))
397 return Status;
398
399 /* (tMk 2004.II.5) in Microsoft SDK I read:
400 * 'if this parameter is NULL or does not point to a valid variable, the function fails'
401 */
402 if(UnsafeOldAccessProtection == NULL)
403 {
404 return(STATUS_INVALID_PARAMETER);
405 }
406
407 Status = ObReferenceObjectByHandle(ProcessHandle,
408 PROCESS_VM_OPERATION,
409 PsProcessType,
410 UserMode,
411 (PVOID*)(&Process),
412 NULL);
413 if (!NT_SUCCESS(Status))
414 {
415 DPRINT("NtProtectVirtualMemory() = %x\n",Status);
416 return(Status);
417 }
418
419 Status = MiProtectVirtualMemory(Process,
420 &BaseAddress,
421 &NumberOfBytesToProtect,
422 NewAccessProtection,
423 &OldAccessProtection);
424
425 ObDereferenceObject(Process);
426
427 MmCopyToCaller(UnsafeOldAccessProtection, &OldAccessProtection, sizeof(ULONG));
428 MmCopyToCaller(UnsafeBaseAddress, &BaseAddress, sizeof(PVOID));
429 MmCopyToCaller(UnsafeNumberOfBytesToProtect, &NumberOfBytesToProtect, sizeof(ULONG));
430
431 return(Status);
432 }
433
434
435 /* (tMk 2004.II.05)
436 * FUNCTION:
437 * Called from ReadProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
438 *
439 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
440 */
441 NTSTATUS STDCALL
442 NtReadVirtualMemory(IN HANDLE ProcessHandle,
443 IN PVOID BaseAddress,
444 OUT PVOID Buffer,
445 IN ULONG NumberOfBytesToRead,
446 OUT PULONG NumberOfBytesRead OPTIONAL)
447 {
448 PMDL Mdl;
449 PVOID SystemAddress;
450 KPROCESSOR_MODE PreviousMode;
451 PEPROCESS Process, CurrentProcess;
452 NTSTATUS Status = STATUS_SUCCESS;
453
454 PAGED_CODE();
455
456 PreviousMode = ExGetPreviousMode();
457
458 if(PreviousMode != KernelMode)
459 {
460 _SEH_TRY
461 {
462 ProbeForWrite(Buffer,
463 NumberOfBytesToRead,
464 1);
465 if(NumberOfBytesRead != NULL)
466 {
467 ProbeForWrite(NumberOfBytesRead,
468 sizeof(ULONG),
469 sizeof(ULONG));
470 }
471 }
472 _SEH_HANDLE
473 {
474 Status = _SEH_GetExceptionCode();
475 }
476 _SEH_END;
477
478 if(!NT_SUCCESS(Status))
479 {
480 return Status;
481 }
482 }
483
484 DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
485 "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress,
486 Buffer,NumberOfBytesToRead);
487
488 Status = ObReferenceObjectByHandle(ProcessHandle,
489 PROCESS_VM_READ,
490 NULL,
491 PreviousMode,
492 (PVOID*)(&Process),
493 NULL);
494 if (!NT_SUCCESS(Status))
495 {
496 return(Status);
497 }
498
499 CurrentProcess = PsGetCurrentProcess();
500
501 if (Process == CurrentProcess)
502 {
503 _SEH_TRY
504 {
505 RtlCopyMemory(Buffer, BaseAddress, NumberOfBytesToRead);
506 }
507 _SEH_HANDLE
508 {
509 Status = _SEH_GetExceptionCode();
510 }
511 _SEH_END;
512 }
513 else
514 {
515 Mdl = MmCreateMdl(NULL,
516 Buffer,
517 NumberOfBytesToRead);
518 if(Mdl == NULL)
519 {
520 ObDereferenceObject(Process);
521 return(STATUS_NO_MEMORY);
522 }
523 _SEH_TRY
524 {
525 MmProbeAndLockPages(Mdl,
526 PreviousMode,
527 IoWriteAccess);
528 }
529 _SEH_HANDLE
530 {
531 Status = _SEH_GetExceptionCode();
532 }
533 _SEH_END;
534
535 if(NT_SUCCESS(Status))
536 {
537 KeAttachProcess(&Process->Pcb);
538
539 SystemAddress = MmGetSystemAddressForMdl(Mdl);
540
541 Status = STATUS_SUCCESS;
542 _SEH_TRY {
543 ProbeForRead(BaseAddress, NumberOfBytesToRead, 1);
544 Status = STATUS_PARTIAL_COPY;
545 RtlCopyMemory(SystemAddress, BaseAddress, NumberOfBytesToRead);
546 Status = STATUS_SUCCESS;
547 } _SEH_HANDLE {
548 if(Status != STATUS_PARTIAL_COPY)
549 Status = _SEH_GetExceptionCode();
550 } _SEH_END;
551
552 KeDetachProcess();
553
554 if (Mdl->MappedSystemVa != NULL)
555 {
556 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
557 }
558 MmUnlockPages(Mdl);
559 }
560 ExFreePool(Mdl);
561 }
562
563 ObDereferenceObject(Process);
564
565 if((NT_SUCCESS(Status) || Status == STATUS_PARTIAL_COPY) &&
566 NumberOfBytesRead != NULL)
567 {
568 _SEH_TRY
569 {
570 *NumberOfBytesRead = NumberOfBytesToRead;
571 }
572 _SEH_HANDLE
573 {
574 Status = _SEH_GetExceptionCode();
575 }
576 _SEH_END;
577 }
578
579 return(Status);
580 }
581
582 /* (tMk 2004.II.05)
583 * FUNCTION: THIS function doesn't make a sense...
584 * Called from VirtualUnlock (lib\kernel32\mem\virtual.c)
585 */
586 NTSTATUS STDCALL
587 NtUnlockVirtualMemory(HANDLE ProcessHandle,
588 PVOID BaseAddress,
589 ULONG NumberOfBytesToUnlock,
590 PULONG NumberOfBytesUnlocked OPTIONAL)
591 {
592 // AG [08-20-03] : I have *no* idea if this is correct, I just used the
593 // other functions as a template and made a few intelligent guesses...
594
595 NTSTATUS Status;
596 PMDL Mdl;
597 PEPROCESS Process;
598
599 DPRINT("NtUnlockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
600 "NumberOfBytesToUnlock %d), NumberOfBytesUnlocked %x\n",ProcessHandle,BaseAddress,
601 NumberOfBytesToUnlock, NumberOfBytesUnlocked);
602
603 Status = ObReferenceObjectByHandle(ProcessHandle,
604 PROCESS_VM_WRITE,
605 NULL,
606 UserMode,
607 (PVOID*)(&Process),
608 NULL);
609 if (!NT_SUCCESS(Status))
610 {
611 return(Status);
612 }
613
614 Mdl = MmCreateMdl(NULL,
615 BaseAddress,
616 NumberOfBytesToUnlock);
617 if(Mdl == NULL)
618 {
619 ObDereferenceObject(Process);
620 return(STATUS_NO_MEMORY);
621 }
622
623 ObDereferenceObject(Process);
624
625 if (Mdl->MappedSystemVa != NULL)
626 {
627 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
628 }
629 MmUnlockPages(Mdl);
630 ExFreePool(Mdl);
631
632 *NumberOfBytesUnlocked = NumberOfBytesToUnlock;
633
634 return(STATUS_SUCCESS);
635 }
636
637
638 /* (tMk 2004.II.05)
639 * FUNCTION:
640 * Called from WriteProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
641 *
642 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
643 */
644 NTSTATUS STDCALL
645 NtWriteVirtualMemory(IN HANDLE ProcessHandle,
646 IN PVOID BaseAddress,
647 IN PVOID Buffer,
648 IN ULONG NumberOfBytesToWrite,
649 OUT PULONG NumberOfBytesWritten OPTIONAL)
650 {
651 NTSTATUS Status;
652 PMDL Mdl;
653 PVOID SystemAddress;
654 PEPROCESS Process;
655 ULONG OldProtection = 0;
656 PVOID ProtectBaseAddress;
657 ULONG ProtectNumberOfBytes;
658
659 DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
660 "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle,BaseAddress,
661 Buffer,NumberOfBytesToWrite);
662
663 Status = ObReferenceObjectByHandle(ProcessHandle,
664 PROCESS_VM_WRITE,
665 NULL,
666 UserMode,
667 (PVOID*)(&Process),
668 NULL);
669 if (!NT_SUCCESS(Status))
670 {
671 return(Status);
672 }
673
674 /* We have to make sure the target memory is writable.
675 *
676 * I am not sure if it is correct to do this in any case, but it has to be
677 * done at least in some cases because you can use WriteProcessMemory to
678 * write into the .text section of a module where memcpy() would crash.
679 * -blight (2005/01/09)
680 */
681 ProtectBaseAddress = BaseAddress;
682 ProtectNumberOfBytes = NumberOfBytesToWrite;
683
684 /* Write memory */
685 if (Process == PsGetCurrentProcess())
686 {
687 Status = MiProtectVirtualMemory(Process,
688 &ProtectBaseAddress,
689 &ProtectNumberOfBytes,
690 PAGE_READWRITE,
691 &OldProtection);
692 if (!NT_SUCCESS(Status))
693 {
694 ObDereferenceObject(Process);
695 return Status;
696 }
697 memcpy(BaseAddress, Buffer, NumberOfBytesToWrite);
698 }
699 else
700 {
701 /* Create MDL describing the source buffer. */
702 Mdl = MmCreateMdl(NULL,
703 Buffer,
704 NumberOfBytesToWrite);
705 if(Mdl == NULL)
706 {
707 ObDereferenceObject(Process);
708 return(STATUS_NO_MEMORY);
709 }
710
711 /* Make the target area writable. */
712 Status = MiProtectVirtualMemory(Process,
713 &ProtectBaseAddress,
714 &ProtectNumberOfBytes,
715 PAGE_READWRITE,
716 &OldProtection);
717 if (!NT_SUCCESS(Status))
718 {
719 ObDereferenceObject(Process);
720 ExFreePool(Mdl);
721 return Status;
722 }
723
724 /* Map the MDL. */
725 MmProbeAndLockPages(Mdl,
726 UserMode,
727 IoReadAccess);
728
729 /* Copy memory from the mapped MDL into the target buffer. */
730 KeAttachProcess(&Process->Pcb);
731
732 SystemAddress = MmGetSystemAddressForMdl(Mdl);
733 memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
734
735 KeDetachProcess();
736
737 /* Free the MDL. */
738 if (Mdl->MappedSystemVa != NULL)
739 {
740 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
741 }
742 MmUnlockPages(Mdl);
743 ExFreePool(Mdl);
744 }
745
746 /* Reset the protection of the target memory. */
747 Status = MiProtectVirtualMemory(Process,
748 &ProtectBaseAddress,
749 &ProtectNumberOfBytes,
750 OldProtection,
751 &OldProtection);
752 if (!NT_SUCCESS(Status))
753 {
754 DPRINT1("Failed to reset protection of the target memory! (Status 0x%x)\n", Status);
755 /* FIXME: Should we bugcheck here? */
756 }
757
758 ObDereferenceObject(Process);
759
760 if (NumberOfBytesWritten != NULL)
761 MmCopyToCaller(NumberOfBytesWritten, &NumberOfBytesToWrite, sizeof(ULONG));
762
763 return(STATUS_SUCCESS);
764 }
765
766 /*
767 * @unimplemented
768 */
769
770 PVOID
771 STDCALL
772 MmGetVirtualForPhysical (
773 IN PHYSICAL_ADDRESS PhysicalAddress
774 )
775 {
776 UNIMPLEMENTED;
777 return 0;
778 }
779
780 /* FUNCTION:
781 * Called from EngSecureMem (subsys\win32k\eng\mem.c)
782 * @unimplemented
783 */
784 PVOID STDCALL
785 MmSecureVirtualMemory (PVOID Address,
786 SIZE_T Length,
787 ULONG Mode)
788 {
789 /* Only works for user space */
790 if (MmHighestUserAddress < Address)
791 {
792 return NULL;
793 }
794
795 UNIMPLEMENTED;
796
797 return 0;
798 }
799
800
801 /* FUNCTION:
802 * Called from EngUnsecureMem (subsys\win32k\eng\mem.c)
803 * @unimplemented
804 */
805 VOID STDCALL
806 MmUnsecureVirtualMemory(PVOID SecureMem)
807 {
808 if (NULL == SecureMem)
809 {
810 return;
811 }
812
813 UNIMPLEMENTED;
814 }
815
816
817 /*
818 * @implemented
819 */
820 VOID STDCALL
821 ProbeForRead (IN CONST VOID *Address,
822 IN ULONG Length,
823 IN ULONG Alignment)
824 {
825 ASSERT(Alignment == 1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
826
827 if (Length == 0)
828 return;
829
830 if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
831 {
832 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
833 }
834 else if ((ULONG_PTR)Address + Length - 1 < (ULONG_PTR)Address ||
835 (ULONG_PTR)Address + Length - 1 > (ULONG_PTR)MmUserProbeAddress)
836 {
837 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
838 }
839 }
840
841
842 /*
843 * @implemented
844 */
845 VOID STDCALL
846 ProbeForWrite (IN CONST VOID *Address,
847 IN ULONG Length,
848 IN ULONG Alignment)
849 {
850 volatile CHAR *Current;
851 PCHAR Last;
852
853 ASSERT(Alignment == 1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
854
855 if (Length == 0)
856 return;
857
858 if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
859 {
860 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
861 }
862
863 Last = (PCHAR)((ULONG_PTR)Address + Length - 1);
864 if ((ULONG_PTR)Last < (ULONG_PTR)Address ||
865 (ULONG_PTR)Last > (ULONG_PTR)MmUserProbeAddress)
866 {
867 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
868 }
869
870 /* Check for accessible pages */
871 Current = (CHAR*)Address;
872 do
873 {
874 *Current = *Current;
875 Current = (CHAR*)((ULONG_PTR)Current + PAGE_SIZE);
876 } while (Current <= Last);
877 }
878
879 /* EOF */