update for HEAD-2002110701
[reactos.git] / ntoskrnl / mm / marea.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 1998, 1999, 2000, 2001 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 /*
20  * PROJECT:         ReactOS kernel
21  * FILE:            ntoskrnl/mm/marea.c
22  * PURPOSE:         Implements memory areas
23  * PROGRAMMER:      David Welch (welch@mcmail.com)
24  * UPDATE HISTORY:
25  *                  Created 22/05/98
26  */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include <internal/mm.h>
32 #include <internal/ps.h>
33 #include <internal/pool.h>
34
35 #define NDEBUG
36 #include <internal/debug.h>
37
38 /* GLOBALS *******************************************************************/
39
40 #define TAG_MAREA   TAG('M', 'A', 'R', 'E')
41
42 /* FUNCTIONS *****************************************************************/
43
44 VOID MmDumpMemoryAreas(PLIST_ENTRY ListHead)
45 {
46    PLIST_ENTRY current_entry;
47    MEMORY_AREA* current;
48    
49    DbgPrint("MmDumpMemoryAreas()\n");
50    
51    current_entry = ListHead->Flink;
52    while (current_entry!=ListHead)
53      {
54         current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
55         DbgPrint("Base %x Length %x End %x Attributes %x Flink %x\n",
56                current->BaseAddress,current->Length,
57                current->BaseAddress+current->Length,current->Attributes,
58                current->Entry.Flink);
59         current_entry = current_entry->Flink;
60      }
61    DbgPrint("Finished MmDumpMemoryAreas()\n");
62 }
63
64 MEMORY_AREA* MmOpenMemoryAreaByAddress(PMADDRESS_SPACE AddressSpace,
65                                        PVOID Address)
66 {
67    PLIST_ENTRY current_entry;
68    MEMORY_AREA* current;
69    PLIST_ENTRY previous_entry;
70
71    DPRINT("MmOpenMemoryAreaByAddress(AddressSpace %x, Address %x)\n",
72            AddressSpace, Address);
73    
74    previous_entry = &AddressSpace->MAreaListHead;
75    current_entry = AddressSpace->MAreaListHead.Flink;
76    while (current_entry != &AddressSpace->MAreaListHead)
77      {
78         current = CONTAINING_RECORD(current_entry,
79                                     MEMORY_AREA,
80                                     Entry);
81         assert(current_entry->Blink->Flink == current_entry);
82         assert(current_entry->Flink->Blink == current_entry);
83         assert(previous_entry->Flink == current_entry);
84         if (current->BaseAddress <= Address &&
85             (current->BaseAddress + current->Length) > Address)
86           {
87              DPRINT("%s() = %x\n",__FUNCTION__,current);
88              return(current);
89           }
90         if (current->BaseAddress > Address)
91           {
92              DPRINT("%s() = NULL\n",__FUNCTION__);
93              return(NULL);
94           }
95         previous_entry = current_entry;
96         current_entry = current_entry->Flink;
97      }
98    DPRINT("%s() = NULL\n",__FUNCTION__);
99    return(NULL);
100 }
101
102 MEMORY_AREA* MmOpenMemoryAreaByRegion(PMADDRESS_SPACE AddressSpace, 
103                                       PVOID Address,
104                                       ULONG Length)
105 {
106    PLIST_ENTRY current_entry;
107    MEMORY_AREA* current;
108    ULONG Extent;
109    
110    DPRINT("MmOpenMemoryByRegion(AddressSpace %x, Address %x, Length %x)\n",
111           AddressSpace, Address, Length);
112    
113    current_entry = AddressSpace->MAreaListHead.Flink;
114    while (current_entry != &AddressSpace->MAreaListHead)
115      {
116         current = CONTAINING_RECORD(current_entry,
117                                     MEMORY_AREA,
118                                     Entry);
119         DPRINT("current->BaseAddress %x current->Length %x\n",
120                current->BaseAddress,current->Length);
121         if (current->BaseAddress >= Address &&
122             current->BaseAddress < (Address+Length))
123           {
124              DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
125                     current);
126              return(current);
127           }
128         Extent = (ULONG)current->BaseAddress + current->Length;
129         if (Extent > (ULONG)Address &&
130             Extent < (ULONG)(Address+Length))
131           {
132              DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
133                     current);
134              return(current);
135           }
136         if (current->BaseAddress <= Address &&
137             Extent >= (ULONG)(Address+Length))
138           {
139              DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
140                     current);
141              return(current);
142           }
143         if (current->BaseAddress >= (Address+Length))
144           {
145              DPRINT("Finished MmOpenMemoryAreaByRegion()= NULL\n",0);
146              return(NULL);
147           }
148         current_entry = current_entry->Flink;
149      }
150    DPRINT("Finished MmOpenMemoryAreaByRegion() = NULL\n",0);
151    return(NULL);
152 }
153
154 static VOID MmInsertMemoryArea(PMADDRESS_SPACE AddressSpace,
155                                MEMORY_AREA* marea)
156 {
157    PLIST_ENTRY ListHead;
158    PLIST_ENTRY current_entry;
159    PLIST_ENTRY inserted_entry = &marea->Entry;
160    MEMORY_AREA* current;
161    MEMORY_AREA* next;   
162    
163    DPRINT("MmInsertMemoryArea(marea %x)\n", marea);
164    DPRINT("marea->BaseAddress %x\n", marea->BaseAddress);
165    DPRINT("marea->Length %x\n", marea->Length);
166    
167    ListHead = &AddressSpace->MAreaListHead;
168    
169    current_entry = ListHead->Flink;
170    if (IsListEmpty(ListHead))
171      {
172         InsertHeadList(ListHead,&marea->Entry);
173         return;
174      }
175    current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
176    if (current->BaseAddress > marea->BaseAddress)
177      {
178         InsertHeadList(ListHead,&marea->Entry);
179         return;
180      }
181    while (current_entry->Flink!=ListHead)
182      {
183         current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
184         next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
185         if (current->BaseAddress < marea->BaseAddress &&
186             current->Entry.Flink==ListHead)
187           {
188              current_entry->Flink = inserted_entry;
189              inserted_entry->Flink=ListHead;
190              inserted_entry->Blink=current_entry;
191              ListHead->Blink = inserted_entry;               
192              return;
193           }
194         if (current->BaseAddress < marea->BaseAddress &&
195             next->BaseAddress > marea->BaseAddress)
196           {          
197              inserted_entry->Flink = current_entry->Flink;
198              inserted_entry->Blink = current_entry;
199              inserted_entry->Flink->Blink = inserted_entry;
200              current_entry->Flink=inserted_entry;
201              return;
202           }
203         current_entry = current_entry->Flink;
204      }
205    InsertTailList(ListHead,inserted_entry);
206 }
207
208 PVOID MmFindGap(PMADDRESS_SPACE AddressSpace, ULONG Length)
209 {
210    PLIST_ENTRY ListHead;
211    PLIST_ENTRY current_entry;
212    MEMORY_AREA* current;
213    MEMORY_AREA* next;
214    ULONG Gap;
215    
216    DPRINT("MmFindGap(Length %x)\n",Length);
217    
218    ListHead = &AddressSpace->MAreaListHead;
219      
220    current_entry = ListHead->Flink;
221    while (current_entry->Flink!=ListHead)
222      {
223         current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
224         next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
225         Gap = next->BaseAddress - (current->BaseAddress + PAGE_ROUND_UP(current->Length));
226         if (Gap >= Length)
227           {
228              return(current->BaseAddress + PAGE_ROUND_UP(current->Length));
229           }
230         current_entry = current_entry->Flink;
231      }
232    
233    if (current_entry == ListHead)
234      {
235         return((PVOID)AddressSpace->LowestAddress);
236      }
237    
238    current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
239    return(current->BaseAddress + PAGE_ROUND_UP(current->Length));
240 }
241
242 NTSTATUS MmInitMemoryAreas(VOID)
243 /*
244  * FUNCTION: Initialize the memory area list
245  */
246 {
247    DPRINT("MmInitMemoryAreas()\n",0);
248    return(STATUS_SUCCESS);
249 }
250
251 NTSTATUS 
252 MmFreeMemoryArea(PMADDRESS_SPACE AddressSpace,
253                  PVOID BaseAddress,
254                  ULONG Length,
255                  VOID (*FreePage)(PVOID Context, MEMORY_AREA* MemoryArea, 
256                                   PVOID Address, PHYSICAL_ADDRESS PhysAddr, 
257                                   SWAPENTRY SwapEntry, BOOLEAN Dirty),
258                  PVOID FreePageContext)
259 {
260    MEMORY_AREA* MemoryArea;
261    ULONG i;
262    
263    DPRINT("MmFreeMemoryArea(AddressSpace %x, BaseAddress %x, Length %x,"
264            "FreePageContext %d)\n",AddressSpace,BaseAddress,Length,
265           FreePageContext);
266
267    MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
268                                           BaseAddress);
269    if (MemoryArea == NULL)
270      {       
271         KeBugCheck(0);
272         return(STATUS_UNSUCCESSFUL);
273      }
274    for (i=0; i<(PAGE_ROUND_UP(MemoryArea->Length)/PAGE_SIZE); i++)
275      {
276        PHYSICAL_ADDRESS PhysAddr = (PHYSICAL_ADDRESS)0LL;
277        BOOL Dirty = FALSE;
278        SWAPENTRY SwapEntry = 0;
279
280        if (MmIsPageSwapEntry(AddressSpace->Process,
281                              MemoryArea->BaseAddress + (i * PAGE_SIZE)))
282          {
283            MmDeletePageFileMapping(AddressSpace->Process,
284                                    MemoryArea->BaseAddress + (i * PAGE_SIZE),
285                                    &SwapEntry);
286          }
287        else
288          {
289            MmDeleteVirtualMapping(AddressSpace->Process, 
290                                   MemoryArea->BaseAddress + (i*PAGE_SIZE),
291                                   FALSE, &Dirty, &PhysAddr);
292          }
293        if (FreePage != NULL)
294          {
295            FreePage(FreePageContext, MemoryArea,
296                     MemoryArea->BaseAddress + (i * PAGE_SIZE), PhysAddr, 
297                     SwapEntry, Dirty);
298          }
299      }
300    
301    RemoveEntryList(&MemoryArea->Entry);
302    ExFreePool(MemoryArea);
303    
304    DPRINT("MmFreeMemoryArea() succeeded\n");
305    
306    return(STATUS_SUCCESS);
307 }
308
309 PMEMORY_AREA MmSplitMemoryArea(PEPROCESS Process,
310                                PMADDRESS_SPACE AddressSpace,
311                                PMEMORY_AREA OriginalMemoryArea,
312                                PVOID BaseAddress,
313                                ULONG Length,
314                                ULONG NewType,
315                                ULONG NewAttributes)
316 {
317    PMEMORY_AREA Result;
318    PMEMORY_AREA Split;
319    
320    Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA), 
321                                   TAG_MAREA);
322    RtlZeroMemory(Result,sizeof(MEMORY_AREA));
323    Result->Type = NewType;
324    Result->BaseAddress = BaseAddress;
325    Result->Length = Length;
326    Result->Attributes = NewAttributes;
327    Result->LockCount = 0;
328    Result->Process = Process;
329    
330    if (BaseAddress == OriginalMemoryArea->BaseAddress)
331      {
332         OriginalMemoryArea->BaseAddress = BaseAddress + Length;
333         OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
334         MmInsertMemoryArea(AddressSpace, Result);
335         return(Result);
336      }
337    if ((BaseAddress + Length) == 
338        (OriginalMemoryArea->BaseAddress + OriginalMemoryArea->Length))
339      {
340         OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length; 
341         MmInsertMemoryArea(AddressSpace, Result);
342
343         return(Result);
344      }
345       
346    Split = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
347                                  TAG_MAREA);
348    RtlCopyMemory(Split,OriginalMemoryArea,sizeof(MEMORY_AREA));
349    Split->BaseAddress = BaseAddress + Length;
350    Split->Length = OriginalMemoryArea->Length - (((ULONG)BaseAddress) 
351                                                  + Length);
352    
353    OriginalMemoryArea->Length = BaseAddress - OriginalMemoryArea->BaseAddress;
354       
355    return(Split);
356 }
357
358 NTSTATUS MmCreateMemoryArea(PEPROCESS Process,
359                             PMADDRESS_SPACE AddressSpace,
360                             ULONG Type,
361                             PVOID* BaseAddress,
362                             ULONG Length,
363                             ULONG Attributes,
364                             MEMORY_AREA** Result,
365                             BOOL FixedAddress)
366 /*
367  * FUNCTION: Create a memory area
368  * ARGUMENTS:
369  *     AddressSpace = Address space to create the area in
370  *     Type = Type of the address space
371  *     BaseAddress = 
372  *     Length = Length to allocate
373  *     Attributes = Protection attributes for the memory area
374  *     Result = Receives a pointer to the memory area on exit
375  * RETURNS: Status
376  * NOTES: Lock the address space before calling this function
377  */
378 {
379    ULONG tmpLength;
380    DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %x,"
381            "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
382            Type,BaseAddress,*BaseAddress,Length,Attributes,Result);
383
384    if ((*BaseAddress)==0 && !FixedAddress)
385      {
386         tmpLength = PAGE_ROUND_UP(Length);
387         *BaseAddress = MmFindGap(AddressSpace,
388                                  PAGE_ROUND_UP(Length) +(PAGE_SIZE*2));
389         if ((*BaseAddress)==0)
390           {
391              DPRINT("No suitable gap\n");
392              return(STATUS_NO_MEMORY);
393           }
394         (*BaseAddress)=(*BaseAddress)+PAGE_SIZE;
395      }
396    else
397      { 
398         tmpLength = (ULONG)*BaseAddress + Length - PAGE_ROUND_DOWN((*BaseAddress));
399         (*BaseAddress) = (PVOID)PAGE_ROUND_DOWN((*BaseAddress));
400         if (MmOpenMemoryAreaByRegion(AddressSpace,
401                                      *BaseAddress,
402                                      tmpLength)!=NULL)
403           {
404              DPRINT("Memory area already occupied\n");
405              return(STATUS_CONFLICTING_ADDRESSES);
406           }
407      }
408    
409    *Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
410                                    TAG_MAREA);
411    RtlZeroMemory(*Result,sizeof(MEMORY_AREA));
412    (*Result)->Type = Type;
413    (*Result)->BaseAddress = *BaseAddress;
414    (*Result)->Length = tmpLength;
415    (*Result)->Attributes = Attributes;
416    (*Result)->LockCount = 0;
417    (*Result)->Process = Process;
418    (*Result)->PageOpCount = 0;
419    (*Result)->DeleteInProgress = FALSE;
420    
421    MmInsertMemoryArea(AddressSpace, *Result);
422    
423    DPRINT("MmCreateMemoryArea() succeeded\n");
424    return(STATUS_SUCCESS);
425 }