fixed implementation of SetErrorMode() which should rather store the mode in the...
[reactos.git] / reactos / ntoskrnl / mm / virtual.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/virtual.c
23 * PURPOSE: Implementing operations on virtual memory.
24 * PROGRAMMER: David Welch
25 */
26
27 /* INCLUDE *****************************************************************/
28
29 #include <ntoskrnl.h>
30
31 #define NDEBUG
32 #include <internal/debug.h>
33
34 /* FUNCTIONS *****************************************************************/
35
36 NTSTATUS STDCALL
37 NtFlushVirtualMemory(IN HANDLE ProcessHandle,
38 IN PVOID BaseAddress,
39 IN ULONG NumberOfBytesToFlush,
40 OUT PULONG NumberOfBytesFlushed OPTIONAL)
41 /*
42 * FUNCTION: Flushes virtual memory to file
43 * ARGUMENTS:
44 * ProcessHandle = Points to the process that allocated the virtual
45 * memory
46 * BaseAddress = Points to the memory address
47 * NumberOfBytesToFlush = Limits the range to flush,
48 * NumberOfBytesFlushed = Actual number of bytes flushed
49 * RETURNS: Status
50 */
51 {
52 UNIMPLEMENTED;
53 return(STATUS_NOT_IMPLEMENTED);
54 }
55
56
57 NTSTATUS STDCALL
58 MiLockVirtualMemory(HANDLE ProcessHandle,
59 PVOID BaseAddress,
60 ULONG NumberOfBytesToLock,
61 PULONG NumberOfBytesLocked,
62 PObReferenceObjectByHandle pObReferenceObjectByHandle,
63 PMmCreateMdl pMmCreateMdl,
64 PObDereferenceObject pObDereferenceObject,
65 PMmProbeAndLockPages pMmProbeAndLockPages,
66 PExFreePool pExFreePool)
67 {
68 PEPROCESS Process;
69 NTSTATUS Status;
70 PMDL Mdl;
71
72 Status = pObReferenceObjectByHandle(ProcessHandle,
73 PROCESS_VM_WRITE,
74 NULL,
75 UserMode,
76 (PVOID*)(&Process),
77 NULL);
78 if (!NT_SUCCESS(Status))
79 return(Status);
80
81 Mdl = pMmCreateMdl(NULL,
82 BaseAddress,
83 NumberOfBytesToLock);
84 if (Mdl == NULL)
85 {
86 pObDereferenceObject(Process);
87 return(STATUS_NO_MEMORY);
88 }
89
90 pMmProbeAndLockPages(Mdl,
91 UserMode,
92 IoWriteAccess);
93
94 pExFreePool(Mdl);
95
96 pObDereferenceObject(Process);
97
98 *NumberOfBytesLocked = NumberOfBytesToLock;
99 return(STATUS_SUCCESS);
100 }
101
102
103 NTSTATUS STDCALL
104 NtLockVirtualMemory(HANDLE ProcessHandle,
105 PVOID BaseAddress,
106 ULONG NumberOfBytesToLock,
107 PULONG NumberOfBytesLocked)
108 {
109 DPRINT("NtLockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
110 "NumberOfBytesToLock %d, NumberOfBytesLocked %x)\n",
111 ProcessHandle,
112 BaseAddress,
113 NumberOfBytesToLock,
114 NumberOfBytesLocked);
115
116 return MiLockVirtualMemory(ProcessHandle,
117 BaseAddress,
118 NumberOfBytesToLock,
119 NumberOfBytesLocked,
120 ObReferenceObjectByHandle,
121 MmCreateMdl,
122 ObfDereferenceObject,
123 MmProbeAndLockPages,
124 ExFreePool);
125 }
126
127
128 NTSTATUS FASTCALL
129 MiQueryVirtualMemory (IN HANDLE ProcessHandle,
130 IN PVOID Address,
131 IN CINT VirtualMemoryInformationClass,
132 OUT PVOID VirtualMemoryInformation,
133 IN ULONG Length,
134 OUT PULONG ResultLength)
135 {
136 NTSTATUS Status;
137 PEPROCESS Process;
138 MEMORY_AREA* MemoryArea;
139 PMADDRESS_SPACE AddressSpace;
140
141 if (Address < (PVOID)KERNEL_BASE)
142 {
143 Status = ObReferenceObjectByHandle(ProcessHandle,
144 PROCESS_QUERY_INFORMATION,
145 NULL,
146 UserMode,
147 (PVOID*)(&Process),
148 NULL);
149
150 if (!NT_SUCCESS(Status))
151 {
152 DPRINT("NtQueryVirtualMemory() = %x\n",Status);
153 return(Status);
154 }
155 AddressSpace = &Process->AddressSpace;
156 }
157 else
158 {
159 AddressSpace = MmGetKernelAddressSpace();
160 }
161 MmLockAddressSpace(AddressSpace);
162 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
163 switch(VirtualMemoryInformationClass)
164 {
165 case MemoryBasicInformation:
166 {
167 PMEMORY_BASIC_INFORMATION Info =
168 (PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation;
169 if (Length != sizeof(MEMORY_BASIC_INFORMATION))
170 {
171 MmUnlockAddressSpace(AddressSpace);
172 ObDereferenceObject(Process);
173 return(STATUS_INFO_LENGTH_MISMATCH);
174 }
175
176 if (MemoryArea == NULL)
177 {
178 Info->Type = 0;
179 Info->State = MEM_FREE;
180 Info->Protect = PAGE_NOACCESS;
181 Info->AllocationProtect = 0;
182 Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
183 Info->AllocationBase = NULL;
184 Info->RegionSize = MmFindGapAtAddress(AddressSpace, Info->BaseAddress);
185 Status = STATUS_SUCCESS;
186 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
187 }
188 else
189 {
190 switch(MemoryArea->Type)
191 {
192 case MEMORY_AREA_VIRTUAL_MEMORY:
193 Status = MmQueryAnonMem(MemoryArea, Address, Info,
194 ResultLength);
195 break;
196 case MEMORY_AREA_SECTION_VIEW:
197 Status = MmQuerySectionView(MemoryArea, Address, Info,
198 ResultLength);
199 break;
200 case MEMORY_AREA_NO_ACCESS:
201 Info->Type = 0;
202 Info->State = MEM_FREE;
203 Info->Protect = MemoryArea->Attributes;
204 Info->AllocationProtect = MemoryArea->Attributes;
205 Info->BaseAddress = MemoryArea->StartingAddress;
206 Info->AllocationBase = MemoryArea->StartingAddress;
207 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
208 (ULONG_PTR)MemoryArea->StartingAddress;
209 Status = STATUS_SUCCESS;
210 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
211 break;
212 case MEMORY_AREA_SHARED_DATA:
213 Info->Type = 0;
214 Info->State = MEM_COMMIT;
215 Info->Protect = MemoryArea->Attributes;
216 Info->AllocationProtect = MemoryArea->Attributes;
217 Info->BaseAddress = MemoryArea->StartingAddress;
218 Info->AllocationBase = MemoryArea->StartingAddress;
219 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
220 (ULONG_PTR)MemoryArea->StartingAddress;
221 Status = STATUS_SUCCESS;
222 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
223 break;
224 case MEMORY_AREA_SYSTEM:
225 {
226 static int warned = 0;
227 if ( !warned )
228 {
229 DPRINT1("FIXME: MEMORY_AREA_SYSTEM case incomplete (or possibly wrong) for NtQueryVirtualMemory()\n");
230 warned = 1;
231 }
232 }
233 /* FIXME - don't have a clue if this is right, but it's better than nothing */
234 Info->Type = 0;
235 Info->State = MEM_COMMIT;
236 Info->Protect = MemoryArea->Attributes;
237 Info->AllocationProtect = MemoryArea->Attributes;
238 Info->BaseAddress = MemoryArea->StartingAddress;
239 Info->AllocationBase = MemoryArea->StartingAddress;
240 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
241 (ULONG_PTR)MemoryArea->StartingAddress;
242 Status = STATUS_SUCCESS;
243 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
244 break;
245 case MEMORY_AREA_KERNEL_STACK:
246 {
247 static int warned = 0;
248 if ( !warned )
249 {
250 DPRINT1("FIXME: MEMORY_AREA_KERNEL_STACK case incomplete (or possibly wrong) for NtQueryVirtualMemory()\n");
251 warned = 1;
252 }
253 }
254 /* FIXME - don't have a clue if this is right, but it's better than nothing */
255 Info->Type = 0;
256 Info->State = MEM_COMMIT;
257 Info->Protect = MemoryArea->Attributes;
258 Info->AllocationProtect = MemoryArea->Attributes;
259 Info->BaseAddress = MemoryArea->StartingAddress;
260 Info->AllocationBase = MemoryArea->StartingAddress;
261 Info->RegionSize = (ULONG_PTR)MemoryArea->EndingAddress -
262 (ULONG_PTR)MemoryArea->StartingAddress;
263 Status = STATUS_SUCCESS;
264 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
265 break;
266 default:
267 DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea->Type);
268 Status = STATUS_UNSUCCESSFUL;
269 *ResultLength = 0;
270 }
271 }
272 break;
273 }
274
275 default:
276 {
277 Status = STATUS_INVALID_INFO_CLASS;
278 *ResultLength = 0;
279 break;
280 }
281 }
282
283 MmUnlockAddressSpace(AddressSpace);
284 if (Address < (PVOID)KERNEL_BASE)
285 {
286 ObDereferenceObject(Process);
287 }
288
289 return Status;
290 }
291
292 /* (tMk 2004.II.4)
293 * FUNCTION:
294 * Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
295 *
296 */
297 NTSTATUS STDCALL
298 NtQueryVirtualMemory (IN HANDLE ProcessHandle,
299 IN PVOID Address,
300 IN CINT VirtualMemoryInformationClass,
301 OUT PVOID VirtualMemoryInformation,
302 IN ULONG Length,
303 OUT PULONG UnsafeResultLength)
304 {
305 NTSTATUS Status;
306 ULONG ResultLength = 0;
307 KPROCESSOR_MODE PrevMode;
308 union
309 {
310 MEMORY_BASIC_INFORMATION BasicInfo;
311 }
312 VirtualMemoryInfo;
313
314 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
315 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
316 "Length %lu ResultLength %x)\n",ProcessHandle,Address,
317 VirtualMemoryInformationClass,VirtualMemoryInformation,
318 Length,ResultLength);
319
320 PrevMode = ExGetPreviousMode();
321
322 if (PrevMode == UserMode && Address >= (PVOID)KERNEL_BASE)
323 {
324 DPRINT1("Invalid parameter\n");
325 return STATUS_INVALID_PARAMETER;
326 }
327
328 Status = MiQueryVirtualMemory ( ProcessHandle,
329 Address,
330 VirtualMemoryInformationClass,
331 &VirtualMemoryInfo,
332 Length,
333 &ResultLength );
334
335 if (NT_SUCCESS(Status) && ResultLength > 0)
336 {
337 Status = MmCopyToCaller(VirtualMemoryInformation, &VirtualMemoryInfo, ResultLength);
338 if (!NT_SUCCESS(Status))
339 {
340 ResultLength = 0;
341 }
342 }
343
344 if (UnsafeResultLength != NULL)
345 {
346 MmCopyToCaller(UnsafeResultLength, &ResultLength, sizeof(ULONG));
347 }
348 return(Status);
349 }
350
351
352 NTSTATUS STDCALL
353 MiProtectVirtualMemory(IN PEPROCESS Process,
354 IN OUT PVOID *BaseAddress,
355 IN OUT PULONG NumberOfBytesToProtect,
356 IN ULONG NewAccessProtection,
357 OUT PULONG OldAccessProtection OPTIONAL)
358 {
359 PMEMORY_AREA MemoryArea;
360 PMADDRESS_SPACE AddressSpace;
361 ULONG OldAccessProtection_;
362 NTSTATUS Status;
363
364 *NumberOfBytesToProtect =
365 PAGE_ROUND_UP((*BaseAddress) + (*NumberOfBytesToProtect)) -
366 PAGE_ROUND_DOWN(*BaseAddress);
367 *BaseAddress = (PVOID)PAGE_ROUND_DOWN(*BaseAddress);
368
369 AddressSpace = &Process->AddressSpace;
370
371 MmLockAddressSpace(AddressSpace);
372 MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, *BaseAddress);
373 if (MemoryArea == NULL)
374 {
375 MmUnlockAddressSpace(AddressSpace);
376 return STATUS_UNSUCCESSFUL;
377 }
378
379 if (OldAccessProtection == NULL)
380 OldAccessProtection = &OldAccessProtection_;
381
382 if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
383 {
384 Status = MmProtectAnonMem(AddressSpace, MemoryArea, *BaseAddress,
385 *NumberOfBytesToProtect, NewAccessProtection,
386 OldAccessProtection);
387 }
388 else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
389 {
390 Status = MmProtectSectionView(AddressSpace, MemoryArea, *BaseAddress,
391 *NumberOfBytesToProtect,
392 NewAccessProtection,
393 OldAccessProtection);
394 }
395 else
396 {
397 /* FIXME: Should we return failure or success in this case? */
398 Status = STATUS_SUCCESS;
399 }
400
401 MmUnlockAddressSpace(AddressSpace);
402
403 return Status;
404 }
405
406
407 /* (tMk 2004.II.5)
408 * FUNCTION:
409 * Called from VirtualProtectEx (lib\kernel32\mem\virtual.c)
410 *
411 */
412 NTSTATUS STDCALL
413 NtProtectVirtualMemory(IN HANDLE ProcessHandle,
414 IN OUT PVOID *UnsafeBaseAddress,
415 IN OUT ULONG *UnsafeNumberOfBytesToProtect,
416 IN ULONG NewAccessProtection,
417 OUT PULONG UnsafeOldAccessProtection)
418 {
419 PEPROCESS Process;
420 NTSTATUS Status;
421 ULONG OldAccessProtection;
422 PVOID BaseAddress;
423 ULONG NumberOfBytesToProtect;
424
425 Status = MmCopyFromCaller(&BaseAddress, UnsafeBaseAddress, sizeof(PVOID));
426 if (!NT_SUCCESS(Status))
427 return Status;
428 Status = MmCopyFromCaller(&NumberOfBytesToProtect, UnsafeNumberOfBytesToProtect, sizeof(ULONG));
429 if (!NT_SUCCESS(Status))
430 return Status;
431
432 /* (tMk 2004.II.5) in Microsoft SDK I read:
433 * 'if this parameter is NULL or does not point to a valid variable, the function fails'
434 */
435 if(UnsafeOldAccessProtection == NULL)
436 {
437 return(STATUS_INVALID_PARAMETER);
438 }
439
440 Status = ObReferenceObjectByHandle(ProcessHandle,
441 PROCESS_VM_OPERATION,
442 PsProcessType,
443 UserMode,
444 (PVOID*)(&Process),
445 NULL);
446 if (!NT_SUCCESS(Status))
447 {
448 DPRINT("NtProtectVirtualMemory() = %x\n",Status);
449 return(Status);
450 }
451
452 Status = MiProtectVirtualMemory(Process,
453 &BaseAddress,
454 &NumberOfBytesToProtect,
455 NewAccessProtection,
456 &OldAccessProtection);
457
458 ObDereferenceObject(Process);
459
460 MmCopyToCaller(UnsafeOldAccessProtection, &OldAccessProtection, sizeof(ULONG));
461 MmCopyToCaller(UnsafeBaseAddress, &BaseAddress, sizeof(PVOID));
462 MmCopyToCaller(UnsafeNumberOfBytesToProtect, &NumberOfBytesToProtect, sizeof(ULONG));
463
464 return(Status);
465 }
466
467
468 /* (tMk 2004.II.05)
469 * FUNCTION:
470 * Called from ReadProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
471 *
472 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
473 */
474 NTSTATUS STDCALL
475 NtReadVirtualMemory(IN HANDLE ProcessHandle,
476 IN PVOID BaseAddress,
477 OUT PVOID Buffer,
478 IN ULONG NumberOfBytesToRead,
479 OUT PULONG NumberOfBytesRead OPTIONAL)
480 {
481 NTSTATUS Status;
482 PMDL Mdl;
483 PVOID SystemAddress;
484 PEPROCESS Process, CurrentProcess;
485
486
487 DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
488 "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress,
489 Buffer,NumberOfBytesToRead);
490
491 Status = ObReferenceObjectByHandle(ProcessHandle,
492 PROCESS_VM_WRITE,
493 NULL,
494 UserMode,
495 (PVOID*)(&Process),
496 NULL);
497 if (!NT_SUCCESS(Status))
498 {
499 return(Status);
500 }
501
502 CurrentProcess = PsGetCurrentProcess();
503
504 if (Process == CurrentProcess)
505 {
506 memcpy(Buffer, BaseAddress, NumberOfBytesToRead);
507 }
508 else
509 {
510 Mdl = MmCreateMdl(NULL,
511 Buffer,
512 NumberOfBytesToRead);
513 if(Mdl == NULL)
514 {
515 ObDereferenceObject(Process);
516 return(STATUS_NO_MEMORY);
517 }
518 MmProbeAndLockPages(Mdl,
519 UserMode,
520 IoWriteAccess);
521
522 KeAttachProcess(&Process->Pcb);
523
524 SystemAddress = MmGetSystemAddressForMdl(Mdl);
525
526 Status = STATUS_SUCCESS;
527 _SEH_TRY {
528 ProbeForRead(BaseAddress, NumberOfBytesToRead, 1);
529 Status = STATUS_PARTIAL_COPY;
530 memcpy(SystemAddress, BaseAddress, NumberOfBytesToRead);
531 Status = STATUS_SUCCESS;
532 } _SEH_HANDLE {
533 if(Status != STATUS_PARTIAL_COPY)
534 Status = _SEH_GetExceptionCode();
535 } _SEH_END;
536
537 KeDetachProcess();
538
539 if (Mdl->MappedSystemVa != NULL)
540 {
541 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
542 }
543 MmUnlockPages(Mdl);
544 ExFreePool(Mdl);
545 }
546
547 ObDereferenceObject(Process);
548
549 if (NumberOfBytesRead)
550 *NumberOfBytesRead = NumberOfBytesToRead;
551 return(Status);
552 }
553
554 /* (tMk 2004.II.05)
555 * FUNCTION: THIS function doesn't make a sense...
556 * Called from VirtualUnlock (lib\kernel32\mem\virtual.c)
557 */
558 NTSTATUS STDCALL
559 NtUnlockVirtualMemory(HANDLE ProcessHandle,
560 PVOID BaseAddress,
561 ULONG NumberOfBytesToUnlock,
562 PULONG NumberOfBytesUnlocked OPTIONAL)
563 {
564 // AG [08-20-03] : I have *no* idea if this is correct, I just used the
565 // other functions as a template and made a few intelligent guesses...
566
567 NTSTATUS Status;
568 PMDL Mdl;
569 PEPROCESS Process;
570
571 DPRINT("NtUnlockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
572 "NumberOfBytesToUnlock %d), NumberOfBytesUnlocked %x\n",ProcessHandle,BaseAddress,
573 NumberOfBytesToUnlock, NumberOfBytesUnlocked);
574
575 Status = ObReferenceObjectByHandle(ProcessHandle,
576 PROCESS_VM_WRITE,
577 NULL,
578 UserMode,
579 (PVOID*)(&Process),
580 NULL);
581 if (!NT_SUCCESS(Status))
582 {
583 return(Status);
584 }
585
586 Mdl = MmCreateMdl(NULL,
587 BaseAddress,
588 NumberOfBytesToUnlock);
589 if(Mdl == NULL)
590 {
591 ObDereferenceObject(Process);
592 return(STATUS_NO_MEMORY);
593 }
594
595 ObDereferenceObject(Process);
596
597 if (Mdl->MappedSystemVa != NULL)
598 {
599 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
600 }
601 MmUnlockPages(Mdl);
602 ExFreePool(Mdl);
603
604 *NumberOfBytesUnlocked = NumberOfBytesToUnlock;
605
606 return(STATUS_SUCCESS);
607 }
608
609
610 /* (tMk 2004.II.05)
611 * FUNCTION:
612 * Called from WriteProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
613 *
614 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
615 */
616 NTSTATUS STDCALL
617 NtWriteVirtualMemory(IN HANDLE ProcessHandle,
618 IN PVOID BaseAddress,
619 IN PVOID Buffer,
620 IN ULONG NumberOfBytesToWrite,
621 OUT PULONG NumberOfBytesWritten OPTIONAL)
622 {
623 NTSTATUS Status;
624 PMDL Mdl;
625 PVOID SystemAddress;
626 PEPROCESS Process;
627 ULONG OldProtection = 0;
628 PVOID ProtectBaseAddress;
629 ULONG ProtectNumberOfBytes;
630
631 DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
632 "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle,BaseAddress,
633 Buffer,NumberOfBytesToWrite);
634
635 Status = ObReferenceObjectByHandle(ProcessHandle,
636 PROCESS_VM_WRITE,
637 NULL,
638 UserMode,
639 (PVOID*)(&Process),
640 NULL);
641 if (!NT_SUCCESS(Status))
642 {
643 return(Status);
644 }
645
646 /* We have to make sure the target memory is writable.
647 *
648 * I am not sure if it is correct to do this in any case, but it has to be
649 * done at least in some cases because you can use WriteProcessMemory to
650 * write into the .text section of a module where memcpy() would crash.
651 * -blight (2005/01/09)
652 */
653 ProtectBaseAddress = BaseAddress;
654 ProtectNumberOfBytes = NumberOfBytesToWrite;
655
656 /* Write memory */
657 if (Process == PsGetCurrentProcess())
658 {
659 Status = MiProtectVirtualMemory(Process,
660 &ProtectBaseAddress,
661 &ProtectNumberOfBytes,
662 PAGE_READWRITE,
663 &OldProtection);
664 if (!NT_SUCCESS(Status))
665 {
666 ObDereferenceObject(Process);
667 return Status;
668 }
669 memcpy(BaseAddress, Buffer, NumberOfBytesToWrite);
670 }
671 else
672 {
673 /* Create MDL describing the source buffer. */
674 Mdl = MmCreateMdl(NULL,
675 Buffer,
676 NumberOfBytesToWrite);
677 if(Mdl == NULL)
678 {
679 ObDereferenceObject(Process);
680 return(STATUS_NO_MEMORY);
681 }
682
683 /* Make the target area writable. */
684 Status = MiProtectVirtualMemory(Process,
685 &ProtectBaseAddress,
686 &ProtectNumberOfBytes,
687 PAGE_READWRITE,
688 &OldProtection);
689 if (!NT_SUCCESS(Status))
690 {
691 ObDereferenceObject(Process);
692 ExFreePool(Mdl);
693 return Status;
694 }
695
696 /* Map the MDL. */
697 MmProbeAndLockPages(Mdl,
698 UserMode,
699 IoReadAccess);
700
701 /* Copy memory from the mapped MDL into the target buffer. */
702 KeAttachProcess(&Process->Pcb);
703
704 SystemAddress = MmGetSystemAddressForMdl(Mdl);
705 memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
706
707 KeDetachProcess();
708
709 /* Free the MDL. */
710 if (Mdl->MappedSystemVa != NULL)
711 {
712 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
713 }
714 MmUnlockPages(Mdl);
715 ExFreePool(Mdl);
716 }
717
718 /* Reset the protection of the target memory. */
719 Status = MiProtectVirtualMemory(Process,
720 &ProtectBaseAddress,
721 &ProtectNumberOfBytes,
722 OldProtection,
723 &OldProtection);
724 if (!NT_SUCCESS(Status))
725 {
726 DPRINT1("Failed to reset protection of the target memory! (Status 0x%x)\n", Status);
727 /* FIXME: Should we bugcheck here? */
728 }
729
730 ObDereferenceObject(Process);
731
732 if (NumberOfBytesWritten != NULL)
733 MmCopyToCaller(NumberOfBytesWritten, &NumberOfBytesToWrite, sizeof(ULONG));
734
735 return(STATUS_SUCCESS);
736 }
737
738 /*
739 * @unimplemented
740 */
741
742 PVOID
743 STDCALL
744 MmGetVirtualForPhysical (
745 IN PHYSICAL_ADDRESS PhysicalAddress
746 )
747 {
748 UNIMPLEMENTED;
749 return 0;
750 }
751
752 /* FUNCTION:
753 * Called from EngSecureMem (subsys\win32k\eng\mem.c)
754 * @unimplemented
755 */
756 PVOID STDCALL
757 MmSecureVirtualMemory (PVOID Address,
758 SIZE_T Length,
759 ULONG Mode)
760 {
761 /* Only works for user space */
762 if (MmHighestUserAddress < Address)
763 {
764 return NULL;
765 }
766
767 UNIMPLEMENTED;
768
769 return 0;
770 }
771
772
773 /* FUNCTION:
774 * Called from EngUnsecureMem (subsys\win32k\eng\mem.c)
775 * @unimplemented
776 */
777 VOID STDCALL
778 MmUnsecureVirtualMemory(PVOID SecureMem)
779 {
780 if (NULL == SecureMem)
781 {
782 return;
783 }
784
785 UNIMPLEMENTED;
786 }
787
788
789 /*
790 * @implemented
791 */
792 VOID STDCALL
793 ProbeForRead (IN CONST VOID *Address,
794 IN ULONG Length,
795 IN ULONG Alignment)
796 {
797 ASSERT(Alignment ==1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
798
799 if (Length == 0)
800 return;
801
802 if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
803 {
804 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
805 }
806 else if ((ULONG_PTR)Address + Length < (ULONG_PTR)Address ||
807 (ULONG_PTR)Address + Length > (ULONG_PTR)MmUserProbeAddress)
808 {
809 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
810 }
811 }
812
813
814 /*
815 * @implemented
816 */
817 VOID STDCALL
818 ProbeForWrite (IN CONST VOID *Address,
819 IN ULONG Length,
820 IN ULONG Alignment)
821 {
822 PULONG Ptr;
823 ULONG x;
824 ULONG i;
825
826 ASSERT(Alignment ==1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
827
828 if (Length == 0)
829 return;
830
831 if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
832 {
833 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
834 }
835 else if ((ULONG_PTR)Address + Length < (ULONG_PTR)Address ||
836 (ULONG_PTR)Address + Length > (ULONG_PTR)MmUserProbeAddress)
837 {
838 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
839 }
840
841 /* Check for accessible pages */
842 for (i = 0; i < Length; i += PAGE_SIZE)
843 {
844 Ptr = (PULONG)(((ULONG_PTR)Address & ~(PAGE_SIZE - 1)) + i);
845 x = *Ptr;
846 *Ptr = x;
847 }
848 }
849
850 /* EOF */