ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

marea.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.