Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygensyspte.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: BSD - See COPYING.ARM in the top level directory 00004 * FILE: ntoskrnl/mm/ARM3/syspte.c 00005 * PURPOSE: ARM Memory Manager System PTE Allocator 00006 * PROGRAMMERS: ReactOS Portable Systems Group 00007 * Roel Messiant (roel.messiant@reactos.org) 00008 */ 00009 00010 /* INCLUDES *******************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 #define MODULE_INVOLVED_IN_ARM3 00017 #include "../ARM3/miarm.h" 00018 00019 /* GLOBALS ********************************************************************/ 00020 00021 PMMPTE MmSystemPteBase; 00022 PMMPTE MmSystemPtesStart[MaximumPtePoolTypes]; 00023 PMMPTE MmSystemPtesEnd[MaximumPtePoolTypes]; 00024 MMPTE MmFirstFreeSystemPte[MaximumPtePoolTypes]; 00025 ULONG MmTotalFreeSystemPtes[MaximumPtePoolTypes]; 00026 ULONG MmTotalSystemPtes; 00027 00028 /* PRIVATE FUNCTIONS **********************************************************/ 00029 00030 // 00031 // The free System Page Table Entries are stored in a bunch of clusters, 00032 // each consisting of one or more PTEs. These PTE clusters are connected 00033 // in a singly linked list, ordered by increasing cluster size. 00034 // 00035 // A cluster consisting of a single PTE is marked by having the OneEntry flag 00036 // of its PTE set. The forward link is contained in the NextEntry field. 00037 // 00038 // Clusters containing multiple PTEs have the OneEntry flag of their first PTE 00039 // reset. The NextEntry field of the first PTE contains the forward link, and 00040 // the size of the cluster is stored in the NextEntry field of its second PTE. 00041 // 00042 // Reserving PTEs currently happens by walking the linked list until a cluster 00043 // is found that contains the requested amount of PTEs or more. This cluster 00044 // is removed from the list, and the requested amount of PTEs is taken from the 00045 // tail of this cluster. If any PTEs remain in the cluster, the linked list is 00046 // walked again until a second cluster is found that contains the same amount 00047 // of PTEs or more. The first cluster is then inserted in front of the second 00048 // one. 00049 // 00050 // Releasing PTEs currently happens by walking the whole linked list, recording 00051 // the first cluster that contains the amount of PTEs to release or more. When 00052 // a cluster is found that is adjacent to the PTEs being released, this cluster 00053 // is removed from the list and subsequently added to the PTEs being released. 00054 // This ensures no two clusters are adjacent, which maximizes their size. 00055 // After the walk is complete, a new cluster is created that contains the PTEs 00056 // being released, which is then inserted in front of the recorded cluster. 00057 // 00058 00059 ULONG 00060 FORCEINLINE 00061 MI_GET_CLUSTER_SIZE(IN PMMPTE Pte) 00062 { 00063 // 00064 // First check for a single PTE 00065 // 00066 if (Pte->u.List.OneEntry) 00067 return 1; 00068 00069 // 00070 // Then read the size from the trailing PTE 00071 // 00072 Pte++; 00073 return (ULONG)Pte->u.List.NextEntry; 00074 } 00075 00076 PMMPTE 00077 NTAPI 00078 MiReserveAlignedSystemPtes(IN ULONG NumberOfPtes, 00079 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType, 00080 IN ULONG Alignment) 00081 { 00082 KIRQL OldIrql; 00083 PMMPTE PreviousPte, NextPte, ReturnPte; 00084 ULONG ClusterSize; 00085 00086 // 00087 // Sanity check 00088 // 00089 ASSERT(Alignment <= PAGE_SIZE); 00090 00091 // 00092 // Acquire the System PTE lock 00093 // 00094 OldIrql = KeAcquireQueuedSpinLock(LockQueueSystemSpaceLock); 00095 00096 // 00097 // Find the last cluster in the list that doesn't contain enough PTEs 00098 // 00099 PreviousPte = &MmFirstFreeSystemPte[SystemPtePoolType]; 00100 00101 while (PreviousPte->u.List.NextEntry != MM_EMPTY_PTE_LIST) 00102 { 00103 // 00104 // Get the next cluster and its size 00105 // 00106 NextPte = MmSystemPteBase + PreviousPte->u.List.NextEntry; 00107 ClusterSize = MI_GET_CLUSTER_SIZE(NextPte); 00108 00109 // 00110 // Check if this cluster contains enough PTEs 00111 // 00112 if (NumberOfPtes <= ClusterSize) 00113 break; 00114 00115 // 00116 // On to the next cluster 00117 // 00118 PreviousPte = NextPte; 00119 } 00120 00121 // 00122 // Make sure we didn't reach the end of the cluster list 00123 // 00124 if (PreviousPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) 00125 { 00126 // 00127 // Release the System PTE lock and return failure 00128 // 00129 KeReleaseQueuedSpinLock(LockQueueSystemSpaceLock, OldIrql); 00130 return NULL; 00131 } 00132 00133 // 00134 // Unlink the cluster 00135 // 00136 PreviousPte->u.List.NextEntry = NextPte->u.List.NextEntry; 00137 00138 // 00139 // Check if the reservation spans the whole cluster 00140 // 00141 if (ClusterSize == NumberOfPtes) 00142 { 00143 // 00144 // Return the first PTE of this cluster 00145 // 00146 ReturnPte = NextPte; 00147 00148 // 00149 // Zero the cluster 00150 // 00151 if (NextPte->u.List.OneEntry == 0) 00152 { 00153 NextPte->u.Long = 0; 00154 NextPte++; 00155 } 00156 NextPte->u.Long = 0; 00157 } 00158 else 00159 { 00160 // 00161 // Divide the cluster into two parts 00162 // 00163 ClusterSize -= NumberOfPtes; 00164 ReturnPte = NextPte + ClusterSize; 00165 00166 // 00167 // Set the size of the first cluster, zero the second if needed 00168 // 00169 if (ClusterSize == 1) 00170 { 00171 NextPte->u.List.OneEntry = 1; 00172 ReturnPte->u.Long = 0; 00173 } 00174 else 00175 { 00176 NextPte++; 00177 NextPte->u.List.NextEntry = ClusterSize; 00178 } 00179 00180 // 00181 // Step through the cluster list to find out where to insert the first 00182 // 00183 PreviousPte = &MmFirstFreeSystemPte[SystemPtePoolType]; 00184 00185 while (PreviousPte->u.List.NextEntry != MM_EMPTY_PTE_LIST) 00186 { 00187 // 00188 // Get the next cluster 00189 // 00190 NextPte = MmSystemPteBase + PreviousPte->u.List.NextEntry; 00191 00192 // 00193 // Check if the cluster to insert is smaller or of equal size 00194 // 00195 if (ClusterSize <= MI_GET_CLUSTER_SIZE(NextPte)) 00196 break; 00197 00198 // 00199 // On to the next cluster 00200 // 00201 PreviousPte = NextPte; 00202 } 00203 00204 // 00205 // Retrieve the first cluster and link it back into the cluster list 00206 // 00207 NextPte = ReturnPte - ClusterSize; 00208 00209 NextPte->u.List.NextEntry = PreviousPte->u.List.NextEntry; 00210 PreviousPte->u.List.NextEntry = NextPte - MmSystemPteBase; 00211 } 00212 00213 // 00214 // Decrease availability 00215 // 00216 MmTotalFreeSystemPtes[SystemPtePoolType] -= NumberOfPtes; 00217 00218 // 00219 // Release the System PTE lock 00220 // 00221 KeReleaseQueuedSpinLock(LockQueueSystemSpaceLock, OldIrql); 00222 00223 // 00224 // Flush the TLB 00225 // 00226 KeFlushProcessTb(); 00227 00228 // 00229 // Return the reserved PTEs 00230 // 00231 return ReturnPte; 00232 } 00233 00234 PMMPTE 00235 NTAPI 00236 MiReserveSystemPtes(IN ULONG NumberOfPtes, 00237 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType) 00238 { 00239 PMMPTE PointerPte; 00240 00241 // 00242 // Use the extended function 00243 // 00244 PointerPte = MiReserveAlignedSystemPtes(NumberOfPtes, SystemPtePoolType, 0); 00245 00246 // 00247 // Check if allocation failed 00248 // 00249 if (!PointerPte) 00250 { 00251 // 00252 // Warn that we are out of memory 00253 // 00254 DPRINT1("MiReserveSystemPtes: Failed to reserve %lu PTE(s)!\n", NumberOfPtes); 00255 } 00256 00257 // 00258 // Return the PTE Pointer 00259 // 00260 return PointerPte; 00261 } 00262 00263 VOID 00264 NTAPI 00265 MiReleaseSystemPtes(IN PMMPTE StartingPte, 00266 IN ULONG NumberOfPtes, 00267 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType) 00268 { 00269 KIRQL OldIrql; 00270 ULONG ClusterSize; 00271 PMMPTE PreviousPte, NextPte, InsertPte; 00272 00273 // 00274 // Check to make sure the PTE address is within bounds 00275 // 00276 ASSERT(NumberOfPtes != 0); 00277 ASSERT(StartingPte >= MmSystemPtesStart[SystemPtePoolType]); 00278 ASSERT(StartingPte + NumberOfPtes - 1 <= MmSystemPtesEnd[SystemPtePoolType]); 00279 00280 // 00281 // Zero PTEs 00282 // 00283 RtlZeroMemory(StartingPte, NumberOfPtes * sizeof(MMPTE)); 00284 00285 // 00286 // Acquire the System PTE lock 00287 // 00288 OldIrql = KeAcquireQueuedSpinLock(LockQueueSystemSpaceLock); 00289 00290 // 00291 // Increase availability 00292 // 00293 MmTotalFreeSystemPtes[SystemPtePoolType] += NumberOfPtes; 00294 00295 // 00296 // Step through the cluster list to find where to insert the PTEs 00297 // 00298 PreviousPte = &MmFirstFreeSystemPte[SystemPtePoolType]; 00299 InsertPte = NULL; 00300 00301 while (PreviousPte->u.List.NextEntry != MM_EMPTY_PTE_LIST) 00302 { 00303 // 00304 // Get the next cluster and its size 00305 // 00306 NextPte = MmSystemPteBase + PreviousPte->u.List.NextEntry; 00307 ClusterSize = MI_GET_CLUSTER_SIZE(NextPte); 00308 00309 // 00310 // Check if this cluster is adjacent to the PTEs being released 00311 // 00312 if ((NextPte + ClusterSize == StartingPte) || 00313 (StartingPte + NumberOfPtes == NextPte)) 00314 { 00315 // 00316 // Add the PTEs in the cluster to the PTEs being released 00317 // 00318 NumberOfPtes += ClusterSize; 00319 00320 if (NextPte < StartingPte) 00321 StartingPte = NextPte; 00322 00323 // 00324 // Unlink this cluster and zero it 00325 // 00326 PreviousPte->u.List.NextEntry = NextPte->u.List.NextEntry; 00327 00328 if (NextPte->u.List.OneEntry == 0) 00329 { 00330 NextPte->u.Long = 0; 00331 NextPte++; 00332 } 00333 NextPte->u.Long = 0; 00334 00335 // 00336 // Invalidate the previously found insertion location, if any 00337 // 00338 InsertPte = NULL; 00339 } 00340 else 00341 { 00342 // 00343 // Check if the insertion location is right before this cluster 00344 // 00345 if ((InsertPte == NULL) && (NumberOfPtes <= ClusterSize)) 00346 InsertPte = PreviousPte; 00347 00348 // 00349 // On to the next cluster 00350 // 00351 PreviousPte = NextPte; 00352 } 00353 } 00354 00355 // 00356 // If no insertion location was found, use the tail of the list 00357 // 00358 if (InsertPte == NULL) 00359 InsertPte = PreviousPte; 00360 00361 // 00362 // Create a new cluster using the PTEs being released 00363 // 00364 if (NumberOfPtes != 1) 00365 { 00366 StartingPte->u.List.OneEntry = 0; 00367 00368 NextPte = StartingPte + 1; 00369 NextPte->u.List.NextEntry = NumberOfPtes; 00370 } 00371 else 00372 StartingPte->u.List.OneEntry = 1; 00373 00374 // 00375 // Link the new cluster into the cluster list at the insertion location 00376 // 00377 StartingPte->u.List.NextEntry = InsertPte->u.List.NextEntry; 00378 InsertPte->u.List.NextEntry = StartingPte - MmSystemPteBase; 00379 00380 // 00381 // Release the System PTE lock 00382 // 00383 KeReleaseQueuedSpinLock(LockQueueSystemSpaceLock, OldIrql); 00384 } 00385 00386 VOID 00387 NTAPI 00388 INIT_FUNCTION 00389 MiInitializeSystemPtes(IN PMMPTE StartingPte, 00390 IN ULONG NumberOfPtes, 00391 IN MMSYSTEM_PTE_POOL_TYPE PoolType) 00392 { 00393 // 00394 // Sanity checks 00395 // 00396 ASSERT(NumberOfPtes >= 1); 00397 00398 // 00399 // Set the starting and ending PTE addresses for this space 00400 // 00401 MmSystemPteBase = MI_SYSTEM_PTE_BASE; 00402 MmSystemPtesStart[PoolType] = StartingPte; 00403 MmSystemPtesEnd[PoolType] = StartingPte + NumberOfPtes - 1; 00404 DPRINT("System PTE space for %d starting at: %p and ending at: %p\n", 00405 PoolType, MmSystemPtesStart[PoolType], MmSystemPtesEnd[PoolType]); 00406 00407 // 00408 // Clear all the PTEs to start with 00409 // 00410 RtlZeroMemory(StartingPte, NumberOfPtes * sizeof(MMPTE)); 00411 00412 // 00413 // Make the first entry free and link it 00414 // 00415 StartingPte->u.List.NextEntry = MM_EMPTY_PTE_LIST; 00416 MmFirstFreeSystemPte[PoolType].u.Long = 0; 00417 MmFirstFreeSystemPte[PoolType].u.List.NextEntry = StartingPte - 00418 MmSystemPteBase; 00419 00420 // 00421 // The second entry stores the size of this PTE space 00422 // 00423 StartingPte++; 00424 StartingPte->u.Long = 0; 00425 StartingPte->u.List.NextEntry = NumberOfPtes; 00426 00427 // 00428 // We also keep a global for it 00429 // 00430 MmTotalFreeSystemPtes[PoolType] = NumberOfPtes; 00431 00432 // 00433 // Check if this is the system PTE space 00434 // 00435 if (PoolType == SystemPteSpace) 00436 { 00437 // 00438 // Remember how many PTEs we have 00439 // 00440 MmTotalSystemPtes = NumberOfPtes; 00441 } 00442 } 00443 00444 /* EOF */ Generated on Mon May 28 2012 04:37:31 for ReactOS by
1.7.6.1
|