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 #define MODULE_INVOLVED_IN_ARM3
16 #include "../ARM3/miarm.h"
18 /* GLOBALS ********************************************************************/
20 PMMPTE MmSystemPteBase
;
21 PMMPTE MmSystemPtesStart
[MaximumPtePoolTypes
];
22 PMMPTE MmSystemPtesEnd
[MaximumPtePoolTypes
];
23 MMPTE MmFirstFreeSystemPte
[MaximumPtePoolTypes
];
24 ULONG MmTotalFreeSystemPtes
[MaximumPtePoolTypes
];
25 ULONG MmTotalSystemPtes
;
27 /* PRIVATE FUNCTIONS **********************************************************/
31 MiReserveAlignedSystemPtes(IN ULONG NumberOfPtes
,
32 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
,
36 PMMPTE PointerPte
, NextPte
, PreviousPte
;
37 ULONG_PTR ClusterSize
;
42 ASSERT(Alignment
<= PAGE_SIZE
);
45 // Lock the system PTE space
47 OldIrql
= KeAcquireQueuedSpinLock(LockQueueSystemSpaceLock
);
50 // Get the first free cluster and make sure we have PTEs available
52 PointerPte
= &MmFirstFreeSystemPte
[SystemPtePoolType
];
53 if (PointerPte
->u
.List
.NextEntry
== ((ULONG
)0xFFFFF))
58 KeReleaseQueuedSpinLock(LockQueueSystemSpaceLock
, OldIrql
);
63 // Now move to the first free system PTE cluster
65 PreviousPte
= PointerPte
;
66 PointerPte
= MmSystemPteBase
+ PointerPte
->u
.List
.NextEntry
;
74 // Check if we're done to only one PTE left
76 if (!PointerPte
->u
.List
.OneEntry
)
79 // Keep track of the next cluster in case we have to relink
81 NextPte
= PointerPte
+ 1;
84 // Can this cluster satisfy the request?
86 ClusterSize
= (ULONG_PTR
)NextPte
->u
.List
.NextEntry
;
87 if (NumberOfPtes
< ClusterSize
)
90 // It can, and it will leave just one PTE left
92 if ((ClusterSize
- NumberOfPtes
) == 1)
95 // This cluster becomes a single system PTE entry
97 PointerPte
->u
.List
.OneEntry
= 1;
102 // Otherwise, the next cluster aborbs what's left
104 NextPte
->u
.List
.NextEntry
= ClusterSize
- NumberOfPtes
;
108 // Decrement the free count and move to the next starting PTE
110 MmTotalFreeSystemPtes
[SystemPtePoolType
] -= NumberOfPtes
;
111 PointerPte
+= (ClusterSize
- NumberOfPtes
);
116 // Did we find exactly what you wanted?
118 if (NumberOfPtes
== ClusterSize
)
121 // Yes, fixup the cluster and decrease free system PTE count
123 PreviousPte
->u
.List
.NextEntry
= PointerPte
->u
.List
.NextEntry
;
124 MmTotalFreeSystemPtes
[SystemPtePoolType
] -= NumberOfPtes
;
128 else if (NumberOfPtes
== 1)
131 // We have one PTE in this cluster, and it's all you want
133 PreviousPte
->u
.List
.NextEntry
= PointerPte
->u
.List
.NextEntry
;
134 MmTotalFreeSystemPtes
[SystemPtePoolType
]--;
139 // We couldn't find what you wanted -- is this the last cluster?
141 if (PointerPte
->u
.List
.NextEntry
== ((ULONG
)0xFFFFF))
146 KeReleaseQueuedSpinLock(LockQueueSystemSpaceLock
, OldIrql
);
151 // Go to the next cluster
153 PreviousPte
= PointerPte
;
154 PointerPte
= MmSystemPteBase
+ PointerPte
->u
.List
.NextEntry
;
155 ASSERT(PointerPte
> PreviousPte
);
159 // Release the lock, flush the TLB and return the first PTE
161 KeReleaseQueuedSpinLock(LockQueueSystemSpaceLock
, OldIrql
);
168 MiReserveSystemPtes(IN ULONG NumberOfPtes
,
169 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
)
174 // Use the extended function
176 PointerPte
= MiReserveAlignedSystemPtes(NumberOfPtes
, SystemPtePoolType
, 0);
179 // Check if allocation failed
184 // Warn that we are out of memory
186 DPRINT1("MiReserveSystemPtes: Failed to reserve %lu PTE(s)!\n", NumberOfPtes
);
190 // Return the PTE Pointer
197 MiReleaseSystemPtes(IN PMMPTE StartingPte
,
198 IN ULONG NumberOfPtes
,
199 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
)
202 ULONG_PTR ClusterSize
, CurrentSize
;
203 PMMPTE CurrentPte
, NextPte
, PointerPte
;
206 // Check to make sure the PTE address is within bounds
208 ASSERT(NumberOfPtes
!= 0);
209 ASSERT(StartingPte
>= MmSystemPtesStart
[SystemPtePoolType
]);
210 ASSERT(StartingPte
<= MmSystemPtesEnd
[SystemPtePoolType
]);
215 RtlZeroMemory(StartingPte
, NumberOfPtes
* sizeof(MMPTE
));
216 CurrentSize
= (ULONG_PTR
)(StartingPte
- MmSystemPteBase
);
219 // Acquire the system PTE lock
221 OldIrql
= KeAcquireQueuedSpinLock(LockQueueSystemSpaceLock
);
224 // Increase availability
226 MmTotalFreeSystemPtes
[SystemPtePoolType
] += NumberOfPtes
;
229 // Get the free cluster and start going through them
231 CurrentPte
= &MmFirstFreeSystemPte
[SystemPtePoolType
];
235 // Get the first real cluster of PTEs and check if it's ours
237 PointerPte
= MmSystemPteBase
+ CurrentPte
->u
.List
.NextEntry
;
238 if (CurrentSize
< CurrentPte
->u
.List
.NextEntry
)
243 ASSERT(((StartingPte
+ NumberOfPtes
) <= PointerPte
) ||
244 (CurrentPte
->u
.List
.NextEntry
== ((ULONG
)0xFFFFF)));
247 // Get the next cluster in case it's the one
249 NextPte
= CurrentPte
+ 1;
252 // Check if this was actually a single-PTE entry
254 if (CurrentPte
->u
.List
.OneEntry
)
257 // We only have one page
264 // The next cluster will have the page count
266 ClusterSize
= (ULONG_PTR
)NextPte
->u
.List
.NextEntry
;
270 // So check if this cluster actually describes the entire mapping
272 if ((CurrentPte
+ ClusterSize
) == StartingPte
)
275 // It does -- collapse the free PTEs into the next cluster
277 NumberOfPtes
+= ClusterSize
;
278 NextPte
->u
.List
.NextEntry
= NumberOfPtes
;
279 CurrentPte
->u
.List
.OneEntry
= 0;
284 StartingPte
= CurrentPte
;
289 // There's still PTEs left -- make us into a cluster
291 StartingPte
->u
.List
.NextEntry
= CurrentPte
->u
.List
.NextEntry
;
292 CurrentPte
->u
.List
.NextEntry
= CurrentSize
;
295 // Is there just one page left?
297 if (NumberOfPtes
== 1)
300 // Then this actually becomes a single PTE entry
302 StartingPte
->u
.List
.OneEntry
= 1;
307 // Otherwise, create a new cluster for the remaining pages
309 StartingPte
->u
.List
.OneEntry
= 0;
310 NextPte
= StartingPte
+ 1;
311 NextPte
->u
.List
.NextEntry
= NumberOfPtes
;
316 // Now check if we've arrived at yet another cluster
318 if ((StartingPte
+ NumberOfPtes
) == PointerPte
)
321 // We'll collapse the next cluster into us
323 StartingPte
->u
.List
.NextEntry
= PointerPte
->u
.List
.NextEntry
;
324 StartingPte
->u
.List
.OneEntry
= 0;
325 NextPte
= StartingPte
+ 1;
328 // Check if the cluster only had one page
330 if (PointerPte
->u
.List
.OneEntry
)
340 // Otherwise, grab the page count from the next-next cluster
343 ClusterSize
= (ULONG_PTR
)PointerPte
->u
.List
.NextEntry
;
347 // And create the final combined cluster
349 NextPte
->u
.List
.NextEntry
= NumberOfPtes
+ ClusterSize
;
353 // We released the PTEs into their cluster (and optimized the list)
355 KeReleaseQueuedSpinLock(LockQueueSystemSpaceLock
, OldIrql
);
360 // Try the next cluster of PTEs...
362 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
= MI_SYSTEM_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
;