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 KeReleaseQueuedSpinLock(LockQueueSystemSpaceLock
, OldIrql
);
113 PointerPte
+= (ClusterSize
- NumberOfPtes
);
118 // Did we find exactly what you wanted?
120 if (NumberOfPtes
== ClusterSize
)
123 // Yes, fixup the cluster and decrease free system PTE count
125 PreviousPte
->u
.List
.NextEntry
= PointerPte
->u
.List
.NextEntry
;
126 MmTotalFreeSystemPtes
[SystemPtePoolType
] -= NumberOfPtes
;
130 else if (NumberOfPtes
== 1)
133 // We have one PTE in this cluster, and it's all you want
135 PreviousPte
->u
.List
.NextEntry
= PointerPte
->u
.List
.NextEntry
;
136 MmTotalFreeSystemPtes
[SystemPtePoolType
]--;
141 // We couldn't find what you wanted -- is this the last cluster?
143 if (PointerPte
->u
.List
.NextEntry
== ((ULONG
)0xFFFFF))
148 KeReleaseQueuedSpinLock(LockQueueSystemSpaceLock
, OldIrql
);
153 // Go to the next cluster
155 PreviousPte
= PointerPte
;
156 PointerPte
= MmSystemPteBase
+ PointerPte
->u
.List
.NextEntry
;
157 ASSERT(PointerPte
> PreviousPte
);
161 // Flush the TLB and return the first PTE
169 MiReserveSystemPtes(IN ULONG NumberOfPtes
,
170 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
)
175 // Use the extended function
177 PointerPte
= MiReserveAlignedSystemPtes(NumberOfPtes
, SystemPtePoolType
, 0);
178 ASSERT(PointerPte
!= NULL
);
184 MiReleaseSystemPtes(IN PMMPTE StartingPte
,
185 IN ULONG NumberOfPtes
,
186 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType
)
189 ULONG_PTR ClusterSize
, CurrentSize
;
190 PMMPTE CurrentPte
, NextPte
, PointerPte
;
193 // Check to make sure the PTE address is within bounds
195 ASSERT(NumberOfPtes
!= 0);
196 ASSERT(StartingPte
>= MmSystemPtesStart
[SystemPtePoolType
]);
197 ASSERT(StartingPte
<= MmSystemPtesEnd
[SystemPtePoolType
]);
202 RtlZeroMemory(StartingPte
, NumberOfPtes
* sizeof(MMPTE
));
203 CurrentSize
= (ULONG_PTR
)(StartingPte
- MmSystemPteBase
);
206 // Acquire the system PTE lock
208 OldIrql
= KeAcquireQueuedSpinLock(LockQueueSystemSpaceLock
);
211 // Increase availability
213 MmTotalFreeSystemPtes
[SystemPtePoolType
] += NumberOfPtes
;
216 // Get the free cluster and start going through them
218 CurrentPte
= &MmFirstFreeSystemPte
[SystemPtePoolType
];
222 // Get the first real cluster of PTEs and check if it's ours
224 PointerPte
= MmSystemPteBase
+ CurrentPte
->u
.List
.NextEntry
;
225 if (CurrentSize
< CurrentPte
->u
.List
.NextEntry
)
230 ASSERT(((StartingPte
+ NumberOfPtes
) <= PointerPte
) ||
231 (CurrentPte
->u
.List
.NextEntry
== ((ULONG
)0xFFFFF)));
234 // Get the next cluster in case it's the one
236 NextPte
= CurrentPte
+ 1;
239 // Check if this was actually a single-PTE entry
241 if (CurrentPte
->u
.List
.OneEntry
)
244 // We only have one page
251 // The next cluster will have the page count
253 ClusterSize
= (ULONG_PTR
)NextPte
->u
.List
.NextEntry
;
257 // So check if this cluster actually describes the entire mapping
259 if ((CurrentPte
+ ClusterSize
) == StartingPte
)
262 // It does -- collapse the free PTEs into the next cluster
264 NumberOfPtes
+= ClusterSize
;
265 NextPte
->u
.List
.NextEntry
= NumberOfPtes
;
266 CurrentPte
->u
.List
.OneEntry
= 0;
271 StartingPte
= CurrentPte
;
276 // There's still PTEs left -- make us into a cluster
278 StartingPte
->u
.List
.NextEntry
= CurrentPte
->u
.List
.NextEntry
;
279 CurrentPte
->u
.List
.NextEntry
= CurrentSize
;
282 // Is there just one page left?
284 if (NumberOfPtes
== 1)
287 // Then this actually becomes a single PTE entry
289 StartingPte
->u
.List
.OneEntry
= 1;
294 // Otherwise, create a new cluster for the remaining pages
296 StartingPte
->u
.List
.OneEntry
= 0;
297 NextPte
= StartingPte
+ 1;
298 NextPte
->u
.List
.NextEntry
= NumberOfPtes
;
303 // Now check if we've arrived at yet another cluster
305 if ((StartingPte
+ NumberOfPtes
) == PointerPte
)
308 // We'll collapse the next cluster into us
310 StartingPte
->u
.List
.NextEntry
= PointerPte
->u
.List
.NextEntry
;
311 StartingPte
->u
.List
.OneEntry
= 0;
312 NextPte
= StartingPte
+ 1;
315 // Check if the cluster only had one page
317 if (PointerPte
->u
.List
.OneEntry
)
327 // Otherwise, grab the page count from the next-next cluster
330 ClusterSize
= (ULONG_PTR
)PointerPte
->u
.List
.NextEntry
;
334 // And create the final combined cluster
336 NextPte
->u
.List
.NextEntry
= NumberOfPtes
+ ClusterSize
;
340 // We released the PTEs into their cluster (and optimized the list)
342 KeReleaseQueuedSpinLock(LockQueueSystemSpaceLock
, OldIrql
);
347 // Try the next cluster of PTEs...
349 CurrentPte
= PointerPte
;
355 MiInitializeSystemPtes(IN PMMPTE StartingPte
,
356 IN ULONG NumberOfPtes
,
357 IN MMSYSTEM_PTE_POOL_TYPE PoolType
)
362 ASSERT(NumberOfPtes
>= 1);
365 // Set the starting and ending PTE addresses for this space
367 MmSystemPteBase
= (PVOID
)PTE_BASE
;
368 MmSystemPtesStart
[PoolType
] = StartingPte
;
369 MmSystemPtesEnd
[PoolType
] = StartingPte
+ NumberOfPtes
- 1;
370 DPRINT("System PTE space for %d starting at: %p and ending at: %p\n",
371 PoolType
, MmSystemPtesStart
[PoolType
], MmSystemPtesEnd
[PoolType
]);
374 // Clear all the PTEs to start with
376 RtlZeroMemory(StartingPte
, NumberOfPtes
* sizeof(MMPTE
));
379 // Make the first entry free and link it
381 StartingPte
->u
.List
.NextEntry
= ((ULONG
)0xFFFFF);
382 MmFirstFreeSystemPte
[PoolType
].u
.Long
= 0;
383 MmFirstFreeSystemPte
[PoolType
].u
.List
.NextEntry
= StartingPte
-
387 // The second entry stores the size of this PTE space
390 StartingPte
->u
.Long
= 0;
391 StartingPte
->u
.List
.NextEntry
= NumberOfPtes
;
394 // We also keep a global for it
396 MmTotalFreeSystemPtes
[PoolType
] = NumberOfPtes
;
399 // Check if this is the system PTE space
401 if (PoolType
== SystemPteSpace
)
404 // Remember how many PTEs we have
406 MmTotalSystemPtes
= NumberOfPtes
;