2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/contmem.c
5 * PURPOSE: ARM Memory Manager Contiguous Memory Allocator
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 #line 15 "ARMĀ³::CONTMEM"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
19 /* PRIVATE FUNCTIONS **********************************************************/
23 MiCheckForContiguousMemory(IN PVOID BaseAddress
,
24 IN PFN_NUMBER BaseAddressPages
,
25 IN PFN_NUMBER SizeInPages
,
26 IN PFN_NUMBER LowestPfn
,
27 IN PFN_NUMBER HighestPfn
,
28 IN PFN_NUMBER BoundaryPfn
,
29 IN MI_PFN_CACHE_ATTRIBUTE CacheAttribute
)
31 PMMPTE StartPte
, EndPte
;
32 PFN_NUMBER PreviousPage
= 0, Page
, HighPage
, BoundaryMask
, Pages
= 0;
35 // Okay, first of all check if the PFNs match our restrictions
37 if (LowestPfn
> HighestPfn
) return NULL
;
38 if (LowestPfn
+ SizeInPages
<= LowestPfn
) return NULL
;
39 if (LowestPfn
+ SizeInPages
- 1 > HighestPfn
) return NULL
;
40 if (BaseAddressPages
< SizeInPages
) return NULL
;
43 // This is the last page we need to get to and the boundary requested
45 HighPage
= HighestPfn
+ 1 - SizeInPages
;
46 BoundaryMask
= ~(BoundaryPfn
- 1);
49 // And here's the PTEs for this allocation. Let's go scan them.
51 StartPte
= MiAddressToPte(BaseAddress
);
52 EndPte
= StartPte
+ BaseAddressPages
;
53 while (StartPte
< EndPte
)
56 // Get this PTE's page number
58 ASSERT (StartPte
->u
.Hard
.Valid
== 1);
59 Page
= PFN_FROM_PTE(StartPte
);
62 // Is this the beginning of our adventure?
67 // Check if this PFN is within our range
69 if ((Page
>= LowestPfn
) && (Page
<= HighPage
))
72 // It is! Do you care about boundary (alignment)?
75 (!((Page
^ (Page
+ SizeInPages
- 1)) & BoundaryMask
)))
78 // You don't care, or you do care but we deliver
85 // Have we found all the pages we need by now?
86 // Incidently, this means you only wanted one page
88 if (Pages
== SizeInPages
)
93 return MiPteToAddress(StartPte
);
99 // Have we found a page that doesn't seem to be contiguous?
101 if (Page
!= (PreviousPage
+ 1))
104 // Ah crap, we have to start over
111 // Otherwise, we're still in the game. Do we have all our pages?
113 if (++Pages
== SizeInPages
)
116 // We do! This entire range was contiguous, so we'll return it!
118 return MiPteToAddress(StartPte
- Pages
+ 1);
123 // Try with the next PTE, remember this PFN
131 // All good returns are within the loop...
138 MiFindContiguousMemory(IN PFN_NUMBER LowestPfn
,
139 IN PFN_NUMBER HighestPfn
,
140 IN PFN_NUMBER BoundaryPfn
,
141 IN PFN_NUMBER SizeInPages
,
142 IN MEMORY_CACHING_TYPE CacheType
)
145 PHYSICAL_ADDRESS PhysicalAddress
;
147 ASSERT(SizeInPages
!= 0);
150 // Our last hope is to scan the free page list for contiguous pages
152 Page
= MiFindContiguousPages(LowestPfn
,
157 if (!Page
) return NULL
;
160 // We'll just piggyback on the I/O memory mapper
162 PhysicalAddress
.QuadPart
= Page
<< PAGE_SHIFT
;
163 return MmMapIoSpace(PhysicalAddress
, SizeInPages
<< PAGE_SHIFT
, CacheType
);
168 MiAllocateContiguousMemory(IN SIZE_T NumberOfBytes
,
169 IN PFN_NUMBER LowestAcceptablePfn
,
170 IN PFN_NUMBER HighestAcceptablePfn
,
171 IN PFN_NUMBER BoundaryPfn
,
172 IN MEMORY_CACHING_TYPE CacheType
)
175 PFN_NUMBER SizeInPages
;
176 MI_PFN_CACHE_ATTRIBUTE CacheAttribute
;
177 ASSERT(NumberOfBytes
!= 0);
180 // Compute size requested
182 SizeInPages
= BYTES_TO_PAGES(NumberOfBytes
);
185 // Convert the cache attribute and check for cached requests
187 CacheAttribute
= MiPlatformCacheAttributes
[FALSE
][CacheType
];
188 if (CacheAttribute
== MiCached
)
191 // Because initial nonpaged pool is supposed to be contiguous, go ahead
192 // and try making a nonpaged pool allocation first.
194 BaseAddress
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
200 // Now make sure it's actually contiguous (if it came from expansion
203 if (MiCheckForContiguousMemory(BaseAddress
,
207 HighestAcceptablePfn
,
212 // Sweet, we're in business!
220 ExFreePool(BaseAddress
);
225 // According to MSDN, the system won't try anything else if you're higher
228 if (KeGetCurrentIrql() > APC_LEVEL
) return NULL
;
231 // Otherwise, we'll go try to find some
233 return MiFindContiguousMemory(LowestAcceptablePfn
,
234 HighestAcceptablePfn
,
242 MiFreeContiguousMemory(IN PVOID BaseAddress
)
245 PFN_NUMBER PageFrameIndex
, LastPage
, PageCount
;
246 PMMPFN Pfn1
, StartPfn
;
250 // First, check if the memory came from initial nonpaged pool, or expansion
252 if (((BaseAddress
>= MmNonPagedPoolStart
) &&
253 (BaseAddress
< (PVOID
)((ULONG_PTR
)MmNonPagedPoolStart
+
254 MmSizeOfNonPagedPoolInBytes
))) ||
255 ((BaseAddress
>= MmNonPagedPoolExpansionStart
) &&
256 (BaseAddress
< MmNonPagedPoolEnd
)))
259 // It did, so just use the pool to free this
261 ExFreePool(BaseAddress
);
266 // Otherwise, get the PTE and page number for the allocation
268 PageFrameIndex
= PFN_FROM_PTE(MiAddressToPte(BaseAddress
));
271 // Now get the PFN entry for this, and make sure it's the correct one
273 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
274 if (Pfn1
->u3
.e1
.StartOfAllocation
== 0)
277 // This probably means you did a free on an address that was in between
279 KeBugCheckEx (BAD_POOL_CALLER
,
281 (ULONG_PTR
)BaseAddress
,
287 // Now this PFN isn't the start of any allocation anymore, it's going out
290 Pfn1
->u3
.e1
.StartOfAllocation
= 0;
298 // Until we find the one that marks the end of the allocation
300 } while (Pfn1
++->u3
.e1
.EndOfAllocation
== 0);
303 // Found it, unmark it
306 Pfn1
->u3
.e1
.EndOfAllocation
= 0;
309 // Now compute how many pages this represents
311 PageCount
= (ULONG
)(Pfn1
- StartPfn
+ 1);
314 // So we can know how much to unmap (recall we piggyback on I/O mappings)
316 MmUnmapIoSpace(BaseAddress
, PageCount
<< PAGE_SHIFT
);
319 // Lock the PFN database
321 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
324 // Loop all the pages
326 LastPage
= PageFrameIndex
+ PageCount
;
330 // Free each one, and move on
332 MmReleasePageMemoryConsumer(MC_NPPOOL
, PageFrameIndex
);
333 } while (++PageFrameIndex
< LastPage
);
336 // Release the PFN lock
338 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
341 /* PUBLIC FUNCTIONS ***********************************************************/
348 MmAllocateContiguousMemorySpecifyCache(IN SIZE_T NumberOfBytes
,
349 IN PHYSICAL_ADDRESS LowestAcceptableAddress OPTIONAL
,
350 IN PHYSICAL_ADDRESS HighestAcceptableAddress
,
351 IN PHYSICAL_ADDRESS BoundaryAddressMultiple OPTIONAL
,
352 IN MEMORY_CACHING_TYPE CacheType OPTIONAL
)
354 PFN_NUMBER LowestPfn
, HighestPfn
, BoundaryPfn
;
355 ASSERT (NumberOfBytes
!= 0);
358 // Convert the lowest address into a PFN
360 LowestPfn
= (PFN_NUMBER
)(LowestAcceptableAddress
.QuadPart
>> PAGE_SHIFT
);
361 if (BYTE_OFFSET(LowestAcceptableAddress
.LowPart
)) LowestPfn
++;
364 // Convert and validate the boundary address into a PFN
366 if (BYTE_OFFSET(BoundaryAddressMultiple
.LowPart
)) return NULL
;
367 BoundaryPfn
= (PFN_NUMBER
)(BoundaryAddressMultiple
.QuadPart
>> PAGE_SHIFT
);
370 // Convert the highest address into a PFN
372 HighestPfn
= (PFN_NUMBER
)(HighestAcceptableAddress
.QuadPart
>> PAGE_SHIFT
);
373 if (HighestPfn
> MmHighestPhysicalPage
) HighestPfn
= MmHighestPhysicalPage
;
376 // Validate the PFN bounds
378 if (LowestPfn
> HighestPfn
) return NULL
;
381 // Let the contiguous memory allocator handle it
383 return MiAllocateContiguousMemory(NumberOfBytes
,
395 MmAllocateContiguousMemory(IN ULONG NumberOfBytes
,
396 IN PHYSICAL_ADDRESS HighestAcceptableAddress
)
398 PFN_NUMBER HighestPfn
;
401 // Convert and normalize the highest address into a PFN
403 HighestPfn
= (PFN_NUMBER
)(HighestAcceptableAddress
.QuadPart
>> PAGE_SHIFT
);
404 if (HighestPfn
> MmHighestPhysicalPage
) HighestPfn
= MmHighestPhysicalPage
;
407 // Let the contiguous memory allocator handle it
409 return MiAllocateContiguousMemory(NumberOfBytes
, 0, HighestPfn
, 0, MmCached
);
417 MmFreeContiguousMemory(IN PVOID BaseAddress
)
420 // Let the contiguous memory allocator handle it
422 MiFreeContiguousMemory(BaseAddress
);
430 MmFreeContiguousMemorySpecifyCache(IN PVOID BaseAddress
,
431 IN ULONG NumberOfBytes
,
432 IN MEMORY_CACHING_TYPE CacheType
)
435 // Just call the non-cached version (there's no cache issues for freeing)
437 MiFreeContiguousMemory(BaseAddress
);