ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

syspte.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.