2002-08-10 David Welch <welch@computer2.darkstar.org>
[reactos.git] / reactos / ntoskrnl / mm / anonmem.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /* $Id: anonmem.c,v 1.1 2002/08/10 16:41:19 dwelch Exp $
20 *
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/anonmem.c
23 * PURPOSE: Implementing anonymous memory.
24 * PROGRAMMER: David Welch
25 */
26
27 /* INCLUDE *****************************************************************/
28
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>
35
36 #define NDEBUG
37 #include <internal/debug.h>
38
39 /* FUNCTIONS *****************************************************************/
40
41 NTSTATUS
42 MmWritePageVirtualMemory(PMADDRESS_SPACE AddressSpace,
43 PMEMORY_AREA MArea,
44 PVOID Address)
45 {
46 return(STATUS_UNSUCCESSFUL);
47 }
48
49
50 NTSTATUS
51 MmPageOutVirtualMemory(PMADDRESS_SPACE AddressSpace,
52 PMEMORY_AREA MemoryArea,
53 PVOID Address,
54 PMM_PAGEOP PageOp)
55 {
56 PHYSICAL_ADDRESS PhysicalAddress;
57 BOOL WasDirty;
58 SWAPENTRY SwapEntry;
59 NTSTATUS Status;
60 PMDL Mdl;
61
62 DPRINT("MmPageOutVirtualMemory(Address 0x%.8X) PID %d\n",
63 Address, MemoryArea->Process->UniqueProcessId);
64
65 /*
66 * Check for paging out from a deleted virtual memory area.
67 */
68 if (MemoryArea->DeleteInProgress)
69 {
70 return(STATUS_UNSUCCESSFUL);
71 }
72
73 /*
74 * Paging out code or readonly data is easy.
75 */
76 if ((MemoryArea->Attributes & PAGE_READONLY) ||
77 (MemoryArea->Attributes & PAGE_EXECUTE_READ))
78 {
79 MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE,
80 NULL, &PhysicalAddress);
81 MmDeleteAllRmaps(PhysicalAddress, NULL, NULL);
82 if (MmGetSavedSwapEntryPage(PhysicalAddress) != 0)
83 {
84 DPRINT1("Read-only page was swapped out.\n");
85 KeBugCheck(0);
86 }
87 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
88
89 PageOp->Status = STATUS_SUCCESS;
90 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
91 MmReleasePageOp(PageOp);
92 return(STATUS_SUCCESS);
93 }
94
95 /*
96 * Otherwise this is read-write data
97 */
98 MmDisableVirtualMapping(MemoryArea->Process, Address,
99 &WasDirty, (PULONG)&PhysicalAddress);
100 if (PhysicalAddress.QuadPart == 0)
101 {
102 KeBugCheck(0);
103 }
104 if (!WasDirty)
105 {
106 MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, NULL, NULL);
107 MmDeleteAllRmaps(PhysicalAddress, NULL, NULL);
108 if ((SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress)) != 0)
109 {
110 MmCreatePageFileMapping(MemoryArea->Process, Address, SwapEntry);
111 MmSetSavedSwapEntryPage(PhysicalAddress, 0);
112 }
113 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
114 PageOp->Status = STATUS_SUCCESS;
115 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
116 MmReleasePageOp(PageOp);
117 return(STATUS_SUCCESS);
118 }
119
120 /*
121 * If necessary, allocate an entry in the paging file for this page
122 */
123 SwapEntry = MmGetSavedSwapEntryPage(PhysicalAddress);
124 if (SwapEntry == 0)
125 {
126 SwapEntry = MmAllocSwapPage();
127 if (SwapEntry == 0)
128 {
129 MmEnableVirtualMapping(MemoryArea->Process, Address);
130 PageOp->Status = STATUS_UNSUCCESSFUL;
131 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
132 MmReleasePageOp(PageOp);
133 return(STATUS_UNSUCCESSFUL);
134 }
135 }
136
137 /*
138 * Write the page to the pagefile
139 */
140 Mdl = MmCreateMdl(NULL, NULL, PAGESIZE);
141 MmBuildMdlFromPages(Mdl, (PULONG)&PhysicalAddress);
142 Status = MmWriteToSwapPage(SwapEntry, Mdl);
143 if (!NT_SUCCESS(Status))
144 {
145 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
146 Status);
147 MmEnableVirtualMapping(MemoryArea->Process, Address);
148 PageOp->Status = STATUS_UNSUCCESSFUL;
149 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
150 MmReleasePageOp(PageOp);
151 return(STATUS_UNSUCCESSFUL);
152 }
153
154 /*
155 * Otherwise we have succeeded, free the page
156 */
157 DPRINT("MM: Swapped out virtual memory page 0x%.8X!\n", PhysicalAddress);
158 MmDeleteVirtualMapping(MemoryArea->Process, Address, FALSE, NULL, NULL);
159 MmCreatePageFileMapping(MemoryArea->Process, Address, SwapEntry);
160 MmDeleteAllRmaps(PhysicalAddress, NULL, NULL);
161 MmSetSavedSwapEntryPage(PhysicalAddress, 0);
162 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddress);
163 PageOp->Status = STATUS_SUCCESS;
164 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
165 MmReleasePageOp(PageOp);
166 return(STATUS_SUCCESS);
167 }
168
169 NTSTATUS
170 MmNotPresentFaultVirtualMemory(PMADDRESS_SPACE AddressSpace,
171 MEMORY_AREA* MemoryArea,
172 PVOID Address,
173 BOOLEAN Locked)
174 /*
175 * FUNCTION: Move data into memory to satisfy a page not present fault
176 * ARGUMENTS:
177 * AddressSpace = Address space within which the fault occurred
178 * MemoryArea = The memory area within which the fault occurred
179 * Address = The absolute address of fault
180 * RETURNS: Status
181 * NOTES: This function is called with the address space lock held.
182 */
183 {
184 PHYSICAL_ADDRESS Page;
185 NTSTATUS Status;
186 PMM_REGION Region;
187 PMM_PAGEOP PageOp;
188
189 /*
190 * There is a window between taking the page fault and locking the
191 * address space when another thread could load the page so we check
192 * that.
193 */
194 if (MmIsPagePresent(NULL, Address))
195 {
196 if (Locked)
197 {
198 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
199 }
200 return(STATUS_SUCCESS);
201 }
202
203 /*
204 * Check for the virtual memory area being deleted.
205 */
206 if (MemoryArea->DeleteInProgress)
207 {
208 return(STATUS_UNSUCCESSFUL);
209 }
210
211 /*
212 * Get the segment corresponding to the virtual address
213 */
214 Region = MmFindRegion(MemoryArea->BaseAddress,
215 &MemoryArea->Data.VirtualMemoryData.RegionListHead,
216 Address, NULL);
217 if (Region->Type == MEM_RESERVE)
218 {
219 return(STATUS_UNSUCCESSFUL);
220 }
221
222 /*
223 * Get or create a page operation
224 */
225 PageOp = MmGetPageOp(MemoryArea, (ULONG)PsGetCurrentProcessId(),
226 (PVOID)PAGE_ROUND_DOWN(Address), NULL, 0,
227 MM_PAGEOP_PAGEIN);
228 if (PageOp == NULL)
229 {
230 DPRINT1("MmGetPageOp failed");
231 KeBugCheck(0);
232 }
233
234 /*
235 * Check if someone else is already handling this fault, if so wait
236 * for them
237 */
238 if (PageOp->Thread != PsGetCurrentThread())
239 {
240 MmUnlockAddressSpace(AddressSpace);
241 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
242 0,
243 KernelMode,
244 FALSE,
245 NULL);
246 /*
247 * Check for various strange conditions
248 */
249 if (Status != STATUS_SUCCESS)
250 {
251 DPRINT1("Failed to wait for page op\n");
252 KeBugCheck(0);
253 }
254 if (PageOp->Status == STATUS_PENDING)
255 {
256 DPRINT1("Woke for page op before completion\n");
257 KeBugCheck(0);
258 }
259 /*
260 * If this wasn't a pagein then we need to restart the handling
261 */
262 if (PageOp->OpType != MM_PAGEOP_PAGEIN)
263 {
264 MmLockAddressSpace(AddressSpace);
265 MmReleasePageOp(PageOp);
266 return(STATUS_MM_RESTART_OPERATION);
267 }
268 /*
269 * If the thread handling this fault has failed then we don't retry
270 */
271 if (!NT_SUCCESS(PageOp->Status))
272 {
273 MmLockAddressSpace(AddressSpace);
274 MmReleasePageOp(PageOp);
275 return(Status);
276 }
277 MmLockAddressSpace(AddressSpace);
278 if (Locked)
279 {
280 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
281 }
282 MmReleasePageOp(PageOp);
283 return(STATUS_SUCCESS);
284 }
285
286 /*
287 * Try to allocate a page
288 */
289 Status = MmRequestPageMemoryConsumer(MC_USER, FALSE, &Page);
290 if (Status == STATUS_NO_MEMORY)
291 {
292 MmUnlockAddressSpace(AddressSpace);
293 Status = MmRequestPageMemoryConsumer(MC_USER, TRUE, &Page);
294 MmLockAddressSpace(AddressSpace);
295 }
296
297 /*
298 * Handle swapped out pages.
299 */
300 if (MmIsPageSwapEntry(NULL, Address))
301 {
302 SWAPENTRY SwapEntry;
303 PMDL Mdl;
304
305 MmDeletePageFileMapping(NULL, Address, &SwapEntry);
306 Mdl = MmCreateMdl(NULL, NULL, PAGESIZE);
307 MmBuildMdlFromPages(Mdl, (PULONG)&Page);
308 Status = MmReadFromSwapPage(SwapEntry, Mdl);
309 if (!NT_SUCCESS(Status))
310 {
311 KeBugCheck(0);
312 }
313 MmSetSavedSwapEntryPage(Page, SwapEntry);
314 }
315
316 /*
317 * Set the page. If we fail because we are out of memory then
318 * try again
319 */
320 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
321 Address,
322 MemoryArea->Attributes,
323 Page,
324 FALSE);
325 while (Status == STATUS_NO_MEMORY)
326 {
327 MmUnlockAddressSpace(AddressSpace);
328 Status = MmCreateVirtualMapping(PsGetCurrentProcess(),
329 Address,
330 MemoryArea->Attributes,
331 Page,
332 TRUE);
333 MmLockAddressSpace(AddressSpace);
334 }
335 if (!NT_SUCCESS(Status))
336 {
337 DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
338 KeBugCheck(0);
339 return(Status);
340 }
341
342 /*
343 * Add the page to the process's working set
344 */
345 MmInsertRmap(Page, PsGetCurrentProcess(), (PVOID)PAGE_ROUND_DOWN(Address));
346
347 /*
348 * Finish the operation
349 */
350 if (Locked)
351 {
352 MmLockPage(MmGetPhysicalAddressForProcess(NULL, Address));
353 }
354 PageOp->Status = STATUS_SUCCESS;
355 KeSetEvent(&PageOp->CompletionEvent, IO_NO_INCREMENT, FALSE);
356 MmReleasePageOp(PageOp);
357 return(STATUS_SUCCESS);
358 }
359
360 VOID STATIC
361 MmModifyAttributes(PMADDRESS_SPACE AddressSpace,
362 PVOID BaseAddress,
363 ULONG RegionSize,
364 ULONG OldType,
365 ULONG OldProtect,
366 ULONG NewType,
367 ULONG NewProtect)
368 /*
369 * FUNCTION: Modify the attributes of a memory region
370 */
371 {
372 /*
373 * If we are switching a previously committed region to reserved then
374 * free any allocated pages within the region
375 */
376 if (NewType == MEM_RESERVE && OldType == MEM_COMMIT)
377 {
378 ULONG i;
379
380 for (i=0; i <= (RegionSize/PAGESIZE); i++)
381 {
382 LARGE_INTEGER PhysicalAddr;
383
384 if (MmIsPageSwapEntry(AddressSpace->Process,
385 BaseAddress + (i * PAGESIZE)))
386 {
387 SWAPENTRY SwapEntry;
388
389 MmDeletePageFileMapping(AddressSpace->Process,
390 BaseAddress + (i * PAGESIZE),
391 &SwapEntry);
392 MmFreeSwapPage(SwapEntry);
393 }
394 else
395 {
396 PhysicalAddr = MmGetPhysicalAddress(BaseAddress + (i*PAGESIZE));
397 MmDeleteVirtualMapping(AddressSpace->Process,
398 BaseAddress + (i*PAGESIZE),
399 FALSE, NULL, NULL);
400 if (PhysicalAddr.QuadPart != 0)
401 {
402 MmDeleteRmap(PhysicalAddr, AddressSpace->Process,
403 BaseAddress + (i * PAGESIZE));
404 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddr);
405 }
406 }
407 }
408 }
409
410 /*
411 * If we are changing the protection attributes of a committed region then
412 * alter the attributes for any allocated pages within the region
413 */
414 if (NewType == MEM_COMMIT && OldType == MEM_COMMIT &&
415 OldProtect != NewProtect)
416 {
417 ULONG i;
418
419 for (i=0; i <= (RegionSize/PAGESIZE); i++)
420 {
421 if (MmIsPagePresent(AddressSpace->Process,
422 BaseAddress + (i*PAGESIZE)))
423 {
424 MmSetPageProtect(AddressSpace->Process,
425 BaseAddress + (i*PAGESIZE),
426 NewProtect);
427 }
428 }
429 }
430 }
431
432 NTSTATUS STDCALL
433 NtAllocateVirtualMemory(IN HANDLE ProcessHandle,
434 IN OUT PVOID* UBaseAddress,
435 IN ULONG ZeroBits,
436 IN OUT PULONG URegionSize,
437 IN ULONG AllocationType,
438 IN ULONG Protect)
439 /*
440 * FUNCTION: Allocates a block of virtual memory in the process address space
441 * ARGUMENTS:
442 * ProcessHandle = The handle of the process which owns the virtual memory
443 * BaseAddress = A pointer to the virtual memory allocated. If you
444 * supply a non zero value the system will try to
445 * allocate the memory at the address supplied. It round
446 * it down to a multiple of the page size.
447 * ZeroBits = (OPTIONAL) You can specify the number of high order bits
448 * that must be zero, ensuring that the memory will be
449 * allocated at a address below a certain value.
450 * RegionSize = The number of bytes to allocate
451 * AllocationType = Indicates the type of virtual memory you like to
452 * allocated, can be a combination of MEM_COMMIT,
453 * MEM_RESERVE, MEM_RESET, MEM_TOP_DOWN.
454 * Protect = Indicates the protection type of the pages allocated, can be
455 * a combination of PAGE_READONLY, PAGE_READWRITE,
456 * PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_GUARD,
457 * PAGE_NOACCESS
458 * REMARKS:
459 * This function maps to the win32 VirtualAllocEx. Virtual memory is
460 * process based so the protocol starts with a ProcessHandle. I
461 * splitted the functionality of obtaining the actual address and
462 * specifying the start address in two parameters ( BaseAddress and
463 * StartAddress ) The NumberOfBytesAllocated specify the range and the
464 * AllocationType and ProctectionType map to the other two parameters.
465 * RETURNS: Status
466 */
467 {
468 PEPROCESS Process;
469 MEMORY_AREA* MemoryArea;
470 ULONG Type;
471 NTSTATUS Status;
472 PMADDRESS_SPACE AddressSpace;
473 PVOID BaseAddress;
474 ULONG RegionSize;
475 PVOID PBaseAddress;
476 ULONG PRegionSize;
477
478 DPRINT("NtAllocateVirtualMemory(*UBaseAddress %x, "
479 "ZeroBits %d, *URegionSize %x, AllocationType %x, Protect %x)\n",
480 *UBaseAddress,ZeroBits,*URegionSize,AllocationType,
481 Protect);
482
483 /*
484 * Check the validity of the parameters
485 */
486 if ((Protect & PAGE_FLAGS_VALID_FROM_USER_MODE) != Protect)
487 {
488 return(STATUS_INVALID_PAGE_PROTECTION);
489 }
490 if ((AllocationType & (MEM_COMMIT | MEM_RESERVE)) == 0)
491 {
492 return(STATUS_INVALID_PARAMETER);
493 }
494
495 PBaseAddress = *UBaseAddress;
496 PRegionSize = *URegionSize;
497
498
499 BaseAddress = (PVOID)PAGE_ROUND_DOWN(PBaseAddress);
500 RegionSize = PAGE_ROUND_UP(PBaseAddress + PRegionSize) -
501 PAGE_ROUND_DOWN(PBaseAddress);
502
503 Status = ObReferenceObjectByHandle(ProcessHandle,
504 PROCESS_VM_OPERATION,
505 NULL,
506 UserMode,
507 (PVOID*)(&Process),
508 NULL);
509 if (!NT_SUCCESS(Status))
510 {
511 DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
512 return(Status);
513 }
514
515 Type = (AllocationType & MEM_COMMIT) ? MEM_COMMIT : MEM_RESERVE;
516 DPRINT("Type %x\n", Type);
517
518 AddressSpace = &Process->AddressSpace;
519 MmLockAddressSpace(AddressSpace);
520
521 if (PBaseAddress != 0)
522 {
523 MemoryArea = MmOpenMemoryAreaByAddress(&Process->AddressSpace,
524 BaseAddress);
525
526 if (MemoryArea != NULL &&
527 MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY &&
528 MemoryArea->Length >= RegionSize)
529 {
530 Status =
531 MmAlterRegion(&Process->AddressSpace,
532 MemoryArea->BaseAddress,
533 &MemoryArea->Data.VirtualMemoryData.RegionListHead,
534 PBaseAddress, RegionSize,
535 Type, Protect, MmModifyAttributes);
536 MmUnlockAddressSpace(AddressSpace);
537 ObDereferenceObject(Process);
538 DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
539 return(Status);
540 }
541 else if (MemoryArea != NULL)
542 {
543 MmUnlockAddressSpace(AddressSpace);
544 ObDereferenceObject(Process);
545 return(STATUS_UNSUCCESSFUL);
546 }
547 }
548
549 Status = MmCreateMemoryArea(Process,
550 &Process->AddressSpace,
551 MEMORY_AREA_VIRTUAL_MEMORY,
552 &BaseAddress,
553 RegionSize,
554 Protect,
555 &MemoryArea,
556 PBaseAddress != 0);
557
558 if (!NT_SUCCESS(Status))
559 {
560 MmUnlockAddressSpace(AddressSpace);
561 ObDereferenceObject(Process);
562 DPRINT("NtAllocateVirtualMemory() = %x\n",Status);
563 return(Status);
564 }
565 MmInitialiseRegion(&MemoryArea->Data.VirtualMemoryData.RegionListHead,
566 RegionSize, Type, Protect);
567
568 if ((AllocationType & MEM_COMMIT) &&
569 ((Protect & PAGE_READWRITE) ||
570 (Protect & PAGE_EXECUTE_READWRITE)))
571 {
572 MmReserveSwapPages(RegionSize);
573 }
574
575 *UBaseAddress = BaseAddress;
576 *URegionSize = RegionSize;
577 DPRINT("*UBaseAddress %x *URegionSize %x\n", BaseAddress, RegionSize);
578
579 MmUnlockAddressSpace(AddressSpace);
580 ObDereferenceObject(Process);
581 return(STATUS_SUCCESS);
582 }
583
584 VOID STATIC
585 MmFreeVirtualMemoryPage(PVOID Context,
586 MEMORY_AREA* MemoryArea,
587 PVOID Address,
588 PHYSICAL_ADDRESS PhysicalAddr,
589 SWAPENTRY SwapEntry,
590 BOOLEAN Dirty)
591 {
592 PEPROCESS Process = (PEPROCESS)Context;
593
594 if (PhysicalAddr.QuadPart != 0)
595 {
596 MmDeleteRmap(PhysicalAddr, Process, Address);
597 MmReleasePageMemoryConsumer(MC_USER, PhysicalAddr);
598 }
599 else if (SwapEntry != 0)
600 {
601 MmFreeSwapPage(SwapEntry);
602 }
603 }
604
605 VOID
606 MmFreeVirtualMemory(PEPROCESS Process,
607 PMEMORY_AREA MemoryArea)
608 {
609 PLIST_ENTRY current_entry;
610 PMM_REGION current;
611 ULONG i;
612
613 DPRINT("MmFreeVirtualMemory(Process %p MemoryArea %p)\n", Process,
614 MemoryArea);
615
616 /* Mark this memory area as about to be deleted. */
617 MemoryArea->DeleteInProgress = TRUE;
618
619 /*
620 * Wait for any ongoing paging operations. Notice that since we have
621 * flagged this memory area as deleted no more page ops will be added.
622 */
623 if (MemoryArea->PageOpCount > 0)
624 {
625 for (i = 0; i < (PAGE_ROUND_UP(MemoryArea->Length) / PAGESIZE); i++)
626 {
627 PMM_PAGEOP PageOp;
628
629 if (MemoryArea->PageOpCount == 0)
630 {
631 break;
632 }
633
634 PageOp = MmCheckForPageOp(MemoryArea, Process->UniqueProcessId,
635 MemoryArea->BaseAddress + (i * PAGESIZE),
636 NULL, 0);
637 if (PageOp != NULL)
638 {
639 NTSTATUS Status;
640 MmUnlockAddressSpace(&Process->AddressSpace);
641 Status = KeWaitForSingleObject(&PageOp->CompletionEvent,
642 0,
643 KernelMode,
644 FALSE,
645 NULL);
646 if (Status != STATUS_SUCCESS)
647 {
648 DPRINT1("Failed to wait for page op\n");
649 KeBugCheck(0);
650 }
651 MmLockAddressSpace(&Process->AddressSpace);
652 MmReleasePageOp(PageOp);
653 }
654 }
655 }
656
657 /* Free all the individual segments. */
658 current_entry = MemoryArea->Data.VirtualMemoryData.RegionListHead.Flink;
659 while (current_entry != &MemoryArea->Data.VirtualMemoryData.RegionListHead)
660 {
661 current = CONTAINING_RECORD(current_entry, MM_REGION, RegionListEntry);
662 current_entry = current_entry->Flink;
663 ExFreePool(current);
664 }
665
666 /* Actually free the memory area. */
667 MmFreeMemoryArea(&Process->AddressSpace,
668 MemoryArea->BaseAddress,
669 0,
670 MmFreeVirtualMemoryPage,
671 (PVOID)Process);
672 }
673
674 NTSTATUS STDCALL
675 NtFreeVirtualMemory(IN HANDLE ProcessHandle,
676 IN PVOID* PBaseAddress,
677 IN PULONG PRegionSize,
678 IN ULONG FreeType)
679 /*
680 * FUNCTION: Frees a range of virtual memory
681 * ARGUMENTS:
682 * ProcessHandle = Points to the process that allocated the virtual
683 * memory
684 * BaseAddress = Points to the memory address, rounded down to a
685 * multiple of the pagesize
686 * RegionSize = Limits the range to free, rounded up to a multiple of
687 * the paging size
688 * FreeType = Can be one of the values: MEM_DECOMMIT, or MEM_RELEASE
689 * RETURNS: Status
690 */
691 {
692 MEMORY_AREA* MemoryArea;
693 NTSTATUS Status;
694 PEPROCESS Process;
695 PMADDRESS_SPACE AddressSpace;
696 PVOID BaseAddress;
697 ULONG RegionSize;
698
699 DPRINT("NtFreeVirtualMemory(ProcessHandle %x, *PBaseAddress %x, "
700 "*PRegionSize %x, FreeType %x)\n",ProcessHandle,*PBaseAddress,
701 *PRegionSize,FreeType);
702
703 BaseAddress = (PVOID)PAGE_ROUND_DOWN((*PBaseAddress));
704 RegionSize = PAGE_ROUND_UP((*PBaseAddress) + (*PRegionSize)) -
705 PAGE_ROUND_DOWN((*PBaseAddress));
706
707 Status = ObReferenceObjectByHandle(ProcessHandle,
708 PROCESS_VM_OPERATION,
709 PsProcessType,
710 UserMode,
711 (PVOID*)(&Process),
712 NULL);
713 if (!NT_SUCCESS(Status))
714 {
715 return(Status);
716 }
717
718 AddressSpace = &Process->AddressSpace;
719
720 MmLockAddressSpace(AddressSpace);
721 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
722 BaseAddress);
723 if (MemoryArea == NULL)
724 {
725 MmUnlockAddressSpace(AddressSpace);
726 ObDereferenceObject(Process);
727 return(STATUS_UNSUCCESSFUL);
728 }
729
730 switch (FreeType)
731 {
732 case MEM_RELEASE:
733 /* We can only free a memory area in one step. */
734 if (MemoryArea->BaseAddress != BaseAddress)
735 {
736 MmUnlockAddressSpace(AddressSpace);
737 ObDereferenceObject(Process);
738 return(STATUS_UNSUCCESSFUL);
739 }
740 MmFreeVirtualMemory(Process, MemoryArea);
741 MmUnlockAddressSpace(AddressSpace);
742 ObDereferenceObject(Process);
743 return(STATUS_SUCCESS);
744
745 case MEM_DECOMMIT:
746 Status =
747 MmAlterRegion(AddressSpace,
748 MemoryArea->BaseAddress,
749 &MemoryArea->Data.VirtualMemoryData.RegionListHead,
750 BaseAddress,
751 RegionSize,
752 MEM_RESERVE,
753 PAGE_NOACCESS,
754 MmModifyAttributes);
755 MmUnlockAddressSpace(AddressSpace);
756 ObDereferenceObject(Process);
757 return(Status);
758 }
759 MmUnlockAddressSpace(AddressSpace);
760 ObDereferenceObject(Process);
761 return(STATUS_NOT_IMPLEMENTED);
762 }
763
764 NTSTATUS
765 MmProtectAnonMem(PMADDRESS_SPACE AddressSpace,
766 PMEMORY_AREA MemoryArea,
767 PVOID BaseAddress,
768 ULONG Length,
769 ULONG Protect,
770 PULONG OldProtect)
771 {
772 PMM_REGION Region;
773 NTSTATUS Status;
774
775 Region = MmFindRegion(MemoryArea->BaseAddress,
776 &MemoryArea->Data.VirtualMemoryData.RegionListHead,
777 BaseAddress, NULL);
778 *OldProtect = Region->Protect;
779 Status = MmAlterRegion(AddressSpace, MemoryArea->BaseAddress,
780 &MemoryArea->Data.VirtualMemoryData.RegionListHead,
781 BaseAddress, Length, Region->Type, Protect,
782 MmModifyAttributes);
783 return(Status);
784 }
785
786 NTSTATUS STDCALL
787 MmQueryAnonMem(PMEMORY_AREA MemoryArea,
788 PVOID Address,
789 PMEMORY_BASIC_INFORMATION Info,
790 PULONG ResultLength)
791 {
792 PMM_REGION Region;
793 PVOID RegionBase;
794
795 Info->BaseAddress = (PVOID)PAGE_ROUND_DOWN(Address);
796
797 Region = MmFindRegion(MemoryArea->BaseAddress,
798 &MemoryArea->Data.VirtualMemoryData.RegionListHead,
799 Address, &RegionBase);
800 Info->AllocationBase = RegionBase;
801 Info->AllocationProtect = Region->Protect; /* FIXME */
802 Info->RegionSize = Region->Length;
803 Info->State = Region->Type;
804 Info->Protect = Region->Protect;
805 Info->Type = MEM_PRIVATE;
806 return(STATUS_SUCCESS);
807 }
808
809 /* EOF */