3 * Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team
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.
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.
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.
19 /* $Id: anonmem.c,v 1.29 2004/07/10 17:01:03 hbirr Exp $
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/anonmem.c
23 * PURPOSE: Implementing anonymous memory.
24 * PROGRAMMER: David Welch
27 /* INCLUDE *****************************************************************/
29 #include <ddk/ntddk.h>
30 #include <internal/mm.h>
31 #include <internal/ob.h>
32 #include <internal/io.h>
33 #include <internal/ps.h>
34 #include <internal/pool.h>
37 #include <internal/debug.h>
39 /* FUNCTIONS *****************************************************************/
42 MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace
,
43 PMEMORY_AREA MemoryArea
,
48 LARGE_INTEGER PhysicalAddress
;
52 * Check for paging out from a deleted virtual memory area.
54 if (MemoryArea
->DeleteInProgress
)
56 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
57 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
58 MmReleasePageOp(PageOp
);
59 return(STATUS_UNSUCCESSFUL
);
63 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
66 * Get that the page actually is dirty.
68 if (!MmIsDirtyPage(MemoryArea
->Process
, Address
))
70 PageOp
->Status
= STATUS_SUCCESS
;
71 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
72 MmReleasePageOp(PageOp
);
73 return(STATUS_SUCCESS
);
77 * Speculatively set the mapping to clean.
79 MmSetCleanPage(MemoryArea
->Process
, Address
);
82 * If necessary, allocate an entry in the paging file for this page
84 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
87 SwapEntry
= MmAllocSwapPage();
90 MmSetDirtyPage(MemoryArea
->Process
, Address
);
91 PageOp
->Status
= STATUS_PAGEFILE_QUOTA_EXCEEDED
;
92 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
93 MmReleasePageOp(PageOp
);
94 return(STATUS_PAGEFILE_QUOTA_EXCEEDED
);
99 * Write the page to the pagefile
101 Status
= MmWriteToSwapPage(SwapEntry
, &PhysicalAddress
);
102 if (!NT_SUCCESS(Status
))
104 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
106 MmSetDirtyPage(MemoryArea
->Process
, Address
);
107 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
108 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
109 MmReleasePageOp(PageOp
);
110 return(STATUS_UNSUCCESSFUL
);
114 * Otherwise we have succeeded.
116 MmSetSavedSwapEntryPage(PhysicalAddress
, SwapEntry
);
117 PageOp
->Status
= STATUS_SUCCESS
;
118 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
119 MmReleasePageOp(PageOp
);
120 return(STATUS_SUCCESS
);
124 MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace
,
125 PMEMORY_AREA MemoryArea
,
129 PHYSICAL_ADDRESS PhysicalAddress
;
134 DPRINT("MmPageOutVirtualMemory(Address 0x%.8X) PID %d\n",
135 Address
, MemoryArea
->Process
->UniqueProcessId
);
138 * Check for paging out from a deleted virtual memory area.
140 if (MemoryArea
->DeleteInProgress
)
142 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
143 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
144 MmReleasePageOp(PageOp
);
145 return(STATUS_UNSUCCESSFUL
);
149 * Disable the virtual mapping.
151 MmDisableVirtualMapping(MemoryArea
->Process
, Address
,
152 &WasDirty
, &PhysicalAddress
);
154 if (PhysicalAddress
.QuadPart
== 0)
160 * Paging out non-dirty data is easy.
164 MmDeleteVirtualMapping(MemoryArea
->Process
, Address
, FALSE
, NULL
, NULL
);
165 MmDeleteAllRmaps(PhysicalAddress
, NULL
, NULL
);
166 if ((SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
)) != 0)
168 MmCreatePageFileMapping(MemoryArea
->Process
, Address
, SwapEntry
);
169 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
171 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
172 PageOp
->Status
= STATUS_SUCCESS
;
173 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
174 MmReleasePageOp(PageOp
);
175 return(STATUS_SUCCESS
);
179 * If necessary, allocate an entry in the paging file for this page
181 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
184 SwapEntry
= MmAllocSwapPage();
187 MmShowOutOfSpaceMessagePagingFile();
188 MmEnableVirtualMapping(MemoryArea
->Process
, Address
);
189 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
190 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
191 MmReleasePageOp(PageOp
);
192 return(STATUS_PAGEFILE_QUOTA
);
197 * Write the page to the pagefile
199 Status
= MmWriteToSwapPage(SwapEntry
, &PhysicalAddress
);
200 if (!NT_SUCCESS(Status
))
202 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
204 MmEnableVirtualMapping(MemoryArea
->Process
, Address
);
205 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
206 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
207 MmReleasePageOp(PageOp
);
208 return(STATUS_UNSUCCESSFUL
);
212 * Otherwise we have succeeded, free the page
214 DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", PhysicalAddress
);
215 MmDeleteVirtualMapping(MemoryArea
->Process
, Address
, FALSE
, NULL
, NULL
);
216 MmCreatePageFileMapping(MemoryArea
->Process
, Address
, SwapEntry
);
217 MmDeleteAllRmaps(PhysicalAddress
, NULL
, NULL
);
218 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
219 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
220 PageOp
->Status
= STATUS_SUCCESS
;
221 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
222 MmReleasePageOp(PageOp
);
223 return(STATUS_SUCCESS
);
227 MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace
,
228 MEMORY_AREA
* MemoryArea
,
232 * FUNCTION: Move data into memory to satisfy a page not present fault
234 * AddressSpace = Address space within which the fault occurred
235 * MemoryArea = The memory area within which the fault occurred
236 * Address = The absolute address of fault
238 * NOTES: This function is called with the address space lock held.
241 PHYSICAL_ADDRESS Page
;
247 * There is a window between taking the page fault and locking the
248 * address space when another thread could load the page so we check
251 if (MmIsPagePresent(NULL
, Address
))
255 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
257 return(STATUS_SUCCESS
);
261 * Check for the virtual memory area being deleted.
263 if (MemoryArea
->DeleteInProgress
)
265 return(STATUS_UNSUCCESSFUL
);
269 * Get the segment corresponding to the virtual address
271 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
272 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
274 if (Region
->Type
== MEM_RESERVE
|| Region
->Protect
== PAGE_NOACCESS
)
276 return(STATUS_ACCESS_VIOLATION
);
280 * Get or create a page operation
282 PageOp
= MmGetPageOp(MemoryArea
, (ULONG
)MemoryArea
->Process
->UniqueProcessId
,
283 (PVOID
)PAGE_ROUND_DOWN(Address
), NULL
, 0,
284 MM_PAGEOP_PAGEIN
, FALSE
);
287 DPRINT1("MmGetPageOp failed");
292 * Check if someone else is already handling this fault, if so wait
295 if (PageOp
->Thread
!= PsGetCurrentThread())
297 MmUnlockAddressSpace(AddressSpace
);
298 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
304 * Check for various strange conditions
306 if (Status
!= STATUS_SUCCESS
)
308 DPRINT1("Failed to wait for page op\n");
311 if (PageOp
->Status
== STATUS_PENDING
)
313 DPRINT1("Woke for page op before completion\n");
317 * If this wasn't a pagein then we need to restart the handling
319 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
321 MmLockAddressSpace(AddressSpace
);
322 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
323 MmReleasePageOp(PageOp
);
324 return(STATUS_MM_RESTART_OPERATION
);
327 * If the thread handling this fault has failed then we don't retry
329 if (!NT_SUCCESS(PageOp
->Status
))
331 MmLockAddressSpace(AddressSpace
);
332 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
333 Status
= PageOp
->Status
;
334 MmReleasePageOp(PageOp
);
337 MmLockAddressSpace(AddressSpace
);
340 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
342 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
343 MmReleasePageOp(PageOp
);
344 return(STATUS_SUCCESS
);
348 * Try to allocate a page
350 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
351 if (Status
== STATUS_NO_MEMORY
)
353 MmUnlockAddressSpace(AddressSpace
);
354 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
355 MmLockAddressSpace(AddressSpace
);
357 if (!NT_SUCCESS(Status
))
359 DPRINT1("MmRequestPageMemoryConsumer failed, status = %x\n", Status
);
364 * Handle swapped out pages.
366 if (MmIsPageSwapEntry(NULL
, Address
))
370 MmDeletePageFileMapping(MemoryArea
->Process
, Address
, &SwapEntry
);
371 Status
= MmReadFromSwapPage(SwapEntry
, &Page
);
372 if (!NT_SUCCESS(Status
))
376 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
380 * Set the page. If we fail because we are out of memory then
383 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
384 (PVOID
)PAGE_ROUND_DOWN(Address
),
388 while (Status
== STATUS_NO_MEMORY
)
390 MmUnlockAddressSpace(AddressSpace
);
391 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
396 MmLockAddressSpace(AddressSpace
);
398 if (!NT_SUCCESS(Status
))
400 DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
406 * Add the page to the process's working set
408 MmInsertRmap(Page
, MemoryArea
->Process
, (PVOID
)PAGE_ROUND_DOWN(Address
));
411 * Finish the operation
415 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
417 PageOp
->Status
= STATUS_SUCCESS
;
418 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
419 MmReleasePageOp(PageOp
);
420 return(STATUS_SUCCESS
);
424 MmModifyAttributes(PMADDRESS_SPACE AddressSpace
,
432 * FUNCTION: Modify the attributes of a memory region
436 * If we are switching a previously committed region to reserved then
437 * free any allocated pages within the region
439 if (NewType
== MEM_RESERVE
&& OldType
== MEM_COMMIT
)
443 for (i
=0; i
< PAGE_ROUND_UP(RegionSize
)/PAGE_SIZE
; i
++)
445 LARGE_INTEGER PhysicalAddr
;
447 if (MmIsPageSwapEntry(AddressSpace
->Process
,
448 (char*)BaseAddress
+ (i
* PAGE_SIZE
)))
452 MmDeletePageFileMapping(AddressSpace
->Process
,
453 (char*)BaseAddress
+ (i
* PAGE_SIZE
),
455 MmFreeSwapPage(SwapEntry
);
459 MmDeleteVirtualMapping(AddressSpace
->Process
,
460 (char*)BaseAddress
+ (i
*PAGE_SIZE
),
461 FALSE
, NULL
, &PhysicalAddr
);
462 if (PhysicalAddr
.QuadPart
!= 0)
464 SWAPENTRY SavedSwapEntry
;
465 SavedSwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddr
);
466 if (SavedSwapEntry
!= 0)
468 MmFreeSwapPage(SavedSwapEntry
);
469 MmSetSavedSwapEntryPage(PhysicalAddr
, 0);
471 MmDeleteRmap(PhysicalAddr
, AddressSpace
->Process
,
472 (char*)BaseAddress
+ (i
* PAGE_SIZE
));
473 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddr
);
480 * If we are changing the protection attributes of a committed region then
481 * alter the attributes for any allocated pages within the region
483 if (NewType
== MEM_COMMIT
&& OldType
== MEM_COMMIT
&&
484 OldProtect
!= NewProtect
)
488 for (i
=0; i
< PAGE_ROUND_UP(RegionSize
)/PAGE_SIZE
; i
++)
490 if (MmIsPagePresent(AddressSpace
->Process
,
491 (char*)BaseAddress
+ (i
*PAGE_SIZE
)))
493 MmSetPageProtect(AddressSpace
->Process
,
494 (char*)BaseAddress
+ (i
*PAGE_SIZE
),
505 NtAllocateVirtualMemory(IN HANDLE ProcessHandle
,
506 IN OUT PVOID
* UBaseAddress
,
508 IN OUT PULONG URegionSize
,
509 IN ULONG AllocationType
,
512 * FUNCTION: Allocates a block of virtual memory in the process address space
514 * ProcessHandle = The handle of the process which owns the virtual memory
515 * BaseAddress = A pointer to the virtual memory allocated. If you
516 * supply a non zero value the system will try to
517 * allocate the memory at the address supplied. It round
518 * it down to a multiple of the page size.
519 * ZeroBits = (OPTIONAL) You can specify the number of high order bits
520 * that must be zero, ensuring that the memory will be
521 * allocated at a address below a certain value.
522 * RegionSize = The number of bytes to allocate
523 * AllocationType = Indicates the type of virtual memory you like to
524 * allocated, can be a combination of MEM_COMMIT,
525 * MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN.
526 * Protect = Indicates the protection type of the pages allocated, can be
527 * a combination of PAGE_READONLY, PAGE_READWRITE,
528 * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD,
534 MEMORY_AREA
* MemoryArea
;
537 PMADDRESS_SPACE AddressSpace
;
542 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
544 DPRINT("NtAllocateVirtualMemory(*UBaseAddress %x, "
545 "ZeroBits %d, *URegionSize %x, AllocationType %x, Protect %x)\n",
546 *UBaseAddress
,ZeroBits
,*URegionSize
,AllocationType
,
550 * Check the validity of the parameters
552 if ((Protect
& PAGE_FLAGS_VALID_FROM_USER_MODE
) != Protect
)
554 return(STATUS_INVALID_PAGE_PROTECTION
);
556 if ((AllocationType
& (MEM_COMMIT
| MEM_RESERVE
)) == 0)
558 return(STATUS_INVALID_PARAMETER
);
561 PBaseAddress
= *UBaseAddress
;
562 PRegionSize
= *URegionSize
;
563 BoundaryAddressMultiple
.QuadPart
= 0;
565 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(PBaseAddress
);
566 RegionSize
= PAGE_ROUND_UP(PBaseAddress
+ PRegionSize
) -
567 PAGE_ROUND_DOWN(PBaseAddress
);
569 Status
= ObReferenceObjectByHandle(ProcessHandle
,
570 PROCESS_VM_OPERATION
,
575 if (!NT_SUCCESS(Status
))
577 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
581 Type
= (AllocationType
& MEM_COMMIT
) ? MEM_COMMIT
: MEM_RESERVE
;
582 DPRINT("Type %x\n", Type
);
584 AddressSpace
= &Process
->AddressSpace
;
585 MmLockAddressSpace(AddressSpace
);
587 if (PBaseAddress
!= 0)
589 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
592 if (MemoryArea
!= NULL
&&
593 MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
&&
594 MemoryArea
->Length
>= RegionSize
)
597 MmAlterRegion(AddressSpace
,
598 MemoryArea
->BaseAddress
,
599 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
600 BaseAddress
, RegionSize
,
601 Type
, Protect
, MmModifyAttributes
);
602 MmUnlockAddressSpace(AddressSpace
);
603 ObDereferenceObject(Process
);
604 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
607 else if (MemoryArea
!= NULL
&& MemoryArea
->Length
>= RegionSize
)
610 MmAlterRegion(AddressSpace
,
611 MemoryArea
->BaseAddress
,
612 &MemoryArea
->Data
.SectionData
.RegionListHead
,
613 BaseAddress
, RegionSize
,
614 Type
, Protect
, MmModifyAttributes
);
615 MmUnlockAddressSpace(AddressSpace
);
616 ObDereferenceObject(Process
);
617 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
620 else if (MemoryArea
!= NULL
)
622 MmUnlockAddressSpace(AddressSpace
);
623 ObDereferenceObject(Process
);
624 return(STATUS_UNSUCCESSFUL
);
628 Status
= MmCreateMemoryArea(Process
,
630 MEMORY_AREA_VIRTUAL_MEMORY
,
636 (AllocationType
& MEM_TOP_DOWN
),
637 BoundaryAddressMultiple
);
638 if (!NT_SUCCESS(Status
))
640 MmUnlockAddressSpace(AddressSpace
);
641 ObDereferenceObject(Process
);
642 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
645 MmInitialiseRegion(&MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
646 RegionSize
, Type
, Protect
);
648 if ((AllocationType
& MEM_COMMIT
) &&
649 ((Protect
& PAGE_READWRITE
) ||
650 (Protect
& PAGE_EXECUTE_READWRITE
)))
652 MmReserveSwapPages(RegionSize
);
655 *UBaseAddress
= BaseAddress
;
656 *URegionSize
= RegionSize
;
657 DPRINT("*UBaseAddress %x *URegionSize %x\n", BaseAddress
, RegionSize
);
659 MmUnlockAddressSpace(AddressSpace
);
660 ObDereferenceObject(Process
);
661 return(STATUS_SUCCESS
);
665 MmFreeVirtualMemoryPage(PVOID Context
,
666 MEMORY_AREA
* MemoryArea
,
668 PHYSICAL_ADDRESS PhysicalAddr
,
672 PEPROCESS Process
= (PEPROCESS
)Context
;
674 if (PhysicalAddr
.QuadPart
!= 0)
676 SWAPENTRY SavedSwapEntry
;
677 SavedSwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddr
);
678 if (SavedSwapEntry
!= 0)
680 MmFreeSwapPage(SavedSwapEntry
);
681 MmSetSavedSwapEntryPage(PhysicalAddr
, 0);
683 MmDeleteRmap(PhysicalAddr
, Process
, Address
);
684 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddr
);
686 else if (SwapEntry
!= 0)
688 MmFreeSwapPage(SwapEntry
);
693 MmFreeVirtualMemory(PEPROCESS Process
,
694 PMEMORY_AREA MemoryArea
)
696 PLIST_ENTRY current_entry
;
700 DPRINT("MmFreeVirtualMemory(Process %p MemoryArea %p)\n", Process
,
703 /* Mark this memory area as about to be deleted. */
704 MemoryArea
->DeleteInProgress
= TRUE
;
707 * Wait for any ongoing paging operations. Notice that since we have
708 * flagged this memory area as deleted no more page ops will be added.
710 if (MemoryArea
->PageOpCount
> 0)
712 for (i
= 0; i
< PAGE_ROUND_UP(MemoryArea
->Length
) / PAGE_SIZE
; i
++)
716 if (MemoryArea
->PageOpCount
== 0)
721 PageOp
= MmCheckForPageOp(MemoryArea
, Process
->UniqueProcessId
,
722 (char*)MemoryArea
->BaseAddress
+ (i
* PAGE_SIZE
),
727 MmUnlockAddressSpace(&Process
->AddressSpace
);
728 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
733 if (Status
!= STATUS_SUCCESS
)
735 DPRINT1("Failed to wait for page op\n");
738 MmLockAddressSpace(&Process
->AddressSpace
);
739 MmReleasePageOp(PageOp
);
744 /* Free all the individual segments. */
745 current_entry
= MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
.Flink
;
746 while (current_entry
!= &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
)
748 current
= CONTAINING_RECORD(current_entry
, MM_REGION
, RegionListEntry
);
749 current_entry
= current_entry
->Flink
;
753 /* Actually free the memory area. */
754 MmFreeMemoryArea(&Process
->AddressSpace
,
755 MemoryArea
->BaseAddress
,
757 MmFreeVirtualMemoryPage
,
765 NtFreeVirtualMemory(IN HANDLE ProcessHandle
,
766 IN PVOID
* PBaseAddress
,
767 IN PULONG PRegionSize
,
770 * FUNCTION: Frees a range of virtual memory
772 * ProcessHandle = Points to the process that allocated the virtual
774 * BaseAddress = Points to the memory address, rounded down to a
775 * multiple of the pagesize
776 * RegionSize = Limits the range to free, rounded up to a multiple of
778 * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
782 MEMORY_AREA
* MemoryArea
;
785 PMADDRESS_SPACE AddressSpace
;
789 DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *PBaseAddress %x, "
790 "*PRegionSize %x, FreeType %x)\n",ProcessHandle
,*PBaseAddress
,
791 *PRegionSize
,FreeType
);
793 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN((*PBaseAddress
));
794 RegionSize
= PAGE_ROUND_UP((*PBaseAddress
) + (*PRegionSize
)) -
795 PAGE_ROUND_DOWN((*PBaseAddress
));
797 Status
= ObReferenceObjectByHandle(ProcessHandle
,
798 PROCESS_VM_OPERATION
,
803 if (!NT_SUCCESS(Status
))
808 AddressSpace
= &Process
->AddressSpace
;
810 MmLockAddressSpace(AddressSpace
);
811 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
813 if (MemoryArea
== NULL
)
815 MmUnlockAddressSpace(AddressSpace
);
816 ObDereferenceObject(Process
);
817 return(STATUS_UNSUCCESSFUL
);
823 /* We can only free a memory area in one step. */
824 if (MemoryArea
->BaseAddress
!= BaseAddress
)
826 MmUnlockAddressSpace(AddressSpace
);
827 ObDereferenceObject(Process
);
828 return(STATUS_UNSUCCESSFUL
);
830 MmFreeVirtualMemory(Process
, MemoryArea
);
831 MmUnlockAddressSpace(AddressSpace
);
832 ObDereferenceObject(Process
);
833 return(STATUS_SUCCESS
);
837 MmAlterRegion(AddressSpace
,
838 MemoryArea
->BaseAddress
,
839 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
845 MmUnlockAddressSpace(AddressSpace
);
846 ObDereferenceObject(Process
);
849 MmUnlockAddressSpace(AddressSpace
);
850 ObDereferenceObject(Process
);
851 return(STATUS_NOT_IMPLEMENTED
);
855 MmProtectAnonMem(PMADDRESS_SPACE AddressSpace
,
856 PMEMORY_AREA MemoryArea
,
865 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
866 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
868 *OldProtect
= Region
->Protect
;
869 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->BaseAddress
,
870 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
871 BaseAddress
, Length
, Region
->Type
, Protect
,
877 MmQueryAnonMem(PMEMORY_AREA MemoryArea
,
879 PMEMORY_BASIC_INFORMATION Info
,
885 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
887 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
888 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
889 Address
, &RegionBase
);
890 Info
->BaseAddress
= RegionBase
;
891 Info
->AllocationBase
= MemoryArea
->BaseAddress
;
892 Info
->AllocationProtect
= MemoryArea
->Attributes
;
893 Info
->RegionSize
= (char*)RegionBase
+ Region
->Length
- (char*)Info
->BaseAddress
;
894 Info
->State
= Region
->Type
;
895 Info
->Protect
= Region
->Protect
;
896 Info
->Type
= MEM_PRIVATE
;
898 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
899 return(STATUS_SUCCESS
);