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

pool.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/pool.c
00005  * PURPOSE:         ARM Memory Manager Pool Allocator
00006  * PROGRAMMERS:     ReactOS Portable Systems Group
00007  */
00008 
00009 /* INCLUDES *******************************************************************/
00010 
00011 #include <ntoskrnl.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 #define MODULE_INVOLVED_IN_ARM3
00016 #include "../ARM3/miarm.h"
00017 
00018 /* GLOBALS ********************************************************************/
00019 
00020 LIST_ENTRY MmNonPagedPoolFreeListHead[MI_MAX_FREE_PAGE_LISTS];
00021 PFN_COUNT MmNumberOfFreeNonPagedPool, MiExpansionPoolPagesInitialCharge;
00022 PVOID MmNonPagedPoolEnd0;
00023 PFN_NUMBER MiStartOfInitialPoolFrame, MiEndOfInitialPoolFrame;
00024 KGUARDED_MUTEX MmPagedPoolMutex;
00025 MM_PAGED_POOL_INFO MmPagedPoolInfo;
00026 SIZE_T MmAllocatedNonPagedPool;
00027 ULONG MmSpecialPoolTag;
00028 ULONG MmConsumedPoolPercentage;
00029 BOOLEAN MmProtectFreedNonPagedPool;
00030 SLIST_HEADER MiNonPagedPoolSListHead;
00031 ULONG MiNonPagedPoolSListMaximum = 4;
00032 SLIST_HEADER MiPagedPoolSListHead;
00033 ULONG MiPagedPoolSListMaximum = 8;
00034 
00035 /* PRIVATE FUNCTIONS **********************************************************/
00036 
00037 VOID
00038 NTAPI
00039 MiProtectFreeNonPagedPool(IN PVOID VirtualAddress,
00040                           IN ULONG PageCount)
00041 {
00042     PMMPTE PointerPte, LastPte;
00043     MMPTE TempPte;
00044 
00045     /* If pool is physical, can't protect PTEs */
00046     if (MI_IS_PHYSICAL_ADDRESS(VirtualAddress)) return;
00047 
00048     /* Get PTE pointers and loop */
00049     PointerPte = MiAddressToPte(VirtualAddress);
00050     LastPte = PointerPte + PageCount;
00051     do
00052     {
00053         /* Capture the PTE for safety */
00054         TempPte = *PointerPte;
00055 
00056         /* Mark it as an invalid PTE, set proto bit to recognize it as pool */
00057         TempPte.u.Hard.Valid = 0;
00058         TempPte.u.Soft.Prototype = 1;
00059         MI_WRITE_INVALID_PTE(PointerPte, TempPte);
00060     } while (++PointerPte < LastPte);
00061 
00062     /* Flush the TLB */
00063     KeFlushEntireTb(TRUE, TRUE);
00064 }
00065 
00066 BOOLEAN
00067 NTAPI
00068 MiUnProtectFreeNonPagedPool(IN PVOID VirtualAddress,
00069                             IN ULONG PageCount)
00070 {
00071     PMMPTE PointerPte;
00072     MMPTE TempPte;
00073     PFN_NUMBER UnprotectedPages = 0;
00074 
00075     /* If pool is physical, can't protect PTEs */
00076     if (MI_IS_PHYSICAL_ADDRESS(VirtualAddress)) return FALSE;
00077 
00078     /* Get, and capture the PTE */
00079     PointerPte = MiAddressToPte(VirtualAddress);
00080     TempPte = *PointerPte;
00081 
00082     /* Loop protected PTEs */
00083     while ((TempPte.u.Hard.Valid == 0) && (TempPte.u.Soft.Prototype == 1))
00084     {
00085         /* Unprotect the PTE */
00086         TempPte.u.Hard.Valid = 1;
00087         TempPte.u.Soft.Prototype = 0;
00088         MI_WRITE_VALID_PTE(PointerPte, TempPte);
00089 
00090         /* One more page */
00091         if (++UnprotectedPages == PageCount) break;
00092 
00093         /* Capture next PTE */
00094         TempPte = *(++PointerPte);
00095     }
00096 
00097     /* Return if any pages were unprotected */
00098     return UnprotectedPages ? TRUE : FALSE;
00099 }
00100 
00101 VOID
00102 FORCEINLINE
00103 MiProtectedPoolUnProtectLinks(IN PLIST_ENTRY Links,
00104                               OUT PVOID* PoolFlink,
00105                               OUT PVOID* PoolBlink)
00106 {
00107     BOOLEAN Safe;
00108     PVOID PoolVa;
00109 
00110     /* Initialize variables */
00111     *PoolFlink = *PoolBlink = NULL;
00112 
00113     /* Check if the list has entries */
00114     if (IsListEmpty(Links) == FALSE)
00115     {
00116         /* We are going to need to forward link to do an insert */
00117         PoolVa = Links->Flink;
00118 
00119         /* So make it safe to access */
00120         Safe = MiUnProtectFreeNonPagedPool(PoolVa, 1);
00121         if (Safe) PoolFlink = PoolVa;
00122     }
00123 
00124     /* Are we going to need a backward link too? */
00125     if (Links != Links->Blink)
00126     {
00127         /* Get the head's backward link for the insert */
00128         PoolVa = Links->Blink;
00129 
00130         /* Make it safe to access */
00131         Safe = MiUnProtectFreeNonPagedPool(PoolVa, 1);
00132         if (Safe) PoolBlink = PoolVa;
00133     }
00134 }
00135 
00136 VOID
00137 FORCEINLINE
00138 MiProtectedPoolProtectLinks(IN PVOID PoolFlink,
00139                             IN PVOID PoolBlink)
00140 {
00141     /* Reprotect the pages, if they got unprotected earlier */
00142     if (PoolFlink) MiProtectFreeNonPagedPool(PoolFlink, 1);
00143     if (PoolBlink) MiProtectFreeNonPagedPool(PoolBlink, 1);
00144 }
00145 
00146 VOID
00147 NTAPI
00148 MiProtectedPoolInsertList(IN PLIST_ENTRY ListHead,
00149                           IN PLIST_ENTRY Entry,
00150                           IN BOOLEAN Critical)
00151 {
00152     PVOID PoolFlink, PoolBlink;
00153 
00154     /* Make the list accessible */
00155     MiProtectedPoolUnProtectLinks(ListHead, &PoolFlink, &PoolBlink);
00156 
00157     /* Now insert in the right position */
00158     Critical ? InsertHeadList(ListHead, Entry) : InsertTailList(ListHead, Entry);
00159 
00160     /* And reprotect the pages containing the free links */
00161     MiProtectedPoolProtectLinks(PoolFlink, PoolBlink);
00162 }
00163 
00164 VOID
00165 NTAPI
00166 MiProtectedPoolRemoveEntryList(IN PLIST_ENTRY Entry)
00167 {
00168     PVOID PoolFlink, PoolBlink;
00169 
00170     /* Make the list accessible */
00171     MiProtectedPoolUnProtectLinks(Entry, &PoolFlink, &PoolBlink);
00172 
00173     /* Now remove */
00174     RemoveEntryList(Entry);
00175 
00176     /* And reprotect the pages containing the free links */
00177     if (PoolFlink) MiProtectFreeNonPagedPool(PoolFlink, 1);
00178     if (PoolBlink) MiProtectFreeNonPagedPool(PoolBlink, 1);
00179 }
00180 
00181 VOID
00182 NTAPI
00183 INIT_FUNCTION
00184 MiInitializeNonPagedPoolThresholds(VOID)
00185 {
00186     PFN_NUMBER Size = MmMaximumNonPagedPoolInPages;
00187 
00188     /* Default low threshold of 8MB or one third of nonpaged pool */
00189     MiLowNonPagedPoolThreshold = (8 * _1MB) >> PAGE_SHIFT;
00190     MiLowNonPagedPoolThreshold = min(MiLowNonPagedPoolThreshold, Size / 3);
00191 
00192     /* Default high threshold of 20MB or 50% */
00193     MiHighNonPagedPoolThreshold = (20 * _1MB) >> PAGE_SHIFT;
00194     MiHighNonPagedPoolThreshold = min(MiHighNonPagedPoolThreshold, Size / 2);
00195     ASSERT(MiLowNonPagedPoolThreshold < MiHighNonPagedPoolThreshold);
00196 }
00197 
00198 VOID
00199 NTAPI
00200 INIT_FUNCTION
00201 MiInitializePoolEvents(VOID)
00202 {
00203     KIRQL OldIrql;
00204     PFN_NUMBER FreePoolInPages;
00205 
00206     /* Lock paged pool */
00207     KeAcquireGuardedMutex(&MmPagedPoolMutex);
00208 
00209     /* Total size of the paged pool minus the allocated size, is free */
00210     FreePoolInPages = MmSizeOfPagedPoolInPages - MmPagedPoolInfo.AllocatedPagedPool;
00211 
00212     /* Check the initial state high state */
00213     if (FreePoolInPages >= MiHighPagedPoolThreshold)
00214     {
00215         /* We have plenty of pool */
00216         KeSetEvent(MiHighPagedPoolEvent, 0, FALSE);
00217     }
00218     else
00219     {
00220         /* We don't */
00221         KeClearEvent(MiHighPagedPoolEvent);
00222     }
00223 
00224     /* Check the initial low state */
00225     if (FreePoolInPages <= MiLowPagedPoolThreshold)
00226     {
00227         /* We're very low in free pool memory */
00228         KeSetEvent(MiLowPagedPoolEvent, 0, FALSE);
00229     }
00230     else
00231     {
00232         /* We're not */
00233         KeClearEvent(MiLowPagedPoolEvent);
00234     }
00235 
00236     /* Release the paged pool lock */
00237     KeReleaseGuardedMutex(&MmPagedPoolMutex);
00238 
00239     /* Now it's time for the nonpaged pool lock */
00240     OldIrql = KeAcquireQueuedSpinLock(LockQueueMmNonPagedPoolLock);
00241 
00242     /* Free pages are the maximum minus what's been allocated */
00243     FreePoolInPages = MmMaximumNonPagedPoolInPages - MmAllocatedNonPagedPool;
00244 
00245     /* Check if we have plenty */
00246     if (FreePoolInPages >= MiHighNonPagedPoolThreshold)
00247     {
00248         /* We do, set the event */
00249         KeSetEvent(MiHighNonPagedPoolEvent, 0, FALSE);
00250     }
00251     else
00252     {
00253         /* We don't, clear the event */
00254         KeClearEvent(MiHighNonPagedPoolEvent);
00255     }
00256 
00257     /* Check if we have very little */
00258     if (FreePoolInPages <= MiLowNonPagedPoolThreshold)
00259     {
00260         /* We do, set the event */
00261         KeSetEvent(MiLowNonPagedPoolEvent, 0, FALSE);
00262     }
00263     else
00264     {
00265         /* We don't, clear it */
00266         KeClearEvent(MiLowNonPagedPoolEvent);
00267     }
00268 
00269     /* We're done, release the nonpaged pool lock */
00270     KeReleaseQueuedSpinLock(LockQueueMmNonPagedPoolLock, OldIrql);
00271 }
00272 
00273 VOID
00274 NTAPI
00275 INIT_FUNCTION
00276 MiInitializeNonPagedPool(VOID)
00277 {
00278     ULONG i;
00279     PFN_COUNT PoolPages;
00280     PMMFREE_POOL_ENTRY FreeEntry, FirstEntry;
00281     PMMPTE PointerPte;
00282     PAGED_CODE();
00283 
00284     //
00285     // Initialize the pool S-LISTs as well as their maximum count. In general,
00286     // we'll allow 8 times the default on a 2GB system, and two times the default
00287     // on a 1GB system.
00288     //
00289     InitializeSListHead(&MiPagedPoolSListHead);
00290     InitializeSListHead(&MiNonPagedPoolSListHead);
00291     if (MmNumberOfPhysicalPages >= ((2 * _1GB) /PAGE_SIZE))
00292     {
00293         MiNonPagedPoolSListMaximum *= 8;
00294         MiPagedPoolSListMaximum *= 8;
00295     }
00296     else if (MmNumberOfPhysicalPages >= (_1GB /PAGE_SIZE))
00297     {
00298         MiNonPagedPoolSListMaximum *= 2;
00299         MiPagedPoolSListMaximum *= 2;
00300     }
00301 
00302     //
00303     // However if debugging options for the pool are enabled, turn off the S-LIST
00304     // to reduce the risk of messing things up even more
00305     //
00306     if (MmProtectFreedNonPagedPool)
00307     {
00308         MiNonPagedPoolSListMaximum = 0;
00309         MiPagedPoolSListMaximum = 0;
00310     }
00311 
00312     //
00313     // We keep 4 lists of free pages (4 lists help avoid contention)
00314     //
00315     for (i = 0; i < MI_MAX_FREE_PAGE_LISTS; i++)
00316     {
00317         //
00318         // Initialize each of them
00319         //
00320         InitializeListHead(&MmNonPagedPoolFreeListHead[i]);
00321     }
00322 
00323     //
00324     // Calculate how many pages the initial nonpaged pool has
00325     //
00326     PoolPages = (PFN_COUNT)BYTES_TO_PAGES(MmSizeOfNonPagedPoolInBytes);
00327     MmNumberOfFreeNonPagedPool = PoolPages;
00328 
00329     //
00330     // Initialize the first free entry
00331     //
00332     FreeEntry = MmNonPagedPoolStart;
00333     FirstEntry = FreeEntry;
00334     FreeEntry->Size = PoolPages;
00335     FreeEntry->Signature = MM_FREE_POOL_SIGNATURE;
00336     FreeEntry->Owner = FirstEntry;
00337 
00338     //
00339     // Insert it into the last list
00340     //
00341     InsertHeadList(&MmNonPagedPoolFreeListHead[MI_MAX_FREE_PAGE_LISTS - 1],
00342                    &FreeEntry->List);
00343 
00344     //
00345     // Now create free entries for every single other page
00346     //
00347     while (PoolPages-- > 1)
00348     {
00349         //
00350         // Link them all back to the original entry
00351         //
00352         FreeEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)FreeEntry + PAGE_SIZE);
00353         FreeEntry->Owner = FirstEntry;
00354         FreeEntry->Signature = MM_FREE_POOL_SIGNATURE;
00355     }
00356 
00357     //
00358     // Validate and remember first allocated pool page
00359     //
00360     PointerPte = MiAddressToPte(MmNonPagedPoolStart);
00361     ASSERT(PointerPte->u.Hard.Valid == 1);
00362     MiStartOfInitialPoolFrame = PFN_FROM_PTE(PointerPte);
00363 
00364     //
00365     // Keep track of where initial nonpaged pool ends
00366     //
00367     MmNonPagedPoolEnd0 = (PVOID)((ULONG_PTR)MmNonPagedPoolStart +
00368                                  MmSizeOfNonPagedPoolInBytes);
00369 
00370     //
00371     // Validate and remember last allocated pool page
00372     //
00373     PointerPte = MiAddressToPte((PVOID)((ULONG_PTR)MmNonPagedPoolEnd0 - 1));
00374     ASSERT(PointerPte->u.Hard.Valid == 1);
00375     MiEndOfInitialPoolFrame = PFN_FROM_PTE(PointerPte);
00376 
00377     //
00378     // Validate the first nonpaged pool expansion page (which is a guard page)
00379     //
00380     PointerPte = MiAddressToPte(MmNonPagedPoolExpansionStart);
00381     ASSERT(PointerPte->u.Hard.Valid == 0);
00382 
00383     //
00384     // Calculate the size of the expansion region alone
00385     //
00386     MiExpansionPoolPagesInitialCharge = (PFN_COUNT)
00387     BYTES_TO_PAGES(MmMaximumNonPagedPoolInBytes - MmSizeOfNonPagedPoolInBytes);
00388 
00389     //
00390     // Remove 2 pages, since there's a guard page on top and on the bottom
00391     //
00392     MiExpansionPoolPagesInitialCharge -= 2;
00393 
00394     //
00395     // Now initialize the nonpaged pool expansion PTE space. Remember there's a
00396     // guard page on top so make sure to skip it. The bottom guard page will be
00397     // guaranteed by the fact our size is off by one.
00398     //
00399     MiInitializeSystemPtes(PointerPte + 1,
00400                            MiExpansionPoolPagesInitialCharge,
00401                            NonPagedPoolExpansion);
00402 }
00403 
00404 POOL_TYPE
00405 NTAPI
00406 MmDeterminePoolType(IN PVOID PoolAddress)
00407 {
00408     //
00409     // Use a simple bounds check
00410     //
00411     return (PoolAddress >= MmPagedPoolStart) && (PoolAddress <= MmPagedPoolEnd) ?
00412             PagedPool : NonPagedPool;
00413 }
00414 
00415 PVOID
00416 NTAPI
00417 MiAllocatePoolPages(IN POOL_TYPE PoolType,
00418                     IN SIZE_T SizeInBytes)
00419 {
00420     PFN_NUMBER PageFrameNumber;
00421     PFN_COUNT SizeInPages, PageTableCount;
00422     ULONG i;
00423     KIRQL OldIrql;
00424     PLIST_ENTRY NextEntry, NextHead, LastHead;
00425     PMMPTE PointerPte, StartPte;
00426     PMMPDE PointerPde;
00427     ULONG EndAllocation;
00428     MMPTE TempPte;
00429     MMPDE TempPde;
00430     PMMPFN Pfn1;
00431     PVOID BaseVa, BaseVaStart;
00432     PMMFREE_POOL_ENTRY FreeEntry;
00433     PKSPIN_LOCK_QUEUE LockQueue;
00434 
00435     //
00436     // Figure out how big the allocation is in pages
00437     //
00438     SizeInPages = (PFN_COUNT)BYTES_TO_PAGES(SizeInBytes);
00439 
00440     //
00441     // Check for overflow
00442     //
00443     if (SizeInPages == 0)
00444     {
00445         //
00446         // Fail
00447         //
00448         return NULL;
00449     }
00450 
00451     //
00452     // Handle paged pool
00453     //
00454     if ((PoolType & BASE_POOL_TYPE_MASK) == PagedPool)
00455     {
00456         //
00457         // If only one page is being requested, try to grab it from the S-LIST
00458         //
00459         if ((SizeInPages == 1) && (ExQueryDepthSList(&MiPagedPoolSListHead)))
00460         {
00461             BaseVa = InterlockedPopEntrySList(&MiPagedPoolSListHead);
00462             if (BaseVa) return BaseVa;
00463         }
00464 
00465         //
00466         // Lock the paged pool mutex
00467         //
00468         KeAcquireGuardedMutex(&MmPagedPoolMutex);
00469 
00470         //
00471         // Find some empty allocation space
00472         //
00473         i = RtlFindClearBitsAndSet(MmPagedPoolInfo.PagedPoolAllocationMap,
00474                                    SizeInPages,
00475                                    MmPagedPoolInfo.PagedPoolHint);
00476         if (i == 0xFFFFFFFF)
00477         {
00478             //
00479             // Get the page bit count
00480             //
00481             i = ((SizeInPages - 1) / PTE_COUNT) + 1;
00482             DPRINT1("Paged pool expansion: %d %x\n", i, SizeInPages);
00483 
00484             //
00485             // Check if there is enougn paged pool expansion space left
00486             //
00487             if (MmPagedPoolInfo.NextPdeForPagedPoolExpansion >
00488                 (PMMPDE)MiAddressToPte(MmPagedPoolInfo.LastPteForPagedPool))
00489             {
00490                 //
00491                 // Out of memory!
00492                 //
00493                 DPRINT1("OUT OF PAGED POOL!!!\n");
00494                 KeReleaseGuardedMutex(&MmPagedPoolMutex);
00495                 return NULL;
00496             }
00497 
00498             //
00499             // Check if we'll have to expand past the last PTE we have available
00500             //
00501             if (((i - 1) + MmPagedPoolInfo.NextPdeForPagedPoolExpansion) >
00502                  (PMMPDE)MiAddressToPte(MmPagedPoolInfo.LastPteForPagedPool))
00503             {
00504                 //
00505                 // We can only support this much then
00506                 //
00507                 PointerPde = MiAddressToPte(MmPagedPoolInfo.LastPteForPagedPool);
00508                 PageTableCount = (PFN_COUNT)(PointerPde + 1 -
00509                                  MmPagedPoolInfo.NextPdeForPagedPoolExpansion);
00510                 ASSERT(PageTableCount < i);
00511                 i = PageTableCount;
00512             }
00513             else
00514             {
00515                 //
00516                 // Otherwise, there is plenty of space left for this expansion
00517                 //
00518                 PageTableCount = i;
00519             }
00520 
00521             //
00522             // Get the template PDE we'll use to expand
00523             //
00524             TempPde = ValidKernelPde;
00525 
00526             //
00527             // Get the first PTE in expansion space
00528             //
00529             PointerPde = MmPagedPoolInfo.NextPdeForPagedPoolExpansion;
00530             BaseVa = MiPdeToPte(PointerPde);
00531             BaseVaStart = BaseVa;
00532 
00533             //
00534             // Lock the PFN database and loop pages
00535             //
00536             OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00537             do
00538             {
00539                 //
00540                 // It should not already be valid
00541                 //
00542                 ASSERT(PointerPde->u.Hard.Valid == 0);
00543 
00544                 /* Request a page */
00545                 MI_SET_USAGE(MI_USAGE_PAGED_POOL);
00546                 MI_SET_PROCESS2("Kernel");
00547                 PageFrameNumber = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
00548                 TempPde.u.Hard.PageFrameNumber = PageFrameNumber;
00549 #if (_MI_PAGING_LEVELS >= 3)
00550                 /* On PAE/x64 systems, there's no double-buffering */
00551                 ASSERT(FALSE);
00552 #else
00553                 //
00554                 // Save it into our double-buffered system page directory
00555                 //
00556                 MmSystemPagePtes[((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE)] = TempPde;
00557 
00558                 /* Initialize the PFN */
00559                 MiInitializePfnForOtherProcess(PageFrameNumber,
00560                                                (PMMPTE)PointerPde,
00561                                                MmSystemPageDirectory[(PointerPde - MiAddressToPde(NULL)) / PDE_COUNT]);
00562 
00563                 /* Write the actual PDE now */
00564 //                MI_WRITE_VALID_PDE(PointerPde, TempPde);
00565 #endif
00566                 //
00567                 // Move on to the next expansion address
00568                 //
00569                 PointerPde++;
00570                 BaseVa = (PVOID)((ULONG_PTR)BaseVa + PAGE_SIZE);
00571                 i--;
00572             } while (i > 0);
00573 
00574             //
00575             // Release the PFN database lock
00576             //
00577             KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00578 
00579             //
00580             // These pages are now available, clear their availablity bits
00581             //
00582             EndAllocation = (ULONG)(MmPagedPoolInfo.NextPdeForPagedPoolExpansion -
00583                              (PMMPDE)MiAddressToPte(MmPagedPoolInfo.FirstPteForPagedPool)) *
00584                              PTE_COUNT;
00585             RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap,
00586                          EndAllocation,
00587                          PageTableCount * PTE_COUNT);
00588 
00589             //
00590             // Update the next expansion location
00591             //
00592             MmPagedPoolInfo.NextPdeForPagedPoolExpansion += PageTableCount;
00593 
00594             //
00595             // Zero out the newly available memory
00596             //
00597             RtlZeroMemory(BaseVaStart, PageTableCount * PAGE_SIZE);
00598 
00599             //
00600             // Now try consuming the pages again
00601             //
00602             i = RtlFindClearBitsAndSet(MmPagedPoolInfo.PagedPoolAllocationMap,
00603                                        SizeInPages,
00604                                        0);
00605             if (i == 0xFFFFFFFF)
00606             {
00607                 //
00608                 // Out of memory!
00609                 //
00610                 DPRINT1("OUT OF PAGED POOL!!!\n");
00611                 KeReleaseGuardedMutex(&MmPagedPoolMutex);
00612                 return NULL;
00613             }
00614         }
00615 
00616         //
00617         // Update the pool hint if the request was just one page
00618         //
00619         if (SizeInPages == 1) MmPagedPoolInfo.PagedPoolHint = i + 1;
00620 
00621         //
00622         // Update the end bitmap so we know the bounds of this allocation when
00623         // the time comes to free it
00624         //
00625         EndAllocation = i + SizeInPages - 1;
00626         RtlSetBit(MmPagedPoolInfo.EndOfPagedPoolBitmap, EndAllocation);
00627 
00628         //
00629         // Now we can release the lock (it mainly protects the bitmap)
00630         //
00631         KeReleaseGuardedMutex(&MmPagedPoolMutex);
00632 
00633         //
00634         // Now figure out where this allocation starts
00635         //
00636         BaseVa = (PVOID)((ULONG_PTR)MmPagedPoolStart + (i << PAGE_SHIFT));
00637 
00638         //
00639         // Flush the TLB
00640         //
00641         KeFlushEntireTb(TRUE, TRUE);
00642 
00643         /* Setup a demand-zero writable PTE */
00644         MI_MAKE_SOFTWARE_PTE(&TempPte, MM_READWRITE);
00645 
00646         //
00647         // Find the first and last PTE, then loop them all
00648         //
00649         PointerPte = MiAddressToPte(BaseVa);
00650         StartPte = PointerPte + SizeInPages;
00651         do
00652         {
00653             //
00654             // Write the demand zero PTE and keep going
00655             //
00656             MI_WRITE_INVALID_PTE(PointerPte, TempPte);
00657         } while (++PointerPte < StartPte);
00658 
00659         //
00660         // Return the allocation address to the caller
00661         //
00662         return BaseVa;
00663     }
00664 
00665     //
00666     // If only one page is being requested, try to grab it from the S-LIST
00667     //
00668     if ((SizeInPages == 1) && (ExQueryDepthSList(&MiNonPagedPoolSListHead)))
00669     {
00670         BaseVa = InterlockedPopEntrySList(&MiNonPagedPoolSListHead);
00671         if (BaseVa) return BaseVa;
00672     }
00673 
00674     //
00675     // Allocations of less than 4 pages go into their individual buckets
00676     //
00677     i = SizeInPages - 1;
00678     if (i >= MI_MAX_FREE_PAGE_LISTS) i = MI_MAX_FREE_PAGE_LISTS - 1;
00679 
00680     //
00681     // Loop through all the free page lists based on the page index
00682     //
00683     NextHead = &MmNonPagedPoolFreeListHead[i];
00684     LastHead = &MmNonPagedPoolFreeListHead[MI_MAX_FREE_PAGE_LISTS];
00685 
00686     //
00687     // Acquire the nonpaged pool lock
00688     //
00689     OldIrql = KeAcquireQueuedSpinLock(LockQueueMmNonPagedPoolLock);
00690     do
00691     {
00692         //
00693         // Now loop through all the free page entries in this given list
00694         //
00695         NextEntry = NextHead->Flink;
00696         while (NextEntry != NextHead)
00697         {
00698             /* Is freed non paged pool enabled */
00699             if (MmProtectFreedNonPagedPool)
00700             {
00701                 /* We need to be able to touch this page, unprotect it */
00702                 MiUnProtectFreeNonPagedPool(NextEntry, 0);
00703             }
00704 
00705             //
00706             // Grab the entry and see if it can handle our allocation
00707             //
00708             FreeEntry = CONTAINING_RECORD(NextEntry, MMFREE_POOL_ENTRY, List);
00709             ASSERT(FreeEntry->Signature == MM_FREE_POOL_SIGNATURE);
00710             if (FreeEntry->Size >= SizeInPages)
00711             {
00712                 //
00713                 // It does, so consume the pages from here
00714                 //
00715                 FreeEntry->Size -= SizeInPages;
00716 
00717                 //
00718                 // The allocation will begin in this free page area
00719                 //
00720                 BaseVa = (PVOID)((ULONG_PTR)FreeEntry +
00721                                  (FreeEntry->Size  << PAGE_SHIFT));
00722 
00723                 /* Remove the item from the list, depending if pool is protected */
00724                 MmProtectFreedNonPagedPool ?
00725                     MiProtectedPoolRemoveEntryList(&FreeEntry->List) :
00726                     RemoveEntryList(&FreeEntry->List);
00727 
00728                 //
00729                 // However, check if its' still got space left
00730                 //
00731                 if (FreeEntry->Size != 0)
00732                 {
00733                     /* Check which list to insert this entry into */
00734                     i = FreeEntry->Size - 1;
00735                     if (i >= MI_MAX_FREE_PAGE_LISTS) i = MI_MAX_FREE_PAGE_LISTS - 1;
00736 
00737                     /* Insert the entry into the free list head, check for prot. pool */
00738                     MmProtectFreedNonPagedPool ?
00739                         MiProtectedPoolInsertList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List, TRUE) :
00740                         InsertTailList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List);
00741 
00742                     /* Is freed non paged pool protected? */
00743                     if (MmProtectFreedNonPagedPool)
00744                     {
00745                         /* Protect the freed pool! */
00746                         MiProtectFreeNonPagedPool(FreeEntry, FreeEntry->Size);
00747                     }
00748                 }
00749 
00750                 //
00751                 // Grab the PTE for this allocation
00752                 //
00753                 PointerPte = MiAddressToPte(BaseVa);
00754                 ASSERT(PointerPte->u.Hard.Valid == 1);
00755 
00756                 //
00757                 // Grab the PFN NextEntry and index
00758                 //
00759                 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte));
00760 
00761                 //
00762                 // Now mark it as the beginning of an allocation
00763                 //
00764                 ASSERT(Pfn1->u3.e1.StartOfAllocation == 0);
00765                 Pfn1->u3.e1.StartOfAllocation = 1;
00766 
00767                 /* Mark it as special pool if needed */
00768                 ASSERT(Pfn1->u4.VerifierAllocation == 0);
00769                 if (PoolType & 64) Pfn1->u4.VerifierAllocation = 1;
00770 
00771                 //
00772                 // Check if the allocation is larger than one page
00773                 //
00774                 if (SizeInPages != 1)
00775                 {
00776                     //
00777                     // Navigate to the last PFN entry and PTE
00778                     //
00779                     PointerPte += SizeInPages - 1;
00780                     ASSERT(PointerPte->u.Hard.Valid == 1);
00781                     Pfn1 = MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber);
00782                 }
00783 
00784                 //
00785                 // Mark this PFN as the last (might be the same as the first)
00786                 //
00787                 ASSERT(Pfn1->u3.e1.EndOfAllocation == 0);
00788                 Pfn1->u3.e1.EndOfAllocation = 1;
00789 
00790                 //
00791                 // Release the nonpaged pool lock, and return the allocation
00792                 //
00793                 KeReleaseQueuedSpinLock(LockQueueMmNonPagedPoolLock, OldIrql);
00794                 return BaseVa;
00795             }
00796 
00797             //
00798             // Try the next free page entry
00799             //
00800             NextEntry = FreeEntry->List.Flink;
00801 
00802             /* Is freed non paged pool protected? */
00803             if (MmProtectFreedNonPagedPool)
00804             {
00805                 /* Protect the freed pool! */
00806                 MiProtectFreeNonPagedPool(FreeEntry, FreeEntry->Size);
00807             }
00808         }
00809     } while (++NextHead < LastHead);
00810 
00811     //
00812     // If we got here, we're out of space.
00813     // Start by releasing the lock
00814     //
00815     KeReleaseQueuedSpinLock(LockQueueMmNonPagedPoolLock, OldIrql);
00816 
00817     //
00818     // Allocate some system PTEs
00819     //
00820     StartPte = MiReserveSystemPtes(SizeInPages, NonPagedPoolExpansion);
00821     PointerPte = StartPte;
00822     if (StartPte == NULL)
00823     {
00824         //
00825         // Ran out of memory
00826         //
00827         DPRINT1("Out of NP Expansion Pool\n");
00828         return NULL;
00829     }
00830 
00831     //
00832     // Acquire the pool lock now
00833     //
00834     OldIrql = KeAcquireQueuedSpinLock(LockQueueMmNonPagedPoolLock);
00835 
00836     //
00837     // Lock the PFN database too
00838     //
00839     LockQueue = &KeGetCurrentPrcb()->LockQueue[LockQueuePfnLock];
00840     KeAcquireQueuedSpinLockAtDpcLevel(LockQueue);
00841 
00842     //
00843     // Loop the pages
00844     //
00845     TempPte = ValidKernelPte;
00846     do
00847     {
00848         /* Allocate a page */
00849         MI_SET_USAGE(MI_USAGE_PAGED_POOL);
00850         MI_SET_PROCESS2("Kernel");
00851         PageFrameNumber = MiRemoveAnyPage(MI_GET_NEXT_COLOR());
00852 
00853         /* Get the PFN entry for it and fill it out */
00854         Pfn1 = MiGetPfnEntry(PageFrameNumber);
00855         Pfn1->u3.e2.ReferenceCount = 1;
00856         Pfn1->u2.ShareCount = 1;
00857         Pfn1->PteAddress = PointerPte;
00858         Pfn1->u3.e1.PageLocation = ActiveAndValid;
00859         Pfn1->u4.VerifierAllocation = 0;
00860 
00861         /* Write the PTE for it */
00862         TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
00863         MI_WRITE_VALID_PTE(PointerPte++, TempPte);
00864     } while (--SizeInPages > 0);
00865 
00866     //
00867     // This is the last page
00868     //
00869     Pfn1->u3.e1.EndOfAllocation = 1;
00870 
00871     //
00872     // Get the first page and mark it as such
00873     //
00874     Pfn1 = MiGetPfnEntry(StartPte->u.Hard.PageFrameNumber);
00875     Pfn1->u3.e1.StartOfAllocation = 1;
00876 
00877     /* Mark it as a verifier allocation if needed */
00878     ASSERT(Pfn1->u4.VerifierAllocation == 0);
00879     if (PoolType & 64) Pfn1->u4.VerifierAllocation = 1;
00880 
00881     //
00882     // Release the PFN and nonpaged pool lock
00883     //
00884     KeReleaseQueuedSpinLockFromDpcLevel(LockQueue);
00885     KeReleaseQueuedSpinLock(LockQueueMmNonPagedPoolLock, OldIrql);
00886 
00887     //
00888     // Return the address
00889     //
00890     return MiPteToAddress(StartPte);
00891 }
00892 
00893 ULONG
00894 NTAPI
00895 MiFreePoolPages(IN PVOID StartingVa)
00896 {
00897     PMMPTE PointerPte, StartPte;
00898     PMMPFN Pfn1, StartPfn;
00899     PFN_COUNT FreePages, NumberOfPages;
00900     KIRQL OldIrql;
00901     PMMFREE_POOL_ENTRY FreeEntry, NextEntry, LastEntry;
00902     ULONG i, End;
00903     ULONG_PTR Offset;
00904 
00905     //
00906     // Handle paged pool
00907     //
00908     if ((StartingVa >= MmPagedPoolStart) && (StartingVa <= MmPagedPoolEnd))
00909     {
00910         //
00911         // Calculate the offset from the beginning of paged pool, and convert it
00912         // into pages
00913         //
00914         Offset = (ULONG_PTR)StartingVa - (ULONG_PTR)MmPagedPoolStart;
00915         i = (ULONG)(Offset >> PAGE_SHIFT);
00916         End = i;
00917 
00918         //
00919         // Now use the end bitmap to scan until we find a set bit, meaning that
00920         // this allocation finishes here
00921         //
00922         while (!RtlTestBit(MmPagedPoolInfo.EndOfPagedPoolBitmap, End)) End++;
00923 
00924         //
00925         // Now calculate the total number of pages this allocation spans. If it's
00926         // only one page, add it to the S-LIST instead of freeing it
00927         //
00928         NumberOfPages = End - i + 1;
00929         if ((NumberOfPages == 1) &&
00930             (ExQueryDepthSList(&MiPagedPoolSListHead) < MiPagedPoolSListMaximum))
00931         {
00932             InterlockedPushEntrySList(&MiPagedPoolSListHead, StartingVa);
00933             return 1;
00934         }
00935 
00936         /* Delete the actual pages */
00937         PointerPte = MmPagedPoolInfo.FirstPteForPagedPool + i;
00938         FreePages = MiDeleteSystemPageableVm(PointerPte, NumberOfPages, 0, NULL);
00939         ASSERT(FreePages == NumberOfPages);
00940 
00941         //
00942         // Acquire the paged pool lock
00943         //
00944         KeAcquireGuardedMutex(&MmPagedPoolMutex);
00945 
00946         //
00947         // Clear the allocation and free bits
00948         //
00949         RtlClearBit(MmPagedPoolInfo.EndOfPagedPoolBitmap, End);
00950         RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, i, NumberOfPages);
00951 
00952         //
00953         // Update the hint if we need to
00954         //
00955         if (i < MmPagedPoolInfo.PagedPoolHint) MmPagedPoolInfo.PagedPoolHint = i;
00956 
00957         //
00958         // Release the lock protecting the bitmaps
00959         //
00960         KeReleaseGuardedMutex(&MmPagedPoolMutex);
00961 
00962         //
00963         // And finally return the number of pages freed
00964         //
00965         return NumberOfPages;
00966     }
00967 
00968     //
00969     // Get the first PTE and its corresponding PFN entry. If this is also the
00970     // last PTE, meaning that this allocation was only for one page, push it into
00971     // the S-LIST instead of freeing it
00972     //
00973     StartPte = PointerPte = MiAddressToPte(StartingVa);
00974     StartPfn = Pfn1 = MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber);
00975     if ((Pfn1->u3.e1.EndOfAllocation == 1) &&
00976         (ExQueryDepthSList(&MiNonPagedPoolSListHead) < MiNonPagedPoolSListMaximum))
00977     {
00978         InterlockedPushEntrySList(&MiNonPagedPoolSListHead, StartingVa);
00979         return 1;
00980     }
00981 
00982     //
00983     // Loop until we find the last PTE
00984     //
00985     while (Pfn1->u3.e1.EndOfAllocation == 0)
00986     {
00987         //
00988         // Keep going
00989         //
00990         PointerPte++;
00991         Pfn1 = MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber);
00992     }
00993 
00994     //
00995     // Now we know how many pages we have
00996     //
00997     NumberOfPages = (PFN_COUNT)(PointerPte - StartPte + 1);
00998 
00999     //
01000     // Acquire the nonpaged pool lock
01001     //
01002     OldIrql = KeAcquireQueuedSpinLock(LockQueueMmNonPagedPoolLock);
01003 
01004     //
01005     // Mark the first and last PTEs as not part of an allocation anymore
01006     //
01007     StartPfn->u3.e1.StartOfAllocation = 0;
01008     Pfn1->u3.e1.EndOfAllocation = 0;
01009 
01010     //
01011     // Assume we will free as many pages as the allocation was
01012     //
01013     FreePages = NumberOfPages;
01014 
01015     //
01016     // Peek one page past the end of the allocation
01017     //
01018     PointerPte++;
01019 
01020     //
01021     // Guard against going past initial nonpaged pool
01022     //
01023     if (MiGetPfnEntryIndex(Pfn1) == MiEndOfInitialPoolFrame)
01024     {
01025         //
01026         // This page is on the outskirts of initial nonpaged pool, so ignore it
01027         //
01028         Pfn1 = NULL;
01029     }
01030     else
01031     {
01032         /* Sanity check */
01033         ASSERT((ULONG_PTR)StartingVa + NumberOfPages <= (ULONG_PTR)MmNonPagedPoolEnd);
01034 
01035         /* Check if protected pool is enabled */
01036         if (MmProtectFreedNonPagedPool)
01037         {
01038             /* The freed block will be merged, it must be made accessible */
01039             MiUnProtectFreeNonPagedPool(MiPteToAddress(PointerPte), 0);
01040         }
01041 
01042         //
01043         // Otherwise, our entire allocation must've fit within the initial non
01044         // paged pool, or the expansion nonpaged pool, so get the PFN entry of
01045         // the next allocation
01046         //
01047         if (PointerPte->u.Hard.Valid == 1)
01048         {
01049             //
01050             // It's either expansion or initial: get the PFN entry
01051             //
01052             Pfn1 = MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber);
01053         }
01054         else
01055         {
01056             //
01057             // This means we've reached the guard page that protects the end of
01058             // the expansion nonpaged pool
01059             //
01060             Pfn1 = NULL;
01061         }
01062 
01063     }
01064 
01065     //
01066     // Check if this allocation actually exists
01067     //
01068     if ((Pfn1) && (Pfn1->u3.e1.StartOfAllocation == 0))
01069     {
01070         //
01071         // It doesn't, so we should actually locate a free entry descriptor
01072         //
01073         FreeEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)StartingVa +
01074                                          (NumberOfPages << PAGE_SHIFT));
01075         ASSERT(FreeEntry->Signature == MM_FREE_POOL_SIGNATURE);
01076         ASSERT(FreeEntry->Owner == FreeEntry);
01077 
01078         /* Consume this entry's pages */
01079         FreePages += FreeEntry->Size;
01080 
01081         /* Remove the item from the list, depending if pool is protected */
01082         MmProtectFreedNonPagedPool ?
01083             MiProtectedPoolRemoveEntryList(&FreeEntry->List) :
01084             RemoveEntryList(&FreeEntry->List);
01085     }
01086 
01087     //
01088     // Now get the official free entry we'll create for the caller's allocation
01089     //
01090     FreeEntry = StartingVa;
01091 
01092     //
01093     // Check if the our allocation is the very first page
01094     //
01095     if (MiGetPfnEntryIndex(StartPfn) == MiStartOfInitialPoolFrame)
01096     {
01097         //
01098         // Then we can't do anything or we'll risk underflowing
01099         //
01100         Pfn1 = NULL;
01101     }
01102     else
01103     {
01104         //
01105         // Otherwise, get the PTE for the page right before our allocation
01106         //
01107         PointerPte -= NumberOfPages + 1;
01108 
01109         /* Check if protected pool is enabled */
01110         if (MmProtectFreedNonPagedPool)
01111         {
01112             /* The freed block will be merged, it must be made accessible */
01113             MiUnProtectFreeNonPagedPool(MiPteToAddress(PointerPte), 0);
01114         }
01115 
01116         /* Check if this is valid pool, or a guard page */
01117         if (PointerPte->u.Hard.Valid == 1)
01118         {
01119             //
01120             // It's either expansion or initial nonpaged pool, get the PFN entry
01121             //
01122             Pfn1 = MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber);
01123         }
01124         else
01125         {
01126             //
01127             // We must've reached the guard page, so don't risk touching it
01128             //
01129             Pfn1 = NULL;
01130         }
01131     }
01132 
01133     //
01134     // Check if there is a valid PFN entry for the page before the allocation
01135     // and then check if this page was actually the end of an allocation.
01136     // If it wasn't, then we know for sure it's a free page
01137     //
01138     if ((Pfn1) && (Pfn1->u3.e1.EndOfAllocation == 0))
01139     {
01140         //
01141         // Get the free entry descriptor for that given page range
01142         //
01143         FreeEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)StartingVa - PAGE_SIZE);
01144         ASSERT(FreeEntry->Signature == MM_FREE_POOL_SIGNATURE);
01145         FreeEntry = FreeEntry->Owner;
01146 
01147         /* Check if protected pool is enabled */
01148         if (MmProtectFreedNonPagedPool)
01149         {
01150             /* The freed block will be merged, it must be made accessible */
01151             MiUnProtectFreeNonPagedPool(FreeEntry, 0);
01152         }
01153 
01154         //
01155         // Check if the entry is small enough to be indexed on a free list
01156         // If it is, we'll want to re-insert it, since we're about to
01157         // collapse our pages on top of it, which will change its count
01158         //
01159         if (FreeEntry->Size < (MI_MAX_FREE_PAGE_LISTS - 1))
01160         {
01161             /* Remove the item from the list, depending if pool is protected */
01162             MmProtectFreedNonPagedPool ?
01163                 MiProtectedPoolRemoveEntryList(&FreeEntry->List) :
01164                 RemoveEntryList(&FreeEntry->List);
01165 
01166             //
01167             // Update its size
01168             //
01169             FreeEntry->Size += FreePages;
01170 
01171             //
01172             // And now find the new appropriate list to place it in
01173             //
01174             i = (ULONG)(FreeEntry->Size - 1);
01175             if (i >= MI_MAX_FREE_PAGE_LISTS) i = MI_MAX_FREE_PAGE_LISTS - 1;
01176 
01177             /* Insert the entry into the free list head, check for prot. pool */
01178             MmProtectFreedNonPagedPool ?
01179                 MiProtectedPoolInsertList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List, TRUE) :
01180                 InsertTailList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List);
01181         }
01182         else
01183         {
01184             //
01185             // Otherwise, just combine our free pages into this entry
01186             //
01187             FreeEntry->Size += FreePages;
01188         }
01189     }
01190 
01191     //
01192     // Check if we were unable to do any compaction, and we'll stick with this
01193     //
01194     if (FreeEntry == StartingVa)
01195     {
01196         //
01197         // Well, now we are a free entry. At worse we just have our newly freed
01198         // pages, at best we have our pages plus whatever entry came after us
01199         //
01200         FreeEntry->Size = FreePages;
01201 
01202         //
01203         // Find the appropriate list we should be on
01204         //
01205         i = FreeEntry->Size - 1;
01206         if (i >= MI_MAX_FREE_PAGE_LISTS) i = MI_MAX_FREE_PAGE_LISTS - 1;
01207 
01208         /* Insert the entry into the free list head, check for prot. pool */
01209         MmProtectFreedNonPagedPool ?
01210             MiProtectedPoolInsertList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List, TRUE) :
01211             InsertTailList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List);
01212     }
01213 
01214     //
01215     // Just a sanity check
01216     //
01217     ASSERT(FreePages != 0);
01218 
01219     //
01220     // Get all the pages between our allocation and its end. These will all now
01221     // become free page chunks.
01222     //
01223     NextEntry = StartingVa;
01224     LastEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)NextEntry + (FreePages << PAGE_SHIFT));
01225     do
01226     {
01227         //
01228         // Link back to the parent free entry, and keep going
01229         //
01230         NextEntry->Owner = FreeEntry;
01231         NextEntry->Signature = MM_FREE_POOL_SIGNATURE;
01232         NextEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)NextEntry + PAGE_SIZE);
01233     } while (NextEntry != LastEntry);
01234 
01235     /* Is freed non paged pool protected? */
01236     if (MmProtectFreedNonPagedPool)
01237     {
01238         /* Protect the freed pool! */
01239         MiProtectFreeNonPagedPool(FreeEntry, FreeEntry->Size);
01240     }
01241 
01242     //
01243     // We're done, release the lock and let the caller know how much we freed
01244     //
01245     KeReleaseQueuedSpinLock(LockQueueMmNonPagedPoolLock, OldIrql);
01246     return NumberOfPages;
01247 }
01248 
01249 
01250 BOOLEAN
01251 NTAPI
01252 MiRaisePoolQuota(IN POOL_TYPE PoolType,
01253                  IN ULONG CurrentMaxQuota,
01254                  OUT PULONG NewMaxQuota)
01255 {
01256     //
01257     // Not implemented
01258     //
01259     UNIMPLEMENTED;
01260     *NewMaxQuota = CurrentMaxQuota + 65536;
01261     return TRUE;
01262 }
01263 
01264 /* PUBLIC FUNCTIONS ***********************************************************/
01265 
01266 /*
01267  * @unimplemented
01268  */
01269 PVOID
01270 NTAPI
01271 MmAllocateMappingAddress(IN SIZE_T NumberOfBytes,
01272                          IN ULONG PoolTag)
01273 {
01274     UNIMPLEMENTED;
01275     return NULL;
01276 }
01277 
01278 /*
01279  * @unimplemented
01280  */
01281 VOID
01282 NTAPI
01283 MmFreeMappingAddress(IN PVOID BaseAddress,
01284                      IN ULONG PoolTag)
01285 {
01286     UNIMPLEMENTED;
01287 }
01288 
01289 /* EOF */

Generated on Sat May 26 2012 04:36:23 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.