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

mdlsup.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/mdlsup.c
00005  * PURPOSE:         ARM Memory Manager Memory Descriptor List (MDL) Management
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 BOOLEAN MmTrackPtes;
00021 BOOLEAN MmTrackLockedPages;
00022 SIZE_T MmSystemLockPagesCount;
00023 
00024 /* PUBLIC FUNCTIONS ***********************************************************/
00025 
00026 /*
00027  * @implemented
00028  */
00029 PMDL
00030 NTAPI
00031 MmCreateMdl(IN PMDL Mdl,
00032             IN PVOID Base,
00033             IN SIZE_T Length)
00034 {
00035     SIZE_T Size;
00036 
00037     //
00038     // Check if we don't have an MDL built
00039     //
00040     if (!Mdl)
00041     {
00042         //
00043         // Calculate the size we'll need  and allocate the MDL
00044         //
00045         Size = MmSizeOfMdl(Base, Length);
00046         Mdl = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MDL);
00047         if (!Mdl) return NULL;
00048     }
00049 
00050     //
00051     // Initialize it
00052     //
00053     MmInitializeMdl(Mdl, Base, Length);
00054     return Mdl;
00055 }
00056 
00057 /*
00058  * @implemented
00059  */
00060 SIZE_T
00061 NTAPI
00062 MmSizeOfMdl(IN PVOID Base,
00063             IN SIZE_T Length)
00064 {
00065     //
00066     // Return the MDL size
00067     //
00068     return sizeof(MDL) +
00069            (ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base, Length) * sizeof(PFN_NUMBER));
00070 }
00071 
00072 /*
00073  * @implemented
00074  */
00075 VOID
00076 NTAPI
00077 MmBuildMdlForNonPagedPool(IN PMDL Mdl)
00078 {
00079     PPFN_NUMBER MdlPages, EndPage;
00080     PFN_NUMBER Pfn, PageCount;
00081     PVOID Base;
00082     PMMPTE PointerPte;
00083 
00084     //
00085     // Sanity checks
00086     //
00087     ASSERT(Mdl->ByteCount != 0);
00088     ASSERT((Mdl->MdlFlags & (MDL_PAGES_LOCKED |
00089                              MDL_MAPPED_TO_SYSTEM_VA |
00090                              MDL_SOURCE_IS_NONPAGED_POOL |
00091                              MDL_PARTIAL)) == 0);
00092 
00093     //
00094     // We know the MDL isn't associated to a process now
00095     //
00096     Mdl->Process = NULL;
00097 
00098     //
00099     // Get page and VA information
00100     //
00101     MdlPages = (PPFN_NUMBER)(Mdl + 1);
00102     Base = Mdl->StartVa;
00103 
00104     //
00105     // Set the system address and now get the page count
00106     //
00107     Mdl->MappedSystemVa = (PVOID)((ULONG_PTR)Base + Mdl->ByteOffset);
00108     PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Mdl->MappedSystemVa,
00109                                                Mdl->ByteCount);
00110     ASSERT(PageCount != 0);
00111     EndPage = MdlPages + PageCount;
00112 
00113     //
00114     // Loop the PTEs
00115     //
00116     PointerPte = MiAddressToPte(Base);
00117     do
00118     {
00119         //
00120         // Write the PFN
00121         //
00122         Pfn = PFN_FROM_PTE(PointerPte++);
00123         *MdlPages++ = Pfn;
00124     } while (MdlPages < EndPage);
00125 
00126     //
00127     // Set the nonpaged pool flag
00128     //
00129     Mdl->MdlFlags |= MDL_SOURCE_IS_NONPAGED_POOL;
00130 
00131     //
00132     // Check if this is an I/O mapping
00133     //
00134     if (!MiGetPfnEntry(Pfn)) Mdl->MdlFlags |= MDL_IO_SPACE;
00135 }
00136 
00137 /*
00138  * @implemented
00139  */
00140 PMDL
00141 NTAPI
00142 MmAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress,
00143                       IN PHYSICAL_ADDRESS HighAddress,
00144                       IN PHYSICAL_ADDRESS SkipBytes,
00145                       IN SIZE_T TotalBytes)
00146 {
00147     //
00148     // Call the internal routine
00149     //
00150     return MiAllocatePagesForMdl(LowAddress,
00151                                  HighAddress,
00152                                  SkipBytes,
00153                                  TotalBytes,
00154                                  MiNotMapped,
00155                                  0);
00156 }
00157 
00158 /*
00159  * @implemented
00160  */
00161 PMDL
00162 NTAPI
00163 MmAllocatePagesForMdlEx(IN PHYSICAL_ADDRESS LowAddress,
00164                         IN PHYSICAL_ADDRESS HighAddress,
00165                         IN PHYSICAL_ADDRESS SkipBytes,
00166                         IN SIZE_T TotalBytes,
00167                         IN MEMORY_CACHING_TYPE CacheType,
00168                         IN ULONG Flags)
00169 {
00170     MI_PFN_CACHE_ATTRIBUTE CacheAttribute;
00171 
00172     //
00173     // Check for invalid cache type
00174     //
00175     if (CacheType > MmWriteCombined)
00176     {
00177         //
00178         // Normalize to default
00179         //
00180         CacheAttribute = MiNotMapped;
00181     }
00182     else
00183     {
00184         //
00185         // Conver to internal caching attribute
00186         //
00187         CacheAttribute = MiPlatformCacheAttributes[FALSE][CacheType];
00188     }
00189 
00190     //
00191     // Only these flags are allowed
00192     //
00193     if (Flags & ~(MM_DONT_ZERO_ALLOCATION | MM_ALLOCATE_FROM_LOCAL_NODE_ONLY))
00194     {
00195         //
00196         // Silently fail
00197         //
00198         return NULL;
00199     }
00200 
00201     //
00202     // Call the internal routine
00203     //
00204     return MiAllocatePagesForMdl(LowAddress,
00205                                  HighAddress,
00206                                  SkipBytes,
00207                                  TotalBytes,
00208                                  CacheAttribute,
00209                                  Flags);
00210 }
00211 
00212 /*
00213  * @implemented
00214  */
00215 VOID
00216 NTAPI
00217 MmFreePagesFromMdl(IN PMDL Mdl)
00218 {
00219     PVOID Base;
00220     PPFN_NUMBER Pages;
00221     LONG NumberOfPages;
00222     PMMPFN Pfn1;
00223     KIRQL OldIrql;
00224     DPRINT("Freeing MDL: %p\n", Mdl);
00225 
00226     //
00227     // Sanity checks
00228     //
00229     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
00230     ASSERT((Mdl->MdlFlags & MDL_IO_SPACE) == 0);
00231     ASSERT(((ULONG_PTR)Mdl->StartVa & (PAGE_SIZE - 1)) == 0);
00232 
00233     //
00234     // Get address and page information
00235     //
00236     Base = (PVOID)((ULONG_PTR)Mdl->StartVa + Mdl->ByteOffset);
00237     NumberOfPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base, Mdl->ByteCount);
00238 
00239     //
00240     // Acquire PFN lock
00241     //
00242     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00243 
00244     //
00245     // Loop all the MDL pages
00246     //
00247     Pages = (PPFN_NUMBER)(Mdl + 1);
00248     do
00249     {
00250         //
00251         // Reached the last page
00252         //
00253         if (*Pages == LIST_HEAD) break;
00254 
00255         //
00256         // Get the page entry
00257         //
00258         Pfn1 = MiGetPfnEntry(*Pages);
00259         ASSERT(Pfn1);
00260         ASSERT(Pfn1->u2.ShareCount == 1);
00261         ASSERT(MI_IS_PFN_DELETED(Pfn1) == TRUE);
00262         if (Pfn1->u4.PteFrame != 0x1FFEDCB)
00263         {
00264             /* Corrupted PFN entry or invalid free */
00265             KeBugCheckEx(MEMORY_MANAGEMENT, 0x1236, (ULONG_PTR)Mdl, (ULONG_PTR)Pages, *Pages);
00266         }
00267 
00268         //
00269         // Clear it
00270         //
00271         Pfn1->u3.e1.StartOfAllocation = 0;
00272         Pfn1->u3.e1.EndOfAllocation = 0;
00273         Pfn1->u2.ShareCount = 0;
00274 
00275         //
00276         // Dereference it
00277         //
00278         ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
00279         if (Pfn1->u3.e2.ReferenceCount != 1)
00280         {
00281             /* Just take off one reference */
00282             InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
00283         }
00284         else
00285         {
00286             /* We'll be nuking the whole page */
00287             MiDecrementReferenceCount(Pfn1, *Pages);
00288         }
00289 
00290         //
00291         // Clear this page and move on
00292         //
00293         *Pages++ = LIST_HEAD;
00294     } while (--NumberOfPages != 0);
00295 
00296     //
00297     // Release the lock
00298     //
00299     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00300 
00301     //
00302     // Remove the pages locked flag
00303     //
00304     Mdl->MdlFlags &= ~MDL_PAGES_LOCKED;
00305 }
00306 
00307 /*
00308  * @implemented
00309  */
00310 PVOID
00311 NTAPI
00312 MmMapLockedPagesSpecifyCache(IN PMDL Mdl,
00313                              IN KPROCESSOR_MODE AccessMode,
00314                              IN MEMORY_CACHING_TYPE CacheType,
00315                              IN PVOID BaseAddress,
00316                              IN ULONG BugCheckOnFailure,
00317                              IN MM_PAGE_PRIORITY Priority)
00318 {
00319     PVOID Base;
00320     PPFN_NUMBER MdlPages, LastPage;
00321     PFN_COUNT PageCount;
00322     BOOLEAN IsIoMapping;
00323     MI_PFN_CACHE_ATTRIBUTE CacheAttribute;
00324     PMMPTE PointerPte;
00325     MMPTE TempPte;
00326 
00327     //
00328     // Sanity check
00329     //
00330     ASSERT(Mdl->ByteCount != 0);
00331 
00332     //
00333     // Get the base
00334     //
00335     Base = (PVOID)((ULONG_PTR)Mdl->StartVa + Mdl->ByteOffset);
00336 
00337     //
00338     // Handle kernel case first
00339     //
00340     if (AccessMode == KernelMode)
00341     {
00342         //
00343         // Get the list of pages and count
00344         //
00345         MdlPages = (PPFN_NUMBER)(Mdl + 1);
00346         PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base, Mdl->ByteCount);
00347         LastPage = MdlPages + PageCount;
00348 
00349         //
00350         // Sanity checks
00351         //
00352         ASSERT((Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA |
00353                                  MDL_SOURCE_IS_NONPAGED_POOL |
00354                                  MDL_PARTIAL_HAS_BEEN_MAPPED)) == 0);
00355         ASSERT((Mdl->MdlFlags & (MDL_PAGES_LOCKED | MDL_PARTIAL)) != 0);
00356 
00357         //
00358         // Get the correct cache type
00359         //
00360         IsIoMapping = (Mdl->MdlFlags & MDL_IO_SPACE) != 0;
00361         CacheAttribute = MiPlatformCacheAttributes[IsIoMapping][CacheType];
00362 
00363         //
00364         // Reserve the PTEs
00365         //
00366         PointerPte = MiReserveSystemPtes(PageCount, SystemPteSpace);
00367         if (!PointerPte)
00368         {
00369             //
00370             // If it can fail, return NULL
00371             //
00372             if (Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL) return NULL;
00373 
00374             //
00375             // Should we bugcheck?
00376             //
00377             if (!BugCheckOnFailure) return NULL;
00378 
00379             //
00380             // Yes, crash the system
00381             //
00382             KeBugCheckEx(NO_MORE_SYSTEM_PTES, 0, PageCount, 0, 0);
00383         }
00384 
00385         //
00386         // Get the mapped address
00387         //
00388         Base = (PVOID)((ULONG_PTR)MiPteToAddress(PointerPte) + Mdl->ByteOffset);
00389 
00390         //
00391         // Get the template
00392         //
00393         TempPte = ValidKernelPte;
00394         switch (CacheAttribute)
00395         {
00396             case MiNonCached:
00397 
00398                 //
00399                 // Disable caching
00400                 //
00401                 MI_PAGE_DISABLE_CACHE(&TempPte);
00402                 MI_PAGE_WRITE_THROUGH(&TempPte);
00403                 break;
00404 
00405             case MiWriteCombined:
00406 
00407                 //
00408                 // Enable write combining
00409                 //
00410                 MI_PAGE_DISABLE_CACHE(&TempPte);
00411                 MI_PAGE_WRITE_COMBINED(&TempPte);
00412                 break;
00413 
00414             default:
00415                 //
00416                 // Nothing to do
00417                 //
00418                 break;
00419         }
00420 
00421         //
00422         // Loop all PTEs
00423         //
00424         do
00425         {
00426             //
00427             // We're done here
00428             //
00429             if (*MdlPages == LIST_HEAD) break;
00430 
00431             //
00432             // Write the PTE
00433             //
00434             TempPte.u.Hard.PageFrameNumber = *MdlPages;
00435             MI_WRITE_VALID_PTE(PointerPte++, TempPte);
00436         } while (++MdlPages < LastPage);
00437 
00438         //
00439         // Mark it as mapped
00440         //
00441         ASSERT((Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) == 0);
00442         Mdl->MappedSystemVa = Base;
00443         Mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
00444 
00445         //
00446         // Check if it was partial
00447         //
00448         if (Mdl->MdlFlags & MDL_PARTIAL)
00449         {
00450             //
00451             // Write the appropriate flag here too
00452             //
00453             Mdl->MdlFlags |= MDL_PARTIAL_HAS_BEEN_MAPPED;
00454         }
00455 
00456         //
00457         // Return the mapped address
00458         //
00459         return Base;
00460     }
00461 
00462     UNIMPLEMENTED;
00463     return NULL;
00464 }
00465 
00466 /*
00467  * @implemented
00468  */
00469 PVOID
00470 NTAPI
00471 MmMapLockedPages(IN PMDL Mdl,
00472                  IN KPROCESSOR_MODE AccessMode)
00473 {
00474     //
00475     // Call the extended version
00476     //
00477     return MmMapLockedPagesSpecifyCache(Mdl,
00478                                         AccessMode,
00479                                         MmCached,
00480                                         NULL,
00481                                         TRUE,
00482                                         HighPagePriority);
00483 }
00484 
00485 /*
00486  * @implemented
00487  */
00488 VOID
00489 NTAPI
00490 MmUnmapLockedPages(IN PVOID BaseAddress,
00491                    IN PMDL Mdl)
00492 {
00493     PVOID Base;
00494     PFN_COUNT PageCount, ExtraPageCount;
00495     PPFN_NUMBER MdlPages;
00496     PMMPTE PointerPte;
00497 
00498     //
00499     // Sanity check
00500     //
00501     ASSERT(Mdl->ByteCount != 0);
00502 
00503     //
00504     // Check if this is a kernel request
00505     //
00506     if (BaseAddress > MM_HIGHEST_USER_ADDRESS)
00507     {
00508         //
00509         // Get base and count information
00510         //
00511         Base = (PVOID)((ULONG_PTR)Mdl->StartVa + Mdl->ByteOffset);
00512         PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base, Mdl->ByteCount);
00513 
00514         //
00515         // Sanity checks
00516         //
00517         ASSERT((Mdl->MdlFlags & MDL_PARENT_MAPPED_SYSTEM_VA) == 0);
00518         ASSERT(PageCount != 0);
00519         ASSERT(Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA);
00520 
00521         //
00522         // Get the PTE
00523         //
00524         PointerPte = MiAddressToPte(BaseAddress);
00525 
00526         //
00527         // This should be a resident system PTE
00528         //
00529         ASSERT(PointerPte >= MmSystemPtesStart[SystemPteSpace]);
00530         ASSERT(PointerPte <= MmSystemPtesEnd[SystemPteSpace]);
00531         ASSERT(PointerPte->u.Hard.Valid == 1);
00532 
00533         //
00534         // Check if the caller wants us to free advanced pages
00535         //
00536         if (Mdl->MdlFlags & MDL_FREE_EXTRA_PTES)
00537         {
00538             //
00539             // Get the MDL page array
00540             //
00541             MdlPages = MmGetMdlPfnArray(Mdl);
00542 
00543             /* Number of extra pages stored after the PFN array */
00544             ExtraPageCount = (PFN_COUNT)*(MdlPages + PageCount);
00545 
00546             //
00547             // Do the math
00548             //
00549             PageCount += ExtraPageCount;
00550             PointerPte -= ExtraPageCount;
00551             ASSERT(PointerPte >= MmSystemPtesStart[SystemPteSpace]);
00552             ASSERT(PointerPte <= MmSystemPtesEnd[SystemPteSpace]);
00553 
00554             //
00555             // Get the new base address
00556             //
00557             BaseAddress = (PVOID)((ULONG_PTR)BaseAddress -
00558                                   (ExtraPageCount << PAGE_SHIFT));
00559         }
00560 
00561         //
00562         // Remove flags
00563         //
00564         Mdl->MdlFlags &= ~(MDL_MAPPED_TO_SYSTEM_VA |
00565                            MDL_PARTIAL_HAS_BEEN_MAPPED |
00566                            MDL_FREE_EXTRA_PTES);
00567 
00568         //
00569         // Release the system PTEs
00570         //
00571         MiReleaseSystemPtes(PointerPte, PageCount, SystemPteSpace);
00572     }
00573     else
00574     {
00575         UNIMPLEMENTED;
00576     }
00577 }
00578 
00579 /*
00580  * @implemented
00581  */
00582 VOID
00583 NTAPI
00584 MmProbeAndLockPages(IN PMDL Mdl,
00585                     IN KPROCESSOR_MODE AccessMode,
00586                     IN LOCK_OPERATION Operation)
00587 {
00588     PPFN_NUMBER MdlPages;
00589     PVOID Base, Address, LastAddress, StartAddress;
00590     ULONG LockPages, TotalPages;
00591     NTSTATUS Status = STATUS_SUCCESS;
00592     PEPROCESS CurrentProcess;
00593     NTSTATUS ProbeStatus;
00594     PMMPTE PointerPte, LastPte;
00595     PMMPDE PointerPde;
00596 #if (_MI_PAGING_LEVELS >= 3)
00597     PMMPDE PointerPpe;
00598 #endif
00599 #if (_MI_PAGING_LEVELS == 4)
00600     PMMPDE PointerPxe;
00601 #endif
00602     PFN_NUMBER PageFrameIndex;
00603     BOOLEAN UsePfnLock;
00604     KIRQL OldIrql;
00605     USHORT OldRefCount, RefCount;
00606     PMMPFN Pfn1;
00607     DPRINT("Probing MDL: %p\n", Mdl);
00608 
00609     //
00610     // Sanity checks
00611     //
00612     ASSERT(Mdl->ByteCount != 0);
00613     ASSERT(((ULONG)Mdl->ByteOffset & ~(PAGE_SIZE - 1)) == 0);
00614     ASSERT(((ULONG_PTR)Mdl->StartVa & (PAGE_SIZE - 1)) == 0);
00615     ASSERT((Mdl->MdlFlags & (MDL_PAGES_LOCKED |
00616                              MDL_MAPPED_TO_SYSTEM_VA |
00617                              MDL_SOURCE_IS_NONPAGED_POOL |
00618                              MDL_PARTIAL |
00619                              MDL_IO_SPACE)) == 0);
00620 
00621     //
00622     // Get page and base information
00623     //
00624     MdlPages = (PPFN_NUMBER)(Mdl + 1);
00625     Base = Mdl->StartVa;
00626 
00627     //
00628     // Get the addresses and how many pages we span (and need to lock)
00629     //
00630     Address = (PVOID)((ULONG_PTR)Base + Mdl->ByteOffset);
00631     LastAddress = (PVOID)((ULONG_PTR)Address + Mdl->ByteCount);
00632     LockPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Address, Mdl->ByteCount);
00633     ASSERT(LockPages != 0);
00634 
00635     /* Block invalid access */
00636     if ((AccessMode != KernelMode) &&
00637         ((LastAddress > (PVOID)MM_USER_PROBE_ADDRESS) || (Address >= LastAddress)))
00638     {
00639         /* Caller should be in SEH, raise the error */
00640         *MdlPages = LIST_HEAD;
00641         ExRaiseStatus(STATUS_ACCESS_VIOLATION);
00642     }
00643 
00644     //
00645     // Get the process
00646     //
00647     if (Address <= MM_HIGHEST_USER_ADDRESS)
00648     {
00649         //
00650         // Get the process
00651         //
00652         CurrentProcess = PsGetCurrentProcess();
00653     }
00654     else
00655     {
00656         //
00657         // No process
00658         //
00659         CurrentProcess = NULL;
00660     }
00661 
00662     //
00663     // Save the number of pages we'll have to lock, and the start address
00664     //
00665     TotalPages = LockPages;
00666     StartAddress = Address;
00667 
00668     /* Large pages not supported */
00669     ASSERT(!MI_IS_PHYSICAL_ADDRESS(Address));
00670 
00671     //
00672     // Now probe them
00673     //
00674     ProbeStatus = STATUS_SUCCESS;
00675     _SEH2_TRY
00676     {
00677         //
00678         // Enter probe loop
00679         //
00680         do
00681         {
00682             //
00683             // Assume failure
00684             //
00685             *MdlPages = LIST_HEAD;
00686 
00687             //
00688             // Read
00689             //
00690             *(volatile CHAR*)Address;
00691 
00692             //
00693             // Check if this is write access (only probe for user-mode)
00694             //
00695             if ((Operation != IoReadAccess) &&
00696                 (Address <= MM_HIGHEST_USER_ADDRESS))
00697             {
00698                 //
00699                 // Probe for write too
00700                 //
00701                 ProbeForWriteChar(Address);
00702             }
00703 
00704             //
00705             // Next address...
00706             //
00707             Address = PAGE_ALIGN((ULONG_PTR)Address + PAGE_SIZE);
00708 
00709             //
00710             // Next page...
00711             //
00712             LockPages--;
00713             MdlPages++;
00714         } while (Address < LastAddress);
00715 
00716         //
00717         // Reset back to the original page
00718         //
00719         ASSERT(LockPages == 0);
00720         MdlPages = (PPFN_NUMBER)(Mdl + 1);
00721     }
00722     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00723     {
00724         //
00725         // Oops :(
00726         //
00727         ProbeStatus = _SEH2_GetExceptionCode();
00728     }
00729     _SEH2_END;
00730 
00731     //
00732     // So how did that go?
00733     //
00734     if (ProbeStatus != STATUS_SUCCESS)
00735     {
00736         //
00737         // Fail
00738         //
00739         DPRINT1("MDL PROBE FAILED!\n");
00740         Mdl->Process = NULL;
00741         ExRaiseStatus(ProbeStatus);
00742     }
00743 
00744     //
00745     // Get the PTE and PDE
00746     //
00747     PointerPte = MiAddressToPte(StartAddress);
00748     PointerPde = MiAddressToPde(StartAddress);
00749 #if (_MI_PAGING_LEVELS >= 3)
00750     PointerPpe = MiAddressToPpe(StartAddress);
00751 #endif
00752 #if (_MI_PAGING_LEVELS == 4)
00753     PointerPxe = MiAddressToPxe(StartAddress);
00754 #endif
00755 
00756     //
00757     // Sanity check
00758     //
00759     ASSERT(MdlPages == (PPFN_NUMBER)(Mdl + 1));
00760 
00761     //
00762     // Check what kind of operation this is
00763     //
00764     if (Operation != IoReadAccess)
00765     {
00766         //
00767         // Set the write flag
00768         //
00769         Mdl->MdlFlags |= MDL_WRITE_OPERATION;
00770     }
00771     else
00772     {
00773         //
00774         // Remove the write flag
00775         //
00776         Mdl->MdlFlags &= ~(MDL_WRITE_OPERATION);
00777     }
00778 
00779     //
00780     // Mark the MDL as locked *now*
00781     //
00782     Mdl->MdlFlags |= MDL_PAGES_LOCKED;
00783 
00784     //
00785     // Check if this came from kernel mode
00786     //
00787     if (Base > MM_HIGHEST_USER_ADDRESS)
00788     {
00789         //
00790         // We should not have a process
00791         //
00792         ASSERT(CurrentProcess == NULL);
00793         Mdl->Process = NULL;
00794 
00795         //
00796         // In kernel mode, we don't need to check for write access
00797         //
00798         Operation = IoReadAccess;
00799 
00800         //
00801         // Use the PFN lock
00802         //
00803         UsePfnLock = TRUE;
00804         OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00805     }
00806     else
00807     {
00808         //
00809         // Sanity checks
00810         //
00811         ASSERT(TotalPages != 0);
00812         ASSERT(CurrentProcess == PsGetCurrentProcess());
00813 
00814         //
00815         // Track locked pages
00816         //
00817         InterlockedExchangeAddSizeT(&CurrentProcess->NumberOfLockedPages,
00818                                     TotalPages);
00819 
00820         //
00821         // Save the process
00822         //
00823         Mdl->Process = CurrentProcess;
00824 
00825         /* Lock the process working set */
00826         MiLockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
00827         UsePfnLock = FALSE;
00828         OldIrql = MM_NOIRQL;
00829     }
00830 
00831     //
00832     // Get the last PTE
00833     //
00834     LastPte = MiAddressToPte((PVOID)((ULONG_PTR)LastAddress - 1));
00835 
00836     //
00837     // Loop the pages
00838     //
00839     do
00840     {
00841         //
00842         // Assume failure and check for non-mapped pages
00843         //
00844         *MdlPages = LIST_HEAD;
00845         while (
00846 #if (_MI_PAGING_LEVELS == 4)
00847                (PointerPxe->u.Hard.Valid == 0) ||
00848 #endif
00849 #if (_MI_PAGING_LEVELS >= 3)
00850                (PointerPpe->u.Hard.Valid == 0) ||
00851 #endif
00852                (PointerPde->u.Hard.Valid == 0) ||
00853                (PointerPte->u.Hard.Valid == 0))
00854         {
00855             //
00856             // What kind of lock were we using?
00857             //
00858             if (UsePfnLock)
00859             {
00860                 //
00861                 // Release PFN lock
00862                 //
00863                 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00864             }
00865             else
00866             {
00867                 /* Release process working set */
00868                 MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
00869             }
00870 
00871             //
00872             // Access the page
00873             //
00874             Address = MiPteToAddress(PointerPte);
00875 
00876             //HACK: Pass a placeholder TrapInformation so the fault handler knows we're unlocked
00877             Status = MmAccessFault(FALSE, Address, KernelMode, (PVOID)0xBADBADA3);
00878             if (!NT_SUCCESS(Status))
00879             {
00880                 //
00881                 // Fail
00882                 //
00883                 DPRINT1("Access fault failed\n");
00884                 goto Cleanup;
00885             }
00886 
00887             //
00888             // What lock should we use?
00889             //
00890             if (UsePfnLock)
00891             {
00892                 //
00893                 // Grab the PFN lock
00894                 //
00895                 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00896             }
00897             else
00898             {
00899                 /* Lock the process working set */
00900                 MiLockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
00901             }
00902         }
00903 
00904         //
00905         // Check if this was a write or modify
00906         //
00907         if (Operation != IoReadAccess)
00908         {
00909             //
00910             // Check if the PTE is not writable
00911             //
00912             if (MI_IS_PAGE_WRITEABLE(PointerPte) == FALSE)
00913             {
00914                 //
00915                 // Check if it's copy on write
00916                 //
00917                 if (MI_IS_PAGE_COPY_ON_WRITE(PointerPte))
00918                 {
00919                     //
00920                     // Get the base address and allow a change for user-mode
00921                     //
00922                     Address = MiPteToAddress(PointerPte);
00923                     if (Address <= MM_HIGHEST_USER_ADDRESS)
00924                     {
00925                         //
00926                         // What kind of lock were we using?
00927                         //
00928                         if (UsePfnLock)
00929                         {
00930                             //
00931                             // Release PFN lock
00932                             //
00933                             KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
00934                         }
00935                         else
00936                         {
00937                             /* Release process working set */
00938                             MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
00939                         }
00940 
00941                         //
00942                         // Access the page
00943                         //
00944 
00945                         //HACK: Pass a placeholder TrapInformation so the fault handler knows we're unlocked
00946                         Status = MmAccessFault(TRUE, Address, KernelMode, (PVOID)0xBADBADA3);
00947                         if (!NT_SUCCESS(Status))
00948                         {
00949                             //
00950                             // Fail
00951                             //
00952                             DPRINT1("Access fault failed\n");
00953                             goto Cleanup;
00954                         }
00955 
00956                         //
00957                         // Re-acquire the lock
00958                         //
00959                         if (UsePfnLock)
00960                         {
00961                             //
00962                             // Grab the PFN lock
00963                             //
00964                             OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
00965                         }
00966                         else
00967                         {
00968                             /* Lock the process working set */
00969                             MiLockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
00970                         }
00971 
00972                         //
00973                         // Start over
00974                         //
00975                         continue;
00976                     }
00977                 }
00978 
00979                 //
00980                 // Fail, since we won't allow this
00981                 //
00982                 Status = STATUS_ACCESS_VIOLATION;
00983                 goto CleanupWithLock;
00984             }
00985         }
00986 
00987         //
00988         // Grab the PFN
00989         //
00990         PageFrameIndex = PFN_FROM_PTE(PointerPte);
00991         Pfn1 = MiGetPfnEntry(PageFrameIndex);
00992         if (Pfn1)
00993         {
00994             /* Either this is for kernel-mode, or the working set is held */
00995             ASSERT((CurrentProcess == NULL) || (UsePfnLock == FALSE));
00996 
00997             /* No Physical VADs supported yet */
00998             if (CurrentProcess) ASSERT(CurrentProcess->PhysicalVadRoot == NULL);
00999 
01000             /* This address should already exist and be fully valid */
01001             ASSERT(Pfn1->u3.e2.ReferenceCount != 0);
01002             if (MI_IS_ROS_PFN(Pfn1))
01003             {
01004                 /* ReactOS Mm doesn't track share count */
01005                 ASSERT(Pfn1->u3.e1.PageLocation == ActiveAndValid);
01006             }
01007             else
01008             {
01009                 /* On ARM3 pages, we should see a valid share count */
01010                 ASSERT((Pfn1->u2.ShareCount != 0) && (Pfn1->u3.e1.PageLocation == ActiveAndValid));
01011 
01012                 /* We don't support mapping a prototype page yet */
01013                 ASSERT((Pfn1->u3.e1.PrototypePte == 0) && (Pfn1->OriginalPte.u.Soft.Prototype == 0));
01014             }
01015 
01016             /* More locked pages! */
01017             InterlockedExchangeAddSizeT(&MmSystemLockPagesCount, 1);
01018 
01019             /* Loop trying to update the reference count */
01020             do
01021             {
01022                 /* Get the current reference count, make sure it's valid */
01023                 OldRefCount = Pfn1->u3.e2.ReferenceCount;
01024                 ASSERT(OldRefCount != 0);
01025                 ASSERT(OldRefCount < 2500);
01026 
01027                 /* Bump it up by one */
01028                 RefCount = InterlockedCompareExchange16((PSHORT)&Pfn1->u3.e2.ReferenceCount,
01029                                                         OldRefCount + 1,
01030                                                         OldRefCount);
01031                 ASSERT(RefCount != 0);
01032             } while (OldRefCount != RefCount);
01033 
01034             /* Was this the first lock attempt? */
01035             if (OldRefCount != 1)
01036             {
01037                 /* Someone else came through */
01038                 InterlockedExchangeAddSizeT(&MmSystemLockPagesCount, -1);
01039             }
01040         }
01041         else
01042         {
01043             //
01044             // For I/O addresses, just remember this
01045             //
01046             Mdl->MdlFlags |= MDL_IO_SPACE;
01047         }
01048 
01049         //
01050         // Write the page and move on
01051         //
01052         *MdlPages++ = PageFrameIndex;
01053         PointerPte++;
01054 
01055         /* Check if we're on a PDE boundary */
01056         if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++;
01057 #if (_MI_PAGING_LEVELS >= 3)
01058         if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++;
01059 #endif
01060 #if (_MI_PAGING_LEVELS == 4)
01061         if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++;
01062 #endif
01063 
01064     } while (PointerPte <= LastPte);
01065 
01066     //
01067     // What kind of lock were we using?
01068     //
01069     if (UsePfnLock)
01070     {
01071         //
01072         // Release PFN lock
01073         //
01074         KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
01075     }
01076     else
01077     {
01078         /* Release process working set */
01079         MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
01080     }
01081 
01082     //
01083     // Sanity check
01084     //
01085     ASSERT((Mdl->MdlFlags & MDL_DESCRIBES_AWE) == 0);
01086     return;
01087 
01088 CleanupWithLock:
01089     //
01090     // This is the failure path
01091     //
01092     ASSERT(!NT_SUCCESS(Status));
01093 
01094     //
01095     // What kind of lock were we using?
01096     //
01097     if (UsePfnLock)
01098     {
01099         //
01100         // Release PFN lock
01101         //
01102         KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
01103     }
01104     else
01105     {
01106         /* Release process working set */
01107         MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread());
01108     }
01109 Cleanup:
01110     //
01111     // Pages must be locked so MmUnlock can work
01112     //
01113     ASSERT(Mdl->MdlFlags & MDL_PAGES_LOCKED);
01114     MmUnlockPages(Mdl);
01115 
01116     //
01117     // Raise the error
01118     //
01119     ExRaiseStatus(Status);
01120 }
01121 
01122 /*
01123  * @implemented
01124  */
01125 VOID
01126 NTAPI
01127 MmUnlockPages(IN PMDL Mdl)
01128 {
01129     PPFN_NUMBER MdlPages, LastPage;
01130     PEPROCESS Process;
01131     PVOID Base;
01132     ULONG Flags, PageCount;
01133     KIRQL OldIrql;
01134     USHORT RefCount, OldRefCount;
01135     PMMPFN Pfn1;
01136     DPRINT("Unlocking MDL: %p\n", Mdl);
01137 
01138     //
01139     // Sanity checks
01140     //
01141     ASSERT((Mdl->MdlFlags & MDL_PAGES_LOCKED) != 0);
01142     ASSERT((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0);
01143     ASSERT((Mdl->MdlFlags & MDL_PARTIAL) == 0);
01144     ASSERT(Mdl->ByteCount != 0);
01145 
01146     //
01147     // Get the process associated and capture the flags which are volatile
01148     //
01149     Process = Mdl->Process;
01150     Flags = Mdl->MdlFlags;
01151 
01152     //
01153     // Automagically undo any calls to MmGetSystemAddressForMdl's for this MDL
01154     //
01155     if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
01156     {
01157         //
01158         // Unmap the pages from system space
01159         //
01160         MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl);
01161     }
01162 
01163     //
01164     // Get the page count
01165     //
01166     MdlPages = (PPFN_NUMBER)(Mdl + 1);
01167     Base = (PVOID)((ULONG_PTR)Mdl->StartVa + Mdl->ByteOffset);
01168     PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base, Mdl->ByteCount);
01169     ASSERT(PageCount != 0);
01170 
01171     //
01172     // We don't support AWE
01173     //
01174     if (Flags & MDL_DESCRIBES_AWE) ASSERT(FALSE);
01175 
01176     //
01177     // Check if the buffer is mapped I/O space
01178     //
01179     if (Flags & MDL_IO_SPACE)
01180     {
01181         //
01182         // Acquire PFN lock
01183         //
01184         OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
01185 
01186         //
01187         // Loop every page
01188         //
01189         LastPage = MdlPages + PageCount;
01190         do
01191         {
01192             //
01193             // Last page, break out
01194             //
01195             if (*MdlPages == LIST_HEAD) break;
01196 
01197             //
01198             // Check if this page is in the PFN database
01199             //
01200             Pfn1 = MiGetPfnEntry(*MdlPages);
01201             if (Pfn1)
01202             {
01203                 /* Get the current entry and reference count */
01204                 OldRefCount = Pfn1->u3.e2.ReferenceCount;
01205                 ASSERT(OldRefCount != 0);
01206 
01207                 /* Is this already the last dereference */
01208                 if (OldRefCount == 1)
01209                 {
01210                     /* It should be on a free list waiting for us */
01211                     ASSERT(Pfn1->u3.e2.ReferenceCount == 1);
01212                     ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid);
01213                     ASSERT(Pfn1->u2.ShareCount == 0);
01214 
01215                     /* Not supported yet */
01216                     ASSERT((Pfn1->u3.e1.PrototypePte == 0) &&
01217                             (Pfn1->OriginalPte.u.Soft.Prototype == 0));
01218 
01219                     /* One less page */
01220                     InterlockedExchangeAddSizeT(&MmSystemLockPagesCount, -1);
01221 
01222                     /* Do the last dereference, we're done here */
01223                     MiDecrementReferenceCount(Pfn1, *MdlPages);
01224                 }
01225                 else
01226                 {
01227                     /* Loop decrementing one reference */
01228                     do
01229                     {
01230                         /* Make sure it's still valid */
01231                         OldRefCount = Pfn1->u3.e2.ReferenceCount;
01232                         ASSERT(OldRefCount != 0);
01233 
01234                         /* Take off one reference */
01235                         RefCount = InterlockedCompareExchange16((PSHORT)&Pfn1->u3.e2.ReferenceCount,
01236                                                                 OldRefCount - 1,
01237                                                                 OldRefCount);
01238                         ASSERT(RefCount != 0);
01239                      } while (OldRefCount != RefCount);
01240                      ASSERT(RefCount > 1);
01241 
01242                      /* Are there only lock references left? */
01243                      if (RefCount == 2)
01244                      {
01245                          /* And does the page still have users? */
01246                          if (Pfn1->u2.ShareCount >= 1)
01247                          {
01248                             /* Then it should still be valid */
01249                             ASSERT(Pfn1->u3.e1.PageLocation == ActiveAndValid);
01250 
01251                             /* Not supported yet */
01252                             ASSERT((Pfn1->u3.e1.PrototypePte == 0) &&
01253                                     (Pfn1->OriginalPte.u.Soft.Prototype == 0));
01254 
01255                             /* But there is one less "locked" page though */
01256                             InterlockedExchangeAddSizeT(&MmSystemLockPagesCount, -1);
01257                          }
01258                      }
01259                  }
01260             }
01261         } while (++MdlPages < LastPage);
01262 
01263         //
01264         // Release the lock
01265         //
01266         KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
01267 
01268         //
01269         // Check if we have a process
01270         //
01271         if (Process)
01272         {
01273             //
01274             // Handle the accounting of locked pages
01275             //
01276             ASSERT(Process->NumberOfLockedPages > 0);
01277             InterlockedExchangeAddSizeT(&Process->NumberOfLockedPages,
01278                                         -(LONG_PTR)PageCount);
01279         }
01280 
01281         //
01282         // We're done
01283         //
01284         Mdl->MdlFlags &= ~MDL_IO_SPACE;
01285         Mdl->MdlFlags &= ~MDL_PAGES_LOCKED;
01286         return;
01287     }
01288 
01289     //
01290     // Check if we have a process
01291     //
01292     if (Process)
01293     {
01294         //
01295         // Handle the accounting of locked pages
01296         //
01297         ASSERT(Process->NumberOfLockedPages > 0);
01298         InterlockedExchangeAddSizeT(&Process->NumberOfLockedPages,
01299                                     -(LONG_PTR)PageCount);
01300     }
01301 
01302     //
01303     // Loop every page
01304     //
01305     LastPage = MdlPages + PageCount;
01306     do
01307     {
01308         //
01309         // Last page reached
01310         //
01311         if (*MdlPages == LIST_HEAD)
01312         {
01313             //
01314             // Were there no pages at all?
01315             //
01316             if (MdlPages == (PPFN_NUMBER)(Mdl + 1))
01317             {
01318                 //
01319                 // We're already done
01320                 //
01321                 Mdl->MdlFlags &= ~MDL_PAGES_LOCKED;
01322                 return;
01323             }
01324 
01325             //
01326             // Otherwise, stop here
01327             //
01328             LastPage = MdlPages;
01329             break;
01330         }
01331 
01332         /* Save the PFN entry instead for the secondary loop */
01333         *MdlPages = (PFN_NUMBER)MiGetPfnEntry(*MdlPages);
01334         ASSERT(*MdlPages != 0);
01335     } while (++MdlPages < LastPage);
01336 
01337     //
01338     // Reset pointer
01339     //
01340     MdlPages = (PPFN_NUMBER)(Mdl + 1);
01341 
01342     //
01343     // Now grab the PFN lock for the actual unlock and dereference
01344     //
01345     OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
01346     do
01347     {
01348         /* Get the current entry and reference count */
01349         Pfn1 = (PMMPFN)*MdlPages;
01350         OldRefCount = Pfn1->u3.e2.ReferenceCount;
01351         ASSERT(OldRefCount != 0);
01352 
01353         /* Is this already the last dereference */
01354         if (OldRefCount == 1)
01355         {
01356             /* It should be on a free list waiting for us */
01357             ASSERT(Pfn1->u3.e2.ReferenceCount == 1);
01358             ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid);
01359             ASSERT(Pfn1->u2.ShareCount == 0);
01360 
01361             /* Not supported yet */
01362             ASSERT(((Pfn1->u3.e1.PrototypePte == 0) &&
01363                     (Pfn1->OriginalPte.u.Soft.Prototype == 0)));
01364 
01365             /* One less page */
01366             InterlockedExchangeAddSizeT(&MmSystemLockPagesCount, -1);
01367 
01368             /* Do the last dereference, we're done here */
01369             MiDecrementReferenceCount(Pfn1, MiGetPfnEntryIndex(Pfn1));
01370         }
01371         else
01372         {
01373             /* Loop decrementing one reference */
01374             do
01375             {
01376                 /* Make sure it's still valid */
01377                 OldRefCount = Pfn1->u3.e2.ReferenceCount;
01378                 ASSERT(OldRefCount != 0);
01379 
01380                 /* Take off one reference */
01381                 RefCount = InterlockedCompareExchange16((PSHORT)&Pfn1->u3.e2.ReferenceCount,
01382                                                         OldRefCount - 1,
01383                                                         OldRefCount);
01384                 ASSERT(RefCount != 0);
01385              } while (OldRefCount != RefCount);
01386              ASSERT(RefCount > 1);
01387 
01388              /* Are there only lock references left? */
01389              if (RefCount == 2)
01390              {
01391                  /* And does the page still have users? */
01392                  if (Pfn1->u2.ShareCount >= 1)
01393                  {
01394                     /* Then it should still be valid */
01395                     ASSERT(Pfn1->u3.e1.PageLocation == ActiveAndValid);
01396 
01397                     /* Not supported yet */
01398                     ASSERT(((Pfn1->u3.e1.PrototypePte == 0) &&
01399                             (Pfn1->OriginalPte.u.Soft.Prototype == 0)));
01400 
01401                     /* But there is one less "locked" page though */
01402                     InterlockedExchangeAddSizeT(&MmSystemLockPagesCount, -1);
01403                  }
01404              }
01405          }
01406     } while (++MdlPages < LastPage);
01407 
01408     //
01409     // Release the lock
01410     //
01411     KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
01412 
01413     //
01414     // We're done
01415     //
01416     Mdl->MdlFlags &= ~MDL_PAGES_LOCKED;
01417 }
01418 
01419 /*
01420  * @unimplemented
01421  */
01422 NTSTATUS
01423 NTAPI
01424 MmAdvanceMdl(IN PMDL Mdl,
01425              IN ULONG NumberOfBytes)
01426 {
01427     UNIMPLEMENTED;
01428     return STATUS_NOT_IMPLEMENTED;
01429 }
01430 
01431 /*
01432  * @unimplemented
01433  */
01434 PVOID
01435 NTAPI
01436 MmMapLockedPagesWithReservedMapping(IN PVOID MappingAddress,
01437                                     IN ULONG PoolTag,
01438                                     IN PMDL MemoryDescriptorList,
01439                                     IN MEMORY_CACHING_TYPE CacheType)
01440 {
01441     UNIMPLEMENTED;
01442     return 0;
01443 }
01444 
01445 /*
01446  * @unimplemented
01447  */
01448 VOID
01449 NTAPI
01450 MmUnmapReservedMapping(IN PVOID BaseAddress,
01451                        IN ULONG PoolTag,
01452                        IN PMDL MemoryDescriptorList)
01453 {
01454     UNIMPLEMENTED;
01455 }
01456 
01457 /*
01458  * @unimplemented
01459  */
01460 NTSTATUS
01461 NTAPI
01462 MmPrefetchPages(IN ULONG NumberOfLists,
01463                 IN PREAD_LIST *ReadLists)
01464 {
01465     UNIMPLEMENTED;
01466     return STATUS_NOT_IMPLEMENTED;
01467 }
01468 
01469 /*
01470  * @unimplemented
01471  */
01472 NTSTATUS
01473 NTAPI
01474 MmProtectMdlSystemAddress(IN PMDL MemoryDescriptorList,
01475                           IN ULONG NewProtect)
01476 {
01477     UNIMPLEMENTED;
01478     return STATUS_NOT_IMPLEMENTED;
01479 }
01480 
01481 /*
01482  * @unimplemented
01483  */
01484 VOID
01485 NTAPI
01486 MmProbeAndLockProcessPages(IN OUT PMDL MemoryDescriptorList,
01487                            IN PEPROCESS Process,
01488                            IN KPROCESSOR_MODE AccessMode,
01489                            IN LOCK_OPERATION Operation)
01490 {
01491     UNIMPLEMENTED;
01492 }
01493 
01494 
01495 /*
01496  * @unimplemented
01497  */
01498 VOID
01499 NTAPI
01500 MmProbeAndLockSelectedPages(IN OUT PMDL MemoryDescriptorList,
01501                             IN LARGE_INTEGER PageList[],
01502                             IN KPROCESSOR_MODE AccessMode,
01503                             IN LOCK_OPERATION Operation)
01504 {
01505     UNIMPLEMENTED;
01506 }
01507 
01508 /*
01509  * @unimplemented
01510  */
01511 VOID
01512 NTAPI
01513 MmMapMemoryDumpMdl(IN PMDL Mdl)
01514 {
01515     UNIMPLEMENTED;
01516 }
01517 
01518 /* EOF */

Generated on Sun May 27 2012 04:37:04 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.