2002-10-01 Casper S. Hornstrup <chorns@users.sourceforge.net>
[reactos.git] / reactos / 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 + 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;
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 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %x,"
380 "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
381 Type,BaseAddress,*BaseAddress,Length,Attributes,Result);
382
383 if ((*BaseAddress)==0 && !FixedAddress)
384 {
385 *BaseAddress = MmFindGap(AddressSpace,
386 PAGE_ROUND_UP(Length) +(PAGE_SIZE*2));
387 if ((*BaseAddress)==0)
388 {
389 DPRINT("No suitable gap\n");
390 return(STATUS_NO_MEMORY);
391 }
392 (*BaseAddress)=(*BaseAddress)+PAGE_SIZE;
393 }
394 else
395 {
396 (*BaseAddress) = (PVOID)PAGE_ROUND_DOWN((*BaseAddress));
397 if (MmOpenMemoryAreaByRegion(AddressSpace,
398 *BaseAddress,
399 Length)!=NULL)
400 {
401 DPRINT("Memory area already occupied\n");
402 return(STATUS_CONFLICTING_ADDRESSES);
403 }
404 }
405
406 *Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
407 TAG_MAREA);
408 RtlZeroMemory(*Result,sizeof(MEMORY_AREA));
409 (*Result)->Type = Type;
410 (*Result)->BaseAddress = *BaseAddress;
411 (*Result)->Length = Length;
412 (*Result)->Attributes = Attributes;
413 (*Result)->LockCount = 0;
414 (*Result)->Process = Process;
415 (*Result)->PageOpCount = 0;
416 (*Result)->DeleteInProgress = FALSE;
417
418 MmInsertMemoryArea(AddressSpace, *Result);
419
420 DPRINT("MmCreateMemoryArea() succeeded\n");
421 return(STATUS_SUCCESS);
422 }