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.
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/anonmem.c
23 * PURPOSE: Implementing anonymous memory.
24 * PROGRAMMER: David Welch
27 /* INCLUDE *****************************************************************/
31 #include <internal/debug.h>
33 /* FUNCTIONS *****************************************************************/
36 MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace
,
37 PMEMORY_AREA MemoryArea
,
46 * Check for paging out from a deleted virtual memory area.
48 if (MemoryArea
->DeleteInProgress
)
50 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
51 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
52 MmReleasePageOp(PageOp
);
53 return(STATUS_UNSUCCESSFUL
);
56 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
59 * Get that the page actually is dirty.
61 if (!MmIsDirtyPage(MemoryArea
->Process
, Address
))
63 PageOp
->Status
= STATUS_SUCCESS
;
64 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
65 MmReleasePageOp(PageOp
);
66 return(STATUS_SUCCESS
);
70 * Speculatively set the mapping to clean.
72 MmSetCleanPage(MemoryArea
->Process
, Address
);
75 * If necessary, allocate an entry in the paging file for this page
77 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
80 SwapEntry
= MmAllocSwapPage();
83 MmSetDirtyPage(MemoryArea
->Process
, Address
);
84 PageOp
->Status
= STATUS_PAGEFILE_QUOTA_EXCEEDED
;
85 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
86 MmReleasePageOp(PageOp
);
87 return(STATUS_PAGEFILE_QUOTA_EXCEEDED
);
92 * Write the page to the pagefile
94 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
95 if (!NT_SUCCESS(Status
))
97 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
99 MmSetDirtyPage(MemoryArea
->Process
, Address
);
100 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
101 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
102 MmReleasePageOp(PageOp
);
103 return(STATUS_UNSUCCESSFUL
);
107 * Otherwise we have succeeded.
109 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
110 PageOp
->Status
= STATUS_SUCCESS
;
111 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
112 MmReleasePageOp(PageOp
);
113 return(STATUS_SUCCESS
);
117 MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace
,
118 PMEMORY_AREA MemoryArea
,
127 DPRINT("MmPageOutVirtualMemory(Address 0x%.8X) PID %d\n",
128 Address
, MemoryArea
->Process
->UniqueProcessId
);
131 * Check for paging out from a deleted virtual memory area.
133 if (MemoryArea
->DeleteInProgress
)
135 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
136 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
137 MmReleasePageOp(PageOp
);
138 return(STATUS_UNSUCCESSFUL
);
142 * Disable the virtual mapping.
144 MmDisableVirtualMapping(MemoryArea
->Process
, Address
,
153 * Paging out non-dirty data is easy.
157 MmDeleteVirtualMapping(MemoryArea
->Process
, Address
, FALSE
, NULL
, NULL
);
158 MmDeleteAllRmaps(Page
, NULL
, NULL
);
159 if ((SwapEntry
= MmGetSavedSwapEntryPage(Page
)) != 0)
161 MmCreatePageFileMapping(MemoryArea
->Process
, Address
, SwapEntry
);
162 MmSetSavedSwapEntryPage(Page
, 0);
164 MmReleasePageMemoryConsumer(MC_USER
, Page
);
165 PageOp
->Status
= STATUS_SUCCESS
;
166 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
167 MmReleasePageOp(PageOp
);
168 return(STATUS_SUCCESS
);
172 * If necessary, allocate an entry in the paging file for this page
174 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
177 SwapEntry
= MmAllocSwapPage();
180 MmShowOutOfSpaceMessagePagingFile();
181 MmEnableVirtualMapping(MemoryArea
->Process
, Address
);
182 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
183 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
184 MmReleasePageOp(PageOp
);
185 return(STATUS_PAGEFILE_QUOTA
);
190 * Write the page to the pagefile
192 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
193 if (!NT_SUCCESS(Status
))
195 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
197 MmEnableVirtualMapping(MemoryArea
->Process
, Address
);
198 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
199 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
200 MmReleasePageOp(PageOp
);
201 return(STATUS_UNSUCCESSFUL
);
205 * Otherwise we have succeeded, free the page
207 DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", Page
<< PAGE_SHIFT
);
208 MmDeleteVirtualMapping(MemoryArea
->Process
, Address
, FALSE
, NULL
, NULL
);
209 MmCreatePageFileMapping(MemoryArea
->Process
, Address
, SwapEntry
);
210 MmDeleteAllRmaps(Page
, NULL
, NULL
);
211 MmSetSavedSwapEntryPage(Page
, 0);
212 MmReleasePageMemoryConsumer(MC_USER
, Page
);
213 PageOp
->Status
= STATUS_SUCCESS
;
214 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
215 MmReleasePageOp(PageOp
);
216 return(STATUS_SUCCESS
);
220 MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace
,
221 MEMORY_AREA
* MemoryArea
,
225 * FUNCTION: Move data into memory to satisfy a page not present fault
227 * AddressSpace = Address space within which the fault occurred
228 * MemoryArea = The memory area within which the fault occurred
229 * Address = The absolute address of fault
231 * NOTES: This function is called with the address space lock held.
240 * There is a window between taking the page fault and locking the
241 * address space when another thread could load the page so we check
244 if (MmIsPagePresent(NULL
, Address
))
248 MmLockPage(MmGetPfnForProcess(NULL
, Address
));
250 return(STATUS_SUCCESS
);
254 * Check for the virtual memory area being deleted.
256 if (MemoryArea
->DeleteInProgress
)
258 return(STATUS_UNSUCCESSFUL
);
262 * Get the segment corresponding to the virtual address
264 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
265 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
267 if (Region
->Type
== MEM_RESERVE
|| Region
->Protect
== PAGE_NOACCESS
)
269 return(STATUS_ACCESS_VIOLATION
);
273 * Get or create a page operation
275 PageOp
= MmGetPageOp(MemoryArea
, (ULONG
)MemoryArea
->Process
->UniqueProcessId
,
276 (PVOID
)PAGE_ROUND_DOWN(Address
), NULL
, 0,
277 MM_PAGEOP_PAGEIN
, FALSE
);
280 DPRINT1("MmGetPageOp failed");
285 * Check if someone else is already handling this fault, if so wait
288 if (PageOp
->Thread
!= PsGetCurrentThread())
290 MmUnlockAddressSpace(AddressSpace
);
291 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
297 * Check for various strange conditions
299 if (Status
!= STATUS_SUCCESS
)
301 DPRINT1("Failed to wait for page op\n");
304 if (PageOp
->Status
== STATUS_PENDING
)
306 DPRINT1("Woke for page op before completion\n");
310 * If this wasn't a pagein then we need to restart the handling
312 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
314 MmLockAddressSpace(AddressSpace
);
315 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
316 MmReleasePageOp(PageOp
);
317 return(STATUS_MM_RESTART_OPERATION
);
320 * If the thread handling this fault has failed then we don't retry
322 if (!NT_SUCCESS(PageOp
->Status
))
324 MmLockAddressSpace(AddressSpace
);
325 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
326 Status
= PageOp
->Status
;
327 MmReleasePageOp(PageOp
);
330 MmLockAddressSpace(AddressSpace
);
333 MmLockPage(MmGetPfnForProcess(NULL
, Address
));
335 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
336 MmReleasePageOp(PageOp
);
337 return(STATUS_SUCCESS
);
341 * Try to allocate a page
343 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
344 if (Status
== STATUS_NO_MEMORY
)
346 MmUnlockAddressSpace(AddressSpace
);
347 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
348 MmLockAddressSpace(AddressSpace
);
350 if (!NT_SUCCESS(Status
))
352 DPRINT1("MmRequestPageMemoryConsumer failed, status = %x\n", Status
);
357 * Handle swapped out pages.
359 if (MmIsPageSwapEntry(NULL
, Address
))
363 MmDeletePageFileMapping(MemoryArea
->Process
, Address
, &SwapEntry
);
364 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
365 if (!NT_SUCCESS(Status
))
369 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
373 * Set the page. If we fail because we are out of memory then
376 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
377 (PVOID
)PAGE_ROUND_DOWN(Address
),
381 while (Status
== STATUS_NO_MEMORY
)
383 MmUnlockAddressSpace(AddressSpace
);
384 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
389 MmLockAddressSpace(AddressSpace
);
391 if (!NT_SUCCESS(Status
))
393 DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
399 * Add the page to the process's working set
401 MmInsertRmap(Page
, MemoryArea
->Process
, (PVOID
)PAGE_ROUND_DOWN(Address
));
404 * Finish the operation
410 PageOp
->Status
= STATUS_SUCCESS
;
411 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
412 MmReleasePageOp(PageOp
);
413 return(STATUS_SUCCESS
);
417 MmModifyAttributes(PMADDRESS_SPACE AddressSpace
,
425 * FUNCTION: Modify the attributes of a memory region
429 * If we are switching a previously committed region to reserved then
430 * free any allocated pages within the region
432 if (NewType
== MEM_RESERVE
&& OldType
== MEM_COMMIT
)
436 for (i
=0; i
< PAGE_ROUND_UP(RegionSize
)/PAGE_SIZE
; i
++)
440 if (MmIsPageSwapEntry(AddressSpace
->Process
,
441 (char*)BaseAddress
+ (i
* PAGE_SIZE
)))
445 MmDeletePageFileMapping(AddressSpace
->Process
,
446 (char*)BaseAddress
+ (i
* PAGE_SIZE
),
448 MmFreeSwapPage(SwapEntry
);
452 MmDeleteVirtualMapping(AddressSpace
->Process
,
453 (char*)BaseAddress
+ (i
*PAGE_SIZE
),
457 SWAPENTRY SavedSwapEntry
;
458 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
459 if (SavedSwapEntry
!= 0)
461 MmFreeSwapPage(SavedSwapEntry
);
462 MmSetSavedSwapEntryPage(Page
, 0);
464 MmDeleteRmap(Page
, AddressSpace
->Process
,
465 (char*)BaseAddress
+ (i
* PAGE_SIZE
));
466 MmReleasePageMemoryConsumer(MC_USER
, Page
);
473 * If we are changing the protection attributes of a committed region then
474 * alter the attributes for any allocated pages within the region
476 if (NewType
== MEM_COMMIT
&& OldType
== MEM_COMMIT
&&
477 OldProtect
!= NewProtect
)
481 for (i
=0; i
< PAGE_ROUND_UP(RegionSize
)/PAGE_SIZE
; i
++)
483 if (MmIsPagePresent(AddressSpace
->Process
,
484 (char*)BaseAddress
+ (i
*PAGE_SIZE
)))
486 MmSetPageProtect(AddressSpace
->Process
,
487 (char*)BaseAddress
+ (i
*PAGE_SIZE
),
498 NtAllocateVirtualMemory(IN HANDLE ProcessHandle
,
499 IN OUT PVOID
* UBaseAddress
,
501 IN OUT PULONG URegionSize
,
502 IN ULONG AllocationType
,
505 * FUNCTION: Allocates a block of virtual memory in the process address space
507 * ProcessHandle = The handle of the process which owns the virtual memory
508 * BaseAddress = A pointer to the virtual memory allocated. If you
509 * supply a non zero value the system will try to
510 * allocate the memory at the address supplied. It round
511 * it down to a multiple of the page size.
512 * ZeroBits = (OPTIONAL) You can specify the number of high order bits
513 * that must be zero, ensuring that the memory will be
514 * allocated at a address below a certain value.
515 * RegionSize = The number of bytes to allocate
516 * AllocationType = Indicates the type of virtual memory you like to
517 * allocated, can be a combination of MEM_COMMIT,
518 * MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN.
519 * Protect = Indicates the protection type of the pages allocated, can be
520 * a combination of PAGE_READONLY, PAGE_READWRITE,
521 * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD,
527 MEMORY_AREA
* MemoryArea
;
528 ULONG_PTR MemoryAreaLength
;
531 PMADDRESS_SPACE AddressSpace
;
536 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
538 DPRINT("NtAllocateVirtualMemory(*UBaseAddress %x, "
539 "ZeroBits %d, *URegionSize %x, AllocationType %x, Protect %x)\n",
540 *UBaseAddress
,ZeroBits
,*URegionSize
,AllocationType
,
544 * Check the validity of the parameters
546 if ((Protect
& PAGE_FLAGS_VALID_FROM_USER_MODE
) != Protect
)
548 return(STATUS_INVALID_PAGE_PROTECTION
);
550 if ((AllocationType
& (MEM_COMMIT
| MEM_RESERVE
)) == 0)
552 return(STATUS_INVALID_PARAMETER
);
555 PBaseAddress
= *UBaseAddress
;
556 PRegionSize
= *URegionSize
;
557 BoundaryAddressMultiple
.QuadPart
= 0;
559 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(PBaseAddress
);
560 RegionSize
= PAGE_ROUND_UP(PBaseAddress
+ PRegionSize
) -
561 PAGE_ROUND_DOWN(PBaseAddress
);
563 Status
= ObReferenceObjectByHandle(ProcessHandle
,
564 PROCESS_VM_OPERATION
,
569 if (!NT_SUCCESS(Status
))
571 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
575 Type
= (AllocationType
& MEM_COMMIT
) ? MEM_COMMIT
: MEM_RESERVE
;
576 DPRINT("Type %x\n", Type
);
578 AddressSpace
= &Process
->AddressSpace
;
579 MmLockAddressSpace(AddressSpace
);
581 if (PBaseAddress
!= 0)
583 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
586 if (MemoryArea
!= NULL
)
588 MemoryAreaLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
589 (ULONG_PTR
)MemoryArea
->StartingAddress
;
590 if (MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
&&
591 MemoryAreaLength
>= RegionSize
)
594 MmAlterRegion(AddressSpace
,
595 MemoryArea
->StartingAddress
,
596 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
597 BaseAddress
, RegionSize
,
598 Type
, Protect
, MmModifyAttributes
);
599 MmUnlockAddressSpace(AddressSpace
);
600 ObDereferenceObject(Process
);
601 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
604 else if (MemoryAreaLength
>= RegionSize
)
607 MmAlterRegion(AddressSpace
,
608 MemoryArea
->StartingAddress
,
609 &MemoryArea
->Data
.SectionData
.RegionListHead
,
610 BaseAddress
, RegionSize
,
611 Type
, Protect
, MmModifyAttributes
);
612 MmUnlockAddressSpace(AddressSpace
);
613 ObDereferenceObject(Process
);
614 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
619 MmUnlockAddressSpace(AddressSpace
);
620 ObDereferenceObject(Process
);
621 return(STATUS_UNSUCCESSFUL
);
626 Status
= MmCreateMemoryArea(Process
,
628 MEMORY_AREA_VIRTUAL_MEMORY
,
634 (AllocationType
& MEM_TOP_DOWN
) == MEM_TOP_DOWN
,
635 BoundaryAddressMultiple
);
636 if (!NT_SUCCESS(Status
))
638 MmUnlockAddressSpace(AddressSpace
);
639 ObDereferenceObject(Process
);
640 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
644 MemoryAreaLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
645 (ULONG_PTR
)MemoryArea
->StartingAddress
;
647 MmInitialiseRegion(&MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
648 MemoryAreaLength
, Type
, Protect
);
650 if ((AllocationType
& MEM_COMMIT
) &&
651 ((Protect
& PAGE_READWRITE
) ||
652 (Protect
& PAGE_EXECUTE_READWRITE
)))
654 MmReserveSwapPages(MemoryAreaLength
);
657 *UBaseAddress
= BaseAddress
;
658 *URegionSize
= MemoryAreaLength
;
659 DPRINT("*UBaseAddress %x *URegionSize %x\n", BaseAddress
, RegionSize
);
661 MmUnlockAddressSpace(AddressSpace
);
662 ObDereferenceObject(Process
);
663 return(STATUS_SUCCESS
);
667 MmFreeVirtualMemoryPage(PVOID Context
,
668 MEMORY_AREA
* MemoryArea
,
674 PEPROCESS Process
= (PEPROCESS
)Context
;
678 SWAPENTRY SavedSwapEntry
;
679 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
680 if (SavedSwapEntry
!= 0)
682 MmFreeSwapPage(SavedSwapEntry
);
683 MmSetSavedSwapEntryPage(Page
, 0);
685 MmDeleteRmap(Page
, Process
, Address
);
686 MmReleasePageMemoryConsumer(MC_USER
, Page
);
688 else if (SwapEntry
!= 0)
690 MmFreeSwapPage(SwapEntry
);
695 MmFreeVirtualMemory(PEPROCESS Process
,
696 PMEMORY_AREA MemoryArea
)
698 PLIST_ENTRY current_entry
;
702 DPRINT("MmFreeVirtualMemory(Process %p MemoryArea %p)\n", Process
,
705 /* Mark this memory area as about to be deleted. */
706 MemoryArea
->DeleteInProgress
= TRUE
;
709 * Wait for any ongoing paging operations. Notice that since we have
710 * flagged this memory area as deleted no more page ops will be added.
712 if (MemoryArea
->PageOpCount
> 0)
714 ULONG_PTR MemoryAreaLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
715 (ULONG_PTR
)MemoryArea
->StartingAddress
;
717 /* FiN TODO: Optimize loop counter! */
718 for (i
= 0; i
< PAGE_ROUND_UP(MemoryAreaLength
) / PAGE_SIZE
; i
++)
722 if (MemoryArea
->PageOpCount
== 0)
727 PageOp
= MmCheckForPageOp(MemoryArea
, Process
->UniqueProcessId
,
728 (PVOID
)((ULONG_PTR
)MemoryArea
->StartingAddress
+ (i
* PAGE_SIZE
)),
733 MmUnlockAddressSpace(&Process
->AddressSpace
);
734 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
739 if (Status
!= STATUS_SUCCESS
)
741 DPRINT1("Failed to wait for page op\n");
744 MmLockAddressSpace(&Process
->AddressSpace
);
745 MmReleasePageOp(PageOp
);
750 /* Free all the individual segments. */
751 current_entry
= MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
.Flink
;
752 while (current_entry
!= &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
)
754 current
= CONTAINING_RECORD(current_entry
, MM_REGION
, RegionListEntry
);
755 current_entry
= current_entry
->Flink
;
759 /* Actually free the memory area. */
760 MmFreeMemoryArea(&Process
->AddressSpace
,
762 MmFreeVirtualMemoryPage
,
770 NtFreeVirtualMemory(IN HANDLE ProcessHandle
,
771 IN PVOID
* PBaseAddress
,
772 IN PULONG PRegionSize
,
775 * FUNCTION: Frees a range of virtual memory
777 * ProcessHandle = Points to the process that allocated the virtual
779 * BaseAddress = Points to the memory address, rounded down to a
780 * multiple of the pagesize
781 * RegionSize = Limits the range to free, rounded up to a multiple of
783 * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
787 MEMORY_AREA
* MemoryArea
;
790 PMADDRESS_SPACE AddressSpace
;
794 DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *PBaseAddress %x, "
795 "*PRegionSize %x, FreeType %x)\n",ProcessHandle
,*PBaseAddress
,
796 *PRegionSize
,FreeType
);
798 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN((*PBaseAddress
));
799 RegionSize
= PAGE_ROUND_UP((*PBaseAddress
) + (*PRegionSize
)) -
800 PAGE_ROUND_DOWN((*PBaseAddress
));
802 Status
= ObReferenceObjectByHandle(ProcessHandle
,
803 PROCESS_VM_OPERATION
,
808 if (!NT_SUCCESS(Status
))
813 AddressSpace
= &Process
->AddressSpace
;
815 MmLockAddressSpace(AddressSpace
);
816 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
818 if (MemoryArea
== NULL
)
820 MmUnlockAddressSpace(AddressSpace
);
821 ObDereferenceObject(Process
);
822 return(STATUS_UNSUCCESSFUL
);
828 /* We can only free a memory area in one step. */
829 if (MemoryArea
->StartingAddress
!= BaseAddress
||
830 MemoryArea
->Type
!= MEMORY_AREA_VIRTUAL_MEMORY
)
832 MmUnlockAddressSpace(AddressSpace
);
833 ObDereferenceObject(Process
);
834 return(STATUS_UNSUCCESSFUL
);
836 MmFreeVirtualMemory(Process
, MemoryArea
);
837 MmUnlockAddressSpace(AddressSpace
);
838 ObDereferenceObject(Process
);
839 return(STATUS_SUCCESS
);
843 MmAlterRegion(AddressSpace
,
844 MemoryArea
->StartingAddress
,
845 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
851 MmUnlockAddressSpace(AddressSpace
);
852 ObDereferenceObject(Process
);
855 MmUnlockAddressSpace(AddressSpace
);
856 ObDereferenceObject(Process
);
857 return(STATUS_NOT_IMPLEMENTED
);
861 MmProtectAnonMem(PMADDRESS_SPACE AddressSpace
,
862 PMEMORY_AREA MemoryArea
,
871 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
872 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
874 *OldProtect
= Region
->Protect
;
875 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
876 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
877 BaseAddress
, Length
, Region
->Type
, Protect
,
883 MmQueryAnonMem(PMEMORY_AREA MemoryArea
,
885 PMEMORY_BASIC_INFORMATION Info
,
891 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
893 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
894 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
895 Address
, &RegionBase
);
896 Info
->BaseAddress
= RegionBase
;
897 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
898 Info
->AllocationProtect
= MemoryArea
->Attributes
;
899 Info
->RegionSize
= (char*)RegionBase
+ Region
->Length
- (char*)Info
->BaseAddress
;
900 Info
->State
= Region
->Type
;
901 Info
->Protect
= Region
->Protect
;
902 Info
->Type
= MEM_PRIVATE
;
904 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
905 return(STATUS_SUCCESS
);