MiQueryVirtualMemory(): created because ZwQueryVirtualMemory() didn't work for me...
[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: virtual.c,v 1.86 2004/12/22 05:17:44 royce Exp $
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 = MmOpenMemoryAreaByAddress(AddressSpace,
163 Address);
164 switch(VirtualMemoryInformationClass)
165 {
166 case MemoryBasicInformation:
167 {
168 PMEMORY_BASIC_INFORMATION Info =
169 (PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation;
170 if (Length != sizeof(MEMORY_BASIC_INFORMATION))
171 {
172 MmUnlockAddressSpace(AddressSpace);
173 ObDereferenceObject(Process);
174 return(STATUS_INFO_LENGTH_MISMATCH);
175 }
176
177 if (MemoryArea == NULL)
178 {
179 Info->Type = 0;
180 Info->State = MEM_FREE;
181 Info->Protect = PAGE_NOACCESS;
182 Info->AllocationProtect = 0;
183 Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
184 Info->AllocationBase = NULL;
185 Info->RegionSize = MmFindGapAtAddress(AddressSpace, Info->BaseAddress);
186 Status = STATUS_SUCCESS;
187 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
188 }
189 else
190 {
191 switch(MemoryArea->Type)
192 {
193 case MEMORY_AREA_VIRTUAL_MEMORY:
194 Status = MmQueryAnonMem(MemoryArea, Address, Info,
195 ResultLength);
196 break;
197 case MEMORY_AREA_SECTION_VIEW:
198 Status = MmQuerySectionView(MemoryArea, Address, Info,
199 ResultLength);
200 break;
201 case MEMORY_AREA_NO_ACCESS:
202 Info->Type = 0;
203 Info->State = MEM_FREE;
204 Info->Protect = MemoryArea->Attributes;
205 Info->AllocationProtect = MemoryArea->Attributes;
206 Info->BaseAddress = MemoryArea->BaseAddress;
207 Info->AllocationBase = MemoryArea->BaseAddress;
208 Info->RegionSize = MemoryArea->Length;
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->BaseAddress;
218 Info->AllocationBase = MemoryArea->BaseAddress;
219 Info->RegionSize = MemoryArea->Length;
220 Status = STATUS_SUCCESS;
221 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
222 break;
223 case MEMORY_AREA_SYSTEM:
224 {
225 static int warned = 0;
226 if ( !warned )
227 {
228 DPRINT1("FIXME: MEMORY_AREA_SYSTEM case incomplete (or possibly wrong) for NtQueryVirtualMemory()\n");
229 warned = 1;
230 }
231 }
232 /* FIXME - don't have a clue if this is right, but it's better than nothing */
233 Info->Type = 0;
234 Info->State = MEM_COMMIT;
235 Info->Protect = MemoryArea->Attributes;
236 Info->AllocationProtect = MemoryArea->Attributes;
237 Info->BaseAddress = MemoryArea->BaseAddress;
238 Info->AllocationBase = MemoryArea->BaseAddress;
239 Info->RegionSize = MemoryArea->Length;
240 Status = STATUS_SUCCESS;
241 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
242 break;
243 case MEMORY_AREA_KERNEL_STACK:
244 {
245 static int warned = 0;
246 if ( !warned )
247 {
248 DPRINT1("FIXME: MEMORY_AREA_KERNEL_STACK case incomplete (or possibly wrong) for NtQueryVirtualMemory()\n");
249 warned = 1;
250 }
251 }
252 /* FIXME - don't have a clue if this is right, but it's better than nothing */
253 Info->Type = 0;
254 Info->State = MEM_COMMIT;
255 Info->Protect = MemoryArea->Attributes;
256 Info->AllocationProtect = MemoryArea->Attributes;
257 Info->BaseAddress = MemoryArea->BaseAddress;
258 Info->AllocationBase = MemoryArea->BaseAddress;
259 Info->RegionSize = MemoryArea->Length;
260 Status = STATUS_SUCCESS;
261 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
262 break;
263 default:
264 DPRINT1("unhandled memory area type: 0x%x\n", MemoryArea->Type);
265 Status = STATUS_UNSUCCESSFUL;
266 *ResultLength = 0;
267 }
268 }
269 break;
270 }
271
272 default:
273 {
274 Status = STATUS_INVALID_INFO_CLASS;
275 *ResultLength = 0;
276 break;
277 }
278 }
279
280 MmUnlockAddressSpace(AddressSpace);
281 if (Address < (PVOID)KERNEL_BASE)
282 {
283 ObDereferenceObject(Process);
284 }
285
286 return Status;
287 }
288
289 /* (tMk 2004.II.4)
290 * FUNCTION:
291 * Called from VirtualQueryEx (lib\kernel32\mem\virtual.c)
292 *
293 */
294 NTSTATUS STDCALL
295 NtQueryVirtualMemory (IN HANDLE ProcessHandle,
296 IN PVOID Address,
297 IN CINT VirtualMemoryInformationClass,
298 OUT PVOID VirtualMemoryInformation,
299 IN ULONG Length,
300 OUT PULONG UnsafeResultLength)
301 {
302 NTSTATUS Status;
303 ULONG ResultLength = 0;
304 KPROCESSOR_MODE PrevMode;
305 union
306 {
307 MEMORY_BASIC_INFORMATION BasicInfo;
308 }
309 VirtualMemoryInfo;
310
311 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
312 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
313 "Length %lu ResultLength %x)\n",ProcessHandle,Address,
314 VirtualMemoryInformationClass,VirtualMemoryInformation,
315 Length,ResultLength);
316
317 PrevMode = ExGetPreviousMode();
318
319 if (PrevMode == UserMode && Address >= (PVOID)KERNEL_BASE)
320 {
321 DPRINT1("Invalid parameter\n");
322 return STATUS_INVALID_PARAMETER;
323 }
324
325 Status = MiQueryVirtualMemory ( ProcessHandle,
326 Address,
327 VirtualMemoryInformationClass,
328 &VirtualMemoryInfo,
329 Length,
330 &ResultLength );
331
332 if (NT_SUCCESS(Status) && ResultLength > 0)
333 {
334 Status = MmCopyToCaller(VirtualMemoryInformation, &VirtualMemoryInfo, ResultLength);
335 if (!NT_SUCCESS(Status))
336 {
337 ResultLength = 0;
338 }
339 }
340
341 if (UnsafeResultLength != NULL)
342 {
343 MmCopyToCaller(UnsafeResultLength, &ResultLength, sizeof(ULONG));
344 }
345 return(Status);
346 }
347
348
349 /* (tMk 2004.II.5)
350 * FUNCTION:
351 * Called from VirtualProtectEx (lib\kernel32\mem\virtual.c)
352 *
353 */
354 NTSTATUS STDCALL
355 NtProtectVirtualMemory(IN HANDLE ProcessHandle,
356 IN PVOID *UnsafeBaseAddress,
357 IN ULONG *UnsafeNumberOfBytesToProtect,
358 IN ULONG NewAccessProtection,
359 OUT PULONG UnsafeOldAccessProtection)
360 {
361 PMEMORY_AREA MemoryArea;
362 PEPROCESS Process;
363 NTSTATUS Status;
364 PMADDRESS_SPACE AddressSpace;
365 ULONG OldAccessProtection;
366 PVOID BaseAddress;
367 ULONG NumberOfBytesToProtect;
368
369 Status = MmCopyFromCaller(&BaseAddress, UnsafeBaseAddress, sizeof(PVOID));
370 if (!NT_SUCCESS(Status))
371 return Status;
372 Status = MmCopyFromCaller(&NumberOfBytesToProtect, UnsafeNumberOfBytesToProtect, sizeof(ULONG));
373 if (!NT_SUCCESS(Status))
374 return Status;
375
376 // (tMk 2004.II.5) in Microsoft SDK I read:
377 // 'if this parameter is NULL or does not point to a valid variable, the function fails'
378 if(UnsafeOldAccessProtection == NULL)
379 {
380 return(STATUS_INVALID_PARAMETER);
381 }
382
383 NumberOfBytesToProtect =
384 PAGE_ROUND_UP(BaseAddress + NumberOfBytesToProtect) -
385 PAGE_ROUND_DOWN(BaseAddress);
386 BaseAddress = (PVOID)PAGE_ROUND_DOWN(BaseAddress);
387
388 Status = ObReferenceObjectByHandle(ProcessHandle,
389 PROCESS_VM_OPERATION,
390 PsProcessType,
391 UserMode,
392 (PVOID*)(&Process),
393 NULL);
394 if (!NT_SUCCESS(Status))
395 {
396 DPRINT("NtProtectVirtualMemory() = %x\n",Status);
397 return(Status);
398 }
399
400 AddressSpace = &Process->AddressSpace;
401
402 MmLockAddressSpace(AddressSpace);
403 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
404 BaseAddress);
405 if (MemoryArea == NULL)
406 {
407 MmUnlockAddressSpace(AddressSpace);
408 ObDereferenceObject(Process);
409 return(STATUS_UNSUCCESSFUL);
410 }
411
412 if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
413 {
414 Status = MmProtectAnonMem(AddressSpace, MemoryArea, BaseAddress,
415 NumberOfBytesToProtect, NewAccessProtection,
416 &OldAccessProtection);
417 }
418 else if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW)
419 {
420 Status = MmProtectSectionView(AddressSpace, MemoryArea, BaseAddress,
421 NumberOfBytesToProtect,
422 NewAccessProtection,
423 &OldAccessProtection);
424 }
425
426 MmUnlockAddressSpace(AddressSpace);
427 ObDereferenceObject(Process);
428
429 MmCopyToCaller(UnsafeOldAccessProtection, &OldAccessProtection, sizeof(ULONG));
430 MmCopyToCaller(UnsafeBaseAddress, &BaseAddress, sizeof(PVOID));
431 MmCopyToCaller(UnsafeNumberOfBytesToProtect, &NumberOfBytesToProtect, sizeof(ULONG));
432
433 return(Status);
434 }
435
436
437 /* (tMk 2004.II.05)
438 * FUNCTION:
439 * Called from ReadProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
440 *
441 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
442 */
443 NTSTATUS STDCALL
444 NtReadVirtualMemory(IN HANDLE ProcessHandle,
445 IN PVOID BaseAddress,
446 OUT PVOID Buffer,
447 IN ULONG NumberOfBytesToRead,
448 OUT PULONG NumberOfBytesRead OPTIONAL)
449 {
450 NTSTATUS Status;
451 PMDL Mdl;
452 PVOID SystemAddress;
453 PEPROCESS Process, CurrentProcess;
454
455
456 DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
457 "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress,
458 Buffer,NumberOfBytesToRead);
459
460 Status = ObReferenceObjectByHandle(ProcessHandle,
461 PROCESS_VM_WRITE,
462 NULL,
463 UserMode,
464 (PVOID*)(&Process),
465 NULL);
466 if (!NT_SUCCESS(Status))
467 {
468 return(Status);
469 }
470
471 CurrentProcess = PsGetCurrentProcess();
472
473 if (Process == CurrentProcess)
474 {
475 memcpy(Buffer, BaseAddress, NumberOfBytesToRead);
476 }
477 else
478 {
479 Mdl = MmCreateMdl(NULL,
480 Buffer,
481 NumberOfBytesToRead);
482 if(Mdl == NULL)
483 {
484 ObDereferenceObject(Process);
485 return(STATUS_NO_MEMORY);
486 }
487 MmProbeAndLockPages(Mdl,
488 UserMode,
489 IoWriteAccess);
490
491 KeAttachProcess(&Process->Pcb);
492
493 SystemAddress = MmGetSystemAddressForMdl(Mdl);
494 memcpy(SystemAddress, BaseAddress, NumberOfBytesToRead);
495
496 KeDetachProcess();
497
498 if (Mdl->MappedSystemVa != NULL)
499 {
500 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
501 }
502 MmUnlockPages(Mdl);
503 ExFreePool(Mdl);
504 }
505
506 ObDereferenceObject(Process);
507
508 if (NumberOfBytesRead)
509 *NumberOfBytesRead = NumberOfBytesToRead;
510 return(STATUS_SUCCESS);
511 }
512
513 /* (tMk 2004.II.05)
514 * FUNCTION: THIS function doesn't make a sense...
515 * Called from VirtualUnlock (lib\kernel32\mem\virtual.c)
516 */
517 NTSTATUS STDCALL
518 NtUnlockVirtualMemory(HANDLE ProcessHandle,
519 PVOID BaseAddress,
520 ULONG NumberOfBytesToUnlock,
521 PULONG NumberOfBytesUnlocked OPTIONAL)
522 {
523 // AG [08-20-03] : I have *no* idea if this is correct, I just used the
524 // other functions as a template and made a few intelligent guesses...
525
526 NTSTATUS Status;
527 PMDL Mdl;
528 PEPROCESS Process;
529
530 DPRINT("NtUnlockVirtualMemory(ProcessHandle %x, BaseAddress %x, "
531 "NumberOfBytesToUnlock %d), NumberOfBytesUnlocked %x\n",ProcessHandle,BaseAddress,
532 NumberOfBytesToUnlock, NumberOfBytesUnlocked);
533
534 Status = ObReferenceObjectByHandle(ProcessHandle,
535 PROCESS_VM_WRITE,
536 NULL,
537 UserMode,
538 (PVOID*)(&Process),
539 NULL);
540 if (!NT_SUCCESS(Status))
541 {
542 return(Status);
543 }
544
545 Mdl = MmCreateMdl(NULL,
546 BaseAddress,
547 NumberOfBytesToUnlock);
548 if(Mdl == NULL)
549 {
550 ObDereferenceObject(Process);
551 return(STATUS_NO_MEMORY);
552 }
553
554 ObDereferenceObject(Process);
555
556 if (Mdl->MappedSystemVa != NULL)
557 {
558 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
559 }
560 MmUnlockPages(Mdl);
561 ExFreePool(Mdl);
562
563 *NumberOfBytesUnlocked = NumberOfBytesToUnlock;
564
565 return(STATUS_SUCCESS);
566 }
567
568
569 /* (tMk 2004.II.05)
570 * FUNCTION:
571 * Called from WriteProcessMemory (lib\kernel32\mem\procmem.c) and KlInitPeb(lib\kernel32\process\create.c)
572 *
573 * NOTE: This function will be correct if MmProbeAndLockPages() would be fully IMPLEMENTED.
574 */
575 NTSTATUS STDCALL
576 NtWriteVirtualMemory(IN HANDLE ProcessHandle,
577 IN PVOID BaseAddress,
578 IN PVOID Buffer,
579 IN ULONG NumberOfBytesToWrite,
580 OUT PULONG NumberOfBytesWritten)
581 {
582 NTSTATUS Status;
583 PMDL Mdl;
584 PVOID SystemAddress;
585 PEPROCESS Process;
586
587 DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
588 "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle,BaseAddress,
589 Buffer,NumberOfBytesToWrite);
590
591 Status = ObReferenceObjectByHandle(ProcessHandle,
592 PROCESS_VM_WRITE,
593 NULL,
594 UserMode,
595 (PVOID*)(&Process),
596 NULL);
597 if (!NT_SUCCESS(Status))
598 {
599 return(Status);
600 }
601
602 if (Process == PsGetCurrentProcess())
603 {
604 memcpy(BaseAddress, Buffer, NumberOfBytesToWrite);
605 }
606 else
607 {
608 Mdl = MmCreateMdl(NULL,
609 Buffer,
610 NumberOfBytesToWrite);
611 MmProbeAndLockPages(Mdl,
612 UserMode,
613 IoReadAccess);
614 if(Mdl == NULL)
615 {
616 ObDereferenceObject(Process);
617 return(STATUS_NO_MEMORY);
618 }
619 KeAttachProcess(&Process->Pcb);
620
621 SystemAddress = MmGetSystemAddressForMdl(Mdl);
622 memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
623
624 KeDetachProcess();
625
626 if (Mdl->MappedSystemVa != NULL)
627 {
628 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
629 }
630 MmUnlockPages(Mdl);
631 ExFreePool(Mdl);
632 }
633
634 ObDereferenceObject(Process);
635
636 *NumberOfBytesWritten = NumberOfBytesToWrite;
637
638 return(STATUS_SUCCESS);
639 }
640
641 /*
642 * @unimplemented
643 */
644
645 PVOID
646 STDCALL
647 MmGetVirtualForPhysical (
648 IN PHYSICAL_ADDRESS PhysicalAddress
649 )
650 {
651 UNIMPLEMENTED;
652 return 0;
653 }
654
655 /* FUNCTION:
656 * Called from EngSecureMem (subsys\win32k\eng\mem.c)
657 * @unimplemented
658 */
659 PVOID STDCALL
660 MmSecureVirtualMemory (PVOID Address,
661 SIZE_T Length,
662 ULONG Mode)
663 {
664 /* Only works for user space */
665 if (MmHighestUserAddress < Address)
666 {
667 return NULL;
668 }
669
670 UNIMPLEMENTED;
671
672 return 0;
673 }
674
675
676 /* FUNCTION:
677 * Called from EngUnsecureMem (subsys\win32k\eng\mem.c)
678 * @unimplemented
679 */
680 VOID STDCALL
681 MmUnsecureVirtualMemory(PVOID SecureMem)
682 {
683 if (NULL == SecureMem)
684 {
685 return;
686 }
687
688 UNIMPLEMENTED;
689 }
690
691
692 /*
693 * @implemented
694 */
695 VOID STDCALL
696 ProbeForRead (IN PVOID Address,
697 IN ULONG Length,
698 IN ULONG Alignment)
699 {
700 ASSERT(Alignment ==1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
701
702 if (Length == 0)
703 return;
704
705 if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
706 {
707 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
708 }
709 else if ((ULONG_PTR)Address + Length < (ULONG_PTR)Address ||
710 (ULONG_PTR)Address + Length > (ULONG_PTR)MmUserProbeAddress)
711 {
712 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
713 }
714 }
715
716
717 /*
718 * @implemented
719 */
720 VOID STDCALL
721 ProbeForWrite (IN PVOID Address,
722 IN ULONG Length,
723 IN ULONG Alignment)
724 {
725 PULONG Ptr;
726 ULONG x;
727 ULONG i;
728
729 ASSERT(Alignment ==1 || Alignment == 2 || Alignment == 4 || Alignment == 8);
730
731 if (Length == 0)
732 return;
733
734 if (((ULONG_PTR)Address & (Alignment - 1)) != 0)
735 {
736 ExRaiseStatus (STATUS_DATATYPE_MISALIGNMENT);
737 }
738 else if ((ULONG_PTR)Address + Length < (ULONG_PTR)Address ||
739 (ULONG_PTR)Address + Length > (ULONG_PTR)MmUserProbeAddress)
740 {
741 ExRaiseStatus (STATUS_ACCESS_VIOLATION);
742 }
743
744 /* Check for accessible pages */
745 for (i = 0; i < Length; i += PAGE_SIZE)
746 {
747 Ptr = (PULONG)(((ULONG_PTR)Address & ~(PAGE_SIZE - 1)) + i);
748 x = *Ptr;
749 *Ptr = x;
750 }
751 }
752
753 /* EOF */