2 * Copyright (C) 2002-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/anonmem.c
21 * PURPOSE: Implementing anonymous memory.
23 * PROGRAMMERS: David Welch
32 * Gunnar Andre' Dalsnes
34 * Thomas Weidenmueller
40 /* INCLUDE *****************************************************************/
44 #include <internal/debug.h>
46 /* FUNCTIONS *****************************************************************/
50 MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace
,
51 PMEMORY_AREA MemoryArea
,
60 * Check for paging out from a deleted virtual memory area.
62 if (MemoryArea
->DeleteInProgress
)
64 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
65 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
66 MmReleasePageOp(PageOp
);
67 return(STATUS_UNSUCCESSFUL
);
70 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
73 * Get that the page actually is dirty.
75 if (!MmIsDirtyPage(AddressSpace
->Process
, Address
))
77 PageOp
->Status
= STATUS_SUCCESS
;
78 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
79 MmReleasePageOp(PageOp
);
80 return(STATUS_SUCCESS
);
84 * Speculatively set the mapping to clean.
86 MmSetCleanPage(AddressSpace
->Process
, Address
);
89 * If necessary, allocate an entry in the paging file for this page
91 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
94 SwapEntry
= MmAllocSwapPage();
97 MmSetDirtyPage(AddressSpace
->Process
, Address
);
98 PageOp
->Status
= STATUS_PAGEFILE_QUOTA_EXCEEDED
;
99 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
100 MmReleasePageOp(PageOp
);
101 return(STATUS_PAGEFILE_QUOTA_EXCEEDED
);
106 * Write the page to the pagefile
108 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
109 if (!NT_SUCCESS(Status
))
111 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
113 MmSetDirtyPage(AddressSpace
->Process
, Address
);
114 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
115 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
116 MmReleasePageOp(PageOp
);
117 return(STATUS_UNSUCCESSFUL
);
121 * Otherwise we have succeeded.
123 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
124 PageOp
->Status
= STATUS_SUCCESS
;
125 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
126 MmReleasePageOp(PageOp
);
127 return(STATUS_SUCCESS
);
132 MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace
,
133 PMEMORY_AREA MemoryArea
,
142 DPRINT("MmPageOutVirtualMemory(Address 0x%.8X) PID %d\n",
143 Address
, AddressSpace
->Process
->UniqueProcessId
);
146 * Check for paging out from a deleted virtual memory area.
148 if (MemoryArea
->DeleteInProgress
)
150 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
151 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
152 MmReleasePageOp(PageOp
);
153 return(STATUS_UNSUCCESSFUL
);
157 * Disable the virtual mapping.
159 MmDisableVirtualMapping(AddressSpace
->Process
, Address
,
168 * Paging out non-dirty data is easy.
172 MmLockAddressSpace(AddressSpace
);
173 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
174 MmDeleteAllRmaps(Page
, NULL
, NULL
);
175 if ((SwapEntry
= MmGetSavedSwapEntryPage(Page
)) != 0)
177 MmCreatePageFileMapping(AddressSpace
->Process
, Address
, SwapEntry
);
178 MmSetSavedSwapEntryPage(Page
, 0);
180 MmUnlockAddressSpace(AddressSpace
);
181 MmReleasePageMemoryConsumer(MC_USER
, Page
);
182 PageOp
->Status
= STATUS_SUCCESS
;
183 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
184 MmReleasePageOp(PageOp
);
185 return(STATUS_SUCCESS
);
189 * If necessary, allocate an entry in the paging file for this page
191 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
194 SwapEntry
= MmAllocSwapPage();
197 MmShowOutOfSpaceMessagePagingFile();
198 MmEnableVirtualMapping(AddressSpace
->Process
, Address
);
199 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
200 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
201 MmReleasePageOp(PageOp
);
202 return(STATUS_PAGEFILE_QUOTA
);
207 * Write the page to the pagefile
209 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
210 if (!NT_SUCCESS(Status
))
212 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
214 MmEnableVirtualMapping(AddressSpace
->Process
, Address
);
215 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
216 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
217 MmReleasePageOp(PageOp
);
218 return(STATUS_UNSUCCESSFUL
);
222 * Otherwise we have succeeded, free the page
224 DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", Page
<< PAGE_SHIFT
);
225 MmLockAddressSpace(AddressSpace
);
226 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
227 MmCreatePageFileMapping(AddressSpace
->Process
, Address
, SwapEntry
);
228 MmUnlockAddressSpace(AddressSpace
);
229 MmDeleteAllRmaps(Page
, NULL
, NULL
);
230 MmSetSavedSwapEntryPage(Page
, 0);
231 MmReleasePageMemoryConsumer(MC_USER
, Page
);
232 PageOp
->Status
= STATUS_SUCCESS
;
233 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
234 MmReleasePageOp(PageOp
);
235 return(STATUS_SUCCESS
);
240 MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace
,
241 MEMORY_AREA
* MemoryArea
,
245 * FUNCTION: Move data into memory to satisfy a page not present fault
247 * AddressSpace = Address space within which the fault occurred
248 * MemoryArea = The memory area within which the fault occurred
249 * Address = The absolute address of fault
251 * NOTES: This function is called with the address space lock held.
260 * There is a window between taking the page fault and locking the
261 * address space when another thread could load the page so we check
264 if (MmIsPagePresent(NULL
, Address
))
268 MmLockPage(MmGetPfnForProcess(NULL
, Address
));
270 return(STATUS_SUCCESS
);
274 * Check for the virtual memory area being deleted.
276 if (MemoryArea
->DeleteInProgress
)
278 return(STATUS_UNSUCCESSFUL
);
282 * Get the segment corresponding to the virtual address
284 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
285 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
287 if (Region
->Type
== MEM_RESERVE
|| Region
->Protect
== PAGE_NOACCESS
)
289 return(STATUS_ACCESS_VIOLATION
);
293 * Get or create a page operation
295 PageOp
= MmGetPageOp(MemoryArea
, AddressSpace
->Process
->UniqueProcessId
,
296 (PVOID
)PAGE_ROUND_DOWN(Address
), NULL
, 0,
297 MM_PAGEOP_PAGEIN
, FALSE
);
300 DPRINT1("MmGetPageOp failed");
305 * Check if someone else is already handling this fault, if so wait
308 if (PageOp
->Thread
!= PsGetCurrentThread())
310 MmUnlockAddressSpace(AddressSpace
);
311 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
317 * Check for various strange conditions
319 if (Status
!= STATUS_SUCCESS
)
321 DPRINT1("Failed to wait for page op\n");
324 if (PageOp
->Status
== STATUS_PENDING
)
326 DPRINT1("Woke for page op before completion\n");
330 * If this wasn't a pagein then we need to restart the handling
332 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
334 MmLockAddressSpace(AddressSpace
);
335 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
336 MmReleasePageOp(PageOp
);
337 return(STATUS_MM_RESTART_OPERATION
);
340 * If the thread handling this fault has failed then we don't retry
342 if (!NT_SUCCESS(PageOp
->Status
))
344 MmLockAddressSpace(AddressSpace
);
345 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
346 Status
= PageOp
->Status
;
347 MmReleasePageOp(PageOp
);
350 MmLockAddressSpace(AddressSpace
);
353 MmLockPage(MmGetPfnForProcess(NULL
, Address
));
355 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
356 MmReleasePageOp(PageOp
);
357 return(STATUS_SUCCESS
);
361 * Try to allocate a page
363 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
364 if (Status
== STATUS_NO_MEMORY
)
366 MmUnlockAddressSpace(AddressSpace
);
367 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
368 MmLockAddressSpace(AddressSpace
);
370 if (!NT_SUCCESS(Status
))
372 DPRINT1("MmRequestPageMemoryConsumer failed, status = %x\n", Status
);
377 * Handle swapped out pages.
379 if (MmIsPageSwapEntry(NULL
, Address
))
383 MmDeletePageFileMapping(AddressSpace
->Process
, Address
, &SwapEntry
);
384 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
385 if (!NT_SUCCESS(Status
))
389 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
393 * Set the page. If we fail because we are out of memory then
396 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
397 (PVOID
)PAGE_ROUND_DOWN(Address
),
401 while (Status
== STATUS_NO_MEMORY
)
403 MmUnlockAddressSpace(AddressSpace
);
404 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
409 MmLockAddressSpace(AddressSpace
);
411 if (!NT_SUCCESS(Status
))
413 DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
419 * Add the page to the process's working set
421 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAGE_ROUND_DOWN(Address
));
424 * Finish the operation
430 PageOp
->Status
= STATUS_SUCCESS
;
431 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
432 MmReleasePageOp(PageOp
);
433 return(STATUS_SUCCESS
);
437 MmModifyAttributes(PMADDRESS_SPACE AddressSpace
,
445 * FUNCTION: Modify the attributes of a memory region
449 * If we are switching a previously committed region to reserved then
450 * free any allocated pages within the region
452 if (NewType
== MEM_RESERVE
&& OldType
== MEM_COMMIT
)
456 for (i
=0; i
< PAGE_ROUND_UP(RegionSize
)/PAGE_SIZE
; i
++)
460 if (MmIsPageSwapEntry(AddressSpace
->Process
,
461 (char*)BaseAddress
+ (i
* PAGE_SIZE
)))
465 MmDeletePageFileMapping(AddressSpace
->Process
,
466 (char*)BaseAddress
+ (i
* PAGE_SIZE
),
468 MmFreeSwapPage(SwapEntry
);
472 MmDeleteVirtualMapping(AddressSpace
->Process
,
473 (char*)BaseAddress
+ (i
*PAGE_SIZE
),
477 SWAPENTRY SavedSwapEntry
;
478 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
479 if (SavedSwapEntry
!= 0)
481 MmFreeSwapPage(SavedSwapEntry
);
482 MmSetSavedSwapEntryPage(Page
, 0);
484 MmDeleteRmap(Page
, AddressSpace
->Process
,
485 (char*)BaseAddress
+ (i
* PAGE_SIZE
));
486 MmReleasePageMemoryConsumer(MC_USER
, Page
);
493 * If we are changing the protection attributes of a committed region then
494 * alter the attributes for any allocated pages within the region
496 if (NewType
== MEM_COMMIT
&& OldType
== MEM_COMMIT
&&
497 OldProtect
!= NewProtect
)
501 for (i
=0; i
< PAGE_ROUND_UP(RegionSize
)/PAGE_SIZE
; i
++)
503 if (MmIsPagePresent(AddressSpace
->Process
,
504 (char*)BaseAddress
+ (i
*PAGE_SIZE
)))
506 MmSetPageProtect(AddressSpace
->Process
,
507 (char*)BaseAddress
+ (i
*PAGE_SIZE
),
518 NtAllocateVirtualMemory(IN HANDLE ProcessHandle
,
519 IN OUT PVOID
* UBaseAddress
,
521 IN OUT PSIZE_T URegionSize
,
522 IN ULONG AllocationType
,
525 * FUNCTION: Allocates a block of virtual memory in the process address space
527 * ProcessHandle = The handle of the process which owns the virtual memory
528 * BaseAddress = A pointer to the virtual memory allocated. If you
529 * supply a non zero value the system will try to
530 * allocate the memory at the address supplied. It round
531 * it down to a multiple of the page size.
532 * ZeroBits = (OPTIONAL) You can specify the number of high order bits
533 * that must be zero, ensuring that the memory will be
534 * allocated at a address below a certain value.
535 * RegionSize = The number of bytes to allocate
536 * AllocationType = Indicates the type of virtual memory you like to
537 * allocated, can be a combination of MEM_COMMIT,
538 * MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN.
539 * Protect = Indicates the protection type of the pages allocated, can be
540 * a combination of PAGE_READONLY, PAGE_READWRITE,
541 * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD,
547 MEMORY_AREA
* MemoryArea
;
548 ULONG_PTR MemoryAreaLength
;
551 PMADDRESS_SPACE AddressSpace
;
556 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
557 KPROCESSOR_MODE PreviousMode
;
561 DPRINT("NtAllocateVirtualMemory(*UBaseAddress %x, "
562 "ZeroBits %d, *URegionSize %x, AllocationType %x, Protect %x)\n",
563 *UBaseAddress
,ZeroBits
,*URegionSize
,AllocationType
,
566 /* Check for valid protection flags */
567 if ((Protect
& PAGE_FLAGS_VALID_FROM_USER_MODE
) != Protect
)
569 DPRINT1("Invalid page protection\n");
570 return STATUS_INVALID_PAGE_PROTECTION
;
573 /* Check for valid Zero bits */
576 DPRINT1("Too many zero bits\n");
577 return STATUS_INVALID_PARAMETER_3
;
580 /* Check for valid Allocation Types */
581 if ((AllocationType
& ~(MEM_COMMIT
| MEM_RESERVE
| MEM_RESET
| MEM_PHYSICAL
|
582 MEM_TOP_DOWN
| MEM_WRITE_WATCH
)))
584 DPRINT1("Invalid Allocation Type\n");
585 return STATUS_INVALID_PARAMETER_5
;
588 /* Check for at least one of these Allocation Types to be set */
589 if (!(AllocationType
& (MEM_COMMIT
| MEM_RESERVE
| MEM_RESET
)))
591 DPRINT1("No memory allocation base type\n");
592 return STATUS_INVALID_PARAMETER_5
;
595 /* MEM_RESET is an exclusive flag, make sure that is valid too */
596 if ((AllocationType
& MEM_RESET
) && (AllocationType
!= MEM_RESET
))
598 DPRINT1("Invalid use of MEM_RESET\n");
599 return STATUS_INVALID_PARAMETER_5
;
602 /* MEM_WRITE_WATCH can only be used if MEM_RESERVE is also used */
603 if ((AllocationType
& MEM_WRITE_WATCH
) && !(AllocationType
& MEM_RESERVE
))
605 DPRINT1("MEM_WRITE_WATCH used without MEM_RESERVE\n");
606 return STATUS_INVALID_PARAMETER_5
;
609 /* MEM_PHYSICAL can only be used with MEM_RESERVE, and can only be R/W */
610 if (AllocationType
& MEM_PHYSICAL
)
612 /* First check for MEM_RESERVE exclusivity */
613 if (AllocationType
!= (MEM_RESERVE
| MEM_PHYSICAL
))
615 DPRINT1("MEM_PHYSICAL used with other flags then MEM_RESERVE or"
616 "MEM_RESERVE was not present at all\n");
617 return STATUS_INVALID_PARAMETER_5
;
620 /* Then make sure PAGE_READWRITE is used */
621 if (Protect
!= PAGE_READWRITE
)
623 DPRINT1("MEM_PHYSICAL used without PAGE_READWRITE\n");
624 return STATUS_INVALID_PAGE_PROTECTION
;
628 PreviousMode
= KeGetPreviousMode();
632 if (PreviousMode
!= KernelMode
)
634 ProbeForWritePointer(UBaseAddress
);
635 ProbeForWriteUlong(URegionSize
);
637 PBaseAddress
= *UBaseAddress
;
638 PRegionSize
= *URegionSize
;
642 /* Get the exception code */
643 Status
= _SEH_GetExceptionCode();
644 _SEH_YIELD(return Status
);
648 BoundaryAddressMultiple
.QuadPart
= 0;
650 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(PBaseAddress
);
651 RegionSize
= PAGE_ROUND_UP((ULONG_PTR
)PBaseAddress
+ PRegionSize
) -
652 PAGE_ROUND_DOWN(PBaseAddress
);
655 * We've captured and calculated the data, now do more checks
656 * Yes, MmCreateMemoryArea does similar checks, but they don't return
657 * the right status codes that a caller of this routine would expect.
659 if ((ULONG_PTR
)BaseAddress
>= USER_SHARED_DATA
)
661 DPRINT1("Virtual allocation base above User Space\n");
662 return STATUS_INVALID_PARAMETER_2
;
666 DPRINT1("Region size is invalid (zero)\n");
667 return STATUS_INVALID_PARAMETER_4
;
669 if ((USER_SHARED_DATA
- (ULONG_PTR
)BaseAddress
) < RegionSize
)
671 DPRINT1("Region size would overflow into kernel-memory\n");
672 return STATUS_INVALID_PARAMETER_4
;
676 * Copy on Write is reserved for system use. This case is a certain failure
677 * but there may be other cases...needs more testing
679 if ((!BaseAddress
|| (AllocationType
& MEM_RESERVE
)) &&
680 (Protect
& (PAGE_WRITECOPY
| PAGE_EXECUTE_WRITECOPY
)))
682 DPRINT1("Copy on write is not supported by VirtualAlloc\n");
683 return STATUS_INVALID_PAGE_PROTECTION
;
687 Status
= ObReferenceObjectByHandle(ProcessHandle
,
688 PROCESS_VM_OPERATION
,
693 if (!NT_SUCCESS(Status
))
695 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
699 Type
= (AllocationType
& MEM_COMMIT
) ? MEM_COMMIT
: MEM_RESERVE
;
700 DPRINT("Type %x\n", Type
);
702 AddressSpace
= (PMADDRESS_SPACE
)&Process
->VadRoot
;
703 MmLockAddressSpace(AddressSpace
);
705 if (PBaseAddress
!= 0)
707 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
709 if (MemoryArea
!= NULL
)
711 MemoryAreaLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
712 (ULONG_PTR
)MemoryArea
->StartingAddress
;
713 if (MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
&&
714 MemoryAreaLength
>= RegionSize
)
717 MmAlterRegion(AddressSpace
,
718 MemoryArea
->StartingAddress
,
719 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
720 BaseAddress
, RegionSize
,
721 Type
, Protect
, MmModifyAttributes
);
722 MmUnlockAddressSpace(AddressSpace
);
723 ObDereferenceObject(Process
);
724 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
727 else if (MemoryAreaLength
>= RegionSize
)
729 /* Region list initialized? */
730 if (MemoryArea
->Data
.SectionData
.RegionListHead
.Flink
)
733 MmAlterRegion(AddressSpace
,
734 MemoryArea
->StartingAddress
,
735 &MemoryArea
->Data
.SectionData
.RegionListHead
,
736 BaseAddress
, RegionSize
,
737 Type
, Protect
, MmModifyAttributes
);
741 Status
= STATUS_ACCESS_VIOLATION
;
744 MmUnlockAddressSpace(AddressSpace
);
745 ObDereferenceObject(Process
);
746 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
751 MmUnlockAddressSpace(AddressSpace
);
752 ObDereferenceObject(Process
);
753 return(STATUS_UNSUCCESSFUL
);
758 Status
= MmCreateMemoryArea(AddressSpace
,
759 MEMORY_AREA_VIRTUAL_MEMORY
,
765 AllocationType
& MEM_TOP_DOWN
,
766 BoundaryAddressMultiple
);
767 if (!NT_SUCCESS(Status
))
769 MmUnlockAddressSpace(AddressSpace
);
770 ObDereferenceObject(Process
);
771 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
775 MemoryAreaLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
776 (ULONG_PTR
)MemoryArea
->StartingAddress
;
778 MmInitializeRegion(&MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
779 MemoryAreaLength
, Type
, Protect
);
781 if ((AllocationType
& MEM_COMMIT
) &&
782 (Protect
& (PAGE_READWRITE
| PAGE_EXECUTE_READWRITE
)))
784 const ULONG nPages
= PAGE_ROUND_UP(MemoryAreaLength
) >> PAGE_SHIFT
;
785 MmReserveSwapPages(nPages
);
788 *UBaseAddress
= BaseAddress
;
789 *URegionSize
= MemoryAreaLength
;
790 DPRINT("*UBaseAddress %x *URegionSize %x\n", BaseAddress
, RegionSize
);
792 MmUnlockAddressSpace(AddressSpace
);
793 ObDereferenceObject(Process
);
794 return(STATUS_SUCCESS
);
798 MmFreeVirtualMemoryPage(PVOID Context
,
799 MEMORY_AREA
* MemoryArea
,
805 PEPROCESS Process
= (PEPROCESS
)Context
;
809 SWAPENTRY SavedSwapEntry
;
810 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
811 if (SavedSwapEntry
!= 0)
813 MmFreeSwapPage(SavedSwapEntry
);
814 MmSetSavedSwapEntryPage(Page
, 0);
816 MmDeleteRmap(Page
, Process
, Address
);
817 MmReleasePageMemoryConsumer(MC_USER
, Page
);
819 else if (SwapEntry
!= 0)
821 MmFreeSwapPage(SwapEntry
);
827 MmFreeVirtualMemory(PEPROCESS Process
,
828 PMEMORY_AREA MemoryArea
)
830 PLIST_ENTRY current_entry
;
834 DPRINT("MmFreeVirtualMemory(Process %p MemoryArea %p)\n", Process
,
837 /* Mark this memory area as about to be deleted. */
838 MemoryArea
->DeleteInProgress
= TRUE
;
841 * Wait for any ongoing paging operations. Notice that since we have
842 * flagged this memory area as deleted no more page ops will be added.
844 if (MemoryArea
->PageOpCount
> 0)
846 ULONG_PTR MemoryAreaLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
847 (ULONG_PTR
)MemoryArea
->StartingAddress
;
848 const ULONG nPages
= PAGE_ROUND_UP(MemoryAreaLength
) >> PAGE_SHIFT
;
850 for (i
= 0; i
< nPages
&& MemoryArea
->PageOpCount
!= 0; ++i
)
853 PageOp
= MmCheckForPageOp(MemoryArea
, Process
->UniqueProcessId
,
854 (PVOID
)((ULONG_PTR
)MemoryArea
->StartingAddress
+ (i
* PAGE_SIZE
)),
859 MmUnlockAddressSpace((PMADDRESS_SPACE
)&Process
->VadRoot
);
860 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
865 if (Status
!= STATUS_SUCCESS
)
867 DPRINT1("Failed to wait for page op\n");
870 MmLockAddressSpace((PMADDRESS_SPACE
)&Process
->VadRoot
);
871 MmReleasePageOp(PageOp
);
876 /* Free all the individual segments. */
877 current_entry
= MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
.Flink
;
878 while (current_entry
!= &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
)
880 current
= CONTAINING_RECORD(current_entry
, MM_REGION
, RegionListEntry
);
881 current_entry
= current_entry
->Flink
;
885 /* Actually free the memory area. */
886 MmFreeMemoryArea((PMADDRESS_SPACE
)&Process
->VadRoot
,
888 MmFreeVirtualMemoryPage
,
896 NtFreeVirtualMemory(IN HANDLE ProcessHandle
,
897 IN PVOID
* PBaseAddress
,
898 IN PSIZE_T PRegionSize
,
901 * FUNCTION: Frees a range of virtual memory
903 * ProcessHandle = Points to the process that allocated the virtual
905 * BaseAddress = Points to the memory address, rounded down to a
906 * multiple of the pagesize
907 * RegionSize = Limits the range to free, rounded up to a multiple of
909 * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
913 MEMORY_AREA
* MemoryArea
;
916 PMADDRESS_SPACE AddressSpace
;
920 DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *PBaseAddress %x, "
921 "*PRegionSize %x, FreeType %x)\n",ProcessHandle
,*PBaseAddress
,
922 *PRegionSize
,FreeType
);
924 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN((*PBaseAddress
));
925 RegionSize
= PAGE_ROUND_UP((ULONG_PTR
)(*PBaseAddress
) + (*PRegionSize
)) -
926 PAGE_ROUND_DOWN((*PBaseAddress
));
928 Status
= ObReferenceObjectByHandle(ProcessHandle
,
929 PROCESS_VM_OPERATION
,
934 if (!NT_SUCCESS(Status
))
939 AddressSpace
= (PMADDRESS_SPACE
)&Process
->VadRoot
;
941 MmLockAddressSpace(AddressSpace
);
942 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
943 if (MemoryArea
== NULL
)
945 Status
= STATUS_UNSUCCESSFUL
;
946 goto unlock_deref_and_return
;
952 /* We can only free a memory area in one step. */
953 if (MemoryArea
->StartingAddress
!= BaseAddress
||
954 MemoryArea
->Type
!= MEMORY_AREA_VIRTUAL_MEMORY
)
956 Status
= STATUS_UNSUCCESSFUL
;
957 goto unlock_deref_and_return
;
960 MmFreeVirtualMemory(Process
, MemoryArea
);
961 Status
= STATUS_SUCCESS
;
962 goto unlock_deref_and_return
;
966 MmAlterRegion(AddressSpace
,
967 MemoryArea
->StartingAddress
,
968 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
974 goto unlock_deref_and_return
;
977 Status
= STATUS_NOT_IMPLEMENTED
;
979 unlock_deref_and_return
:
981 MmUnlockAddressSpace(AddressSpace
);
982 ObDereferenceObject(Process
);
989 MmProtectAnonMem(PMADDRESS_SPACE AddressSpace
,
990 PMEMORY_AREA MemoryArea
,
999 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1000 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
1002 *OldProtect
= Region
->Protect
;
1003 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
1004 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
1005 BaseAddress
, Length
, Region
->Type
, Protect
,
1006 MmModifyAttributes
);
1011 MmQueryAnonMem(PMEMORY_AREA MemoryArea
,
1013 PMEMORY_BASIC_INFORMATION Info
,
1014 PULONG ResultLength
)
1017 PVOID RegionBase
= NULL
;
1019 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1021 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1022 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
1023 Address
, &RegionBase
);
1024 Info
->BaseAddress
= RegionBase
;
1025 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
1026 Info
->AllocationProtect
= MemoryArea
->Protect
;
1027 Info
->RegionSize
= Region
->Length
;
1028 Info
->State
= Region
->Type
;
1029 Info
->Protect
= Region
->Protect
;
1030 Info
->Type
= MEM_PRIVATE
;
1032 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
1033 return(STATUS_SUCCESS
);