Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmarea.c
Go to the documentation of this file.
00001 /* 00002 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section) 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * 00019 * PROJECT: ReactOS kernel 00020 * FILE: ntoskrnl/mm/marea.c 00021 * PURPOSE: Implements memory areas 00022 * 00023 * PROGRAMMERS: Rex Jolliff 00024 * David Welch 00025 * Eric Kohl 00026 * Philip Susi 00027 * Casper Hornstrup 00028 * Eric Kohl 00029 * Ge van Geldorp 00030 * Royce Mitchell III 00031 * Aleksey Bragin 00032 * Jason Filby 00033 * Thomas Weidenmueller 00034 * Gunnar Andre' Dalsnes 00035 * Mike Nordell 00036 * Alex Ionescu 00037 * Filip Navara 00038 * Herve Poussineau 00039 * Steven Edwards 00040 */ 00041 00042 /* INCLUDES *****************************************************************/ 00043 00044 #include <ntoskrnl.h> 00045 #define NDEBUG 00046 #include "../cache/section/newmm.h" 00047 #include <debug.h> 00048 00049 #include "ARM3/miarm.h" 00050 00051 MEMORY_AREA MiStaticMemoryAreas[MI_STATIC_MEMORY_AREAS]; 00052 ULONG MiStaticMemoryAreaCount; 00053 00054 /* FUNCTIONS *****************************************************************/ 00055 00066 static PMEMORY_AREA MmIterateFirstNode(PMEMORY_AREA Node) 00067 { 00068 while (Node->LeftChild != NULL) 00069 Node = Node->LeftChild; 00070 00071 return Node; 00072 } 00073 00083 static PMEMORY_AREA MmIterateNextNode(PMEMORY_AREA Node) 00084 { 00085 if (Node->RightChild != NULL) 00086 { 00087 Node = Node->RightChild; 00088 while (Node->LeftChild != NULL) 00089 Node = Node->LeftChild; 00090 } 00091 else 00092 { 00093 PMEMORY_AREA TempNode = NULL; 00094 00095 do 00096 { 00097 /* Check if we're at the end of tree. */ 00098 if (Node->Parent == NULL) 00099 return NULL; 00100 00101 TempNode = Node; 00102 Node = Node->Parent; 00103 } 00104 while (TempNode == Node->RightChild); 00105 } 00106 return Node; 00107 } 00108 00119 static PMEMORY_AREA MmIterateLastNode(PMEMORY_AREA Node) 00120 { 00121 while (Node->RightChild != NULL) 00122 Node = Node->RightChild; 00123 00124 return Node; 00125 } 00126 00136 static PMEMORY_AREA MmIteratePrevNode(PMEMORY_AREA Node) 00137 { 00138 if (Node->LeftChild != NULL) 00139 { 00140 Node = Node->LeftChild; 00141 while (Node->RightChild != NULL) 00142 Node = Node->RightChild; 00143 } 00144 else 00145 { 00146 PMEMORY_AREA TempNode = NULL; 00147 00148 do 00149 { 00150 /* Check if we're at the end of tree. */ 00151 if (Node->Parent == NULL) 00152 return NULL; 00153 00154 TempNode = Node; 00155 Node = Node->Parent; 00156 } 00157 while (TempNode == Node->LeftChild); 00158 } 00159 return Node; 00160 } 00161 00162 PMEMORY_AREA NTAPI 00163 MmLocateMemoryAreaByAddress( 00164 PMMSUPPORT AddressSpace, 00165 PVOID Address) 00166 { 00167 PMEMORY_AREA Node = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; 00168 00169 DPRINT("MmLocateMemoryAreaByAddress(AddressSpace %p, Address %p)\n", 00170 AddressSpace, Address); 00171 00172 while (Node != NULL) 00173 { 00174 if (Address < Node->StartingAddress) 00175 Node = Node->LeftChild; 00176 else if (Address >= Node->EndingAddress) 00177 Node = Node->RightChild; 00178 else 00179 { 00180 DPRINT("MmLocateMemoryAreaByAddress(%p): %p [%p - %p]\n", 00181 Address, Node, Node->StartingAddress, Node->EndingAddress); 00182 return Node; 00183 } 00184 } 00185 00186 DPRINT("MmLocateMemoryAreaByAddress(%p): 0\n", Address); 00187 return NULL; 00188 } 00189 00190 PMEMORY_AREA NTAPI 00191 MmLocateMemoryAreaByRegion( 00192 PMMSUPPORT AddressSpace, 00193 PVOID Address, 00194 ULONG_PTR Length) 00195 { 00196 PMEMORY_AREA Node; 00197 PVOID Extent = (PVOID)((ULONG_PTR)Address + Length); 00198 00199 /* Special case for empty tree. */ 00200 if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL) 00201 return NULL; 00202 00203 /* Traverse the tree from left to right. */ 00204 for (Node = MmIterateFirstNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink); 00205 Node != NULL; 00206 Node = MmIterateNextNode(Node)) 00207 { 00208 if (Node->StartingAddress >= Address && 00209 Node->StartingAddress < Extent) 00210 { 00211 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n", 00212 Address, (ULONG_PTR)Address + Length, Node->StartingAddress, 00213 Node->EndingAddress); 00214 return Node; 00215 } 00216 if (Node->EndingAddress > Address && 00217 Node->EndingAddress < Extent) 00218 { 00219 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n", 00220 Address, (ULONG_PTR)Address + Length, Node->StartingAddress, 00221 Node->EndingAddress); 00222 return Node; 00223 } 00224 if (Node->StartingAddress <= Address && 00225 Node->EndingAddress >= Extent) 00226 { 00227 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n", 00228 Address, (ULONG_PTR)Address + Length, Node->StartingAddress, 00229 Node->EndingAddress); 00230 return Node; 00231 } 00232 if (Node->StartingAddress >= Extent) 00233 { 00234 DPRINT("Finished MmLocateMemoryAreaByRegion() = NULL\n"); 00235 return NULL; 00236 } 00237 } 00238 00239 return NULL; 00240 } 00241 00249 static VOID 00250 MmCompressHelper( 00251 PMMSUPPORT AddressSpace, 00252 ULONG Count) 00253 { 00254 PMEMORY_AREA Root = NULL; 00255 PMEMORY_AREA Red = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; 00256 PMEMORY_AREA Black = Red->LeftChild; 00257 00258 while (Count--) 00259 { 00260 if (Root) 00261 Root->LeftChild = Black; 00262 else 00263 AddressSpace->WorkingSetExpansionLinks.Flink = (PVOID)Black; 00264 Black->Parent = Root; 00265 Red->LeftChild = Black->RightChild; 00266 if (Black->RightChild) 00267 Black->RightChild->Parent = Red; 00268 Black->RightChild = Red; 00269 Red->Parent = Black; 00270 Root = Black; 00271 00272 if (Count) 00273 { 00274 Red = Root->LeftChild; 00275 Black = Red->LeftChild; 00276 } 00277 } 00278 } 00279 00288 static VOID 00289 MmRebalanceTree( 00290 PMMSUPPORT AddressSpace) 00291 { 00292 PMEMORY_AREA PreviousNode; 00293 PMEMORY_AREA CurrentNode; 00294 PMEMORY_AREA TempNode; 00295 ULONG NodeCount = 0; 00296 ULONG Vine; /* Number of nodes in main vine. */ 00297 ULONG Leaves; /* Nodes in incomplete bottom level, if any. */ 00298 INT Height; /* Height of produced balanced tree. */ 00299 00300 /* Transform the tree into Vine. */ 00301 00302 PreviousNode = NULL; 00303 CurrentNode = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; 00304 while (CurrentNode != NULL) 00305 { 00306 if (CurrentNode->RightChild == NULL) 00307 { 00308 PreviousNode = CurrentNode; 00309 CurrentNode = CurrentNode->LeftChild; 00310 NodeCount++; 00311 } 00312 else 00313 { 00314 TempNode = CurrentNode->RightChild; 00315 00316 CurrentNode->RightChild = TempNode->LeftChild; 00317 if (TempNode->LeftChild) 00318 TempNode->LeftChild->Parent = CurrentNode; 00319 00320 TempNode->LeftChild = CurrentNode; 00321 CurrentNode->Parent = TempNode; 00322 00323 CurrentNode = TempNode; 00324 00325 if (PreviousNode != NULL) 00326 PreviousNode->LeftChild = TempNode; 00327 else 00328 AddressSpace->WorkingSetExpansionLinks.Flink = (PVOID)TempNode; 00329 TempNode->Parent = PreviousNode; 00330 } 00331 } 00332 00333 /* Transform Vine back into a balanced tree. */ 00334 00335 Leaves = NodeCount + 1; 00336 for (;;) 00337 { 00338 ULONG Next = Leaves & (Leaves - 1); 00339 if (Next == 0) 00340 break; 00341 Leaves = Next; 00342 } 00343 Leaves = NodeCount + 1 - Leaves; 00344 00345 MmCompressHelper(AddressSpace, Leaves); 00346 00347 Vine = NodeCount - Leaves; 00348 Height = 1 + (Leaves > 0); 00349 while (Vine > 1) 00350 { 00351 MmCompressHelper(AddressSpace, Vine / 2); 00352 Vine /= 2; 00353 Height++; 00354 } 00355 } 00356 00357 VOID 00358 NTAPI 00359 MiInsertVad(IN PMMVAD Vad, 00360 IN PEPROCESS Process); 00361 00362 ULONG 00363 NTAPI 00364 MiMakeProtectionMask( 00365 IN ULONG Protect 00366 ); 00367 00368 static VOID 00369 MmInsertMemoryArea( 00370 PMMSUPPORT AddressSpace, 00371 PMEMORY_AREA marea) 00372 { 00373 PMEMORY_AREA Node; 00374 PMEMORY_AREA PreviousNode; 00375 ULONG Depth = 0; 00376 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); 00377 00378 /* Build a lame VAD if this is a user-space allocation */ 00379 if ((marea->EndingAddress < MmSystemRangeStart) && (marea->Type != MEMORY_AREA_OWNED_BY_ARM3)) 00380 { 00381 PMMVAD Vad; 00382 00383 ASSERT(marea->Type == MEMORY_AREA_SECTION_VIEW || marea->Type == MEMORY_AREA_CACHE); 00384 Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD), TAG_MVAD); 00385 ASSERT(Vad); 00386 RtlZeroMemory(Vad, sizeof(MMVAD)); 00387 Vad->StartingVpn = PAGE_ROUND_DOWN(marea->StartingAddress) >> PAGE_SHIFT; 00388 /* 00389 * For some strange reason, it is perfectly valid to create a MAREA from 0x1000 to... 0x1000. 00390 * In a normal OS/Memory Manager, this would be retarded, but ReactOS allows this (how it works 00391 * I don't even want to know). 00392 */ 00393 if (marea->EndingAddress != marea->StartingAddress) 00394 { 00395 Vad->EndingVpn = PAGE_ROUND_DOWN((ULONG_PTR)marea->EndingAddress - 1) >> PAGE_SHIFT; 00396 } 00397 else 00398 { 00399 Vad->EndingVpn = Vad->StartingVpn; 00400 } 00401 Vad->u.VadFlags.Spare = 1; 00402 Vad->u.VadFlags.PrivateMemory = 1; 00403 Vad->u.VadFlags.Protection = MiMakeProtectionMask(marea->Protect); 00404 00405 /* Insert the VAD */ 00406 MiInsertVad(Vad, Process); 00407 marea->Vad = Vad; 00408 } 00409 else 00410 { 00411 marea->Vad = NULL; 00412 } 00413 00414 if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL) 00415 { 00416 AddressSpace->WorkingSetExpansionLinks.Flink = (PVOID)marea; 00417 marea->LeftChild = marea->RightChild = marea->Parent = NULL; 00418 return; 00419 } 00420 00421 Node = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; 00422 do 00423 { 00424 DPRINT("marea->EndingAddress: %p Node->StartingAddress: %p\n", 00425 marea->EndingAddress, Node->StartingAddress); 00426 DPRINT("marea->StartingAddress: %p Node->EndingAddress: %p\n", 00427 marea->StartingAddress, Node->EndingAddress); 00428 ASSERT(marea->EndingAddress <= Node->StartingAddress || 00429 marea->StartingAddress >= Node->EndingAddress); 00430 ASSERT(marea->StartingAddress != Node->StartingAddress); 00431 00432 PreviousNode = Node; 00433 00434 if (marea->StartingAddress < Node->StartingAddress) 00435 Node = Node->LeftChild; 00436 else 00437 Node = Node->RightChild; 00438 00439 if (Node) 00440 { 00441 Depth++; 00442 if (Depth == 22) 00443 { 00444 MmRebalanceTree(AddressSpace); 00445 PreviousNode = Node->Parent; 00446 } 00447 } 00448 } 00449 while (Node != NULL); 00450 00451 marea->LeftChild = marea->RightChild = NULL; 00452 marea->Parent = PreviousNode; 00453 if (marea->StartingAddress < PreviousNode->StartingAddress) 00454 PreviousNode->LeftChild = marea; 00455 else 00456 PreviousNode->RightChild = marea; 00457 } 00458 00459 static PVOID 00460 MmFindGapBottomUp( 00461 PMMSUPPORT AddressSpace, 00462 ULONG_PTR Length, 00463 ULONG_PTR Granularity) 00464 { 00465 ULONG_PTR LowestAddress, HighestAddress, Candidate; 00466 PMEMORY_AREA Root, Node; 00467 00468 /* Get the margins of the address space */ 00469 if (MmGetAddressSpaceOwner(AddressSpace) != NULL) 00470 { 00471 LowestAddress = (ULONG_PTR)MM_LOWEST_USER_ADDRESS; 00472 HighestAddress = (ULONG_PTR)MmHighestUserAddress; 00473 } 00474 else 00475 { 00476 LowestAddress = (ULONG_PTR)MmSystemRangeStart; 00477 HighestAddress = MAXULONG_PTR; 00478 } 00479 00480 /* Start with the lowest address */ 00481 Candidate = LowestAddress; 00482 00483 /* Check for overflow */ 00484 if ((Candidate + Length) < Candidate) return NULL; 00485 00486 /* Get the root of the address space tree */ 00487 Root = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; 00488 00489 /* Go to the node with lowest address in the tree. */ 00490 Node = Root ? MmIterateFirstNode(Root) : NULL; 00491 while (Node && ((ULONG_PTR)Node->EndingAddress < LowestAddress)) 00492 { 00493 Node = MmIterateNextNode(Node); 00494 } 00495 00496 /* Traverse the tree from low to high addresses */ 00497 while (Node && ((ULONG_PTR)Node->EndingAddress < HighestAddress)) 00498 { 00499 /* Check if the memory area fits before the current node */ 00500 if ((ULONG_PTR)Node->StartingAddress >= (Candidate + Length)) 00501 { 00502 DPRINT("MmFindGapBottomUp: %p\n", Candidate); 00503 ASSERT(Candidate >= LowestAddress); 00504 return (PVOID)Candidate; 00505 } 00506 00507 /* Calculate next possible adress above this node */ 00508 Candidate = ALIGN_UP_BY((ULONG_PTR)Node->EndingAddress, Granularity); 00509 00510 /* Check for overflow */ 00511 if ((Candidate + Length) < (ULONG_PTR)Node->EndingAddress) return NULL; 00512 00513 /* Go to the next higher node */ 00514 Node = MmIterateNextNode(Node); 00515 } 00516 00517 /* Check if there is enough space after the last memory area. */ 00518 if ((Candidate + Length) <= HighestAddress) 00519 { 00520 DPRINT("MmFindGapBottomUp: %p\n", Candidate); 00521 ASSERT(Candidate >= LowestAddress); 00522 return (PVOID)Candidate; 00523 } 00524 00525 DPRINT("MmFindGapBottomUp: 0\n"); 00526 return NULL; 00527 } 00528 00529 00530 static PVOID 00531 MmFindGapTopDown( 00532 PMMSUPPORT AddressSpace, 00533 ULONG_PTR Length, 00534 ULONG_PTR Granularity) 00535 { 00536 ULONG_PTR LowestAddress, HighestAddress, Candidate; 00537 PMEMORY_AREA Root, Node; 00538 00539 /* Get the margins of the address space */ 00540 if (MmGetAddressSpaceOwner(AddressSpace) != NULL) 00541 { 00542 LowestAddress = (ULONG_PTR)MM_LOWEST_USER_ADDRESS; 00543 HighestAddress = (ULONG_PTR)MmHighestUserAddress; 00544 } 00545 else 00546 { 00547 LowestAddress = (ULONG_PTR)MmSystemRangeStart; 00548 HighestAddress = MAXULONG_PTR; 00549 } 00550 00551 /* Calculate the highest candidate */ 00552 Candidate = ALIGN_DOWN_BY(HighestAddress + 1 - Length, Granularity); 00553 00554 /* Check for overflow. */ 00555 if (Candidate > HighestAddress) return NULL; 00556 00557 /* Get the root of the address space tree */ 00558 Root = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; 00559 00560 /* Go to the node with highest address in the tree. */ 00561 Node = Root ? MmIterateLastNode(Root) : NULL; 00562 while (Node && ((ULONG_PTR)Node->StartingAddress > HighestAddress)) 00563 { 00564 Node = MmIteratePrevNode(Node); 00565 } 00566 00567 /* Traverse the tree from high to low addresses */ 00568 while (Node && ((ULONG_PTR)Node->StartingAddress > LowestAddress)) 00569 { 00570 /* Check if the memory area fits after the current node */ 00571 if ((ULONG_PTR)Node->EndingAddress <= Candidate) 00572 { 00573 DPRINT("MmFindGapTopDown: %p\n", Candidate); 00574 return (PVOID)Candidate; 00575 } 00576 00577 /* Calculate next possible adress below this node */ 00578 Candidate = ALIGN_DOWN_BY((ULONG_PTR)Node->StartingAddress - Length, 00579 Granularity); 00580 00581 /* Check for overflow. */ 00582 if (Candidate > (ULONG_PTR)Node->StartingAddress) 00583 return NULL; 00584 00585 /* Go to the next lower node */ 00586 Node = MmIteratePrevNode(Node); 00587 } 00588 00589 /* Check if the last candidate is inside the given range */ 00590 if (Candidate >= LowestAddress) 00591 { 00592 DPRINT("MmFindGapTopDown: %p\n", Candidate); 00593 return (PVOID)Candidate; 00594 } 00595 00596 DPRINT("MmFindGapTopDown: 0\n"); 00597 return NULL; 00598 } 00599 00600 00601 PVOID NTAPI 00602 MmFindGap( 00603 PMMSUPPORT AddressSpace, 00604 ULONG_PTR Length, 00605 ULONG_PTR Granularity, 00606 BOOLEAN TopDown) 00607 { 00608 if (TopDown) 00609 return MmFindGapTopDown(AddressSpace, Length, Granularity); 00610 00611 return MmFindGapBottomUp(AddressSpace, Length, Granularity); 00612 } 00613 00614 ULONG_PTR NTAPI 00615 MmFindGapAtAddress( 00616 PMMSUPPORT AddressSpace, 00617 PVOID Address) 00618 { 00619 PMEMORY_AREA Node = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; 00620 PMEMORY_AREA RightNeighbour = NULL; 00621 PVOID LowestAddress = MmGetAddressSpaceOwner(AddressSpace) ? MM_LOWEST_USER_ADDRESS : MmSystemRangeStart; 00622 PVOID HighestAddress = MmGetAddressSpaceOwner(AddressSpace) ? 00623 (PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR; 00624 00625 Address = MM_ROUND_DOWN(Address, PAGE_SIZE); 00626 00627 if (LowestAddress < MmSystemRangeStart) 00628 { 00629 if (Address >= MmSystemRangeStart) 00630 { 00631 return 0; 00632 } 00633 } 00634 else 00635 { 00636 if (Address < LowestAddress) 00637 { 00638 return 0; 00639 } 00640 } 00641 00642 while (Node != NULL) 00643 { 00644 if (Address < Node->StartingAddress) 00645 { 00646 RightNeighbour = Node; 00647 Node = Node->LeftChild; 00648 } 00649 else if (Address >= Node->EndingAddress) 00650 { 00651 Node = Node->RightChild; 00652 } 00653 else 00654 { 00655 DPRINT("MmFindGapAtAddress: 0\n"); 00656 return 0; 00657 } 00658 } 00659 00660 if (RightNeighbour) 00661 { 00662 DPRINT("MmFindGapAtAddress: %p [%p]\n", Address, 00663 (ULONG_PTR)RightNeighbour->StartingAddress - (ULONG_PTR)Address); 00664 return (ULONG_PTR)RightNeighbour->StartingAddress - (ULONG_PTR)Address; 00665 } 00666 else 00667 { 00668 DPRINT("MmFindGapAtAddress: %p [%p]\n", Address, 00669 (ULONG_PTR)HighestAddress - (ULONG_PTR)Address); 00670 return (ULONG_PTR)HighestAddress - (ULONG_PTR)Address; 00671 } 00672 } 00673 00674 VOID 00675 NTAPI 00676 MiRemoveNode(IN PMMADDRESS_NODE Node, 00677 IN PMM_AVL_TABLE Table); 00678 00697 VOID 00698 NTAPI 00699 MiDeletePte(IN PMMPTE PointerPte, 00700 IN PVOID VirtualAddress, 00701 IN PEPROCESS CurrentProcess, 00702 IN PMMPTE PrototypePte); 00703 00704 NTSTATUS NTAPI 00705 MmFreeMemoryArea( 00706 PMMSUPPORT AddressSpace, 00707 PMEMORY_AREA MemoryArea, 00708 PMM_FREE_PAGE_FUNC FreePage, 00709 PVOID FreePageContext) 00710 { 00711 PMEMORY_AREA *ParentReplace; 00712 ULONG_PTR Address; 00713 PVOID EndAddress; 00714 00715 if (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3) 00716 { 00717 PEPROCESS CurrentProcess = PsGetCurrentProcess(); 00718 PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); 00719 00720 if (Process != NULL && 00721 Process != CurrentProcess) 00722 { 00723 KeAttachProcess(&Process->Pcb); 00724 } 00725 00726 EndAddress = MM_ROUND_UP(MemoryArea->EndingAddress, PAGE_SIZE); 00727 for (Address = (ULONG_PTR)MemoryArea->StartingAddress; 00728 Address < (ULONG_PTR)EndAddress; 00729 Address += PAGE_SIZE) 00730 { 00731 BOOLEAN Dirty = FALSE; 00732 SWAPENTRY SwapEntry = 0; 00733 PFN_NUMBER Page = 0; 00734 00735 if (MmIsPageSwapEntry(Process, (PVOID)Address)) 00736 { 00737 MmDeletePageFileMapping(Process, (PVOID)Address, &SwapEntry); 00738 } 00739 else 00740 { 00741 MmDeleteVirtualMapping(Process, (PVOID)Address, FALSE, &Dirty, &Page); 00742 } 00743 if (FreePage != NULL) 00744 { 00745 FreePage(FreePageContext, MemoryArea, (PVOID)Address, 00746 Page, SwapEntry, (BOOLEAN)Dirty); 00747 } 00748 #if (_MI_PAGING_LEVELS == 2) 00749 /* Remove page table reference */ 00750 ASSERT(KeGetCurrentIrql() <= APC_LEVEL); 00751 if((SwapEntry || Page) && ((PVOID)Address < MmSystemRangeStart)) 00752 { 00753 ASSERT(AddressSpace != MmGetKernelAddressSpace()); 00754 if(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] == 0) 00755 { 00756 /* No PTE relies on this PDE. Release it */ 00757 KIRQL OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 00758 PMMPDE PointerPde = MiAddressToPde(Address); 00759 ASSERT(PointerPde->u.Hard.Valid == 1); 00760 MiDeletePte(PointerPde, MiPdeToPte(PointerPde), Process, NULL); 00761 ASSERT(PointerPde->u.Hard.Valid == 0); 00762 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 00763 } 00764 } 00765 #endif 00766 } 00767 00768 if (Process != NULL && 00769 Process != CurrentProcess) 00770 { 00771 KeDetachProcess(); 00772 } 00773 00774 if (MemoryArea->Vad) 00775 { 00776 ASSERT(MemoryArea->EndingAddress < MmSystemRangeStart); 00777 ASSERT(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW || MemoryArea->Type == MEMORY_AREA_CACHE); 00778 00779 /* MmCleanProcessAddressSpace might have removed it (and this would be MmDeleteProcessAdressSpace) */ 00780 ASSERT(((PMMVAD)MemoryArea->Vad)->u.VadFlags.Spare != 0); 00781 if (((PMMVAD)MemoryArea->Vad)->u.VadFlags.Spare == 1) 00782 { 00783 MiRemoveNode(MemoryArea->Vad, &Process->VadRoot); 00784 } 00785 00786 ExFreePoolWithTag(MemoryArea->Vad, TAG_MVAD); 00787 MemoryArea->Vad = NULL; 00788 } 00789 } 00790 00791 /* There must be no page ops in progress */ 00792 ASSERT(MemoryArea->PageOpCount == 0); 00793 00794 /* Remove the tree item. */ 00795 { 00796 if (MemoryArea->Parent != NULL) 00797 { 00798 if (MemoryArea->Parent->LeftChild == MemoryArea) 00799 ParentReplace = &MemoryArea->Parent->LeftChild; 00800 else 00801 ParentReplace = &MemoryArea->Parent->RightChild; 00802 } 00803 else 00804 ParentReplace = (PMEMORY_AREA*)&AddressSpace->WorkingSetExpansionLinks.Flink; 00805 00806 if (MemoryArea->RightChild == NULL) 00807 { 00808 *ParentReplace = MemoryArea->LeftChild; 00809 if (MemoryArea->LeftChild) 00810 MemoryArea->LeftChild->Parent = MemoryArea->Parent; 00811 } 00812 else 00813 { 00814 if (MemoryArea->RightChild->LeftChild == NULL) 00815 { 00816 MemoryArea->RightChild->LeftChild = MemoryArea->LeftChild; 00817 if (MemoryArea->LeftChild) 00818 MemoryArea->LeftChild->Parent = MemoryArea->RightChild; 00819 00820 *ParentReplace = MemoryArea->RightChild; 00821 MemoryArea->RightChild->Parent = MemoryArea->Parent; 00822 } 00823 else 00824 { 00825 PMEMORY_AREA LowestNode; 00826 00827 LowestNode = MemoryArea->RightChild->LeftChild; 00828 while (LowestNode->LeftChild != NULL) 00829 LowestNode = LowestNode->LeftChild; 00830 00831 LowestNode->Parent->LeftChild = LowestNode->RightChild; 00832 if (LowestNode->RightChild) 00833 LowestNode->RightChild->Parent = LowestNode->Parent; 00834 00835 LowestNode->LeftChild = MemoryArea->LeftChild; 00836 if (MemoryArea->LeftChild) 00837 MemoryArea->LeftChild->Parent = LowestNode; 00838 00839 LowestNode->RightChild = MemoryArea->RightChild; 00840 MemoryArea->RightChild->Parent = LowestNode; 00841 00842 *ParentReplace = LowestNode; 00843 LowestNode->Parent = MemoryArea->Parent; 00844 } 00845 } 00846 } 00847 00848 ExFreePoolWithTag(MemoryArea, TAG_MAREA); 00849 00850 DPRINT("MmFreeMemoryAreaByNode() succeeded\n"); 00851 00852 return STATUS_SUCCESS; 00853 } 00854 00881 NTSTATUS NTAPI 00882 MmCreateMemoryArea(PMMSUPPORT AddressSpace, 00883 ULONG Type, 00884 PVOID *BaseAddress, 00885 ULONG_PTR Length, 00886 ULONG Protect, 00887 PMEMORY_AREA *Result, 00888 BOOLEAN FixedAddress, 00889 ULONG AllocationFlags, 00890 PHYSICAL_ADDRESS BoundaryAddressMultiple) 00891 { 00892 PVOID EndAddress; 00893 ULONG Granularity; 00894 ULONG_PTR tmpLength; 00895 PMEMORY_AREA MemoryArea; 00896 00897 DPRINT("MmCreateMemoryArea(Type 0x%lx, BaseAddress %p, " 00898 "*BaseAddress %p, Length %p, AllocationFlags %x, " 00899 "FixedAddress %x, Result %p)\n", 00900 Type, BaseAddress, *BaseAddress, Length, AllocationFlags, 00901 FixedAddress, Result); 00902 00903 Granularity = PAGE_SIZE; 00904 if ((*BaseAddress) == 0 && !FixedAddress) 00905 { 00906 tmpLength = (ULONG_PTR)MM_ROUND_UP(Length, Granularity); 00907 *BaseAddress = MmFindGap(AddressSpace, 00908 tmpLength, 00909 Granularity, 00910 (AllocationFlags & MEM_TOP_DOWN) == MEM_TOP_DOWN); 00911 if ((*BaseAddress) == 0) 00912 { 00913 DPRINT("No suitable gap\n"); 00914 return STATUS_NO_MEMORY; 00915 } 00916 } 00917 else 00918 { 00919 tmpLength = Length + ((ULONG_PTR) *BaseAddress 00920 - (ULONG_PTR) MM_ROUND_DOWN(*BaseAddress, Granularity)); 00921 tmpLength = (ULONG_PTR)MM_ROUND_UP(tmpLength, Granularity); 00922 *BaseAddress = MM_ROUND_DOWN(*BaseAddress, Granularity); 00923 00924 if (!MmGetAddressSpaceOwner(AddressSpace) && *BaseAddress < MmSystemRangeStart) 00925 { 00926 return STATUS_ACCESS_VIOLATION; 00927 } 00928 00929 if (MmGetAddressSpaceOwner(AddressSpace) && 00930 (ULONG_PTR)(*BaseAddress) + tmpLength > (ULONG_PTR)MmSystemRangeStart) 00931 { 00932 DPRINT("Memory area for user mode address space exceeds MmSystemRangeStart\n"); 00933 return STATUS_ACCESS_VIOLATION; 00934 } 00935 00936 if (BoundaryAddressMultiple.QuadPart != 0) 00937 { 00938 EndAddress = ((char*)(*BaseAddress)) + tmpLength-1; 00939 ASSERT(((ULONG_PTR)*BaseAddress/BoundaryAddressMultiple.QuadPart) == ((DWORD_PTR)EndAddress/BoundaryAddressMultiple.QuadPart)); 00940 } 00941 00942 if (MmLocateMemoryAreaByRegion(AddressSpace, 00943 *BaseAddress, 00944 tmpLength) != NULL) 00945 { 00946 DPRINT("Memory area already occupied\n"); 00947 return STATUS_CONFLICTING_ADDRESSES; 00948 } 00949 } 00950 00951 // 00952 // Is this a static memory area? 00953 // 00954 if (Type & MEMORY_AREA_STATIC) 00955 { 00956 // 00957 // Use the static array instead of the pool 00958 // 00959 ASSERT(MiStaticMemoryAreaCount < MI_STATIC_MEMORY_AREAS); 00960 MemoryArea = &MiStaticMemoryAreas[MiStaticMemoryAreaCount++]; 00961 Type &= ~MEMORY_AREA_STATIC; 00962 } 00963 else 00964 { 00965 // 00966 // Allocate the memory area from nonpaged pool 00967 // 00968 MemoryArea = ExAllocatePoolWithTag(NonPagedPool, 00969 sizeof(MEMORY_AREA), 00970 TAG_MAREA); 00971 } 00972 00973 if (!MemoryArea) return STATUS_NO_MEMORY; 00974 00975 RtlZeroMemory(MemoryArea, sizeof(MEMORY_AREA)); 00976 MemoryArea->Type = Type; 00977 MemoryArea->StartingAddress = *BaseAddress; 00978 MemoryArea->EndingAddress = (PVOID)((ULONG_PTR)*BaseAddress + tmpLength); 00979 MemoryArea->Protect = Protect; 00980 MemoryArea->Flags = AllocationFlags; 00981 //MemoryArea->LockCount = 0; 00982 MemoryArea->PageOpCount = 0; 00983 MemoryArea->DeleteInProgress = FALSE; 00984 00985 MmInsertMemoryArea(AddressSpace, MemoryArea); 00986 00987 *Result = MemoryArea; 00988 00989 DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress); 00990 return STATUS_SUCCESS; 00991 } 00992 00993 VOID NTAPI 00994 MmMapMemoryArea(PVOID BaseAddress, 00995 SIZE_T Length, 00996 ULONG Consumer, 00997 ULONG Protection) 00998 { 00999 ULONG i; 01000 NTSTATUS Status; 01001 01002 ASSERT(((ULONG_PTR)BaseAddress % PAGE_SIZE) == 0); 01003 01004 for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++) 01005 { 01006 PFN_NUMBER Page; 01007 01008 Status = MmRequestPageMemoryConsumer(Consumer, TRUE, &Page); 01009 if (!NT_SUCCESS(Status)) 01010 { 01011 DPRINT1("Unable to allocate page\n"); 01012 KeBugCheck(MEMORY_MANAGEMENT); 01013 } 01014 Status = MmCreateVirtualMapping (NULL, 01015 (PVOID)((ULONG_PTR)BaseAddress + (i * PAGE_SIZE)), 01016 Protection, 01017 &Page, 01018 1); 01019 if (!NT_SUCCESS(Status)) 01020 { 01021 DPRINT1("Unable to create virtual mapping\n"); 01022 KeBugCheck(MEMORY_MANAGEMENT); 01023 } 01024 } 01025 } 01026 01027 VOID 01028 NTAPI 01029 MmDeleteProcessAddressSpace2(IN PEPROCESS Process); 01030 01031 NTSTATUS 01032 NTAPI 01033 MmDeleteProcessAddressSpace(PEPROCESS Process) 01034 { 01035 PVOID Address; 01036 PMEMORY_AREA MemoryArea; 01037 01038 DPRINT("MmDeleteProcessAddressSpace(Process %x (%s))\n", Process, 01039 Process->ImageFileName); 01040 01041 #ifndef _M_AMD64 01042 RemoveEntryList(&Process->MmProcessLinks); 01043 #endif 01044 MmLockAddressSpace(&Process->Vm); 01045 01046 while ((MemoryArea = (PMEMORY_AREA)Process->Vm.WorkingSetExpansionLinks.Flink) != NULL) 01047 { 01048 switch (MemoryArea->Type) 01049 { 01050 case MEMORY_AREA_SECTION_VIEW: 01051 Address = (PVOID)MemoryArea->StartingAddress; 01052 MmUnlockAddressSpace(&Process->Vm); 01053 MmUnmapViewOfSection(Process, Address); 01054 MmLockAddressSpace(&Process->Vm); 01055 break; 01056 01057 case MEMORY_AREA_CACHE: 01058 Address = (PVOID)MemoryArea->StartingAddress; 01059 MmUnlockAddressSpace(&Process->Vm); 01060 MmUnmapViewOfCacheSegment(&Process->Vm, Address); 01061 MmLockAddressSpace(&Process->Vm); 01062 break; 01063 01064 case MEMORY_AREA_OWNED_BY_ARM3: 01065 MmFreeMemoryArea(&Process->Vm, 01066 MemoryArea, 01067 NULL, 01068 NULL); 01069 break; 01070 01071 default: 01072 KeBugCheck(MEMORY_MANAGEMENT); 01073 } 01074 } 01075 01076 #if (_MI_PAGING_LEVELS == 2) 01077 { 01078 KIRQL OldIrql; 01079 PMMPDE pointerPde; 01080 /* Attach to Process */ 01081 KeAttachProcess(&Process->Pcb); 01082 01083 /* Acquire PFN lock */ 01084 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 01085 01086 for(Address = MI_LOWEST_VAD_ADDRESS; 01087 Address < MM_HIGHEST_VAD_ADDRESS; 01088 Address =(PVOID)((ULONG_PTR)Address + (PAGE_SIZE * PTE_COUNT))) 01089 { 01090 /* At this point all references should be dead */ 01091 ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] == 0); 01092 pointerPde = MiAddressToPde(Address); 01093 /* Unlike in ARM3, we don't necesarrily free the PDE page as soon as reference reaches 0, 01094 * so we must clean up a bit when process closes */ 01095 if(pointerPde->u.Hard.Valid) 01096 MiDeletePte(pointerPde, MiPdeToPte(pointerPde), Process, NULL); 01097 ASSERT(pointerPde->u.Hard.Valid == 0); 01098 } 01099 /* Release lock */ 01100 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 01101 01102 /* Detach */ 01103 KeDetachProcess(); 01104 } 01105 #endif 01106 01107 MmUnlockAddressSpace(&Process->Vm); 01108 01109 DPRINT("Finished MmReleaseMmInfo()\n"); 01110 MmDeleteProcessAddressSpace2(Process); 01111 return(STATUS_SUCCESS); 01112 } 01113 01114 /* EOF */ Generated on Fri May 25 2012 04:36:04 for ReactOS by
1.7.6.1
|