Added runtime configuration of debug prints from kernel debugger (on a per file basis)
[reactos.git] / reactos / ntoskrnl / mm / virtual.c
1 /* $Id: virtual.c,v 1.47 2001/05/05 19:13:10 chorns Exp $
2 *
3 * COPYRIGHT: See COPYING in the top directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/virtual.c
6 * PURPOSE: implementing the Virtualxxx section of the win32 api
7 * PROGRAMMER: David Welch
8 * UPDATE HISTORY:
9 * 09/4/98: Created
10 * 10/6/98: Corrections from Iwan Fatahi (i_fatahi@hotmail.com)
11 * 30/9/98: Implemented ZwxxxVirtualMemory functions
12 */
13
14 /* INCLUDE *****************************************************************/
15
16 #include <ddk/ntddk.h>
17 #include <internal/mm.h>
18 #include <internal/ob.h>
19 #include <internal/io.h>
20 #include <internal/ps.h>
21 #include <internal/pool.h>
22
23 #define NDEBUG
24 #include <internal/debug.h>
25
26 /* TYPES *********************************************************************/
27
28 typedef struct _MM_SEGMENT
29 {
30 ULONG Type;
31 ULONG Protect;
32 ULONG Length;
33 LIST_ENTRY SegmentListEntry;
34 } MM_SEGMENT, *PMM_SEGMENT;
35
36 /* GLOBALS *******************************************************************/
37
38 #define TAG_MM_SEGMENT TAG('M', 'S', 'E', 'G')
39
40 /* FUNCTIONS *****************************************************************/
41
42 PMM_SEGMENT
43 MmGetSegmentForAddress(PMEMORY_AREA MArea,
44 PVOID Address,
45 PVOID* PCurrentAddress)
46 /*
47 * FUNCTION: Get the segment corresponding to a particular memory area and
48 * address.
49 * ARGUMENTS:
50 * MArea (IN) = The memory area
51 * Address (IN) = The address to get the segment for
52 * PCurrentAddress (OUT) = The start of the segment
53 * RETURNS:
54 * The corresponding segment or NULL if an error occurred
55 */
56 {
57 PVOID CurrentAddress;
58 PMM_SEGMENT CurrentSegment;
59 PLIST_ENTRY Current;
60
61 if (Address < MArea->BaseAddress ||
62 Address >= (MArea->BaseAddress + MArea->Length))
63 {
64 KeBugCheck(0);
65 *PCurrentAddress = NULL;
66 return(NULL);
67 }
68
69 Current = MArea->Data.VirtualMemoryData.SegmentListHead.Flink;
70 CurrentAddress = MArea->BaseAddress;
71 while (Current != &MArea->Data.VirtualMemoryData.SegmentListHead)
72 {
73 CurrentSegment = CONTAINING_RECORD(Current,
74 MM_SEGMENT,
75 SegmentListEntry);
76 if (Address >= CurrentAddress &&
77 Address < (CurrentAddress + CurrentSegment->Length))
78 {
79 *PCurrentAddress = CurrentAddress;
80 return(CurrentSegment);
81 }
82 CurrentAddress = CurrentAddress + CurrentSegment->Length;
83 Current = Current->Flink;
84 }
85 KeBugCheck(0);
86 return(NULL);
87 }
88
89 NTSTATUS
90 MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
91 PMEMORY_AREA MArea,
92 PVOID Address)
93 {
94 return(STATUS_UNSUCCESSFUL);
95 }
96
97
98 ULONG MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
99 PMEMORY_AREA MemoryArea,
100 PVOID Address,
101 PBOOLEAN Ul)
102 {
103 ULONG PhysicalAddress;
104 BOOL WasDirty;
105 SWAPENTRY SwapEntry;
106 NTSTATUS Status;
107 PMDL Mdl;
108 PMM_PAGEOP PageOp;
109
110 /*
111 * Get or create a pageop
112 */
113 PageOp = MmGetPageOp(MemoryArea, AddressSpace->Process->UniqueProcessId,
114 (PVOID)PAGE_ROUND_DOWN(Address), NULL, 0,
115 MM_PAGEOP_PAGEOUT);
116 if (PageOp->Thread != PsGetCurrentThread())
117 {
118 /*
119 * On the assumption that handling pageouts speedly rather than
120 * in strict order is better abandon this one.
121 */
122 (*Ul) = FALSE;
123 MmReleasePageOp(PageOp);
124 return(STATUS_UNSUCCESSFUL);
125 }
126
127 /*
128 * Paging out code or readonly data is easy.
129 */
130 if ((MemoryArea->Attributes & PAGE_READONLY) ||
131 (MemoryArea->Attributes & PAGE_EXECUTE_READ))
132 {
133 MmRemovePageFromWorkingSet(AddressSpace->Process, Address);
134 MmDeleteVirtualMapping(PsGetCurrentProcess(), Address, FALSE,
135 NULL, &PhysicalAddress);
136 MmDereferencePage((PVOID)PhysicalAddress);
137
138 *Ul = TRUE;
139 PageOp->Status = STATUS_SUCCESS;
140 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
141 MmReleasePageOp(PageOp);
142 return(1);
143 }
144
145 /*
146 * Otherwise this is read-write data
147 */
148 MmDeleteVirtualMapping(PsGetCurrentProcess(), Address, FALSE,
149 &WasDirty, &PhysicalAddress);
150 if (!WasDirty)
151 {
152 MmRemovePageFromWorkingSet(AddressSpace->Process, Address);
153 MmDereferencePage((PVOID)PhysicalAddress);
154 *Ul = TRUE;
155 PageOp->Status = STATUS_SUCCESS;
156 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
157 MmReleasePageOp(PageOp);
158 return(1);
159 }
160
161 /*
162 * If necessary, allocate an entry in the paging file for this page
163 */
164 SwapEntry = MmGetSavedSwapEntryPage((PVOID)PhysicalAddress);
165 if (SwapEntry == 0)
166 {
167 SwapEntry = MmAllocSwapPage();
168 if (SwapEntry == 0)
169 {
170 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
171 Address,
172 MemoryArea->Attributes,
173 PhysicalAddress);
174 *Ul = FALSE;
175 PageOp->Status = STATUS_UNSUCCESSFUL;
176 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
177 MmReleasePageOp(PageOp);
178 return(0);
179 }
180 }
181
182 /*
183 * Write the page to the pagefile
184 */
185 Mdl = MmCreateMdl(NULL, NULL, PAGESIZE);
186 MmBuildMdlFromPages(Mdl, &PhysicalAddress);
187 Status = MmWriteToSwapPage(SwapEntry, Mdl);
188 if (!NT_SUCCESS(Status))
189 {
190 DPRINT1("MM: Failed to write to swap page\n");
191 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
192 Address,
193 MemoryArea->Attributes,
194 PhysicalAddress);
195 *Ul = FALSE;
196 PageOp->Status = STATUS_UNSUCCESSFUL;
197 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
198 MmReleasePageOp(PageOp);
199 return(0);
200 }
201
202 /*
203 * Otherwise we have succeeded, free the page
204 */
205 MmRemovePageFromWorkingSet(AddressSpace->Process, Address);
206 MmDereferencePage((PVOID)PhysicalAddress);
207 *Ul = TRUE;
208 PageOp->Status = STATUS_SUCCESS;
209 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
210 MmReleasePageOp(PageOp);
211 return(1);
212 }
213
214 NTSTATUS
215 MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
216 MEMORY_AREA* MemoryArea,
217 PVOID Address,
218 BOOLEAN Locked)
219 /*
220 * FUNCTION: Move data into memory to satisfy a page not present fault
221 * ARGUMENTS:
222 * AddressSpace = Address space within which the fault occurred
223 * MemoryArea = The memory area within which the fault occurred
224 * Address = The absolute address of fault
225 * RETURNS: Status
226 * NOTES: This function is called with the address space lock held.
227 */
228 {
229 PVOID Page;
230 NTSTATUS Status;
231 PMM_SEGMENT Segment;
232 PVOID CurrentAddress;
233 PMM_PAGEOP PageOp;
234
235 /*
236 * There is a window between taking the page fault and locking the
237 * address space when another thread could load the page so we check
238 * that.
239 */
240 if (MmIsPagePresent(NULL, Address))
241 {
242 if (Locked)
243 {
244 MmLockPage((PVOID)MmGetPhysicalAddressForProcess(NULL, Address));
245 }
246 return(STATUS_SUCCESS);
247 }
248
249 /*
250 * Get the segment corresponding to the virtual address
251 */
252 Segment = MmGetSegmentForAddress(MemoryArea, Address, &CurrentAddress);
253 if (Segment == NULL)
254 {
255 return(STATUS_UNSUCCESSFUL);
256 }
257 if (Segment->Type == MEM_RESERVE)
258 {
259 return(STATUS_UNSUCCESSFUL);
260 }
261
262 /*
263 * Get or create a page operation
264 */
265 PageOp = MmGetPageOp(MemoryArea, (ULONG)PsGetCurrentProcessId(),
266 (PVOID)PAGE_ROUND_DOWN(Address), NULL, 0,
267 MM_PAGEOP_PAGEIN);
268 if (PageOp == NULL)
269 {
270 DPRINT1("MmGetPageOp failed");
271 KeBugCheck(0);
272 }
273
274 /*
275 * Check if someone else is already handling this fault, if so wait
276 * for them
277 */
278 if (PageOp->Thread != PsGetCurrentThread())
279 {
280 MmUnlockAddressSpace(AddressSpace);
281 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
282 0,
283 KernelMode,
284 FALSE,
285 NULL);
286 /*
287 * Check for various strange conditions
288 */
289 if (Status != STATUS_SUCCESS)
290 {
291 DPRINT1("Failed to wait for page op\n");
292 KeBugCheck(0);
293 }
294 if (PageOp->Status == STATUS_PENDING)
295 {
296 DPRINT1("Woke for page op before completion\n");
297 KeBugCheck(0);
298 }
299 /*
300 * If this wasn't a pagein then we need to restart the handling
301 */
302 if (PageOp->OpType != MM_PAGEOP_PAGEIN)
303 {
304 MmReleasePageOp(PageOp);
305 return(STATUS_MM_RESTART_OPERATION);
306 }
307 /*
308 * If the thread handling this fault has failed then we don't retry
309 */
310 if (!NT_SUCCESS(PageOp->Status))
311 {
312 MmReleasePageOp(PageOp);
313 return(Status);
314 }
315 MmLockAddressSpace(AddressSpace);
316 if (Locked)
317 {
318 MmLockPage((PVOID)MmGetPhysicalAddressForProcess(NULL, Address));
319 }
320 MmReleasePageOp(PageOp);
321 return(STATUS_SUCCESS);
322 }
323
324 /*
325 * Try to allocate a page
326 */
327 Page = MmAllocPage(0);
328 while (Page == NULL)
329 {
330 MmUnlockAddressSpace(AddressSpace);
331 MmWaitForFreePages();
332 MmLockAddressSpace(AddressSpace);
333 Page = MmAllocPage(0);
334 }
335
336 /*
337 * Add the page to the process's working set
338 */
339 MmAddPageToWorkingSet(PsGetCurrentProcess(),
340 (PVOID)PAGE_ROUND_DOWN(Address));
341
342 /*
343 * Set the page. If we fail because we are out of memory then
344 * try again
345 */
346 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
347 Address,
348 MemoryArea->Attributes,
349 (ULONG)Page);
350 while (Status == STATUS_NO_MEMORY)
351 {
352 MmUnlockAddressSpace(AddressSpace);
353 MmWaitForFreePages();
354 MmLockAddressSpace(AddressSpace);
355 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
356 Address,
357 MemoryArea->Attributes,
358 (ULONG)Page);
359 }
360 if (!NT_SUCCESS(Status))
361 {
362 DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
363 KeBugCheck(0);
364 return(Status);
365 }
366
367 /*
368 * Finish the operation
369 */
370 if (Locked)
371 {
372 MmLockPage((PVOID)MmGetPhysicalAddressForProcess(NULL, Address));
373 }
374 PageOp->Status = STATUS_SUCCESS;
375 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
376 MmReleasePageOp(PageOp);
377 return(STATUS_SUCCESS);
378 }
379
380 VOID STATIC
381 MmModifyAttributes(PMADDRESS_SPACE AddressSpace,
382 PVOID BaseAddress,
383 ULONG RegionSize,
384 ULONG OldType,
385 ULONG OldProtect,
386 ULONG NewType,
387 ULONG NewProtect)
388 /*
389 * FUNCTION: Modify the attributes of a memory region
390 */
391 {
392 /*
393 * If we are switching a previously committed region to reserved then
394 * free any allocated pages within the region
395 */
396 if (NewType == MEM_RESERVE && OldType == MEM_COMMIT)
397 {
398 ULONG i;
399
400 for (i=0; i <= (RegionSize/PAGESIZE); i++)
401 {
402 LARGE_INTEGER PhysicalAddr;
403
404 PhysicalAddr = MmGetPhysicalAddress(BaseAddress + (i*PAGESIZE));
405 MmDeleteVirtualMapping(AddressSpace->Process,
406 BaseAddress + (i*PAGESIZE),
407 FALSE, NULL, NULL);
408 if (PhysicalAddr.u.LowPart != 0)
409 {
410 MmRemovePageFromWorkingSet(AddressSpace->Process,
411 BaseAddress + (i*PAGESIZE));
412 MmDereferencePage((PVOID)(ULONG)(PhysicalAddr.u.LowPart));
413 }
414 }
415 }
416
417 /*
418 * If we are changing the protection attributes of a committed region then
419 * alter the attributes for any allocated pages within the region
420 */
421 if (NewType == MEM_COMMIT && OldType == MEM_COMMIT &&
422 OldProtect != NewProtect)
423 {
424 ULONG i;
425
426 for (i=0; i <= (RegionSize/PAGESIZE); i++)
427 {
428 if (MmIsPagePresent(AddressSpace->Process,
429 BaseAddress + (i*PAGESIZE)))
430 {
431 MmSetPageProtect(AddressSpace->Process,
432 BaseAddress + (i*PAGESIZE),
433 NewProtect);
434 }
435 }
436 }
437 }
438
439 VOID STATIC
440 InsertAfterEntry(PLIST_ENTRY Previous,
441 PLIST_ENTRY Entry)
442 /*
443 * FUNCTION: Insert a list entry after another entry in the list
444 */
445 {
446 Previous->Flink->Blink = Entry;
447
448 Entry->Flink = Previous->Flink;
449 Entry->Blink = Previous;
450
451 Previous->Flink = Entry;
452 }
453
454 #if 0
455 VOID STATIC
456 MmDumpSegmentsMemoryArea(PMEMORY_AREA MemoryArea)
457 {
458 PVOID CurrentAddress;
459 PLIST_ENTRY CurrentEntry;
460 PMM_SEGMENT CurrentSegment;
461 PLIST_ENTRY ListHead;
462
463 CurrentEntry = MemoryArea->Data.VirtualMemoryData.SegmentListHead.Flink;
464 ListHead = &MemoryArea->Data.VirtualMemoryData.SegmentListHead;
465
466 CurrentAddress = MemoryArea->BaseAddress;
467 while (CurrentEntry != ListHead)
468 {
469 CurrentSegment = CONTAINING_RECORD(CurrentEntry,
470 MM_SEGMENT,
471 SegmentListEntry);
472
473 DbgPrint("0x%x 0x%x %d %d\n",
474 CurrentAddress,
475 CurrentSegment->Length,
476 CurrentSegment->Type,
477 CurrentSegment->Protect);
478
479 CurrentAddress = CurrentAddress + CurrentSegment->Length;
480 CurrentEntry = CurrentEntry->Flink;
481 }
482 }
483 #endif
484
485 NTSTATUS
486 MmSplitSegment(PMADDRESS_SPACE AddressSpace,
487 PMEMORY_AREA MemoryArea,
488 PVOID RegionAddress,
489 ULONG RegionLength,
490 ULONG Type,
491 ULONG Protect,
492 PMM_SEGMENT FirstSegment,
493 PVOID FirstAddress)
494 /*
495 * FUNCTION: Split a memory segment internally
496 */
497 {
498 PMM_SEGMENT NewTopSegment;
499 PMM_SEGMENT RegionSegment;
500 ULONG OldType;
501 ULONG OldProtect;
502 ULONG OldLength;
503
504 /*
505 * Save the type and protection and length of the current segment
506 */
507 OldType = FirstSegment->Type;
508 OldProtect = FirstSegment->Protect;
509 OldLength = FirstSegment->Length;
510
511 /*
512 * If the segment is already of the right type and protection then
513 * there is nothing to do.
514 */
515 if (FirstSegment->Type == Type && FirstSegment->Protect == Protect)
516 {
517 return(STATUS_SUCCESS);
518 }
519
520 /*
521 * Allocate the segment we might need here because if the allocation
522 * fails below it will be difficult to undo what we've done already.
523 */
524 NewTopSegment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SEGMENT),
525 TAG_MM_SEGMENT);
526 if (NewTopSegment == NULL)
527 {
528 return(STATUS_NO_MEMORY);
529 }
530
531 if (FirstAddress < RegionAddress)
532 {
533 /*
534 * If the region to be affected starts at a higher address than
535 * the current segment then create a new segment for the
536 * affected portion
537 */
538 RegionSegment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SEGMENT),
539 TAG_MM_SEGMENT);
540 if (RegionSegment == NULL)
541 {
542 ExFreePool(NewTopSegment);
543 return(STATUS_NO_MEMORY);
544 }
545
546 RegionSegment->Type = Type;
547 RegionSegment->Protect = Protect;
548 RegionSegment->Length = RegionLength;
549
550 FirstSegment->Length = RegionAddress - FirstAddress;
551
552 InsertAfterEntry(&FirstSegment->SegmentListEntry,
553 &RegionSegment->SegmentListEntry);
554 }
555 else
556 {
557 /*
558 * Otherwise just set its type and protection and length
559 */
560
561 FirstSegment->Type = Type;
562 FirstSegment->Protect = Protect;
563 FirstSegment->Length = RegionLength;
564
565 RegionSegment = FirstSegment;
566 }
567
568 if ((FirstAddress + OldLength) > (RegionAddress + RegionLength))
569 {
570 /*
571 * If the top of the current segment extends after the affected
572 * region then create a segment for the unaffected portion
573 */
574
575 NewTopSegment->Type = OldType;
576 NewTopSegment->Protect = OldProtect;
577 NewTopSegment->Length = (FirstAddress + OldLength) -
578 (RegionAddress + RegionLength);
579
580 InsertAfterEntry(&RegionSegment->SegmentListEntry,
581 &NewTopSegment->SegmentListEntry);
582 }
583 else
584 {
585 ExFreePool(NewTopSegment);
586 NewTopSegment = NULL;
587 }
588
589 /*
590 * Actually set the type and protection of the affected region
591 */
592 MmModifyAttributes(AddressSpace,
593 RegionAddress,
594 RegionLength,
595 OldType,
596 OldProtect,
597 Type,
598 Protect);
599 return(STATUS_SUCCESS);
600 }
601
602 NTSTATUS MmGatherSegment(PMADDRESS_SPACE AddressSpace,
603 PMEMORY_AREA MemoryArea,
604 PVOID RegionAddress,
605 ULONG RegionLength,
606 ULONG Type,
607 ULONG Protect,
608 PMM_SEGMENT FirstSegment,
609 PVOID FirstAddress)
610 /*
611 * FUNCTION: Do a virtual memory operation that will effect several
612 * memory segments.
613 * ARGUMENTS:
614 * AddressSpace (IN) = Address space to affect
615 * MemoryArea (IN) = Memory area to affect
616 * BaseAddress (IN) = Base address of the region to affect
617 * RegionSize (IN) = Size of the region to affect
618 * Type (IN) = New type of the region
619 * Protect (IN) = New protection of the region
620 * CurrentSegment (IN) = First segment intersecting with the region
621 * CurrentAddress (IN) = Start address of the first segment
622 * interesting with the region
623 * RETURNS: Status
624 */
625 {
626 PMM_SEGMENT RegionSegment;
627 PVOID CurrentAddress;
628 ULONG RemainingLength;
629 PLIST_ENTRY CurrentEntry;
630 PLIST_ENTRY ListHead;
631 PMM_SEGMENT CurrentSegment;
632
633 if (FirstAddress < RegionAddress)
634 {
635 /*
636 * If a portion of the first segment is not covered by the region then
637 * we need to split it into two segments
638 */
639
640 RegionSegment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SEGMENT),
641 TAG_MM_SEGMENT);
642 if (RegionSegment == NULL)
643 {
644 return(STATUS_NO_MEMORY);
645 }
646
647 RegionSegment->Type = Type;
648 RegionSegment->Protect = Protect;
649 RegionSegment->Length = (FirstAddress + FirstSegment->Length) -
650 RegionAddress;
651
652 FirstSegment->Length = RegionAddress - FirstAddress;
653
654 InsertAfterEntry(&FirstSegment->SegmentListEntry,
655 &RegionSegment->SegmentListEntry);
656
657 MmModifyAttributes(AddressSpace,
658 RegionAddress,
659 RegionSegment->Length,
660 FirstSegment->Type,
661 FirstSegment->Protect,
662 Type,
663 Protect);
664
665 CurrentAddress = FirstAddress + FirstSegment->Length +
666 RegionSegment->Length;
667 }
668 else
669 {
670 /*
671 * Otherwise just change the attributes of the segment
672 */
673
674 ULONG OldType;
675 ULONG OldProtect;
676
677 OldType = FirstSegment->Type;
678 OldProtect = FirstSegment->Protect;
679
680 FirstSegment->Type = Type;
681 FirstSegment->Protect = Protect;
682
683 RegionSegment = FirstSegment;
684
685 MmModifyAttributes(AddressSpace,
686 RegionAddress,
687 FirstSegment->Length,
688 OldType,
689 OldProtect,
690 Type,
691 Protect);
692
693 CurrentAddress = FirstAddress + RegionSegment->Length;
694 }
695
696 /*
697 * Change the attributes of all the complete segments lying inside the
698 * affected region
699 */
700 RemainingLength = RegionLength - RegionSegment->Length;
701 CurrentEntry = RegionSegment->SegmentListEntry.Flink;
702 CurrentSegment = CONTAINING_RECORD(CurrentEntry,
703 MM_SEGMENT,
704 SegmentListEntry);
705 ListHead = &MemoryArea->Data.VirtualMemoryData.SegmentListHead;
706
707 while (CurrentEntry != ListHead && RemainingLength > 0)
708 {
709 ULONG OldType;
710 ULONG OldProtect;
711 ULONG OldLength;
712
713 /*
714 * If this segment will not be completely covered by the
715 * affected region then break
716 */
717 if (CurrentSegment->Length > RemainingLength)
718 {
719 break;
720 }
721
722 OldType = CurrentSegment->Type;
723 OldProtect = CurrentSegment->Protect;
724 OldLength = CurrentSegment->Length;
725
726 /*
727 * Extend the length of the previous segment to cover this one
728 */
729 RegionSegment->Length = RegionSegment->Length + OldLength;
730 RemainingLength = RemainingLength - OldLength;
731 CurrentAddress = CurrentAddress + OldLength;
732 CurrentEntry = CurrentEntry->Flink;
733
734 /*
735 * Remove the current segment from the list
736 */
737 RemoveEntryList(&CurrentSegment->SegmentListEntry);
738 ExFreePool(CurrentSegment);
739
740 MmModifyAttributes(AddressSpace,
741 CurrentAddress,
742 OldLength,
743 OldType,
744 OldProtect,
745 Type,
746 Protect);
747
748 CurrentSegment = CONTAINING_RECORD(CurrentEntry,
749 MM_SEGMENT,
750 SegmentListEntry);
751 }
752
753 /*
754 * If we've run off the top of the memory area then bug check
755 */
756 if (CurrentEntry == ListHead && RemainingLength > 0)
757 {
758 KeBugCheck(0);
759 }
760
761 /*
762 * We've only affected a portion of a segment then split it in two
763 */
764 if (RemainingLength > 0)
765 {
766 CurrentSegment->Length = CurrentSegment->Length - RemainingLength;
767
768 RegionSegment->Length = RegionSegment->Length + RemainingLength;
769
770 MmModifyAttributes(AddressSpace,
771 CurrentAddress,
772 RemainingLength,
773 CurrentSegment->Type,
774 CurrentSegment->Protect,
775 Type,
776 Protect);
777 }
778
779 return(STATUS_SUCCESS);
780 }
781
782 NTSTATUS MmComplexVirtualMemoryOperation(PMADDRESS_SPACE AddressSpace,
783 PMEMORY_AREA MemoryArea,
784 PVOID BaseAddress,
785 ULONG RegionSize,
786 ULONG Type,
787 ULONG Protect)
788 {
789 PMM_SEGMENT CurrentSegment;
790 PVOID CurrentAddress;
791
792 CurrentSegment = MmGetSegmentForAddress(MemoryArea,
793 BaseAddress,
794 &CurrentAddress);
795 if (CurrentSegment == NULL)
796 {
797 KeBugCheck(0);
798 }
799
800 if (BaseAddress >= CurrentAddress &&
801 (BaseAddress + RegionSize) <= (CurrentAddress + CurrentSegment->Length))
802 {
803 return((MmSplitSegment(AddressSpace,
804 MemoryArea,
805 BaseAddress,
806 RegionSize,
807 Type,
808 Protect,
809 CurrentSegment,
810 CurrentAddress)));
811 }
812 else
813 {
814 return((MmGatherSegment(AddressSpace,
815 MemoryArea,
816 BaseAddress,
817 RegionSize,
818 Type,
819 Protect,
820 CurrentSegment,
821 CurrentAddress)));
822 }
823 }
824
825
826 NTSTATUS STDCALL
827 NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
828 IN OUT PVOID* UBaseAddress,
829 IN ULONG ZeroBits,
830 IN OUT PULONG URegionSize,
831 IN ULONG AllocationType,
832 IN ULONG Protect)
833 /*
834 * FUNCTION: Allocates a block of virtual memory in the process address space
835 * ARGUMENTS:
836 * ProcessHandle = The handle of the process which owns the virtual memory
837 * BaseAddress = A pointer to the virtual memory allocated. If you
838 * supply a non zero value the system will try to
839 * allocate the memory at the address supplied. It round
840 * it down to a multiple of the page size.
841 * ZeroBits = (OPTIONAL) You can specify the number of high order bits
842 * that must be zero, ensuring that the memory will be
843 * allocated at a address below a certain value.
844 * RegionSize = The number of bytes to allocate
845 * AllocationType = Indicates the type of virtual memory you like to
846 * allocated, can be one of the values : MEM_COMMIT,
847 * MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN
848 * Protect = Indicates the protection type of the pages allocated, can be
849 * a combination of PAGE_READONLY, PAGE_READWRITE,
850 * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD,
851 * PAGE_NOACCESS
852 * REMARKS:
853 * This function maps to the win32 VirtualAllocEx. Virtual memory is
854 * process based so the protocol starts with a ProcessHandle. I
855 * splitted the functionality of obtaining the actual address and
856 * specifying the start address in two parameters ( BaseAddress and
857 * StartAddress ) The NumberOfBytesAllocated specify the range and the
858 * AllocationType and ProctectionType map to the other two parameters.
859 * RETURNS: Status
860 */
861 {
862 PEPROCESS Process;
863 MEMORY_AREA* MemoryArea;
864 ULONG Type;
865 NTSTATUS Status;
866 PMADDRESS_SPACE AddressSpace;
867 PMM_SEGMENT Segment;
868 PVOID BaseAddress;
869 ULONG RegionSize;
870 PVOID PBaseAddress;
871 ULONG PRegionSize;
872
873 DPRINT("NtAllocateVirtualMemory(*UBaseAddress %x, "
874 "ZeroBits %d, *URegionSize %x, AllocationType %x, Protect %x)\n",
875 *UBaseAddress,ZeroBits,*URegionSize,AllocationType,
876 Protect);
877
878 /*
879 * Check the validity of the parameters
880 */
881 if ((Protect & PAGE_FLAGS_VALID_FROM_USER_MODE) != Protect)
882 {
883 return(STATUS_INVALID_PAGE_PROTECTION);
884 }
885 PBaseAddress = *UBaseAddress;
886 PRegionSize = *URegionSize;
887
888
889 BaseAddress = (PVOID)PAGE_ROUND_DOWN(PBaseAddress);
890 RegionSize = PAGE_ROUND_UP(PBaseAddress + PRegionSize) -
891 PAGE_ROUND_DOWN(PBaseAddress);
892
893 Status = ObReferenceObjectByHandle(ProcessHandle,
894 PROCESS_VM_OPERATION,
895 NULL,
896 UserMode,
897 (PVOID*)(&Process),
898 NULL);
899 if (!NT_SUCCESS(Status))
900 {
901 DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
902 return(Status);
903 }
904
905 if (AllocationType & MEM_RESERVE)
906 {
907 Type = MEM_RESERVE;
908 }
909 else
910 {
911 Type = MEM_COMMIT;
912 }
913
914 AddressSpace = &Process->AddressSpace;
915 MmLockAddressSpace(AddressSpace);
916
917 if (PBaseAddress != 0)
918 {
919 MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace,
920 BaseAddress);
921
922 if (MemoryArea != NULL &&
923 MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY &&
924 MemoryArea->Length >= RegionSize)
925 {
926 Status = MmComplexVirtualMemoryOperation(AddressSpace,
927 MemoryArea,
928 BaseAddress,
929 RegionSize,
930 Type,
931 Protect);
932 /* FIXME: Reserve/dereserve swap pages */
933 MmUnlockAddressSpace(AddressSpace);
934 ObDereferenceObject(Process);
935 return(Status);
936 }
937 else if (MemoryArea != NULL)
938 {
939 MmUnlockAddressSpace(AddressSpace);
940 ObDereferenceObject(Process);
941 return(STATUS_UNSUCCESSFUL);
942 }
943 }
944
945 Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_SEGMENT),
946 TAG_MM_SEGMENT);
947 if (Segment == NULL)
948 {
949 MmUnlockAddressSpace(AddressSpace);
950 ObDereferenceObject(Process);
951 return(STATUS_UNSUCCESSFUL);
952 }
953
954 Status = MmCreateMemoryArea(Process,
955 &Process->AddressSpace,
956 MEMORY_AREA_VIRTUAL_MEMORY,
957 &BaseAddress,
958 RegionSize,
959 Protect,
960 &MemoryArea,
961 PBaseAddress != 0);
962
963 if (!NT_SUCCESS(Status))
964 {
965 DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
966 MmUnlockAddressSpace(AddressSpace);
967 ObDereferenceObject(Process);
968 return(Status);
969 }
970
971 InitializeListHead(&MemoryArea->Data.VirtualMemoryData.SegmentListHead);
972
973 Segment->Type = Type;
974 Segment->Protect = Protect;
975 Segment->Length = RegionSize;
976 InsertTailList(&MemoryArea->Data.VirtualMemoryData.SegmentListHead,
977 &Segment->SegmentListEntry);
978
979 DPRINT("*UBaseAddress %x\n",*UBaseAddress);
980 if ((AllocationType & MEM_COMMIT) &&
981 ((Protect & PAGE_READWRITE) ||
982 (Protect & PAGE_EXECUTE_READWRITE)))
983 {
984 MmReserveSwapPages(RegionSize);
985 }
986
987 *UBaseAddress = BaseAddress;
988 *URegionSize = RegionSize;
989
990 MmUnlockAddressSpace(AddressSpace);
991 ObDereferenceObject(Process);
992 return(STATUS_SUCCESS);
993 }
994
995
996 NTSTATUS STDCALL
997 NtFlushVirtualMemory(IN HANDLE ProcessHandle,
998 IN PVOID BaseAddress,
999 IN ULONG NumberOfBytesToFlush,
1000 OUT PULONG NumberOfBytesFlushed OPTIONAL)
1001 /*
1002 * FUNCTION: Flushes virtual memory to file
1003 * ARGUMENTS:
1004 * ProcessHandle = Points to the process that allocated the virtual
1005 * memory
1006 * BaseAddress = Points to the memory address
1007 * NumberOfBytesToFlush = Limits the range to flush,
1008 * NumberOfBytesFlushed = Actual number of bytes flushed
1009 * RETURNS: Status
1010 */
1011 {
1012 UNIMPLEMENTED;
1013 }
1014
1015 VOID STATIC
1016 MmFreeVirtualMemoryPage(PVOID Context, PVOID Address, ULONG PhysicalAddr)
1017 {
1018 PEPROCESS Process = (PEPROCESS)Context;
1019
1020 if (PhysicalAddr != 0)
1021 {
1022 MmRemovePageFromWorkingSet(Process, Address);
1023 MmDereferencePage((PVOID)PhysicalAddr);
1024 }
1025 }
1026
1027 VOID
1028 MmFreeVirtualMemory(PEPROCESS Process, PMEMORY_AREA MemoryArea)
1029 {
1030 PLIST_ENTRY current_entry;
1031 PMM_SEGMENT current;
1032
1033 current_entry = MemoryArea->Data.VirtualMemoryData.SegmentListHead.Flink;
1034 while (current_entry != &MemoryArea->Data.VirtualMemoryData.SegmentListHead)
1035 {
1036 current = CONTAINING_RECORD(current_entry, MM_SEGMENT, SegmentListEntry);
1037 current_entry = current_entry->Flink;
1038 ExFreePool(current);
1039 }
1040
1041 MmFreeMemoryArea(&Process->AddressSpace,
1042 MemoryArea->BaseAddress,
1043 0,
1044 MmFreeVirtualMemoryPage,
1045 (PVOID)Process);
1046 }
1047
1048 NTSTATUS STDCALL
1049 NtFreeVirtualMemory(IN HANDLE ProcessHandle,
1050 IN PVOID* PBaseAddress,
1051 IN PULONG PRegionSize,
1052 IN ULONG FreeType)
1053 /*
1054 * FUNCTION: Frees a range of virtual memory
1055 * ARGUMENTS:
1056 * ProcessHandle = Points to the process that allocated the virtual
1057 * memory
1058 * BaseAddress = Points to the memory address, rounded down to a
1059 * multiple of the pagesize
1060 * RegionSize = Limits the range to free, rounded up to a multiple of
1061 * the paging size
1062 * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
1063 * RETURNS: Status
1064 */
1065 {
1066 MEMORY_AREA* MemoryArea;
1067 NTSTATUS Status;
1068 PEPROCESS Process;
1069 PMADDRESS_SPACE AddressSpace;
1070 PVOID BaseAddress;
1071 ULONG RegionSize;
1072
1073 DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *PBaseAddress %x, "
1074 "*PRegionSize %x, FreeType %x)\n",ProcessHandle,*PBaseAddress,
1075 *PRegionSize,FreeType);
1076
1077 BaseAddress = (PVOID)PAGE_ROUND_DOWN((*PBaseAddress));
1078 RegionSize = PAGE_ROUND_UP((*PBaseAddress) + (*PRegionSize)) -
1079 PAGE_ROUND_DOWN((*PBaseAddress));
1080
1081 Status = ObReferenceObjectByHandle(ProcessHandle,
1082 PROCESS_VM_OPERATION,
1083 PsProcessType,
1084 UserMode,
1085 (PVOID*)(&Process),
1086 NULL);
1087 if (!NT_SUCCESS(Status))
1088 {
1089 return(Status);
1090 }
1091
1092 AddressSpace = &Process->AddressSpace;
1093
1094 MmLockAddressSpace(AddressSpace);
1095 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
1096 BaseAddress);
1097 if (MemoryArea == NULL)
1098 {
1099 MmUnlockAddressSpace(AddressSpace);
1100 ObDereferenceObject(Process);
1101 return(STATUS_UNSUCCESSFUL);
1102 }
1103
1104 switch (FreeType)
1105 {
1106 case MEM_RELEASE:
1107 if (MemoryArea->BaseAddress != BaseAddress)
1108 {
1109 MmUnlockAddressSpace(AddressSpace);
1110 ObDereferenceObject(Process);
1111 return(STATUS_UNSUCCESSFUL);
1112 }
1113 #if 0
1114 if ((MemoryArea->Type == MEMORY_AREA_COMMIT) &&
1115 ((MemoryArea->Attributes & PAGE_READWRITE) ||
1116 (MemoryArea->Attributes & PAGE_EXECUTE_READWRITE)))
1117 {
1118 MmDereserveSwapPages(PAGE_ROUND_UP(MemoryArea->Length));
1119 }
1120 #endif
1121
1122 MmFreeVirtualMemory(Process, MemoryArea);
1123 MmUnlockAddressSpace(AddressSpace);
1124 ObDereferenceObject(Process);
1125 return(STATUS_SUCCESS);
1126
1127 case MEM_DECOMMIT:
1128 Status = MmComplexVirtualMemoryOperation(AddressSpace,
1129 MemoryArea,
1130 BaseAddress,
1131 RegionSize,
1132 MEM_RESERVE,
1133 PAGE_NOACCESS);
1134 MmUnlockAddressSpace(AddressSpace);
1135 ObDereferenceObject(Process);
1136 return(Status);
1137 }
1138 MmUnlockAddressSpace(AddressSpace);
1139 ObDereferenceObject(Process);
1140 return(STATUS_NOT_IMPLEMENTED);
1141 }
1142
1143
1144 NTSTATUS STDCALL
1145 NtLockVirtualMemory(HANDLE ProcessHandle,
1146 PVOID BaseAddress,
1147 ULONG NumberOfBytesToLock,
1148 PULONG NumberOfBytesLocked)
1149 {
1150 UNIMPLEMENTED;
1151 }
1152
1153
1154 VOID
1155 MmChangeAreaProtection(PEPROCESS Process,
1156 PVOID BaseAddress,
1157 ULONG Length,
1158 ULONG Protect)
1159 {
1160 ULONG i;
1161
1162 for (i=0; i<(Length/PAGESIZE); i++)
1163 {
1164 if (MmIsPagePresent(Process, BaseAddress + (i*PAGESIZE)))
1165 {
1166 MmSetPageProtect(Process,
1167 BaseAddress + (i*PAGESIZE),
1168 Protect);
1169 }
1170 }
1171 }
1172
1173
1174 NTSTATUS STDCALL NtProtectVirtualMemory(IN HANDLE ProcessHandle,
1175 IN PVOID BaseAddress,
1176 IN ULONG NumberOfBytesToProtect,
1177 IN ULONG NewAccessProtection,
1178 OUT PULONG OldAccessProtection)
1179 {
1180 PMEMORY_AREA MemoryArea;
1181 PEPROCESS Process;
1182 NTSTATUS Status;
1183 PMADDRESS_SPACE AddressSpace;
1184
1185 Status = ObReferenceObjectByHandle(ProcessHandle,
1186 PROCESS_VM_OPERATION,
1187 PsProcessType,
1188 UserMode,
1189 (PVOID*)(&Process),
1190 NULL);
1191 if (Status != STATUS_SUCCESS)
1192 {
1193 DPRINT("NtProtectVirtualMemory() = %x\n",Status);
1194 return(Status);
1195 }
1196
1197 AddressSpace = &Process->AddressSpace;
1198
1199 MmLockAddressSpace(AddressSpace);
1200 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
1201 BaseAddress);
1202 if (MemoryArea == NULL)
1203 {
1204 DPRINT("NtProtectVirtualMemory() = %x\n",STATUS_UNSUCCESSFUL);
1205 MmUnlockAddressSpace(AddressSpace);
1206 ObDereferenceObject(Process);
1207 return(STATUS_UNSUCCESSFUL);
1208 }
1209
1210 *OldAccessProtection = MemoryArea->Attributes;
1211
1212 if (MemoryArea->BaseAddress == BaseAddress &&
1213 MemoryArea->Length == NumberOfBytesToProtect)
1214 {
1215 MemoryArea->Attributes = NewAccessProtection;
1216 }
1217 else
1218 {
1219 MemoryArea = MmSplitMemoryArea(Process,
1220 &Process->AddressSpace,
1221 MemoryArea,
1222 BaseAddress,
1223 NumberOfBytesToProtect,
1224 MemoryArea->Type,
1225 NewAccessProtection);
1226 }
1227 MmChangeAreaProtection(Process,
1228 BaseAddress,
1229 NumberOfBytesToProtect,
1230 NewAccessProtection);
1231 MmUnlockAddressSpace(AddressSpace);
1232 ObDereferenceObject(Process);
1233 return(STATUS_SUCCESS);
1234 }
1235
1236
1237 NTSTATUS STDCALL NtQueryVirtualMemory (IN HANDLE ProcessHandle,
1238 IN PVOID Address,
1239 IN CINT VirtualMemoryInformationClass,
1240 OUT PVOID VirtualMemoryInformation,
1241 IN ULONG Length,
1242 OUT PULONG ResultLength)
1243 {
1244 NTSTATUS Status;
1245 PEPROCESS Process;
1246 MEMORY_AREA* MemoryArea;
1247
1248 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
1249 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
1250 "Length %lu ResultLength %x)\n",ProcessHandle,Address,
1251 VirtualMemoryInformationClass,VirtualMemoryInformation,
1252 Length,ResultLength);
1253
1254 switch(VirtualMemoryInformationClass)
1255 {
1256 case MemoryBasicInformation:
1257 {
1258 PMEMORY_BASIC_INFORMATION Info =
1259 (PMEMORY_BASIC_INFORMATION)VirtualMemoryInformation;
1260 PMADDRESS_SPACE AddressSpace;
1261
1262 if (Length < sizeof(MEMORY_BASIC_INFORMATION))
1263 {
1264 ObDereferenceObject(Process);
1265 return STATUS_INFO_LENGTH_MISMATCH;
1266 }
1267
1268 if (ResultLength)
1269 {
1270 *ResultLength = sizeof(MEMORY_BASIC_INFORMATION);
1271 }
1272
1273 Status = ObReferenceObjectByHandle(ProcessHandle,
1274 PROCESS_QUERY_INFORMATION,
1275 NULL,
1276 UserMode,
1277 (PVOID*)(&Process),
1278 NULL);
1279
1280 if (!NT_SUCCESS(Status))
1281 {
1282 DPRINT("NtQueryVirtualMemory() = %x\n",Status);
1283 return(Status);
1284 }
1285
1286 AddressSpace = &Process->AddressSpace;
1287 MmLockAddressSpace(AddressSpace);
1288 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
1289 Address);
1290
1291 if (MemoryArea == NULL)
1292 {
1293 Info->State = MEM_FREE;
1294 DPRINT("Virtual memory at %p is free.\n", Address);
1295 MmUnlockAddressSpace(AddressSpace);
1296 ObDereferenceObject(Process);
1297 return (STATUS_SUCCESS);
1298 }
1299
1300 #if 0
1301 if (MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY)
1302 {
1303 Info->State = MEM_COMMIT;
1304 }
1305 else
1306 {
1307 Info->State = MEM_RESERVE;
1308 }
1309 #endif
1310
1311 Info->BaseAddress = MemoryArea->BaseAddress;
1312 Info->RegionSize = MemoryArea->Length;
1313
1314 DPRINT("BaseAddress %p, RegionSize %x State %x\n",
1315 Info->BaseAddress, Info->RegionSize, Info->State);
1316
1317 MmUnlockAddressSpace(AddressSpace);
1318 ObDereferenceObject(Process);
1319 return STATUS_SUCCESS;
1320 }
1321 break;
1322 }
1323
1324 return STATUS_INVALID_INFO_CLASS;
1325 }
1326
1327
1328 NTSTATUS STDCALL
1329 NtReadVirtualMemory(IN HANDLE ProcessHandle,
1330 IN PVOID BaseAddress,
1331 OUT PVOID Buffer,
1332 IN ULONG NumberOfBytesToRead,
1333 OUT PULONG NumberOfBytesRead)
1334 {
1335 NTSTATUS Status;
1336 PMDL Mdl;
1337 PVOID SystemAddress;
1338 PEPROCESS Process;
1339
1340 DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
1341 "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle,BaseAddress,
1342 Buffer,NumberOfBytesToRead);
1343
1344 Status = ObReferenceObjectByHandle(ProcessHandle,
1345 PROCESS_VM_WRITE,
1346 NULL,
1347 UserMode,
1348 (PVOID*)(&Process),
1349 NULL);
1350 if (Status != STATUS_SUCCESS)
1351 {
1352 return(Status);
1353 }
1354
1355 Mdl = MmCreateMdl(NULL,
1356 Buffer,
1357 NumberOfBytesToRead);
1358 MmProbeAndLockPages(Mdl,
1359 UserMode,
1360 IoWriteAccess);
1361
1362 KeAttachProcess(Process);
1363
1364 SystemAddress = MmGetSystemAddressForMdl(Mdl);
1365 memcpy(SystemAddress, BaseAddress, NumberOfBytesToRead);
1366
1367 KeDetachProcess();
1368
1369 if (Mdl->MappedSystemVa != NULL)
1370 {
1371 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
1372 }
1373 MmUnlockPages(Mdl);
1374 ExFreePool(Mdl);
1375
1376 ObDereferenceObject(Process);
1377
1378 *NumberOfBytesRead = NumberOfBytesToRead;
1379 return(STATUS_SUCCESS);
1380 }
1381
1382
1383 NTSTATUS STDCALL
1384 NtUnlockVirtualMemory(HANDLE ProcessHandle,
1385 PVOID BaseAddress,
1386 ULONG NumberOfBytesToUnlock,
1387 PULONG NumberOfBytesUnlocked OPTIONAL)
1388 {
1389 UNIMPLEMENTED;
1390 }
1391
1392
1393 NTSTATUS STDCALL
1394 NtWriteVirtualMemory(IN HANDLE ProcessHandle,
1395 IN PVOID BaseAddress,
1396 IN PVOID Buffer,
1397 IN ULONG NumberOfBytesToWrite,
1398 OUT PULONG NumberOfBytesWritten)
1399 {
1400 NTSTATUS Status;
1401 PMDL Mdl;
1402 PVOID SystemAddress;
1403 PEPROCESS Process;
1404
1405 DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
1406 "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle,BaseAddress,
1407 Buffer,NumberOfBytesToWrite);
1408
1409 Status = ObReferenceObjectByHandle(ProcessHandle,
1410 PROCESS_VM_WRITE,
1411 NULL,
1412 UserMode,
1413 (PVOID*)(&Process),
1414 NULL);
1415 if (Status != STATUS_SUCCESS)
1416 {
1417 return(Status);
1418 }
1419
1420 Mdl = MmCreateMdl(NULL,
1421 Buffer,
1422 NumberOfBytesToWrite);
1423 MmProbeAndLockPages(Mdl,
1424 UserMode,
1425 IoReadAccess);
1426
1427 KeAttachProcess(Process);
1428
1429 DPRINT("Attached to process copying memory\n");
1430
1431 SystemAddress = MmGetSystemAddressForMdl(Mdl);
1432 memcpy(BaseAddress, SystemAddress, NumberOfBytesToWrite);
1433
1434 DPRINT("Done copy\n");
1435
1436 KeDetachProcess();
1437
1438 ObDereferenceObject(Process);
1439
1440 if (Mdl->MappedSystemVa != NULL)
1441 {
1442 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
1443 }
1444 MmUnlockPages(Mdl);
1445 ExFreePool(Mdl);
1446
1447 *NumberOfBytesWritten = NumberOfBytesToWrite;
1448
1449 DPRINT("Finished NtWriteVirtualMemory()\n");
1450
1451 return(STATUS_SUCCESS);
1452 }
1453
1454
1455 DWORD
1456 STDCALL
1457 MmSecureVirtualMemory (
1458 DWORD Unknown0,
1459 DWORD Unknown1,
1460 DWORD Unknown2
1461 )
1462 {
1463 UNIMPLEMENTED;
1464 return 0;
1465 }
1466
1467
1468 VOID
1469 STDCALL
1470 MmUnsecureVirtualMemory (
1471 DWORD Unknown0
1472 )
1473 {
1474 UNIMPLEMENTED;
1475 }
1476
1477 /* EOF */