Don't use more than a single page for a TEB
[reactos.git] / reactos / ntoskrnl / mm / marea.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001, 2003 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 <ntoskrnl.h>
31 #define NDEBUG
32 #include <internal/debug.h>
33
34 /* GLOBALS *******************************************************************/
35
36 #define TAG_MAREA TAG('M', 'A', 'R', 'E')
37
38 /* FUNCTIONS *****************************************************************/
39
40 VOID MmDumpMemoryAreas(PLIST_ENTRY ListHead)
41 {
42 PLIST_ENTRY current_entry;
43 MEMORY_AREA* current;
44
45 DbgPrint("MmDumpMemoryAreas()\n");
46
47 current_entry = ListHead->Flink;
48 while (current_entry!=ListHead)
49 {
50 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
51 DbgPrint("Base %x Length %x End %x Attributes %x Flink %x\n",
52 current->BaseAddress,current->Length,
53 (char*)current->BaseAddress+current->Length,current->Attributes,
54 current->Entry.Flink);
55 current_entry = current_entry->Flink;
56 }
57 DbgPrint("Finished MmDumpMemoryAreas()\n");
58 }
59
60 MEMORY_AREA* MmOpenMemoryAreaByAddress(PMADDRESS_SPACE AddressSpace,
61 PVOID Address)
62 {
63 PLIST_ENTRY current_entry;
64 MEMORY_AREA* current;
65 PLIST_ENTRY previous_entry;
66
67 DPRINT("MmOpenMemoryAreaByAddress(AddressSpace %x, Address %x)\n",
68 AddressSpace, Address);
69
70 previous_entry = &AddressSpace->MAreaListHead;
71 current_entry = AddressSpace->MAreaListHead.Flink;
72 while (current_entry != &AddressSpace->MAreaListHead)
73 {
74 current = CONTAINING_RECORD(current_entry,
75 MEMORY_AREA,
76 Entry);
77 assert(current_entry->Blink->Flink == current_entry);
78 assert(current_entry->Flink->Blink == current_entry);
79 assert(previous_entry->Flink == current_entry);
80 if (current->BaseAddress <= Address &&
81 (PVOID)((char*)current->BaseAddress + current->Length) > Address)
82 {
83 DPRINT("%s() = %x\n",__FUNCTION__,current);
84 return(current);
85 }
86 if (current->BaseAddress > Address)
87 {
88 DPRINT("%s() = NULL\n",__FUNCTION__);
89 return(NULL);
90 }
91 previous_entry = current_entry;
92 current_entry = current_entry->Flink;
93 }
94 DPRINT("%s() = NULL\n",__FUNCTION__);
95 return(NULL);
96 }
97
98 MEMORY_AREA* MmOpenMemoryAreaByRegion(PMADDRESS_SPACE AddressSpace,
99 PVOID Address,
100 ULONG Length)
101 {
102 PLIST_ENTRY current_entry;
103 MEMORY_AREA* current;
104 ULONG Extent;
105
106 DPRINT("MmOpenMemoryByRegion(AddressSpace %x, Address %x, Length %x)\n",
107 AddressSpace, Address, Length);
108
109 current_entry = AddressSpace->MAreaListHead.Flink;
110 while (current_entry != &AddressSpace->MAreaListHead)
111 {
112 current = CONTAINING_RECORD(current_entry,
113 MEMORY_AREA,
114 Entry);
115 DPRINT("current->BaseAddress %x current->Length %x\n",
116 current->BaseAddress,current->Length);
117 if (current->BaseAddress >= Address &&
118 current->BaseAddress < (PVOID)((char*)Address+Length))
119 {
120 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
121 current);
122 return(current);
123 }
124 Extent = (ULONG)current->BaseAddress + current->Length;
125 if (Extent > (ULONG)Address &&
126 Extent < (ULONG)((char*)Address+Length))
127 {
128 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
129 current);
130 return(current);
131 }
132 if (current->BaseAddress <= Address &&
133 Extent >= (ULONG)((char*)Address+Length))
134 {
135 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
136 current);
137 return(current);
138 }
139 if (current->BaseAddress >= (PVOID)((char*)Address+Length))
140 {
141 DPRINT("Finished MmOpenMemoryAreaByRegion()= NULL\n",0);
142 return(NULL);
143 }
144 current_entry = current_entry->Flink;
145 }
146 DPRINT("Finished MmOpenMemoryAreaByRegion() = NULL\n",0);
147 return(NULL);
148 }
149
150 static VOID MmInsertMemoryArea(PMADDRESS_SPACE AddressSpace,
151 MEMORY_AREA* marea)
152 {
153 PLIST_ENTRY ListHead;
154 PLIST_ENTRY current_entry;
155 PLIST_ENTRY inserted_entry = &marea->Entry;
156 MEMORY_AREA* current;
157 MEMORY_AREA* next;
158
159 DPRINT("MmInsertMemoryArea(marea %x)\n", marea);
160 DPRINT("marea->BaseAddress %x\n", marea->BaseAddress);
161 DPRINT("marea->Length %x\n", marea->Length);
162
163 ListHead = &AddressSpace->MAreaListHead;
164
165 current_entry = ListHead->Flink;
166 if (IsListEmpty(ListHead))
167 {
168 InsertHeadList(ListHead,&marea->Entry);
169 return;
170 }
171 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
172 if (current->BaseAddress > marea->BaseAddress)
173 {
174 InsertHeadList(ListHead,&marea->Entry);
175 return;
176 }
177 while (current_entry->Flink!=ListHead)
178 {
179 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
180 next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
181 if (current->BaseAddress < marea->BaseAddress &&
182 current->Entry.Flink==ListHead)
183 {
184 current_entry->Flink = inserted_entry;
185 inserted_entry->Flink=ListHead;
186 inserted_entry->Blink=current_entry;
187 ListHead->Blink = inserted_entry;
188 return;
189 }
190 if (current->BaseAddress < marea->BaseAddress &&
191 next->BaseAddress > marea->BaseAddress)
192 {
193 inserted_entry->Flink = current_entry->Flink;
194 inserted_entry->Blink = current_entry;
195 inserted_entry->Flink->Blink = inserted_entry;
196 current_entry->Flink=inserted_entry;
197 return;
198 }
199 current_entry = current_entry->Flink;
200 }
201 InsertTailList(ListHead,inserted_entry);
202 }
203
204 static PVOID MmFindGapBottomUp(PMADDRESS_SPACE AddressSpace, ULONG Length, ULONG Granularity)
205 {
206 PLIST_ENTRY ListHead;
207 PLIST_ENTRY current_entry;
208 MEMORY_AREA* current;
209 MEMORY_AREA* next;
210 ULONG Gap;
211 PVOID Address;
212
213 DPRINT("MmFindGapBottomUp(Length %x)\n",Length);
214
215 #ifdef DBG
216 Length += PAGE_SIZE; /* For a guard page following the area */
217 #endif
218
219 ListHead = &AddressSpace->MAreaListHead;
220
221 current_entry = ListHead->Flink;
222 while (current_entry->Flink!=ListHead)
223 {
224 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
225 next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
226 Address = (PVOID) ((char*)current->BaseAddress + PAGE_ROUND_UP(current->Length));
227 #ifdef DBG
228 Address = (PVOID) ((char *) Address + PAGE_SIZE); /* For a guard page preceding the area */
229 #endif
230 Address = (PVOID) MM_ROUND_UP(Address, Granularity);
231 if (Address < next->BaseAddress)
232 {
233 Gap = (char*)next->BaseAddress - ((char*)current->BaseAddress + PAGE_ROUND_UP(current->Length));
234 if (Gap >= Length)
235 {
236 return Address;
237 }
238 }
239 current_entry = current_entry->Flink;
240 }
241
242 if (current_entry == ListHead)
243 {
244 Address = (PVOID) MM_ROUND_UP(AddressSpace->LowestAddress, Granularity);
245 }
246 else
247 {
248 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
249 Address = (char*)current->BaseAddress + PAGE_ROUND_UP(current->Length);
250 #ifdef DBG
251 Address = (PVOID) ((char *) Address + PAGE_SIZE); /* For a guard page preceding the area */
252 #endif
253 Address = (PVOID) MM_ROUND_UP(Address, Granularity);
254 }
255 /* Check if enough space for the block */
256 if (AddressSpace->LowestAddress < KERNEL_BASE)
257 {
258 if ((ULONG_PTR) Address >= KERNEL_BASE || Length > KERNEL_BASE - (ULONG_PTR) Address)
259 {
260 DPRINT1("Failed to find gap\n");
261 return NULL;
262 }
263 }
264 else
265 {
266 if (Length >= ~ ((ULONG_PTR) 0) - (ULONG_PTR) Address)
267 {
268 DPRINT1("Failed to find gap\n");
269 return NULL;
270 }
271 }
272 return Address;
273 }
274
275
276 static PVOID MmFindGapTopDown(PMADDRESS_SPACE AddressSpace, ULONG Length, ULONG Granularity)
277 {
278 PLIST_ENTRY ListHead;
279 PLIST_ENTRY current_entry;
280 MEMORY_AREA* current;
281 ULONG Gap;
282 PVOID Address;
283 PVOID TopAddress;
284 PVOID BottomAddress;
285 PVOID HighestAddress;
286
287 DPRINT("MmFindGapTopDown(Length %lx)\n",Length);
288
289 #ifdef DBG
290 Length += PAGE_SIZE; /* For a guard page following the area */
291 #endif
292
293 if (AddressSpace->LowestAddress < KERNEL_BASE) //(ULONG_PTR)MmSystemRangeStart)
294 {
295 HighestAddress = MmHighestUserAddress;
296 }
297 else
298 {
299 HighestAddress = (PVOID)0xFFFFFFFF;
300 }
301
302 TopAddress = HighestAddress;
303
304 ListHead = &AddressSpace->MAreaListHead;
305 current_entry = ListHead->Blink;
306 while (current_entry->Blink != ListHead)
307 {
308 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
309 BottomAddress = (char*)current->BaseAddress + PAGE_ROUND_UP(current->Length);
310 #ifdef DBG
311 BottomAddress = (PVOID) ((char *) BottomAddress + PAGE_SIZE); /* For a guard page preceding the area */
312 #endif
313 BottomAddress = (PVOID) MM_ROUND_UP(BottomAddress, Granularity);
314 DPRINT("Base %p Length %lx\n", current->BaseAddress, PAGE_ROUND_UP(current->Length));
315
316 if (BottomAddress < TopAddress && BottomAddress < HighestAddress)
317 {
318 Gap = (char*)TopAddress - (char*) BottomAddress + 1;
319 DPRINT("Bottom %p Top %p Gap %lx\n", BottomAddress, TopAddress, Gap);
320 if (Gap >= Length)
321 {
322 DPRINT("Found gap at %p\n", (char*) TopAddress - Length);
323 return (PVOID) MM_ROUND_DOWN((char*) TopAddress - Length + 1, Granularity);
324 }
325 }
326 TopAddress = (char*)current->BaseAddress - 1;
327 current_entry = current_entry->Blink;
328 }
329
330 if (current_entry == ListHead)
331 {
332 Address = (PVOID) MM_ROUND_DOWN((char*) HighestAddress - Length + 1, Granularity);
333 }
334 else
335 {
336 Address = (PVOID) MM_ROUND_DOWN((char*)TopAddress - Length + 1, Granularity);
337 }
338
339 /* Check if enough space for the block */
340 if (AddressSpace->LowestAddress < KERNEL_BASE)
341 {
342 if ((ULONG_PTR) Address >= KERNEL_BASE || Length > KERNEL_BASE - (ULONG_PTR) Address)
343 {
344 DPRINT1("Failed to find gap\n");
345 return NULL;
346 }
347 }
348 else
349 {
350 if (Length >= ~ ((ULONG_PTR) 0) - (ULONG_PTR) Address)
351 {
352 DPRINT1("Failed to find gap\n");
353 return NULL;
354 }
355 }
356
357 DPRINT("Found gap at %p\n", Address);
358 return Address;
359 }
360
361
362 PVOID MmFindGap(PMADDRESS_SPACE AddressSpace, ULONG Length, ULONG Granularity, BOOL TopDown)
363 {
364 if (TopDown)
365 return MmFindGapTopDown(AddressSpace, Length, Granularity);
366
367 return MmFindGapBottomUp(AddressSpace, Length, Granularity);
368 }
369
370 ULONG MmFindGapAtAddress(PMADDRESS_SPACE AddressSpace, PVOID Address)
371 {
372 PLIST_ENTRY current_entry, ListHead;
373 PMEMORY_AREA current;
374
375 Address = (PVOID)PAGE_ROUND_DOWN(Address);
376
377 if (AddressSpace->LowestAddress < KERNEL_BASE)
378 {
379 if (Address >= (PVOID)KERNEL_BASE)
380 {
381 return 0;
382 }
383 }
384 else
385 {
386 if ((ULONG_PTR)Address < AddressSpace->LowestAddress)
387 {
388 return 0;
389 }
390 }
391
392 ListHead = &AddressSpace->MAreaListHead;
393
394 current_entry = ListHead->Flink;
395 while (current_entry != ListHead)
396 {
397 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
398 if (current->BaseAddress <= Address && (char*)Address < (char*)current->BaseAddress + current->Length)
399 {
400 return 0;
401 }
402 else if (current->BaseAddress > Address)
403 {
404 return (ULONG_PTR)current->BaseAddress - (ULONG_PTR)Address;
405 }
406 current_entry = current_entry->Flink;
407 }
408 if (AddressSpace->LowestAddress < KERNEL_BASE)
409 {
410 return KERNEL_BASE - (ULONG_PTR)Address;
411 }
412 else
413 {
414 return 0 - (ULONG_PTR)Address;
415 }
416 }
417
418 NTSTATUS INIT_FUNCTION
419 MmInitMemoryAreas(VOID)
420 /*
421 * FUNCTION: Initialize the memory area list
422 */
423 {
424 DPRINT("MmInitMemoryAreas()\n",0);
425 return(STATUS_SUCCESS);
426 }
427
428 NTSTATUS
429 MmFreeMemoryArea(PMADDRESS_SPACE AddressSpace,
430 PVOID BaseAddress,
431 ULONG Length,
432 VOID (*FreePage)(PVOID Context, MEMORY_AREA* MemoryArea,
433 PVOID Address, PFN_TYPE Page,
434 SWAPENTRY SwapEntry, BOOLEAN Dirty),
435 PVOID FreePageContext)
436 {
437 MEMORY_AREA* MemoryArea;
438 char* Address;
439 char* EndAddress;
440 PEPROCESS CurrentProcess = PsGetCurrentProcess();
441
442 DPRINT("MmFreeMemoryArea(AddressSpace %x, BaseAddress %x, Length %x,"
443 "FreePageContext %d)\n",AddressSpace,BaseAddress,Length,
444 FreePageContext);
445
446 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
447 BaseAddress);
448 if (MemoryArea == NULL)
449 {
450 KEBUGCHECK(0);
451 return(STATUS_UNSUCCESSFUL);
452 }
453 if (AddressSpace->Process != NULL &&
454 AddressSpace->Process != CurrentProcess)
455 {
456 KeAttachProcess(AddressSpace->Process);
457 }
458 EndAddress = (char*)MemoryArea->BaseAddress + PAGE_ROUND_UP(MemoryArea->Length);
459 for (Address = MemoryArea->BaseAddress; Address < EndAddress; Address += PAGE_SIZE)
460 {
461
462 if (MemoryArea->Type == MEMORY_AREA_IO_MAPPING)
463 {
464 MmRawDeleteVirtualMapping(Address);
465 }
466 else
467 {
468 BOOL Dirty = FALSE;
469 SWAPENTRY SwapEntry = 0;
470 PFN_TYPE Page = 0;
471
472
473 if (MmIsPageSwapEntry(AddressSpace->Process, Address))
474 {
475 MmDeletePageFileMapping(AddressSpace->Process, Address, &SwapEntry);
476 }
477 else
478 {
479 MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, &Dirty, &Page);
480 }
481 if (FreePage != NULL)
482 {
483 FreePage(FreePageContext, MemoryArea, Address,
484 Page, SwapEntry, (BOOLEAN)Dirty);
485 }
486 }
487 }
488 if (AddressSpace->Process != NULL &&
489 AddressSpace->Process != CurrentProcess)
490 {
491 KeDetachProcess();
492 }
493 RemoveEntryList(&MemoryArea->Entry);
494 ExFreePool(MemoryArea);
495
496 DPRINT("MmFreeMemoryArea() succeeded\n");
497
498 return(STATUS_SUCCESS);
499 }
500
501 PMEMORY_AREA MmSplitMemoryArea(PEPROCESS Process,
502 PMADDRESS_SPACE AddressSpace,
503 PMEMORY_AREA OriginalMemoryArea,
504 PVOID BaseAddress,
505 ULONG Length,
506 ULONG NewType,
507 ULONG NewAttributes)
508 {
509 PMEMORY_AREA Result;
510 PMEMORY_AREA Split;
511
512 Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
513 TAG_MAREA);
514 RtlZeroMemory(Result,sizeof(MEMORY_AREA));
515 Result->Type = NewType;
516 Result->BaseAddress = BaseAddress;
517 Result->Length = Length;
518 Result->Attributes = NewAttributes;
519 Result->LockCount = 0;
520 Result->Process = Process;
521
522 if (BaseAddress == OriginalMemoryArea->BaseAddress)
523 {
524 OriginalMemoryArea->BaseAddress = (char*)BaseAddress + Length;
525 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
526 MmInsertMemoryArea(AddressSpace, Result);
527 return(Result);
528 }
529 if (((char*)BaseAddress + Length) ==
530 ((char*)OriginalMemoryArea->BaseAddress + OriginalMemoryArea->Length))
531 {
532 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
533 MmInsertMemoryArea(AddressSpace, Result);
534
535 return(Result);
536 }
537
538 Split = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
539 TAG_MAREA);
540 RtlCopyMemory(Split,OriginalMemoryArea,sizeof(MEMORY_AREA));
541 Split->BaseAddress = (char*)BaseAddress + Length;
542 Split->Length = OriginalMemoryArea->Length - (((ULONG)BaseAddress)
543 + Length);
544
545 OriginalMemoryArea->Length = (char*)BaseAddress - (char*)OriginalMemoryArea->BaseAddress;
546
547 return(Split);
548 }
549
550 NTSTATUS MmCreateMemoryArea(PEPROCESS Process,
551 PMADDRESS_SPACE AddressSpace,
552 ULONG Type,
553 PVOID* BaseAddress,
554 ULONG Length,
555 ULONG Attributes,
556 MEMORY_AREA** Result,
557 BOOL FixedAddress,
558 BOOL TopDown,
559 PHYSICAL_ADDRESS BoundaryAddressMultiple)
560 /*
561 * FUNCTION: Create a memory area
562 * ARGUMENTS:
563 * AddressSpace = Address space to create the area in
564 * Type = Type of the address space
565 * BaseAddress =
566 * Length = Length to allocate
567 * Attributes = Protection attributes for the memory area
568 * Result = Receives a pointer to the memory area on exit
569 * RETURNS: Status
570 * NOTES: Lock the address space before calling this function
571 */
572 {
573 PVOID EndAddress;
574 ULONG Granularity;
575 ULONG tmpLength;
576 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %x,"
577 "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
578 Type,BaseAddress,*BaseAddress,Length,Attributes,Result);
579
580 Granularity = (MEMORY_AREA_VIRTUAL_MEMORY == Type ? MM_VIRTMEM_GRANULARITY : PAGE_SIZE);
581 if ((*BaseAddress) == 0 && !FixedAddress)
582 {
583 tmpLength = PAGE_ROUND_UP(Length);
584 *BaseAddress = MmFindGap(AddressSpace,
585 PAGE_ROUND_UP(Length),
586 Granularity,
587 TopDown);
588 if ((*BaseAddress) == 0)
589 {
590 DPRINT("No suitable gap\n");
591 return STATUS_NO_MEMORY;
592 }
593 }
594 else
595 {
596 tmpLength = Length + ((ULONG_PTR) *BaseAddress
597 - (ULONG_PTR) MM_ROUND_DOWN(*BaseAddress, Granularity));
598 *BaseAddress = MM_ROUND_DOWN(*BaseAddress, Granularity);
599
600 if (AddressSpace->LowestAddress == KERNEL_BASE &&
601 (*BaseAddress) < (PVOID)KERNEL_BASE)
602 {
603 return STATUS_ACCESS_VIOLATION;
604 }
605
606 if (AddressSpace->LowestAddress < KERNEL_BASE &&
607 (PVOID)((char*)(*BaseAddress) + tmpLength) > (PVOID)KERNEL_BASE)
608 {
609 return STATUS_ACCESS_VIOLATION;
610 }
611
612 if (BoundaryAddressMultiple.QuadPart != 0)
613 {
614 EndAddress = ((char*)(*BaseAddress)) + tmpLength-1;
615 assert(((DWORD_PTR)*BaseAddress/BoundaryAddressMultiple.QuadPart) == ((DWORD_PTR)EndAddress/BoundaryAddressMultiple.QuadPart));
616 }
617
618 if (MmOpenMemoryAreaByRegion(AddressSpace,
619 *BaseAddress,
620 tmpLength)!=NULL)
621 {
622 DPRINT("Memory area already occupied\n");
623 return STATUS_CONFLICTING_ADDRESSES;
624 }
625 }
626
627 *Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
628 TAG_MAREA);
629 RtlZeroMemory(*Result,sizeof(MEMORY_AREA));
630 (*Result)->Type = Type;
631 (*Result)->BaseAddress = *BaseAddress;
632 (*Result)->Length = tmpLength;
633 (*Result)->Attributes = Attributes;
634 (*Result)->LockCount = 0;
635 (*Result)->Process = Process;
636 (*Result)->PageOpCount = 0;
637 (*Result)->DeleteInProgress = FALSE;
638
639 MmInsertMemoryArea(AddressSpace, *Result);
640
641 DPRINT("MmCreateMemoryArea() succeeded\n");
642 return STATUS_SUCCESS;
643 }
644
645
646 void
647 MmReleaseMemoryAreaIfDecommitted(PEPROCESS Process,
648 PMADDRESS_SPACE AddressSpace,
649 PVOID BaseAddress)
650 {
651 PMEMORY_AREA MemoryArea;
652 PLIST_ENTRY Entry;
653 PMM_REGION Region;
654 BOOLEAN Reserved;
655
656 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, BaseAddress);
657 if (NULL != MemoryArea)
658 {
659 Entry = MemoryArea->Data.VirtualMemoryData.RegionListHead.Flink;
660 Reserved = TRUE;
661 while (Reserved && Entry != &MemoryArea->Data.VirtualMemoryData.RegionListHead)
662 {
663 Region = CONTAINING_RECORD(Entry, MM_REGION, RegionListEntry);
664 Reserved = (MEM_RESERVE == Region->Type);
665 Entry = Entry->Flink;
666 }
667
668 if (Reserved)
669 {
670 DPRINT("Release TebBlock at %p\n", TebBlock);
671 MmFreeVirtualMemory(Process, MemoryArea);
672 }
673 }
674 }
675
676 /* EOF */