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
;
179 // Verify count and cache type
181 ASSERT(NumberOfBytes
!= 0);
182 ASSERT(CacheType
<= MmWriteCombined
);
185 // Compute size requested
187 SizeInPages
= BYTES_TO_PAGES(NumberOfBytes
);
190 // Convert the cache attribute and check for cached requests
192 CacheAttribute
= MiPlatformCacheAttributes
[FALSE
][CacheType
];
193 if (CacheAttribute
== MiCached
)
196 // Because initial nonpaged pool is supposed to be contiguous, go ahead
197 // and try making a nonpaged pool allocation first.
199 BaseAddress
= ExAllocatePoolWithTag(NonPagedPoolCacheAligned
,
205 // Now make sure it's actually contiguous (if it came from expansion
208 if (MiCheckForContiguousMemory(BaseAddress
,
212 HighestAcceptablePfn
,
217 // Sweet, we're in business!
225 ExFreePool(BaseAddress
);
230 // According to MSDN, the system won't try anything else if you're higher
233 if (KeGetCurrentIrql() > APC_LEVEL
) return NULL
;
236 // Otherwise, we'll go try to find some
238 return MiFindContiguousMemory(LowestAcceptablePfn
,
239 HighestAcceptablePfn
,
247 MiFreeContiguousMemory(IN PVOID BaseAddress
)
250 PFN_NUMBER PageFrameIndex
, LastPage
, PageCount
;
251 PMMPFN Pfn1
, StartPfn
;
255 // First, check if the memory came from initial nonpaged pool, or expansion
257 if (((BaseAddress
>= MmNonPagedPoolStart
) &&
258 (BaseAddress
< (PVOID
)((ULONG_PTR
)MmNonPagedPoolStart
+
259 MmSizeOfNonPagedPoolInBytes
))) ||
260 ((BaseAddress
>= MmNonPagedPoolExpansionStart
) &&
261 (BaseAddress
< MmNonPagedPoolEnd
)))
264 // It did, so just use the pool to free this
266 ExFreePool(BaseAddress
);
271 // Otherwise, get the PTE and page number for the allocation
273 PageFrameIndex
= PFN_FROM_PTE(MiAddressToPte(BaseAddress
));
276 // Now get the PFN entry for this, and make sure it's the correct one
278 Pfn1
= MiGetPfnEntry(PageFrameIndex
);
279 if (Pfn1
->u3
.e1
.StartOfAllocation
== 0)
282 // This probably means you did a free on an address that was in between
284 KeBugCheckEx (BAD_POOL_CALLER
,
286 (ULONG_PTR
)BaseAddress
,
292 // Now this PFN isn't the start of any allocation anymore, it's going out
295 Pfn1
->u3
.e1
.StartOfAllocation
= 0;
303 // Until we find the one that marks the end of the allocation
305 } while (Pfn1
++->u3
.e1
.EndOfAllocation
== 0);
308 // Found it, unmark it
311 Pfn1
->u3
.e1
.EndOfAllocation
= 0;
314 // Now compute how many pages this represents
316 PageCount
= (ULONG
)(Pfn1
- StartPfn
+ 1);
319 // So we can know how much to unmap (recall we piggyback on I/O mappings)
321 MmUnmapIoSpace(BaseAddress
, PageCount
<< PAGE_SHIFT
);
324 // Lock the PFN database
326 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
329 // Loop all the pages
331 LastPage
= PageFrameIndex
+ PageCount
;
335 // Free each one, and move on
337 MmReleasePageMemoryConsumer(MC_NPPOOL
, PageFrameIndex
);
338 } while (++PageFrameIndex
< LastPage
);
341 // Release the PFN lock
343 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
346 /* PUBLIC FUNCTIONS ***********************************************************/
353 MmAllocateContiguousMemorySpecifyCache(IN SIZE_T NumberOfBytes
,
354 IN PHYSICAL_ADDRESS LowestAcceptableAddress OPTIONAL
,
355 IN PHYSICAL_ADDRESS HighestAcceptableAddress
,
356 IN PHYSICAL_ADDRESS BoundaryAddressMultiple OPTIONAL
,
357 IN MEMORY_CACHING_TYPE CacheType OPTIONAL
)
359 PFN_NUMBER LowestPfn
, HighestPfn
, BoundaryPfn
;
362 // Verify count and cache type
364 ASSERT(NumberOfBytes
!= 0);
365 ASSERT(CacheType
<= MmWriteCombined
);
368 // Convert the lowest address into a PFN
370 LowestPfn
= (PFN_NUMBER
)(LowestAcceptableAddress
.QuadPart
>> PAGE_SHIFT
);
371 if (BYTE_OFFSET(LowestAcceptableAddress
.LowPart
)) LowestPfn
++;
374 // Convert and validate the boundary address into a PFN
376 if (BYTE_OFFSET(BoundaryAddressMultiple
.LowPart
)) return NULL
;
377 BoundaryPfn
= (PFN_NUMBER
)(BoundaryAddressMultiple
.QuadPart
>> PAGE_SHIFT
);
380 // Convert the highest address into a PFN
382 HighestPfn
= (PFN_NUMBER
)(HighestAcceptableAddress
.QuadPart
>> PAGE_SHIFT
);
383 if (HighestPfn
> MmHighestPhysicalPage
) HighestPfn
= MmHighestPhysicalPage
;
386 // Validate the PFN bounds
388 if (LowestPfn
> HighestPfn
) return NULL
;
391 // Let the contiguous memory allocator handle it
393 return MiAllocateContiguousMemory(NumberOfBytes
,
405 MmAllocateContiguousMemory(IN ULONG NumberOfBytes
,
406 IN PHYSICAL_ADDRESS HighestAcceptableAddress
)
408 PFN_NUMBER HighestPfn
;
413 ASSERT(NumberOfBytes
!= 0);
416 // Convert and normalize the highest address into a PFN
418 HighestPfn
= (PFN_NUMBER
)(HighestAcceptableAddress
.QuadPart
>> PAGE_SHIFT
);
419 if (HighestPfn
> MmHighestPhysicalPage
) HighestPfn
= MmHighestPhysicalPage
;
422 // Let the contiguous memory allocator handle it
424 return MiAllocateContiguousMemory(NumberOfBytes
, 0, HighestPfn
, 0, MmCached
);
432 MmFreeContiguousMemory(IN PVOID BaseAddress
)
435 // Let the contiguous memory allocator handle it
437 MiFreeContiguousMemory(BaseAddress
);
445 MmFreeContiguousMemorySpecifyCache(IN PVOID BaseAddress
,
446 IN ULONG NumberOfBytes
,
447 IN MEMORY_CACHING_TYPE CacheType
)
450 // Just call the non-cached version (there's no cache issues for freeing)
452 MiFreeContiguousMemory(BaseAddress
);