2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/mm/ARM3/syspte.c
5 * PURPOSE: ARM Memory Manager System PTE Allocator
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 #line 15 "ARMĀ³::SYSPTE"
16 #define MODULE_INVOLVED_IN_ARM3
17 #include "../ARM3/miarm.h"
19 /* GLOBALS ********************************************************************/
21 PMMPTE MmSystemPteBase
;
22 PMMPTE MmSystemPtesStart
[MaximumPtePoolTypes
];
23 PMMPTE MmSystemPtesEnd
[MaximumPtePoolTypes
];
24 MMPTE MmFirstFreeSystemPte
[MaximumPtePoolTypes
];
25 ULONG MmTotalFreeSystemPtes
[MaximumPtePoolTypes
];
26 ULONG MmTotalSystemPtes
;
28 /* PRIVATE FUNCTIONS **********************************************************/
32 MiReserveAlignedSystemPtes(IN ULONG NumberOfPtes
,
33 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
,
37 PMMPTE PointerPte
, NextPte
, PreviousPte
;
38 ULONG_PTR ClusterSize
;
43 ASSERT(Alignment
<= PAGE_SIZE
);
46 // Lock the system PTE space
48 OldIrql
= KeAcquireQueuedSpinLock(LockQueueSystemSpaceLock
);
51 // Get the first free cluster and make sure we have PTEs available
53 PointerPte
= &MmFirstFreeSystemPte
[SystemPtePoolType
];
54 if (PointerPte
->u
.List
.NextEntry
== ((ULONG
)0xFFFFF))
59 KeReleaseQueuedSpinLock(LockQueueSystemSpaceLock
, OldIrql
);
64 // Now move to the first free system PTE cluster
66 PreviousPte
= PointerPte
;
67 PointerPte
= MmSystemPteBase
+ PointerPte
->u
.List
.NextEntry
;
75 // Check if we're done to only one PTE left
77 if (!PointerPte
->u
.List
.OneEntry
)
80 // Keep track of the next cluster in case we have to relink
82 NextPte
= PointerPte
+ 1;
85 // Can this cluster satisfy the request?
87 ClusterSize
= (ULONG_PTR
)NextPte
->u
.List
.NextEntry
;
88 if (NumberOfPtes
< ClusterSize
)
91 // It can, and it will leave just one PTE left
93 if ((ClusterSize
- NumberOfPtes
) == 1)
96 // This cluster becomes a single system PTE entry
98 PointerPte
->u
.List
.OneEntry
= 1;
103 // Otherwise, the next cluster aborbs what's left
105 NextPte
->u
.List
.NextEntry
= ClusterSize
- NumberOfPtes
;
109 // Decrement the free count and move to the next starting PTE
111 MmTotalFreeSystemPtes
[SystemPtePoolType
] -= NumberOfPtes
;
112 PointerPte
+= (ClusterSize
- NumberOfPtes
);
117 // Did we find exactly what you wanted?
119 if (NumberOfPtes
== ClusterSize
)
122 // Yes, fixup the cluster and decrease free system PTE count
124 PreviousPte
->u
.List
.NextEntry
= PointerPte
->u
.List
.NextEntry
;
125 MmTotalFreeSystemPtes
[SystemPtePoolType
] -= NumberOfPtes
;
129 else if (NumberOfPtes
== 1)
132 // We have one PTE in this cluster, and it's all you want
134 PreviousPte
->u
.List
.NextEntry
= PointerPte
->u
.List
.NextEntry
;
135 MmTotalFreeSystemPtes
[SystemPtePoolType
]--;
140 // We couldn't find what you wanted -- is this the last cluster?
142 if (PointerPte
->u
.List
.NextEntry
== ((ULONG
)0xFFFFF))
147 KeReleaseQueuedSpinLock(LockQueueSystemSpaceLock
, OldIrql
);
152 // Go to the next cluster
154 PreviousPte
= PointerPte
;
155 PointerPte
= MmSystemPteBase
+ PointerPte
->u
.List
.NextEntry
;
156 ASSERT(PointerPte
> PreviousPte
);
160 // Release the lock, flush the TLB and return the first PTE
162 KeReleaseQueuedSpinLock(LockQueueSystemSpaceLock
, OldIrql
);
169 MiReserveSystemPtes(IN ULONG NumberOfPtes
,
170 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
)
175 // Use the extended function
177 PointerPte
= MiReserveAlignedSystemPtes(NumberOfPtes
, SystemPtePoolType
, 0);
180 // Check if allocation failed
185 // Warn that we are out of memory
187 DPRINT1("MiReserveSystemPtes: Failed to reserve %lu PTE(s)!\n", NumberOfPtes
);
191 // Return the PTE Pointer
198 MiReleaseSystemPtes(IN PMMPTE StartingPte
,
199 IN ULONG NumberOfPtes
,
200 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
)
203 ULONG_PTR ClusterSize
, CurrentSize
;
204 PMMPTE CurrentPte
, NextPte
, PointerPte
;
207 // Check to make sure the PTE address is within bounds
209 ASSERT(NumberOfPtes
!= 0);
210 ASSERT(StartingPte
>= MmSystemPtesStart
[SystemPtePoolType
]);
211 ASSERT(StartingPte
<= MmSystemPtesEnd
[SystemPtePoolType
]);
216 RtlZeroMemory(StartingPte
, NumberOfPtes
* sizeof(MMPTE
));
217 CurrentSize
= (ULONG_PTR
)(StartingPte
- MmSystemPteBase
);
220 // Acquire the system PTE lock
222 OldIrql
= KeAcquireQueuedSpinLock(LockQueueSystemSpaceLock
);
225 // Increase availability
227 MmTotalFreeSystemPtes
[SystemPtePoolType
] += NumberOfPtes
;
230 // Get the free cluster and start going through them
232 CurrentPte
= &MmFirstFreeSystemPte
[SystemPtePoolType
];
236 // Get the first real cluster of PTEs and check if it's ours
238 PointerPte
= MmSystemPteBase
+ CurrentPte
->u
.List
.NextEntry
;
239 if (CurrentSize
< CurrentPte
->u
.List
.NextEntry
)
244 ASSERT(((StartingPte
+ NumberOfPtes
) <= PointerPte
) ||
245 (CurrentPte
->u
.List
.NextEntry
== ((ULONG
)0xFFFFF)));
248 // Get the next cluster in case it's the one
250 NextPte
= CurrentPte
+ 1;
253 // Check if this was actually a single-PTE entry
255 if (CurrentPte
->u
.List
.OneEntry
)
258 // We only have one page
265 // The next cluster will have the page count
267 ClusterSize
= (ULONG_PTR
)NextPte
->u
.List
.NextEntry
;
271 // So check if this cluster actually describes the entire mapping
273 if ((CurrentPte
+ ClusterSize
) == StartingPte
)
276 // It does -- collapse the free PTEs into the next cluster
278 NumberOfPtes
+= ClusterSize
;
279 NextPte
->u
.List
.NextEntry
= NumberOfPtes
;
280 CurrentPte
->u
.List
.OneEntry
= 0;
285 StartingPte
= CurrentPte
;
290 // There's still PTEs left -- make us into a cluster
292 StartingPte
->u
.List
.NextEntry
= CurrentPte
->u
.List
.NextEntry
;
293 CurrentPte
->u
.List
.NextEntry
= CurrentSize
;
296 // Is there just one page left?
298 if (NumberOfPtes
== 1)
301 // Then this actually becomes a single PTE entry
303 StartingPte
->u
.List
.OneEntry
= 1;
308 // Otherwise, create a new cluster for the remaining pages
310 StartingPte
->u
.List
.OneEntry
= 0;
311 NextPte
= StartingPte
+ 1;
312 NextPte
->u
.List
.NextEntry
= NumberOfPtes
;
317 // Now check if we've arrived at yet another cluster
319 if ((StartingPte
+ NumberOfPtes
) == PointerPte
)
322 // We'll collapse the next cluster into us
324 StartingPte
->u
.List
.NextEntry
= PointerPte
->u
.List
.NextEntry
;
325 StartingPte
->u
.List
.OneEntry
= 0;
326 NextPte
= StartingPte
+ 1;
329 // Check if the cluster only had one page
331 if (PointerPte
->u
.List
.OneEntry
)
341 // Otherwise, grab the page count from the next-next cluster
344 ClusterSize
= (ULONG_PTR
)PointerPte
->u
.List
.NextEntry
;
348 // And create the final combined cluster
350 NextPte
->u
.List
.NextEntry
= NumberOfPtes
+ ClusterSize
;
354 // We released the PTEs into their cluster (and optimized the list)
356 KeReleaseQueuedSpinLock(LockQueueSystemSpaceLock
, OldIrql
);
361 // Try the next cluster of PTEs...
363 CurrentPte
= PointerPte
;
369 MiInitializeSystemPtes(IN PMMPTE StartingPte
,
370 IN ULONG NumberOfPtes
,
371 IN MMSYSTEM_PTE_POOL_TYPE PoolType
)
376 ASSERT(NumberOfPtes
>= 1);
379 // Set the starting and ending PTE addresses for this space
381 MmSystemPteBase
= (PVOID
)PTE_BASE
;
382 MmSystemPtesStart
[PoolType
] = StartingPte
;
383 MmSystemPtesEnd
[PoolType
] = StartingPte
+ NumberOfPtes
- 1;
384 DPRINT("System PTE space for %d starting at: %p and ending at: %p\n",
385 PoolType
, MmSystemPtesStart
[PoolType
], MmSystemPtesEnd
[PoolType
]);
388 // Clear all the PTEs to start with
390 RtlZeroMemory(StartingPte
, NumberOfPtes
* sizeof(MMPTE
));
393 // Make the first entry free and link it
395 StartingPte
->u
.List
.NextEntry
= ((ULONG
)0xFFFFF);
396 MmFirstFreeSystemPte
[PoolType
].u
.Long
= 0;
397 MmFirstFreeSystemPte
[PoolType
].u
.List
.NextEntry
= StartingPte
-
401 // The second entry stores the size of this PTE space
404 StartingPte
->u
.Long
= 0;
405 StartingPte
->u
.List
.NextEntry
= NumberOfPtes
;
408 // We also keep a global for it
410 MmTotalFreeSystemPtes
[PoolType
] = NumberOfPtes
;
413 // Check if this is the system PTE space
415 if (PoolType
== SystemPteSpace
)
418 // Remember how many PTEs we have
420 MmTotalSystemPtes
= NumberOfPtes
;