1 /* $Id: virtual.c,v 1.33 2000/08/18 22:27:03 dwelch Exp $
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
10 * 10/6/98: Corrections from Fatahi (i_fatahi@hotmail.com)
11 * 30/9/98: Implemented ZwxxxVirtualMemory functions
14 /* INCLUDE *****************************************************************/
16 #include <ddk/ntddk.h>
17 #include <internal/mm.h>
18 #include <internal/mmhal.h>
19 #include <internal/ob.h>
20 #include <internal/io.h>
21 #include <internal/ps.h>
23 #include <internal/string.h>
26 #include <internal/debug.h>
28 /* TYPES *********************************************************************/
30 typedef struct _MM_SEGMENT
35 LIST_ENTRY SegmentListEntry
;
36 } MM_SEGMENT
, *PMM_SEGMENT
;
38 /* FUNCTIONS *****************************************************************/
40 PMM_SEGMENT
MmGetSegmentForAddress(PMEMORY_AREA MArea
,
42 PVOID
* PCurrentAddress
)
44 * FUNCTION: Get the segment corresponding to a particular memory area and
47 * MArea (IN) = The memory area
48 * Address (IN) = The address to get the segment for
49 * PCurrentAddress (OUT) = The start of the segment
51 * The corresponding memory or NULL if an error occurred
55 PMM_SEGMENT CurrentSegment
;
58 if (Address
< MArea
->BaseAddress
||
59 Address
>= (MArea
->BaseAddress
+ MArea
->Length
))
62 *PCurrentAddress
= NULL
;
66 Current
= MArea
->Data
.VirtualMemoryData
.SegmentListHead
.Flink
;
67 CurrentAddress
= MArea
->BaseAddress
;
68 while (Current
!= &MArea
->Data
.VirtualMemoryData
.SegmentListHead
)
70 CurrentSegment
= CONTAINING_RECORD(Current
,
73 if (Address
>= CurrentAddress
&&
74 Address
< (CurrentAddress
+ CurrentSegment
->Length
))
76 *PCurrentAddress
= CurrentAddress
;
77 return(CurrentSegment
);
79 CurrentAddress
= CurrentAddress
+ CurrentSegment
->Length
;
80 Current
= Current
->Flink
;
86 NTSTATUS
MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace
,
92 PHYSICAL_ADDRESS PhysicalAddress
;
97 * FIXME: What should we do if an i/o operation is pending on
102 * If the memory area is readonly then there is nothing to do
104 if (MArea
->Attributes
& PAGE_READONLY
||
105 MArea
->Attributes
& PAGE_EXECUTE_READ
)
107 return(STATUS_SUCCESS
);
110 * Set the page to readonly. This ensures the current contents aren't
111 * modified while we are writing it to swap.
113 MmSetPageProtect(AddressSpace
->Process
,
117 * If the page isn't dirty then there is nothing to do.
119 if (!MmIsPageDirty(AddressSpace
->Process
, Address
))
121 MmSetPageProtect(AddressSpace
->Process
,
124 return(STATUS_SUCCESS
);
126 PhysicalAddress
= MmGetPhysicalAddress(Address
);
128 * If we haven't already allocated a swap entry for this page
131 if ((se
= MmGetSavedSwapEntryPage((PVOID
)PhysicalAddress
.u
.LowPart
)) != 0)
133 se
= MmAllocSwapPage();
136 MmSetPageProtect(AddressSpace
->Process
,
139 return(STATUS_UNSUCCESSFUL
);
141 MmSetSavedSwapEntryPage((PVOID
)PhysicalAddress
.u
.LowPart
, se
);
144 * Set the flags so other threads will know what we are doing
146 Flags
= MmGetFlagsPage((PVOID
)PhysicalAddress
.u
.LowPart
);
147 Flags
= Flags
| MM_PHYSICAL_PAGE_MPW_PENDING
;
148 MmSetFlagsPage((PVOID
)PhysicalAddress
.u
.LowPart
, Flags
);
150 * Build an mdl to hold the page for writeout
152 Mdl
= MmCreateMdl(NULL
, NULL
, PAGESIZE
);
153 MmBuildMdlFromPages(Mdl
, (PULONG
)&PhysicalAddress
.u
.LowPart
);
155 * Unlock the address space and write out the page to swap.
157 MmUnlockAddressSpace(AddressSpace
);
158 Status
= MmWriteToSwapPage(se
, Mdl
);
162 MmLockAddressSpace(AddressSpace
);
163 Flags
= MmGetFlagsPage((PVOID
)PhysicalAddress
.u
.LowPart
);
164 Flags
= Flags
& (~MM_PHYSICAL_PAGE_MPW_PENDING
);
165 MmSetFlagsPage((PVOID
)PhysicalAddress
.u
.LowPart
,Flags
);
167 * If we successfully wrote the page then reset the dirty bit
169 if (NT_SUCCESS(Status
))
171 MmSetCleanPage(AddressSpace
->Process
, Address
);
177 ULONG
MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace
,
178 PMEMORY_AREA MemoryArea
,
182 PHYSICAL_ADDRESS PhysicalAddress
;
184 if ((MemoryArea
->Attributes
& PAGE_READONLY
) ||
185 (MemoryArea
->Attributes
& PAGE_EXECUTE_READ
) ||
186 !MmIsPageDirty(PsGetCurrentProcess(), Address
))
188 PhysicalAddress
= MmGetPhysicalAddress(Address
);
190 MmRemovePageFromWorkingSet(AddressSpace
->Process
,
192 MmSetPage(PsGetCurrentProcess(),
196 MmDereferencePage((PVOID
)PhysicalAddress
.u
.LowPart
);
204 NTSTATUS
MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace
,
205 MEMORY_AREA
* MemoryArea
,
208 * FUNCTION: Move data into memory to satisfy a page not present fault
210 * AddressSpace = Address space within which the fault occurred
211 * MemoryArea = The memory area within which the fault occurred
212 * Address = The absolute address of fault
214 * NOTES: This function is called with the address space lock held.
220 PVOID CurrentAddress
;
222 Segment
= MmGetSegmentForAddress(MemoryArea
, Address
, &CurrentAddress
);
225 return(STATUS_UNSUCCESSFUL
);
227 if (Segment
->Type
== MEM_RESERVE
)
229 return(STATUS_UNSUCCESSFUL
);
232 if (MmIsPagePresent(NULL
, Address
))
234 return(STATUS_SUCCESS
);
237 Page
= MmAllocPage(0);
240 MmUnlockAddressSpace(AddressSpace
);
241 MmWaitForFreePages();
242 MmLockAddressSpace(AddressSpace
);
243 if (MmIsPagePresent(NULL
, Address
))
245 return(STATUS_SUCCESS
);
247 Page
= MmAllocPage(0);
249 Status
= MmCreatePageTable(Address
);
250 while (!NT_SUCCESS(Status
))
252 MmUnlockAddressSpace(AddressSpace
);
253 MmWaitForFreePages();
254 MmLockAddressSpace(AddressSpace
);
255 if (MmIsPagePresent(NULL
, Address
))
257 MmDereferencePage(Page
);
258 return(STATUS_SUCCESS
);
260 Status
= MmCreatePageTable(Address
);
262 MmAddPageToWorkingSet(PsGetCurrentProcess(), Address
);
263 MmSetPage(PsGetCurrentProcess(),
265 MemoryArea
->Attributes
,
268 return(STATUS_SUCCESS
);
271 VOID
MmModifyAttributes(PMADDRESS_SPACE AddressSpace
,
279 if (NewType
== MEM_RESERVE
&&
280 OldType
== MEM_COMMIT
)
284 for (i
=0; i
<=(RegionSize
/PAGESIZE
); i
++)
286 LARGE_INTEGER PhysicalAddr
;
288 PhysicalAddr
= MmGetPhysicalAddress(BaseAddress
+ (i
*PAGESIZE
));
289 if (PhysicalAddr
.u
.LowPart
!= 0)
291 MmRemovePageFromWorkingSet(AddressSpace
->Process
,
292 BaseAddress
+ (i
*PAGESIZE
));
293 MmDereferencePage((PVOID
)(ULONG
)(PhysicalAddr
.u
.LowPart
));
297 if (NewType
== MEM_COMMIT
&& OldType
== MEM_COMMIT
&&
298 OldProtect
!= NewProtect
)
302 for (i
=0; i
<(RegionSize
/PAGESIZE
); i
++)
304 if (MmIsPagePresent(AddressSpace
->Process
,
305 BaseAddress
+ (i
*PAGESIZE
)))
307 MmSetPageProtect(AddressSpace
->Process
,
308 BaseAddress
+ (i
*PAGESIZE
),
315 VOID
InsertAfterEntry(PLIST_ENTRY Previous
,
318 Previous
->Flink
->Blink
= Entry
;
320 Entry
->Flink
= Previous
->Flink
;
321 Entry
->Blink
= Previous
;
323 Previous
->Flink
= Entry
;
326 NTSTATUS
MmSplitSegment(PMADDRESS_SPACE AddressSpace
,
327 PMEMORY_AREA MemoryArea
,
332 PMM_SEGMENT CurrentSegment
,
333 PVOID CurrentAddress
)
335 * FUNCTION: Split a memory segment internally
338 PMM_SEGMENT NewSegment
;
339 PMM_SEGMENT NewTopSegment
;
340 PMM_SEGMENT PreviousSegment
;
344 OldType
= CurrentSegment
->Type
;
345 OldProtect
= CurrentSegment
->Protect
;
347 NewSegment
= ExAllocatePool(NonPagedPool
, sizeof(MM_SEGMENT
));
348 if (NewSegment
== NULL
)
350 return(STATUS_NO_MEMORY
);
352 NewTopSegment
= ExAllocatePool(NonPagedPool
, sizeof(MM_SEGMENT
));
353 if (NewTopSegment
== NULL
)
355 ExFreePool(NewSegment
);
356 return(STATUS_NO_MEMORY
);
359 if (CurrentSegment
->Type
== Type
&&
360 CurrentSegment
->Protect
== Protect
)
362 return(STATUS_SUCCESS
);
365 if (CurrentAddress
< BaseAddress
)
367 NewSegment
->Type
= Type
;
368 NewSegment
->Protect
= Protect
;
369 NewSegment
->Length
= RegionSize
;
371 CurrentSegment
->Length
= BaseAddress
- CurrentAddress
;
373 InsertAfterEntry(&CurrentSegment
->SegmentListEntry
,
374 &NewSegment
->SegmentListEntry
);
376 PreviousSegment
= NewSegment
;
380 CurrentSegment
->Type
= Type
;
381 CurrentSegment
->Protect
= Protect
;
383 PreviousSegment
= CurrentSegment
;
385 ExFreePool(NewSegment
);
389 if ((CurrentAddress
+ CurrentSegment
->Length
) > (BaseAddress
+ RegionSize
))
391 NewTopSegment
->Type
= OldType
;
392 NewTopSegment
->Protect
= OldProtect
;
393 NewTopSegment
->Length
=
394 (CurrentAddress
+ CurrentSegment
->Length
) -
395 (BaseAddress
+ RegionSize
);
397 InsertAfterEntry(&PreviousSegment
->SegmentListEntry
,
398 &NewTopSegment
->SegmentListEntry
);
402 ExFreePool(NewTopSegment
);
403 NewTopSegment
= NULL
;
406 MmModifyAttributes(AddressSpace
, BaseAddress
, RegionSize
,
407 OldType
, OldProtect
, Type
, Protect
);
408 return(STATUS_SUCCESS
);
411 NTSTATUS
MmGatherSegment(PMADDRESS_SPACE AddressSpace
,
412 PMEMORY_AREA MemoryArea
,
417 PMM_SEGMENT CurrentSegment
,
418 PVOID CurrentAddress
)
420 * FUNCTION: Do a virtual memory operation that will effect several
423 * AddressSpace (IN) = Address space to affect
424 * MemoryArea (IN) = Memory area to affect
425 * BaseAddress (IN) = Base address of the region to affect
426 * RegionSize (IN) = Size of the region to affect
427 * Type (IN) = New type of the region
428 * Protect (IN) = New protection of the region
429 * CurrentSegment (IN) = First segment intersecting with the region
430 * CurrentAddress (IN) = Start address of the first segment
431 * interesting with the region
435 PMM_SEGMENT NewSegment
;
436 PMM_SEGMENT NewTopSegment
;
437 PMM_SEGMENT PreviousSegment
;
440 PLIST_ENTRY CurrentEntry
;
441 PLIST_ENTRY ListHead
;
444 * We will need a maximum of two new segments. Allocate them now
445 * because if we fail latter we may not be able to reverse the
446 * what we've already done
448 NewSegment
= ExAllocatePool(NonPagedPool
, sizeof(MM_SEGMENT
));
449 if (NewSegment
== NULL
)
451 return(STATUS_NO_MEMORY
);
453 NewTopSegment
= ExAllocatePool(NonPagedPool
, sizeof(MM_SEGMENT
));
454 if (NewTopSegment
== NULL
)
456 ExFreePool(NewSegment
);
457 return(STATUS_NO_MEMORY
);
460 if (CurrentAddress
< BaseAddress
)
463 * If a portion of the first segment is not covered by the region then
464 * we need to split it into two segments
467 NewSegment
->Type
= Type
;
468 NewSegment
->Protect
= Protect
;
469 NewSegment
->Length
= RegionSize
;
471 CurrentSegment
->Length
=
472 BaseAddress
- CurrentAddress
;
474 InsertAfterEntry(&CurrentSegment
->SegmentListEntry
,
475 &NewSegment
->SegmentListEntry
);
477 PreviousSegment
= NewSegment
;
479 MmModifyAttributes(AddressSpace
, BaseAddress
, NewSegment
->Length
,
480 CurrentSegment
->Type
,
481 CurrentSegment
->Protect
, Type
, Protect
);
486 * Otherwise just change the attributes of the segment
492 OldType
= CurrentSegment
->Type
;
493 OldProtect
= CurrentSegment
->Protect
;
495 CurrentSegment
->Type
= Type
;
496 CurrentSegment
->Protect
= Protect
;
498 PreviousSegment
= CurrentSegment
;
500 ExFreePool(NewSegment
);
503 MmModifyAttributes(AddressSpace
, BaseAddress
, CurrentSegment
->Length
,
504 OldType
, OldProtect
, Type
, Protect
);
507 LAddress
= BaseAddress
+ PreviousSegment
->Length
;
508 RSize
= RegionSize
- PreviousSegment
->Length
;
509 CurrentEntry
= PreviousSegment
->SegmentListEntry
.Flink
;
510 ListHead
= &MemoryArea
->Data
.VirtualMemoryData
.SegmentListHead
;
512 while (CurrentEntry
!= ListHead
&& RSize
> 0)
517 CurrentSegment
= CONTAINING_RECORD(CurrentEntry
,
521 if (CurrentSegment
->Length
> RSize
)
526 OldType
= CurrentSegment
->Type
;
527 OldProtect
= CurrentSegment
->Protect
;
528 CurrentSegment
->Type
= Type
;
529 CurrentSegment
->Protect
= Protect
;
531 MmModifyAttributes(AddressSpace
, LAddress
, CurrentSegment
->Length
,
532 OldType
, OldProtect
, Type
, Protect
);
534 RSize
= RSize
- CurrentSegment
->Length
;
535 LAddress
= LAddress
+ CurrentSegment
->Length
;
537 CurrentEntry
= CurrentEntry
->Flink
;
540 if (CurrentEntry
== ListHead
&& RSize
> 0)
547 NewTopSegment
->Type
= CurrentSegment
->Type
;
548 NewTopSegment
->Protect
= CurrentSegment
->Protect
;
549 NewTopSegment
->Length
= CurrentSegment
->Length
- RSize
;
551 CurrentSegment
->Length
= RSize
;
552 CurrentSegment
->Type
= Type
;
553 CurrentSegment
->Protect
= Protect
;
555 InsertAfterEntry(&CurrentSegment
->SegmentListEntry
,
556 &NewTopSegment
->SegmentListEntry
);
558 MmModifyAttributes(AddressSpace
, LAddress
, RSize
,
560 NewTopSegment
->Protect
, Type
, Protect
);
563 return(STATUS_SUCCESS
);
566 NTSTATUS
MmComplexVirtualMemoryOperation(PMADDRESS_SPACE AddressSpace
,
567 PMEMORY_AREA MemoryArea
,
573 PMM_SEGMENT CurrentSegment
;
574 PVOID CurrentAddress
;
576 CurrentSegment
= MmGetSegmentForAddress(MemoryArea
,
579 if (CurrentSegment
== NULL
)
584 if (BaseAddress
>= CurrentAddress
&&
585 (BaseAddress
+ RegionSize
) <= (CurrentAddress
+ CurrentSegment
->Length
))
587 return((MmSplitSegment(AddressSpace
,
598 return((MmGatherSegment(AddressSpace
,
610 NTSTATUS STDCALL
NtAllocateVirtualMemory(IN HANDLE ProcessHandle
,
611 IN OUT PVOID
* PBaseAddress
,
613 IN OUT PULONG PRegionSize
,
614 IN ULONG AllocationType
,
617 * FUNCTION: Allocates a block of virtual memory in the process address space
619 * ProcessHandle = The handle of the process which owns the virtual memory
620 * BaseAddress = A pointer to the virtual memory allocated. If you
621 * supply a non zero value the system will try to
622 * allocate the memory at the address supplied. It round
623 * it down to a multiple of the page size.
624 * ZeroBits = (OPTIONAL) You can specify the number of high order bits
625 * that must be zero, ensuring that the memory will be
626 * allocated at a address below a certain value.
627 * RegionSize = The number of bytes to allocate
628 * AllocationType = Indicates the type of virtual memory you like to
629 * allocated, can be one of the values : MEM_COMMIT,
630 * MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN
631 * Protect = Indicates the protection type of the pages allocated, can be
632 * a combination of PAGE_READONLY, PAGE_READWRITE,
633 * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD,
636 * This function maps to the win32 VirtualAllocEx. Virtual memory is
637 * process based so the protocol starts with a ProcessHandle. I
638 * splitted the functionality of obtaining the actual address and
639 * specifying the start address in two parameters ( BaseAddress and
640 * StartAddress ) The NumberOfBytesAllocated specify the range and the
641 * AllocationType and ProctectionType map to the other two parameters.
646 MEMORY_AREA
* MemoryArea
;
649 PMADDRESS_SPACE AddressSpace
;
654 DPRINT("NtAllocateVirtualMemory(ProcessHandle %x, *BaseAddress %x, "
655 "ZeroBits %d, *RegionSize %x, AllocationType %x, Protect %x)\n",
656 ProcessHandle
,*BaseAddress
,ZeroBits
,*RegionSize
,AllocationType
,
659 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN((*PBaseAddress
));
660 RegionSize
= PAGE_ROUND_UP((*PBaseAddress
) + (*PRegionSize
)) -
661 PAGE_ROUND_DOWN((*PBaseAddress
));
663 Status
= ObReferenceObjectByHandle(ProcessHandle
,
664 PROCESS_VM_OPERATION
,
669 if (!NT_SUCCESS(Status
))
671 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
675 if (AllocationType
& MEM_RESERVE
)
684 AddressSpace
= &Process
->AddressSpace
;
685 MmLockAddressSpace(AddressSpace
);
687 if (BaseAddress
!= 0)
689 MemoryArea
= MmOpenMemoryAreaByAddress(&Process
->AddressSpace
,
692 if (MemoryArea
!= NULL
&&
693 MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
&&
694 MemoryArea
->Length
>= RegionSize
)
696 Status
= MmComplexVirtualMemoryOperation(AddressSpace
,
702 /* FIXME: Reserve/dereserve swap pages */
703 MmUnlockAddressSpace(AddressSpace
);
704 ObDereferenceObject(Process
);
707 else if (MemoryArea
!= NULL
)
709 MmUnlockAddressSpace(AddressSpace
);
710 ObDereferenceObject(Process
);
711 return(STATUS_UNSUCCESSFUL
);
715 Segment
= ExAllocatePool(NonPagedPool
, sizeof(MM_SEGMENT
));
718 MmUnlockAddressSpace(AddressSpace
);
719 ObDereferenceObject(Process
);
720 return(STATUS_UNSUCCESSFUL
);
723 Status
= MmCreateMemoryArea(Process
,
724 &Process
->AddressSpace
,
725 MEMORY_AREA_VIRTUAL_MEMORY
,
731 if (!NT_SUCCESS(Status
))
733 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
734 MmUnlockAddressSpace(AddressSpace
);
735 ObDereferenceObject(Process
);
739 InitializeListHead(&MemoryArea
->Data
.VirtualMemoryData
.SegmentListHead
);
741 Segment
->Type
= Type
;
742 Segment
->Protect
= Protect
;
743 Segment
->Length
= RegionSize
;
744 InsertTailList(&MemoryArea
->Data
.VirtualMemoryData
.SegmentListHead
,
745 &Segment
->SegmentListEntry
);
747 DPRINT("*BaseAddress %x\n",*BaseAddress
);
748 if ((AllocationType
& MEM_COMMIT
) &&
749 ((Protect
& PAGE_READWRITE
) ||
750 (Protect
& PAGE_EXECUTE_READWRITE
)))
752 MmReserveSwapPages(RegionSize
);
755 *PBaseAddress
= BaseAddress
;
756 *PRegionSize
= RegionSize
;
758 MmUnlockAddressSpace(AddressSpace
);
759 ObDereferenceObject(Process
);
760 return(STATUS_SUCCESS
);
764 NTSTATUS STDCALL
NtFlushVirtualMemory(IN HANDLE ProcessHandle
,
765 IN PVOID BaseAddress
,
766 IN ULONG NumberOfBytesToFlush
,
767 OUT PULONG NumberOfBytesFlushed OPTIONAL
)
769 * FUNCTION: Flushes virtual memory to file
771 * ProcessHandle = Points to the process that allocated the virtual
773 * BaseAddress = Points to the memory address
774 * NumberOfBytesToFlush = Limits the range to flush,
775 * NumberOfBytesFlushed = Actual number of bytes flushed
783 NTSTATUS STDCALL
NtFreeVirtualMemory(IN HANDLE ProcessHandle
,
784 IN PVOID
* PBaseAddress
,
785 IN PULONG PRegionSize
,
788 * FUNCTION: Frees a range of virtual memory
790 * ProcessHandle = Points to the process that allocated the virtual
792 * BaseAddress = Points to the memory address, rounded down to a
793 * multiple of the pagesize
794 * RegionSize = Limits the range to free, rounded up to a multiple of
796 * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
800 MEMORY_AREA
* MemoryArea
;
803 PMADDRESS_SPACE AddressSpace
;
808 DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *BaseAddress %x, "
809 "*RegionSize %x, FreeType %x)\n",ProcessHandle
,*BaseAddress
,
810 *RegionSize
,FreeType
);
812 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN((*PBaseAddress
));
813 RegionSize
= PAGE_ROUND_UP((*PBaseAddress
) + (*PRegionSize
)) -
814 PAGE_ROUND_DOWN((*PBaseAddress
));
816 Status
= ObReferenceObjectByHandle(ProcessHandle
,
817 PROCESS_VM_OPERATION
,
822 if (!NT_SUCCESS(Status
))
827 AddressSpace
= &Process
->AddressSpace
;
829 MmLockAddressSpace(AddressSpace
);
830 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
832 if (MemoryArea
== NULL
)
834 MmUnlockAddressSpace(AddressSpace
);
835 ObDereferenceObject(Process
);
836 return(STATUS_UNSUCCESSFUL
);
842 if (MemoryArea
->BaseAddress
!= BaseAddress
)
844 MmUnlockAddressSpace(AddressSpace
);
845 ObDereferenceObject(Process
);
846 return(STATUS_UNSUCCESSFUL
);
849 if ((MemoryArea
->Type
== MEMORY_AREA_COMMIT
) &&
850 ((MemoryArea
->Attributes
& PAGE_READWRITE
) ||
851 (MemoryArea
->Attributes
& PAGE_EXECUTE_READWRITE
)))
853 MmDereserveSwapPages(PAGE_ROUND_UP(MemoryArea
->Length
));
857 for (i
=0; i
<=(MemoryArea
->Length
/PAGESIZE
); i
++)
859 LARGE_INTEGER PhysicalAddr
;
861 PhysicalAddr
= MmGetPhysicalAddress(MemoryArea
->BaseAddress
+
863 if (PhysicalAddr
.u
.LowPart
!= 0)
865 MmRemovePageFromWorkingSet(AddressSpace
->Process
,
866 MemoryArea
->BaseAddress
+
868 MmDereferencePage((PVOID
)(ULONG
)(PhysicalAddr
.u
.LowPart
));
872 MmFreeMemoryArea(&Process
->AddressSpace
,
876 MmUnlockAddressSpace(AddressSpace
);
877 ObDereferenceObject(Process
);
878 return(STATUS_SUCCESS
);
881 Status
= MmComplexVirtualMemoryOperation(AddressSpace
,
887 MmUnlockAddressSpace(AddressSpace
);
888 ObDereferenceObject(Process
);
891 MmUnlockAddressSpace(AddressSpace
);
892 ObDereferenceObject(Process
);
893 return(STATUS_NOT_IMPLEMENTED
);
897 NTSTATUS STDCALL
NtLockVirtualMemory(HANDLE ProcessHandle
,
899 ULONG NumberOfBytesToLock
,
900 PULONG NumberOfBytesLocked
)
906 VOID
MmChangeAreaProtection(PEPROCESS Process
,
913 for (i
=0; i
<(Length
/PAGESIZE
); i
++)
915 if (MmIsPagePresent(Process
, BaseAddress
+ (i
*PAGESIZE
)))
917 MmSetPageProtect(Process
,
918 BaseAddress
+ (i
*PAGESIZE
),
925 NTSTATUS STDCALL
NtProtectVirtualMemory(IN HANDLE ProcessHandle
,
926 IN PVOID BaseAddress
,
927 IN ULONG NumberOfBytesToProtect
,
928 IN ULONG NewAccessProtection
,
929 OUT PULONG OldAccessProtection
)
931 PMEMORY_AREA MemoryArea
;
934 PMADDRESS_SPACE AddressSpace
;
936 Status
= ObReferenceObjectByHandle(ProcessHandle
,
937 PROCESS_VM_OPERATION
,
942 if (Status
!= STATUS_SUCCESS
)
944 DPRINT("NtProtectVirtualMemory() = %x\n",Status
);
948 AddressSpace
= &Process
->AddressSpace
;
950 MmLockAddressSpace(AddressSpace
);
951 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
953 if (MemoryArea
== NULL
)
955 DPRINT("NtProtectVirtualMemory() = %x\n",STATUS_UNSUCCESSFUL
);
956 MmUnlockAddressSpace(AddressSpace
);
957 ObDereferenceObject(Process
);
958 return(STATUS_UNSUCCESSFUL
);
961 *OldAccessProtection
= MemoryArea
->Attributes
;
963 if (MemoryArea
->BaseAddress
== BaseAddress
&&
964 MemoryArea
->Length
== NumberOfBytesToProtect
)
966 MemoryArea
->Attributes
= NewAccessProtection
;
970 MemoryArea
= MmSplitMemoryArea(Process
,
971 &Process
->AddressSpace
,
974 NumberOfBytesToProtect
,
976 NewAccessProtection
);
978 MmChangeAreaProtection(Process
,
980 NumberOfBytesToProtect
,
981 NewAccessProtection
);
982 MmUnlockAddressSpace(AddressSpace
);
983 ObDereferenceObject(Process
);
984 return(STATUS_SUCCESS
);
988 NTSTATUS STDCALL
NtQueryVirtualMemory (IN HANDLE ProcessHandle
,
990 IN CINT VirtualMemoryInformationClass
,
991 OUT PVOID VirtualMemoryInformation
,
993 OUT PULONG ResultLength
)
997 MEMORY_AREA
* MemoryArea
;
999 DPRINT("NtQueryVirtualMemory(ProcessHandle %x, Address %x, "
1000 "VirtualMemoryInformationClass %d, VirtualMemoryInformation %x, "
1001 "Length %lu ResultLength %x)\n",ProcessHandle
,Address
,
1002 VirtualMemoryInformationClass
,VirtualMemoryInformation
,
1003 Length
,ResultLength
);
1005 switch(VirtualMemoryInformationClass
)
1007 case MemoryBasicInformation
:
1009 PMEMORY_BASIC_INFORMATION Info
=
1010 (PMEMORY_BASIC_INFORMATION
)VirtualMemoryInformation
;
1011 PMADDRESS_SPACE AddressSpace
;
1013 if (Length
< sizeof(MEMORY_BASIC_INFORMATION
))
1015 ObDereferenceObject(Process
);
1016 return STATUS_INFO_LENGTH_MISMATCH
;
1021 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
1024 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1025 PROCESS_QUERY_INFORMATION
,
1031 if (!NT_SUCCESS(Status
))
1033 DPRINT("NtQueryVirtualMemory() = %x\n",Status
);
1037 AddressSpace
= &Process
->AddressSpace
;
1038 MmLockAddressSpace(AddressSpace
);
1039 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
1042 if (MemoryArea
== NULL
)
1044 Info
->State
= MEM_FREE
;
1045 DPRINT("Virtual memory at %p is free.\n", Address
);
1046 MmUnlockAddressSpace(AddressSpace
);
1047 ObDereferenceObject(Process
);
1048 return (STATUS_SUCCESS
);
1052 if (MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
)
1054 Info
->State
= MEM_COMMIT
;
1058 Info
->State
= MEM_RESERVE
;
1062 Info
->BaseAddress
= MemoryArea
->BaseAddress
;
1063 Info
->RegionSize
= MemoryArea
->Length
;
1065 DPRINT("BaseAddress %p, RegionSize %x State %x\n",
1066 Info
->BaseAddress
, Info
->RegionSize
, Info
->State
);
1068 MmUnlockAddressSpace(AddressSpace
);
1069 ObDereferenceObject(Process
);
1070 return STATUS_SUCCESS
;
1075 return STATUS_INVALID_INFO_CLASS
;
1079 NTSTATUS STDCALL
NtReadVirtualMemory(IN HANDLE ProcessHandle
,
1080 IN PVOID BaseAddress
,
1082 IN ULONG NumberOfBytesToRead
,
1083 OUT PULONG NumberOfBytesRead
)
1087 PVOID SystemAddress
;
1090 DPRINT("NtReadVirtualMemory(ProcessHandle %x, BaseAddress %x, "
1091 "Buffer %x, NumberOfBytesToRead %d)\n",ProcessHandle
,BaseAddress
,
1092 Buffer
,NumberOfBytesToRead
);
1094 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1100 if (Status
!= STATUS_SUCCESS
)
1105 Mdl
= MmCreateMdl(NULL
,
1107 NumberOfBytesToRead
);
1108 MmProbeAndLockPages(Mdl
,
1112 KeAttachProcess(Process
);
1114 SystemAddress
= MmGetSystemAddressForMdl(Mdl
);
1115 memcpy(SystemAddress
, BaseAddress
, NumberOfBytesToRead
);
1119 ObDereferenceObject(Process
);
1121 *NumberOfBytesRead
= NumberOfBytesToRead
;
1122 return(STATUS_SUCCESS
);
1126 NTSTATUS STDCALL
NtUnlockVirtualMemory(HANDLE ProcessHandle
,
1128 ULONG NumberOfBytesToUnlock
,
1129 PULONG NumberOfBytesUnlocked OPTIONAL
)
1135 NTSTATUS STDCALL
NtWriteVirtualMemory(IN HANDLE ProcessHandle
,
1136 IN PVOID BaseAddress
,
1138 IN ULONG NumberOfBytesToWrite
,
1139 OUT PULONG NumberOfBytesWritten
)
1143 PVOID SystemAddress
;
1146 DPRINT("NtWriteVirtualMemory(ProcessHandle %x, BaseAddress %x, "
1147 "Buffer %x, NumberOfBytesToWrite %d)\n",ProcessHandle
,BaseAddress
,
1148 Buffer
,NumberOfBytesToWrite
);
1150 Status
= ObReferenceObjectByHandle(ProcessHandle
,
1156 if (Status
!= STATUS_SUCCESS
)
1161 Mdl
= MmCreateMdl(NULL
,
1163 NumberOfBytesToWrite
);
1164 MmProbeAndLockPages(Mdl
,
1168 KeAttachProcess(Process
);
1170 DPRINT("Attached to process copying memory\n");
1172 SystemAddress
= MmGetSystemAddressForMdl(Mdl
);
1173 memcpy(BaseAddress
, SystemAddress
, NumberOfBytesToWrite
);
1175 DPRINT("Done copy\n");
1179 ObDereferenceObject(Process
);
1181 *NumberOfBytesWritten
= NumberOfBytesToWrite
;
1183 DPRINT("Finished NtWriteVirtualMemory()\n");
1185 return(STATUS_SUCCESS
);
1191 MmSecureVirtualMemory (
1204 MmUnsecureVirtualMemory (