3 * Copyright (C) 2002-2005 ReactOS Team (and the authors from the programmers section)
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/mm/anonmem.c
22 * PURPOSE: Implementing anonymous memory.
24 * PROGRAMMERS: David Welch
34 * Gunnar Andre' Dalsnes
36 * Thomas Weidenmueller
42 /* INCLUDE *****************************************************************/
46 #include <internal/debug.h>
48 /* FUNCTIONS *****************************************************************/
51 MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace
,
52 PMEMORY_AREA MemoryArea
,
61 * Check for paging out from a deleted virtual memory area.
63 if (MemoryArea
->DeleteInProgress
)
65 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
66 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
67 MmReleasePageOp(PageOp
);
68 return(STATUS_UNSUCCESSFUL
);
71 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
74 * Get that the page actually is dirty.
76 if (!MmIsDirtyPage(AddressSpace
->Process
, Address
))
78 PageOp
->Status
= STATUS_SUCCESS
;
79 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
80 MmReleasePageOp(PageOp
);
81 return(STATUS_SUCCESS
);
85 * Speculatively set the mapping to clean.
87 MmSetCleanPage(AddressSpace
->Process
, Address
);
90 * If necessary, allocate an entry in the paging file for this page
92 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
95 SwapEntry
= MmAllocSwapPage();
98 MmSetDirtyPage(AddressSpace
->Process
, Address
);
99 PageOp
->Status
= STATUS_PAGEFILE_QUOTA_EXCEEDED
;
100 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
101 MmReleasePageOp(PageOp
);
102 return(STATUS_PAGEFILE_QUOTA_EXCEEDED
);
107 * Write the page to the pagefile
109 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
110 if (!NT_SUCCESS(Status
))
112 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
114 MmSetDirtyPage(AddressSpace
->Process
, Address
);
115 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
116 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
117 MmReleasePageOp(PageOp
);
118 return(STATUS_UNSUCCESSFUL
);
122 * Otherwise we have succeeded.
124 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
125 PageOp
->Status
= STATUS_SUCCESS
;
126 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
127 MmReleasePageOp(PageOp
);
128 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 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
173 MmDeleteAllRmaps(Page
, NULL
, NULL
);
174 if ((SwapEntry
= MmGetSavedSwapEntryPage(Page
)) != 0)
176 MmCreatePageFileMapping(AddressSpace
->Process
, Address
, SwapEntry
);
177 MmSetSavedSwapEntryPage(Page
, 0);
179 MmReleasePageMemoryConsumer(MC_USER
, Page
);
180 PageOp
->Status
= STATUS_SUCCESS
;
181 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
182 MmReleasePageOp(PageOp
);
183 return(STATUS_SUCCESS
);
187 * If necessary, allocate an entry in the paging file for this page
189 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
192 SwapEntry
= MmAllocSwapPage();
195 MmShowOutOfSpaceMessagePagingFile();
196 MmEnableVirtualMapping(AddressSpace
->Process
, Address
);
197 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
198 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
199 MmReleasePageOp(PageOp
);
200 return(STATUS_PAGEFILE_QUOTA
);
205 * Write the page to the pagefile
207 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
208 if (!NT_SUCCESS(Status
))
210 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
212 MmEnableVirtualMapping(AddressSpace
->Process
, Address
);
213 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
214 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
215 MmReleasePageOp(PageOp
);
216 return(STATUS_UNSUCCESSFUL
);
220 * Otherwise we have succeeded, free the page
222 DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", Page
<< PAGE_SHIFT
);
223 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
224 MmCreatePageFileMapping(AddressSpace
->Process
, Address
, SwapEntry
);
225 MmDeleteAllRmaps(Page
, NULL
, NULL
);
226 MmSetSavedSwapEntryPage(Page
, 0);
227 MmReleasePageMemoryConsumer(MC_USER
, Page
);
228 PageOp
->Status
= STATUS_SUCCESS
;
229 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
230 MmReleasePageOp(PageOp
);
231 return(STATUS_SUCCESS
);
235 MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace
,
236 MEMORY_AREA
* MemoryArea
,
240 * FUNCTION: Move data into memory to satisfy a page not present fault
242 * AddressSpace = Address space within which the fault occurred
243 * MemoryArea = The memory area within which the fault occurred
244 * Address = The absolute address of fault
246 * NOTES: This function is called with the address space lock held.
255 * There is a window between taking the page fault and locking the
256 * address space when another thread could load the page so we check
259 if (MmIsPagePresent(NULL
, Address
))
263 MmLockPage(MmGetPfnForProcess(NULL
, Address
));
265 return(STATUS_SUCCESS
);
269 * Check for the virtual memory area being deleted.
271 if (MemoryArea
->DeleteInProgress
)
273 return(STATUS_UNSUCCESSFUL
);
277 * Get the segment corresponding to the virtual address
279 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
280 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
282 if (Region
->Type
== MEM_RESERVE
|| Region
->Protect
== PAGE_NOACCESS
)
284 return(STATUS_ACCESS_VIOLATION
);
288 * Get or create a page operation
290 PageOp
= MmGetPageOp(MemoryArea
, AddressSpace
->Process
->UniqueProcessId
,
291 (PVOID
)PAGE_ROUND_DOWN(Address
), NULL
, 0,
292 MM_PAGEOP_PAGEIN
, FALSE
);
295 DPRINT1("MmGetPageOp failed");
300 * Check if someone else is already handling this fault, if so wait
303 if (PageOp
->Thread
!= PsGetCurrentThread())
305 MmUnlockAddressSpace(AddressSpace
);
306 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
312 * Check for various strange conditions
314 if (Status
!= STATUS_SUCCESS
)
316 DPRINT1("Failed to wait for page op\n");
319 if (PageOp
->Status
== STATUS_PENDING
)
321 DPRINT1("Woke for page op before completion\n");
325 * If this wasn't a pagein then we need to restart the handling
327 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
329 MmLockAddressSpace(AddressSpace
);
330 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
331 MmReleasePageOp(PageOp
);
332 return(STATUS_MM_RESTART_OPERATION
);
335 * If the thread handling this fault has failed then we don't retry
337 if (!NT_SUCCESS(PageOp
->Status
))
339 MmLockAddressSpace(AddressSpace
);
340 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
341 Status
= PageOp
->Status
;
342 MmReleasePageOp(PageOp
);
345 MmLockAddressSpace(AddressSpace
);
348 MmLockPage(MmGetPfnForProcess(NULL
, Address
));
350 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
351 MmReleasePageOp(PageOp
);
352 return(STATUS_SUCCESS
);
356 * Try to allocate a page
358 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
359 if (Status
== STATUS_NO_MEMORY
)
361 MmUnlockAddressSpace(AddressSpace
);
362 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
363 MmLockAddressSpace(AddressSpace
);
365 if (!NT_SUCCESS(Status
))
367 DPRINT1("MmRequestPageMemoryConsumer failed, status = %x\n", Status
);
372 * Handle swapped out pages.
374 if (MmIsPageSwapEntry(NULL
, Address
))
378 MmDeletePageFileMapping(AddressSpace
->Process
, Address
, &SwapEntry
);
379 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
380 if (!NT_SUCCESS(Status
))
384 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
388 * Set the page. If we fail because we are out of memory then
391 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
392 (PVOID
)PAGE_ROUND_DOWN(Address
),
396 while (Status
== STATUS_NO_MEMORY
)
398 MmUnlockAddressSpace(AddressSpace
);
399 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
404 MmLockAddressSpace(AddressSpace
);
406 if (!NT_SUCCESS(Status
))
408 DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
414 * Add the page to the process's working set
416 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAGE_ROUND_DOWN(Address
));
419 * Finish the operation
425 PageOp
->Status
= STATUS_SUCCESS
;
426 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
427 MmReleasePageOp(PageOp
);
428 return(STATUS_SUCCESS
);
432 MmModifyAttributes(PMADDRESS_SPACE AddressSpace
,
440 * FUNCTION: Modify the attributes of a memory region
444 * If we are switching a previously committed region to reserved then
445 * free any allocated pages within the region
447 if (NewType
== MEM_RESERVE
&& OldType
== MEM_COMMIT
)
451 for (i
=0; i
< PAGE_ROUND_UP(RegionSize
)/PAGE_SIZE
; i
++)
455 if (MmIsPageSwapEntry(AddressSpace
->Process
,
456 (char*)BaseAddress
+ (i
* PAGE_SIZE
)))
460 MmDeletePageFileMapping(AddressSpace
->Process
,
461 (char*)BaseAddress
+ (i
* PAGE_SIZE
),
463 MmFreeSwapPage(SwapEntry
);
467 MmDeleteVirtualMapping(AddressSpace
->Process
,
468 (char*)BaseAddress
+ (i
*PAGE_SIZE
),
472 SWAPENTRY SavedSwapEntry
;
473 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
474 if (SavedSwapEntry
!= 0)
476 MmFreeSwapPage(SavedSwapEntry
);
477 MmSetSavedSwapEntryPage(Page
, 0);
479 MmDeleteRmap(Page
, AddressSpace
->Process
,
480 (char*)BaseAddress
+ (i
* PAGE_SIZE
));
481 MmReleasePageMemoryConsumer(MC_USER
, Page
);
488 * If we are changing the protection attributes of a committed region then
489 * alter the attributes for any allocated pages within the region
491 if (NewType
== MEM_COMMIT
&& OldType
== MEM_COMMIT
&&
492 OldProtect
!= NewProtect
)
496 for (i
=0; i
< PAGE_ROUND_UP(RegionSize
)/PAGE_SIZE
; i
++)
498 if (MmIsPagePresent(AddressSpace
->Process
,
499 (char*)BaseAddress
+ (i
*PAGE_SIZE
)))
501 MmSetPageProtect(AddressSpace
->Process
,
502 (char*)BaseAddress
+ (i
*PAGE_SIZE
),
513 NtAllocateVirtualMemory(IN HANDLE ProcessHandle
,
514 IN OUT PVOID
* UBaseAddress
,
516 IN OUT PULONG URegionSize
,
517 IN ULONG AllocationType
,
520 * FUNCTION: Allocates a block of virtual memory in the process address space
522 * ProcessHandle = The handle of the process which owns the virtual memory
523 * BaseAddress = A pointer to the virtual memory allocated. If you
524 * supply a non zero value the system will try to
525 * allocate the memory at the address supplied. It round
526 * it down to a multiple of the page size.
527 * ZeroBits = (OPTIONAL) You can specify the number of high order bits
528 * that must be zero, ensuring that the memory will be
529 * allocated at a address below a certain value.
530 * RegionSize = The number of bytes to allocate
531 * AllocationType = Indicates the type of virtual memory you like to
532 * allocated, can be a combination of MEM_COMMIT,
533 * MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN.
534 * Protect = Indicates the protection type of the pages allocated, can be
535 * a combination of PAGE_READONLY, PAGE_READWRITE,
536 * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD,
542 MEMORY_AREA
* MemoryArea
;
543 ULONG_PTR MemoryAreaLength
;
546 PMADDRESS_SPACE AddressSpace
;
551 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
553 DPRINT("NtAllocateVirtualMemory(*UBaseAddress %x, "
554 "ZeroBits %d, *URegionSize %x, AllocationType %x, Protect %x)\n",
555 *UBaseAddress
,ZeroBits
,*URegionSize
,AllocationType
,
558 /* Check for valid protection flags */
559 if ((Protect
& PAGE_FLAGS_VALID_FROM_USER_MODE
) != Protect
)
561 DPRINT1("Invalid page protection\n");
562 return STATUS_INVALID_PAGE_PROTECTION
;
565 /* Check for valid Allocation Types */
566 if ((AllocationType
&~ (MEM_COMMIT
| MEM_RESERVE
| MEM_RESET
| MEM_PHYSICAL
|
567 MEM_TOP_DOWN
| MEM_WRITE_WATCH
)))
569 DPRINT1("Invalid Allocation Type\n");
570 return STATUS_INVALID_PARAMETER_5
;
573 /* Check for at least one of these Allocation Types to be set */
574 if (!(AllocationType
& (MEM_COMMIT
| MEM_RESERVE
| MEM_RESET
)))
576 DPRINT1("No memory allocation base type\n");
577 return STATUS_INVALID_PARAMETER_5
;
580 /* MEM_RESET is an exclusive flag, make sure that is valid too */
581 if ((AllocationType
& MEM_RESET
) && (AllocationType
!= MEM_RESET
))
583 DPRINT1("MEM_RESET used illegaly\n");
584 return STATUS_INVALID_PARAMETER_5
;
587 /* MEM_WRITE_WATCH can only be used if MEM_RESERVE is also used */
588 if ((AllocationType
& MEM_WRITE_WATCH
) && !(AllocationType
& MEM_RESERVE
))
590 DPRINT1("MEM_WRITE_WATCH used without MEM_RESERVE\n");
591 return STATUS_INVALID_PARAMETER_5
;
594 /* MEM_PHYSICAL can only be used with MEM_RESERVE, and can only be R/W */
595 if (AllocationType
& MEM_PHYSICAL
)
597 /* First check for MEM_RESERVE exclusivity */
598 if (AllocationType
!= (MEM_RESERVE
| MEM_PHYSICAL
))
600 DPRINT1("MEM_PHYSICAL used with other flags then MEM_RESERVE or"
601 "MEM_RESERVE was not present at all\n");
602 return STATUS_INVALID_PARAMETER_5
;
605 /* Then make sure PAGE_READWRITE is used */
606 if (Protect
!= PAGE_READWRITE
)
608 DPRINT1("MEM_PHYSICAL used without PAGE_READWRITE\n");
609 return STATUS_INVALID_PAGE_PROTECTION
;
613 PBaseAddress
= *UBaseAddress
;
614 PRegionSize
= *URegionSize
;
615 BoundaryAddressMultiple
.QuadPart
= 0;
617 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(PBaseAddress
);
618 RegionSize
= PAGE_ROUND_UP(PBaseAddress
+ PRegionSize
) -
619 PAGE_ROUND_DOWN(PBaseAddress
);
622 * We've captured and calculated the data, now do more checks
623 * Yes, MmCreateMemoryArea does similar checks, but they don't return
624 * the right status codes that a caller of this routine would expect.
626 if (BaseAddress
>= MM_HIGHEST_USER_ADDRESS
)
628 DPRINT1("Virtual allocation above User Space\n");
629 return STATUS_INVALID_PARAMETER_2
;
633 DPRINT1("Region size is invalid\n");
634 return STATUS_INVALID_PARAMETER_4
;
636 if (((ULONG_PTR
)MM_HIGHEST_USER_ADDRESS
- (ULONG_PTR
)BaseAddress
) < RegionSize
)
638 DPRINT1("Region size would overflow into kernel-memory\n");
639 return STATUS_INVALID_PARAMETER_4
;
642 Status
= ObReferenceObjectByHandle(ProcessHandle
,
643 PROCESS_VM_OPERATION
,
648 if (!NT_SUCCESS(Status
))
650 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
654 Type
= (AllocationType
& MEM_COMMIT
) ? MEM_COMMIT
: MEM_RESERVE
;
655 DPRINT("Type %x\n", Type
);
657 AddressSpace
= &Process
->AddressSpace
;
658 MmLockAddressSpace(AddressSpace
);
660 if (PBaseAddress
!= 0)
662 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
664 if (MemoryArea
!= NULL
)
666 MemoryAreaLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
667 (ULONG_PTR
)MemoryArea
->StartingAddress
;
668 if (MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
&&
669 MemoryAreaLength
>= RegionSize
)
672 MmAlterRegion(AddressSpace
,
673 MemoryArea
->StartingAddress
,
674 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
675 BaseAddress
, RegionSize
,
676 Type
, Protect
, MmModifyAttributes
);
677 MmUnlockAddressSpace(AddressSpace
);
678 ObDereferenceObject(Process
);
679 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
682 else if (MemoryAreaLength
>= RegionSize
)
685 MmAlterRegion(AddressSpace
,
686 MemoryArea
->StartingAddress
,
687 &MemoryArea
->Data
.SectionData
.RegionListHead
,
688 BaseAddress
, RegionSize
,
689 Type
, Protect
, MmModifyAttributes
);
690 MmUnlockAddressSpace(AddressSpace
);
691 ObDereferenceObject(Process
);
692 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
697 MmUnlockAddressSpace(AddressSpace
);
698 ObDereferenceObject(Process
);
699 return(STATUS_UNSUCCESSFUL
);
704 Status
= MmCreateMemoryArea(Process
,
706 MEMORY_AREA_VIRTUAL_MEMORY
,
712 (AllocationType
& MEM_TOP_DOWN
) == MEM_TOP_DOWN
,
713 BoundaryAddressMultiple
);
714 if (!NT_SUCCESS(Status
))
716 MmUnlockAddressSpace(AddressSpace
);
717 ObDereferenceObject(Process
);
718 DPRINT("NtAllocateVirtualMemory() = %x\n",Status
);
722 MemoryAreaLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
723 (ULONG_PTR
)MemoryArea
->StartingAddress
;
725 MmInitialiseRegion(&MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
726 MemoryAreaLength
, Type
, Protect
);
728 if ((AllocationType
& MEM_COMMIT
) &&
729 ((Protect
& PAGE_READWRITE
) ||
730 (Protect
& PAGE_EXECUTE_READWRITE
)))
732 MmReserveSwapPages(MemoryAreaLength
);
735 *UBaseAddress
= BaseAddress
;
736 *URegionSize
= MemoryAreaLength
;
737 DPRINT("*UBaseAddress %x *URegionSize %x\n", BaseAddress
, RegionSize
);
739 MmUnlockAddressSpace(AddressSpace
);
740 ObDereferenceObject(Process
);
741 return(STATUS_SUCCESS
);
745 MmFreeVirtualMemoryPage(PVOID Context
,
746 MEMORY_AREA
* MemoryArea
,
752 PEPROCESS Process
= (PEPROCESS
)Context
;
756 SWAPENTRY SavedSwapEntry
;
757 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
758 if (SavedSwapEntry
!= 0)
760 MmFreeSwapPage(SavedSwapEntry
);
761 MmSetSavedSwapEntryPage(Page
, 0);
763 MmDeleteRmap(Page
, Process
, Address
);
764 MmReleasePageMemoryConsumer(MC_USER
, Page
);
766 else if (SwapEntry
!= 0)
768 MmFreeSwapPage(SwapEntry
);
773 MmFreeVirtualMemory(PEPROCESS Process
,
774 PMEMORY_AREA MemoryArea
)
776 PLIST_ENTRY current_entry
;
780 DPRINT("MmFreeVirtualMemory(Process %p MemoryArea %p)\n", Process
,
783 /* Mark this memory area as about to be deleted. */
784 MemoryArea
->DeleteInProgress
= TRUE
;
787 * Wait for any ongoing paging operations. Notice that since we have
788 * flagged this memory area as deleted no more page ops will be added.
790 if (MemoryArea
->PageOpCount
> 0)
792 ULONG_PTR MemoryAreaLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
-
793 (ULONG_PTR
)MemoryArea
->StartingAddress
;
795 /* FiN TODO: Optimize loop counter! */
796 for (i
= 0; i
< PAGE_ROUND_UP(MemoryAreaLength
) / PAGE_SIZE
; i
++)
800 if (MemoryArea
->PageOpCount
== 0)
805 PageOp
= MmCheckForPageOp(MemoryArea
, Process
->UniqueProcessId
,
806 (PVOID
)((ULONG_PTR
)MemoryArea
->StartingAddress
+ (i
* PAGE_SIZE
)),
811 MmUnlockAddressSpace(&Process
->AddressSpace
);
812 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
817 if (Status
!= STATUS_SUCCESS
)
819 DPRINT1("Failed to wait for page op\n");
822 MmLockAddressSpace(&Process
->AddressSpace
);
823 MmReleasePageOp(PageOp
);
828 /* Free all the individual segments. */
829 current_entry
= MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
.Flink
;
830 while (current_entry
!= &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
)
832 current
= CONTAINING_RECORD(current_entry
, MM_REGION
, RegionListEntry
);
833 current_entry
= current_entry
->Flink
;
837 /* Actually free the memory area. */
838 MmFreeMemoryArea(&Process
->AddressSpace
,
840 MmFreeVirtualMemoryPage
,
848 NtFreeVirtualMemory(IN HANDLE ProcessHandle
,
849 IN PVOID
* PBaseAddress
,
850 IN PULONG PRegionSize
,
853 * FUNCTION: Frees a range of virtual memory
855 * ProcessHandle = Points to the process that allocated the virtual
857 * BaseAddress = Points to the memory address, rounded down to a
858 * multiple of the pagesize
859 * RegionSize = Limits the range to free, rounded up to a multiple of
861 * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
865 MEMORY_AREA
* MemoryArea
;
868 PMADDRESS_SPACE AddressSpace
;
872 DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *PBaseAddress %x, "
873 "*PRegionSize %x, FreeType %x)\n",ProcessHandle
,*PBaseAddress
,
874 *PRegionSize
,FreeType
);
876 BaseAddress
= (PVOID
)PAGE_ROUND_DOWN((*PBaseAddress
));
877 RegionSize
= PAGE_ROUND_UP((*PBaseAddress
) + (*PRegionSize
)) -
878 PAGE_ROUND_DOWN((*PBaseAddress
));
880 Status
= ObReferenceObjectByHandle(ProcessHandle
,
881 PROCESS_VM_OPERATION
,
886 if (!NT_SUCCESS(Status
))
891 AddressSpace
= &Process
->AddressSpace
;
893 MmLockAddressSpace(AddressSpace
);
894 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
895 if (MemoryArea
== NULL
)
897 MmUnlockAddressSpace(AddressSpace
);
898 ObDereferenceObject(Process
);
899 return(STATUS_UNSUCCESSFUL
);
905 /* We can only free a memory area in one step. */
906 if (MemoryArea
->StartingAddress
!= BaseAddress
||
907 MemoryArea
->Type
!= MEMORY_AREA_VIRTUAL_MEMORY
)
909 MmUnlockAddressSpace(AddressSpace
);
910 ObDereferenceObject(Process
);
911 return(STATUS_UNSUCCESSFUL
);
913 MmFreeVirtualMemory(Process
, MemoryArea
);
914 MmUnlockAddressSpace(AddressSpace
);
915 ObDereferenceObject(Process
);
916 return(STATUS_SUCCESS
);
920 MmAlterRegion(AddressSpace
,
921 MemoryArea
->StartingAddress
,
922 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
928 MmUnlockAddressSpace(AddressSpace
);
929 ObDereferenceObject(Process
);
932 MmUnlockAddressSpace(AddressSpace
);
933 ObDereferenceObject(Process
);
934 return(STATUS_NOT_IMPLEMENTED
);
938 MmProtectAnonMem(PMADDRESS_SPACE AddressSpace
,
939 PMEMORY_AREA MemoryArea
,
948 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
949 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
951 *OldProtect
= Region
->Protect
;
952 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
953 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
954 BaseAddress
, Length
, Region
->Type
, Protect
,
960 MmQueryAnonMem(PMEMORY_AREA MemoryArea
,
962 PMEMORY_BASIC_INFORMATION Info
,
968 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
970 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
971 &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
,
972 Address
, &RegionBase
);
973 Info
->BaseAddress
= RegionBase
;
974 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
975 Info
->AllocationProtect
= MemoryArea
->Attributes
;
976 Info
->RegionSize
= (char*)RegionBase
+ Region
->Length
- (char*)Info
->BaseAddress
;
977 Info
->State
= Region
->Type
;
978 Info
->Protect
= Region
->Protect
;
979 Info
->Type
= MEM_PRIVATE
;
981 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
982 return(STATUS_SUCCESS
);