fd77ab366101401966510620aaa1588921cb5537
[reactos.git] / reactos / ntoskrnl / mm / marea.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/marea.c
5 * PURPOSE: Implements memory areas
6 * PROGRAMMER: David Welch (welch@mcmail.com)
7 * UPDATE HISTORY:
8 * Created 22/05/98
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ddk/ntddk.h>
14 #include <internal/mm.h>
15 #include <internal/mmhal.h>
16
17 #define NDEBUG
18 #include <internal/debug.h>
19
20 /* GLOBALS *******************************************************************/
21
22 static LIST_ENTRY SystemAreaList;
23 static KSPIN_LOCK SystemAreaListLock;
24
25 /* FUNCTIONS *****************************************************************/
26
27 VOID MmDumpMemoryAreas(PLIST_ENTRY ListHead)
28 {
29 PLIST_ENTRY current_entry;
30 MEMORY_AREA* current;
31
32 DbgPrint("MmDumpMemoryAreas()\n");
33
34 current_entry = ListHead->Flink;
35 while (current_entry!=ListHead)
36 {
37 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
38 DbgPrint("Base %x Length %x End %x Attributes %x Flink %x\n",
39 current->BaseAddress,current->Length,
40 current->BaseAddress+current->Length,current->Attributes,
41 current->Entry.Flink);
42 current_entry = current_entry->Flink;
43 }
44 DbgPrint("Finished MmDumpMemoryAreas()\n");
45 }
46
47 VOID MmLockMemoryAreaList(PVOID Address, PKIRQL oldlvl)
48 {
49 if (Address >= (PVOID)KERNEL_BASE)
50 {
51 KeAcquireSpinLock(&SystemAreaListLock,oldlvl);
52 }
53 else
54 {
55 PKPROCESS CurrentProcess = KeGetCurrentProcess();
56
57 KeAcquireSpinLock(&(CurrentProcess->SpinLock),oldlvl);
58 }
59 }
60
61 VOID MmUnlockMemoryAreaList(PVOID Address, PKIRQL oldlvl)
62 {
63 if (Address >= (PVOID)KERNEL_BASE)
64 {
65 KeReleaseSpinLock(&SystemAreaListLock,*oldlvl);
66 }
67 else
68 {
69 PKPROCESS CurrentProcess = KeGetCurrentProcess();
70 KeReleaseSpinLock(&(CurrentProcess->SpinLock),*oldlvl);
71 }
72
73 }
74
75 VOID MmLockMemoryAreaListByMode(KPROCESSOR_MODE Mode, PKIRQL oldlvl)
76 {
77 if (Mode == KernelMode)
78 {
79 KeAcquireSpinLock(&SystemAreaListLock,oldlvl);
80 }
81 else
82 {
83 PKPROCESS CurrentProcess = KeGetCurrentProcess();
84
85 KeAcquireSpinLock(&(CurrentProcess->SpinLock),oldlvl);
86 }
87 }
88
89 VOID MmUnlockMemoryAreaListByMode(KPROCESSOR_MODE Mode, PKIRQL oldlvl)
90 {
91 if (Mode == KernelMode)
92 {
93 KeReleaseSpinLock(&SystemAreaListLock,*oldlvl);
94 }
95 else
96 {
97 PKPROCESS CurrentProcess = KeGetCurrentProcess();
98 KeReleaseSpinLock(&(CurrentProcess->SpinLock),*oldlvl);
99 }
100
101 }
102
103
104 static PLIST_ENTRY MmGetRelatedListHead(PEPROCESS Process, PVOID BaseAddress)
105 {
106 if (BaseAddress >= (PVOID)KERNEL_BASE)
107 {
108 return(&SystemAreaList);
109 }
110 else
111 {
112 return(&(Process->Pcb.MemoryAreaList));
113 }
114 }
115
116 static MEMORY_AREA* MmInternalOpenMemoryAreaByAddress(PLIST_ENTRY ListHead,
117 PVOID Address)
118 {
119 PLIST_ENTRY current_entry;
120 MEMORY_AREA* current;
121 PLIST_ENTRY previous_entry;
122
123 // MmDumpMemoryAreas();
124
125 DPRINT("MmInternalOpenMemoryAreaByAddress(ListHead %x, Address %x)\n",
126 ListHead,Address);
127
128 if (ListHead==NULL)
129 {
130 return(NULL);
131 }
132
133 previous_entry = ListHead;
134 current_entry = ListHead->Flink;
135 while (current_entry!=ListHead)
136 {
137 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
138 DPRINT("Scanning %x BaseAddress %x Length %x\n",
139 current, current->BaseAddress, current->Length);
140 assert(current_entry->Blink->Flink == current_entry);
141 assert(current_entry->Flink->Blink == current_entry);
142 assert(previous_entry->Flink == current_entry);
143 if (current->BaseAddress <= Address &&
144 (current->BaseAddress + current->Length) > Address)
145 {
146 DPRINT("%s() = %x\n",__FUNCTION__,current);
147 return(current);
148 }
149 if (current->BaseAddress > Address)
150 {
151 DPRINT("%s() = NULL\n",__FUNCTION__);
152 return(NULL);
153 }
154 previous_entry = current_entry;
155 current_entry = current_entry->Flink;
156 }
157 DPRINT("%s() = NULL\n",__FUNCTION__);
158 return(NULL);
159 }
160
161
162 MEMORY_AREA* MmInternalOpenMemoryAreaByRegion(PLIST_ENTRY ListHead,
163 PVOID Address,
164 ULONG Length)
165 {
166 PLIST_ENTRY current_entry;
167 MEMORY_AREA* current;
168 ULONG Extent;
169
170 DPRINT("MmInternalOpenMemoryAreaByRegion(ListHead %x, Address %x, "
171 "Length %x)\n",ListHead,Address,Length);
172
173 // MmDumpMemoryAreas();
174
175 current_entry = ListHead->Flink;
176 while (current_entry!=ListHead)
177 {
178 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
179 DPRINT("current->BaseAddress %x current->Length %x\n",
180 current->BaseAddress,current->Length);
181 if (current->BaseAddress >= Address &&
182 current->BaseAddress <= (Address+Length))
183 {
184 DPRINT("Finished MmInternalOpenMemoryAreaByRegion() = %x\n",
185 current);
186 return(current);
187 }
188 Extent = (ULONG)current->BaseAddress + current->Length;
189 if (Extent > (ULONG)Address &&
190 Extent < (ULONG)(Address+Length))
191 {
192 DPRINT("Finished MmInternalOpenMemoryAreaByRegion() = %x\n",
193 current);
194 return(current);
195 }
196 if (current->BaseAddress <= Address &&
197 Extent >= (ULONG)(Address+Length))
198 {
199 DPRINT("Finished MmInternalOpenMemoryAreaByRegion() = %x\n",
200 current);
201 return(current);
202 }
203 if (current->BaseAddress >= (Address+Length))
204 {
205 DPRINT("Finished MmInternalOpenMemoryAreaByRegion()= NULL\n",0);
206 return(NULL);
207 }
208 current_entry = current_entry->Flink;
209 }
210 DPRINT("Finished MmInternalOpenMemoryAreaByRegion() = NULL\n",0);
211 return(NULL);
212 }
213
214 MEMORY_AREA* MmOpenMemoryAreaByRegion(PEPROCESS Process,
215 PVOID Address,
216 ULONG Length)
217 {
218 KIRQL oldlvl;
219 MEMORY_AREA* Result;
220 PLIST_ENTRY ListHead;
221
222 DPRINT("MmOpenMemoryByRegion(Process %x, Address %x, Length %x)\n",
223 Process,Address,Length);
224
225 MmLockMemoryAreaList(Address,&oldlvl);
226 ListHead = MmGetRelatedListHead(Process,Address);
227 Result = MmInternalOpenMemoryAreaByRegion(ListHead,Address,Length);
228 MmUnlockMemoryAreaList(Address,&oldlvl);
229 return(Result);
230 }
231
232
233 MEMORY_AREA* MmOpenMemoryAreaByRegionWithoutLock(PEPROCESS Process,
234 PVOID Address,
235 ULONG Length)
236 {
237 MEMORY_AREA* Result;
238 PLIST_ENTRY ListHead;
239
240 ListHead = MmGetRelatedListHead(Process, Address);
241 Result = MmInternalOpenMemoryAreaByRegion(ListHead,Address,Length);
242 return(Result);
243 }
244
245 MEMORY_AREA* MmOpenMemoryAreaByAddress(PEPROCESS Process, PVOID Address)
246 {
247 KIRQL oldlvl;
248 MEMORY_AREA* Result;
249 PLIST_ENTRY ListHead;
250
251 DPRINT("MmOpenMemoryAreaByAddress(Address %x)\n",Address);
252
253 MmLockMemoryAreaList(Address,&oldlvl);
254 ListHead = MmGetRelatedListHead(Process, Address);
255 Result = MmInternalOpenMemoryAreaByAddress(ListHead,Address);
256 MmUnlockMemoryAreaList(Address,&oldlvl);
257 return(Result);
258 }
259
260 MEMORY_AREA* MmOpenMemoryAreaByAddressWithoutLock(PEPROCESS Process,
261 PVOID Address)
262 {
263 MEMORY_AREA* Result;
264 PLIST_ENTRY ListHead;
265
266 ListHead = MmGetRelatedListHead(Process, Address);
267 Result = MmInternalOpenMemoryAreaByAddress(ListHead, Address);
268 return(Result);
269 }
270
271 static VOID MmInsertMemoryAreaWithoutLock(PEPROCESS Process,
272 MEMORY_AREA* marea)
273 {
274 PLIST_ENTRY ListHead;
275 PLIST_ENTRY current_entry;
276 PLIST_ENTRY inserted_entry = &(marea->Entry);
277 MEMORY_AREA* current;
278 MEMORY_AREA* next;
279
280 DPRINT("MmInsertMemoryAreaWithoutLock(marea %x)\n",marea);
281 DPRINT("marea->BaseAddress %x\n",marea->BaseAddress);
282 DPRINT("marea->Length %x\n",marea->Length);
283
284 ListHead=MmGetRelatedListHead(Process,marea->BaseAddress);
285 current_entry = ListHead->Flink;
286 CHECKPOINT;
287 if (IsListEmpty(ListHead))
288 {
289 CHECKPOINT;
290 InsertHeadList(ListHead,&marea->Entry);
291 CHECKPOINT;
292 return;
293 }
294 CHECKPOINT;
295 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
296 CHECKPOINT;
297 if (current->BaseAddress > marea->BaseAddress)
298 {
299 CHECKPOINT;
300 InsertHeadList(ListHead,&marea->Entry);
301 CHECKPOINT;
302 return;
303 }
304 CHECKPOINT;
305 while (current_entry->Flink!=ListHead)
306 {
307 // CHECKPOINT;
308 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
309 next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
310 assert(current->BaseAddress != marea->BaseAddress);
311 assert(next->BaseAddress != marea->BaseAddress);
312 if (current->BaseAddress < marea->BaseAddress &&
313 current->Entry.Flink==ListHead)
314 {
315 current_entry->Flink = inserted_entry;
316 inserted_entry->Flink=ListHead;
317 inserted_entry->Blink=current_entry;
318 ListHead->Blink = inserted_entry;
319 return;
320 }
321 if (current->BaseAddress < marea->BaseAddress &&
322 next->BaseAddress > marea->BaseAddress)
323 {
324 inserted_entry->Flink = current_entry->Flink;
325 inserted_entry->Blink = current_entry;
326 inserted_entry->Flink->Blink = inserted_entry;
327 current_entry->Flink=inserted_entry;
328 return;
329 }
330 current_entry = current_entry->Flink;
331 }
332 CHECKPOINT;
333 InsertTailList(ListHead,inserted_entry);
334 }
335
336 static PVOID MmFindGapWithoutLock(PEPROCESS Process,
337 KPROCESSOR_MODE Mode, ULONG Length)
338 {
339 PLIST_ENTRY ListHead;
340 PLIST_ENTRY current_entry;
341 MEMORY_AREA* current;
342 MEMORY_AREA* next;
343 ULONG Gap;
344
345 DPRINT("MmFindGapWithoutLock(Mode %x Length %x)\n",Mode,Length);
346
347
348 if (Mode == KernelMode)
349 {
350 ListHead = &SystemAreaList;
351 }
352 else
353 {
354 ListHead = &(Process->Pcb.MemoryAreaList);
355 }
356
357
358 current_entry = ListHead->Flink;
359 while (current_entry->Flink!=ListHead)
360 {
361 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
362 next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
363 DPRINT("current %x current->BaseAddress %x ",current,
364 current->BaseAddress);
365 DPRINT("current->Length %x\n",current->Length);
366 DPRINT("next %x next->BaseAddress %x ",next,next->BaseAddress);
367 Gap = (next->BaseAddress ) -(current->BaseAddress + current->Length);
368 DPRINT("Base %x Gap %x\n",current->BaseAddress,Gap);
369 if (Gap >= Length)
370 {
371 return(current->BaseAddress + PAGE_ROUND_UP(current->Length));
372 }
373 current_entry = current_entry->Flink;
374 }
375
376 if (current_entry == ListHead)
377 {
378 assert(Mode==UserMode);
379 return((PVOID)MM_LOWEST_USER_ADDRESS);
380 }
381
382 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
383 //DbgPrint("current %x returning %x\n",current,current->BaseAddress+
384 // current->Length);
385 return(current->BaseAddress + PAGE_ROUND_UP(current->Length));
386 }
387
388 NTSTATUS MmInitMemoryAreas(VOID)
389 /*
390 * FUNCTION: Initialize the memory area list
391 */
392 {
393 DPRINT("MmInitMemoryAreas()\n",0);
394 InitializeListHead(&SystemAreaList);
395 KeInitializeSpinLock(&SystemAreaListLock);
396 return(STATUS_SUCCESS);
397 }
398
399 NTSTATUS MmFreeMemoryArea(PEPROCESS Process,
400 PVOID BaseAddress,
401 ULONG Length,
402 BOOLEAN FreePages)
403 {
404 MEMORY_AREA* MemoryArea;
405 ULONG i;
406 KIRQL oldlvl;
407 LARGE_INTEGER PhysicalAddr;
408
409 DPRINT("MmFreeMemoryArea(Process %x, BaseAddress %x, Length %x,"
410 "FreePages %d)\n",Process,BaseAddress,Length,FreePages);
411
412 if (SystemAreaList.Flink != (&SystemAreaList) &&
413 SystemAreaList.Flink->Flink != (&SystemAreaList))
414 {
415 #ifndef NDEBUG
416 PMEMORY_AREA Snd = CONTAINING_RECORD(SystemAreaList.Flink->Flink,
417 MEMORY_AREA,
418 Entry);
419 DPRINT("SystemAreaList.Flink->Flink->BaseAddress %x\n",
420 Snd->BaseAddress);
421 #endif
422 // assert(Snd->BaseAddress == (PVOID)0x0c001c000);
423 }
424
425 MmLockMemoryAreaList(BaseAddress, &oldlvl);
426
427 MemoryArea = MmOpenMemoryAreaByAddressWithoutLock(Process,
428 BaseAddress);
429 if (MemoryArea==NULL)
430 {
431 MmUnlockMemoryAreaList(BaseAddress, &oldlvl);
432 KeBugCheck(0);
433 return(STATUS_UNSUCCESSFUL);
434 }
435 if (FreePages)
436 {
437 for (i=0;i<=(MemoryArea->Length/PAGESIZE);i++)
438 {
439 PhysicalAddr = MmGetPhysicalAddress(MemoryArea->BaseAddress +
440 (i*PAGESIZE));
441 MmFreePage((PVOID)(ULONG)(PhysicalAddr.u.LowPart), 1);
442 }
443 }
444 for (i=0; i<=(MemoryArea->Length/PAGESIZE); i++)
445 {
446 MmSetPage(NULL,
447 MemoryArea->BaseAddress + (i*PAGESIZE),
448 0,
449 0);
450 }
451
452 RemoveEntryList(&(MemoryArea->Entry));
453 ExFreePool(MemoryArea);
454 MmUnlockMemoryAreaList(BaseAddress, &oldlvl);
455
456 if (SystemAreaList.Flink != (&SystemAreaList) &&
457 SystemAreaList.Flink->Flink != (&SystemAreaList))
458 {
459 #ifndef NDEBUG
460 PMEMORY_AREA Snd = CONTAINING_RECORD(SystemAreaList.Flink->Flink,
461 MEMORY_AREA,
462 Entry);
463 DPRINT("SystemAreaList.Flink->Flink->BaseAddress %x\n",
464 Snd->BaseAddress);
465 #endif
466 // assert(Snd->BaseAddress == (PVOID)0x0c001c000);
467 }
468
469 return(STATUS_SUCCESS);
470 }
471
472 PMEMORY_AREA MmSplitMemoryArea(PEPROCESS Process,
473 PMEMORY_AREA OriginalMemoryArea,
474 PVOID BaseAddress,
475 ULONG Length,
476 ULONG NewType,
477 ULONG NewAttributes)
478 {
479 KIRQL oldlvl;
480 PMEMORY_AREA Result;
481 PMEMORY_AREA Split;
482
483 Result = ExAllocatePool(NonPagedPool,sizeof(MEMORY_AREA));
484 RtlZeroMemory(Result,sizeof(MEMORY_AREA));
485 Result->Type=NewType;
486 Result->BaseAddress=BaseAddress;
487 Result->Length=Length;
488 Result->Attributes=NewAttributes;
489 Result->LockCount=0;
490 Result->Process = Process;
491
492 MmLockMemoryAreaList(OriginalMemoryArea->BaseAddress,&oldlvl);
493
494 // MmDumpMemoryAreas(MmGetRelatedListHead(Process,BaseAddress));
495
496 if (BaseAddress == OriginalMemoryArea->BaseAddress)
497 {
498 OriginalMemoryArea->BaseAddress = BaseAddress + Length;
499 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
500 MmInsertMemoryAreaWithoutLock(Process,Result);
501 MmUnlockMemoryAreaList(OriginalMemoryArea->BaseAddress,&oldlvl);
502
503 // MmDumpMemoryAreas(MmGetRelatedListHead(Process,BaseAddress));
504
505 return(Result);
506 }
507 if ((BaseAddress + Length) ==
508 (OriginalMemoryArea->BaseAddress + OriginalMemoryArea->Length))
509 {
510 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
511 MmInsertMemoryAreaWithoutLock(Process,Result);
512 MmUnlockMemoryAreaList(OriginalMemoryArea->BaseAddress,&oldlvl);
513
514 // MmDumpMemoryAreas(MmGetRelatedListHead(Process,BaseAddress));
515
516 return(Result);
517 }
518
519 Split = ExAllocatePool(NonPagedPool,sizeof(MEMORY_AREA));
520 RtlCopyMemory(Split,OriginalMemoryArea,sizeof(MEMORY_AREA));
521 Split->BaseAddress = BaseAddress + Length;
522 Split->Length = OriginalMemoryArea->Length - (((ULONG)BaseAddress)
523 + Length);
524
525 OriginalMemoryArea->Length = BaseAddress - OriginalMemoryArea->BaseAddress;
526
527 MmUnlockMemoryAreaList(OriginalMemoryArea->BaseAddress,&oldlvl);
528
529 // MmDumpMemoryAreas(MmGetRelatedListHead(Process,BaseAddress));
530
531 return(Split);
532 }
533
534 NTSTATUS MmCreateMemoryArea(KPROCESSOR_MODE Mode,
535 PEPROCESS Process,
536 ULONG Type,
537 PVOID* BaseAddress,
538 ULONG Length,
539 ULONG Attributes,
540 MEMORY_AREA** Result)
541 {
542 KIRQL oldlvl;
543
544 DPRINT("MmCreateMemoryArea(Mode %x, Type %d, BaseAddress %x,"
545 "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
546 Mode,Type,BaseAddress,*BaseAddress,Length,Attributes,Result);
547
548 if (SystemAreaList.Flink != (&SystemAreaList) &&
549 SystemAreaList.Flink->Flink != (&SystemAreaList))
550 {
551 #ifndef NDEBUG
552 PMEMORY_AREA Snd = CONTAINING_RECORD(SystemAreaList.Flink->Flink,
553 MEMORY_AREA,
554 Entry);
555 DPRINT("SystemAreaList.Flink->Flink->BaseAddress %x\n",
556 Snd->BaseAddress);
557 // assert(Snd->BaseAddress == (PVOID)0x0c001c000);
558 #endif
559 }
560
561 if ((*BaseAddress)==0)
562 {
563 MmLockMemoryAreaListByMode(Mode,&oldlvl);
564 }
565 else
566 {
567 MmLockMemoryAreaList(*BaseAddress,&oldlvl);
568 }
569
570 if ((*BaseAddress)==0)
571 {
572 *BaseAddress = MmFindGapWithoutLock(Process,Mode,PAGE_ROUND_UP(Length)
573 +(PAGESIZE*2));
574 if ((*BaseAddress)==0)
575 {
576 DPRINT("No suitable gap\n");
577 MmUnlockMemoryAreaListByMode(Mode,&oldlvl);
578 return(STATUS_UNSUCCESSFUL);
579 }
580 (*BaseAddress)=(*BaseAddress)+PAGESIZE;
581 }
582 else
583 {
584 (*BaseAddress) = (PVOID)PAGE_ROUND_DOWN((*BaseAddress));
585 if (MmOpenMemoryAreaByRegionWithoutLock(Process,
586 *BaseAddress,
587 Length)!=NULL)
588 {
589 DPRINT("Memory area already occupied\n");
590 MmUnlockMemoryAreaList(*BaseAddress,&oldlvl);
591 return(STATUS_UNSUCCESSFUL);
592 }
593 }
594
595 *Result = ExAllocatePool(NonPagedPool,sizeof(MEMORY_AREA));
596 RtlZeroMemory(*Result,sizeof(MEMORY_AREA));
597 (*Result)->Type=Type;
598 (*Result)->BaseAddress=*BaseAddress;
599 (*Result)->Length=Length;
600 (*Result)->Attributes=Attributes;
601 (*Result)->LockCount=0;
602 (*Result)->Process = Process;
603
604 MmInsertMemoryAreaWithoutLock(Process,*Result);
605 MmUnlockMemoryAreaList(*BaseAddress,&oldlvl);
606
607 if (SystemAreaList.Flink != (&SystemAreaList) &&
608 SystemAreaList.Flink->Flink != (&SystemAreaList))
609 {
610 #ifndef NDEBUG
611 PMEMORY_AREA Snd = CONTAINING_RECORD(SystemAreaList.Flink->Flink,
612 MEMORY_AREA,
613 Entry);
614 DPRINT("SystemAreaList.Flink->Flink->BaseAddress %x\n",
615 Snd->BaseAddress);
616 #endif
617 // assert(Snd->BaseAddress == (PVOID)0x0c001c000);
618 }
619
620 return(STATUS_SUCCESS);
621 }