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

page.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:       See COPYING in the top level directory
00003  * PROJECT:         ReactOS kernel
00004  * FILE:            ntoskrnl/mm/i386/page.c
00005  * PURPOSE:         Low level memory managment manipulation
00006  *
00007  * PROGRAMMERS:     David Welch (welch@cwcom.net)
00008  */
00009 
00010 /* INCLUDES ***************************************************************/
00011 
00012 #include <ntoskrnl.h>
00013 #define NDEBUG
00014 #include <debug.h>
00015 #include "../ARM3/miarm.h"
00016 
00017 #if defined (ALLOC_PRAGMA)
00018 #pragma alloc_text(INIT, MmInitGlobalKernelPageDirectory)
00019 #pragma alloc_text(INIT, MiInitPageDirectoryMap)
00020 #endif
00021 
00022 
00023 /* GLOBALS *****************************************************************/
00024 
00025 #define PA_BIT_PRESENT   (0)
00026 #define PA_BIT_READWRITE (1)
00027 #define PA_BIT_USER      (2)
00028 #define PA_BIT_WT        (3)
00029 #define PA_BIT_CD        (4)
00030 #define PA_BIT_ACCESSED  (5)
00031 #define PA_BIT_DIRTY     (6)
00032 #define PA_BIT_GLOBAL    (8)
00033 
00034 #define PA_PRESENT   (1 << PA_BIT_PRESENT)
00035 #define PA_READWRITE (1 << PA_BIT_READWRITE)
00036 #define PA_USER      (1 << PA_BIT_USER)
00037 #define PA_DIRTY     (1 << PA_BIT_DIRTY)
00038 #define PA_WT        (1 << PA_BIT_WT)
00039 #define PA_CD        (1 << PA_BIT_CD)
00040 #define PA_ACCESSED  (1 << PA_BIT_ACCESSED)
00041 #define PA_GLOBAL    (1 << PA_BIT_GLOBAL)
00042 
00043 #define HYPERSPACE          (0xc0400000)
00044 #define IS_HYPERSPACE(v)    (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000))
00045 
00046 #define PTE_TO_PFN(X)  ((X) >> PAGE_SHIFT)
00047 #define PFN_TO_PTE(X)  ((X) << PAGE_SHIFT)
00048 
00049 #if defined(__GNUC__)
00050 #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X)))
00051 #else
00052 __inline LARGE_INTEGER PTE_TO_PAGE(ULONG npage)
00053 {
00054     LARGE_INTEGER dummy;
00055     dummy.QuadPart = (LONGLONG)(PAGE_MASK(npage));
00056     return dummy;
00057 }
00058 #endif
00059 
00060 const
00061 ULONG
00062 MmProtectToPteMask[32] =
00063 {
00064     //
00065     // These are the base MM_ protection flags
00066     //
00067     0,
00068     PTE_READONLY            | PTE_ENABLE_CACHE,
00069     PTE_EXECUTE             | PTE_ENABLE_CACHE,
00070     PTE_EXECUTE_READ        | PTE_ENABLE_CACHE,
00071     PTE_READWRITE           | PTE_ENABLE_CACHE,
00072     PTE_WRITECOPY           | PTE_ENABLE_CACHE,
00073     PTE_EXECUTE_READWRITE   | PTE_ENABLE_CACHE,
00074     PTE_EXECUTE_WRITECOPY   | PTE_ENABLE_CACHE,
00075     //
00076     // These OR in the MM_NOCACHE flag
00077     //
00078     0,
00079     PTE_READONLY            | PTE_DISABLE_CACHE,
00080     PTE_EXECUTE             | PTE_DISABLE_CACHE,
00081     PTE_EXECUTE_READ        | PTE_DISABLE_CACHE,
00082     PTE_READWRITE           | PTE_DISABLE_CACHE,
00083     PTE_WRITECOPY           | PTE_DISABLE_CACHE,
00084     PTE_EXECUTE_READWRITE   | PTE_DISABLE_CACHE,
00085     PTE_EXECUTE_WRITECOPY   | PTE_DISABLE_CACHE,
00086     //
00087     // These OR in the MM_DECOMMIT flag, which doesn't seem supported on x86/64/ARM
00088     //
00089     0,
00090     PTE_READONLY            | PTE_ENABLE_CACHE,
00091     PTE_EXECUTE             | PTE_ENABLE_CACHE,
00092     PTE_EXECUTE_READ        | PTE_ENABLE_CACHE,
00093     PTE_READWRITE           | PTE_ENABLE_CACHE,
00094     PTE_WRITECOPY           | PTE_ENABLE_CACHE,
00095     PTE_EXECUTE_READWRITE   | PTE_ENABLE_CACHE,
00096     PTE_EXECUTE_WRITECOPY   | PTE_ENABLE_CACHE,
00097     //
00098     // These OR in the MM_NOACCESS flag, which seems to enable WriteCombining?
00099     //
00100     0,
00101     PTE_READONLY            | PTE_WRITECOMBINED_CACHE,
00102     PTE_EXECUTE             | PTE_WRITECOMBINED_CACHE,
00103     PTE_EXECUTE_READ        | PTE_WRITECOMBINED_CACHE,
00104     PTE_READWRITE           | PTE_WRITECOMBINED_CACHE,
00105     PTE_WRITECOPY           | PTE_WRITECOMBINED_CACHE,
00106     PTE_EXECUTE_READWRITE   | PTE_WRITECOMBINED_CACHE,
00107     PTE_EXECUTE_WRITECOPY   | PTE_WRITECOMBINED_CACHE,
00108 };
00109 
00110 const
00111 ULONG MmProtectToValue[32] =
00112 {
00113     PAGE_NOACCESS,
00114     PAGE_READONLY,
00115     PAGE_EXECUTE,
00116     PAGE_EXECUTE_READ,
00117     PAGE_READWRITE,
00118     PAGE_WRITECOPY,
00119     PAGE_EXECUTE_READWRITE,
00120     PAGE_EXECUTE_WRITECOPY,
00121     PAGE_NOACCESS,
00122     PAGE_NOCACHE | PAGE_READONLY,
00123     PAGE_NOCACHE | PAGE_EXECUTE,
00124     PAGE_NOCACHE | PAGE_EXECUTE_READ,
00125     PAGE_NOCACHE | PAGE_READWRITE,
00126     PAGE_NOCACHE | PAGE_WRITECOPY,
00127     PAGE_NOCACHE | PAGE_EXECUTE_READWRITE,
00128     PAGE_NOCACHE | PAGE_EXECUTE_WRITECOPY,
00129     PAGE_NOACCESS,
00130     PAGE_GUARD | PAGE_READONLY,
00131     PAGE_GUARD | PAGE_EXECUTE,
00132     PAGE_GUARD | PAGE_EXECUTE_READ,
00133     PAGE_GUARD | PAGE_READWRITE,
00134     PAGE_GUARD | PAGE_WRITECOPY,
00135     PAGE_GUARD | PAGE_EXECUTE_READWRITE,
00136     PAGE_GUARD | PAGE_EXECUTE_WRITECOPY,
00137     PAGE_NOACCESS,
00138     PAGE_WRITECOMBINE | PAGE_READONLY,
00139     PAGE_WRITECOMBINE | PAGE_EXECUTE,
00140     PAGE_WRITECOMBINE | PAGE_EXECUTE_READ,
00141     PAGE_WRITECOMBINE | PAGE_READWRITE,
00142     PAGE_WRITECOMBINE | PAGE_WRITECOPY,
00143     PAGE_WRITECOMBINE | PAGE_EXECUTE_READWRITE,
00144     PAGE_WRITECOMBINE | PAGE_EXECUTE_WRITECOPY
00145 };
00146 
00147 /* FUNCTIONS ***************************************************************/
00148 
00149 BOOLEAN MmUnmapPageTable(PULONG Pt);
00150 
00151 VOID
00152 MiFlushTlb(PULONG Pt, PVOID Address)
00153 {
00154     if ((Pt && MmUnmapPageTable(Pt)) || Address >= MmSystemRangeStart)
00155     {
00156         KeInvalidateTlbEntry(Address);
00157     }
00158 }
00159 
00160 static ULONG
00161 ProtectToPTE(ULONG flProtect)
00162 {
00163     ULONG Attributes = 0;
00164 
00165     if (flProtect & (PAGE_NOACCESS|PAGE_GUARD))
00166     {
00167         Attributes = 0;
00168     }
00169     else if (flProtect & PAGE_IS_WRITABLE)
00170     {
00171         Attributes = PA_PRESENT | PA_READWRITE;
00172     }
00173     else if (flProtect & (PAGE_IS_READABLE | PAGE_IS_EXECUTABLE))
00174     {
00175         Attributes = PA_PRESENT;
00176     }
00177     else
00178     {
00179         DPRINT1("Unknown main protection type.\n");
00180         KeBugCheck(MEMORY_MANAGEMENT);
00181     }
00182 
00183     if (flProtect & PAGE_SYSTEM)
00184     {
00185     }
00186     else
00187     {
00188         Attributes = Attributes | PA_USER;
00189     }
00190     if (flProtect & PAGE_NOCACHE)
00191     {
00192         Attributes = Attributes | PA_CD;
00193     }
00194     if (flProtect & PAGE_WRITETHROUGH)
00195     {
00196         Attributes = Attributes | PA_WT;
00197     }
00198     return(Attributes);
00199 }
00200 
00201 /* Taken from ARM3/pagfault.c */
00202 BOOLEAN
00203 FORCEINLINE
00204 MiSynchronizeSystemPde(PMMPDE PointerPde)
00205 {
00206     MMPDE SystemPde;
00207     ULONG Index;
00208 
00209     /* Get the Index from the PDE */
00210     Index = ((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE);
00211 
00212     /* Copy the PDE from the double-mapped system page directory */
00213     SystemPde = MmSystemPagePtes[Index];
00214     *PointerPde = SystemPde;
00215 
00216     /* Make sure we re-read the PDE and PTE */
00217     KeMemoryBarrierWithoutFence();
00218 
00219     /* Return, if we had success */
00220     return SystemPde.u.Hard.Valid != 0;
00221 }
00222 
00223 NTSTATUS
00224 NTAPI
00225 MiDispatchFault(IN BOOLEAN StoreInstruction,
00226                 IN PVOID Address,
00227                 IN PMMPTE PointerPte,
00228                 IN PMMPTE PointerProtoPte,
00229                 IN BOOLEAN Recursive,
00230                 IN PEPROCESS Process,
00231                 IN PVOID TrapInformation,
00232                 IN PVOID Vad);
00233 
00234 NTSTATUS
00235 NTAPI
00236 MiFillSystemPageDirectory(IN PVOID Base,
00237                           IN SIZE_T NumberOfBytes);
00238 
00239 static PULONG
00240 MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
00241 {
00242     PFN_NUMBER Pfn;
00243     PULONG Pt;
00244     PMMPDE PointerPde;
00245 
00246     if (Address < MmSystemRangeStart)
00247     {
00248         /* We should have a process for user land addresses */
00249         ASSERT(Process != NULL);
00250 
00251         if(Process != PsGetCurrentProcess())
00252         {
00253             PMMPDE PdeBase;
00254             ULONG PdeOffset = MiGetPdeOffset(Address);
00255             
00256             /* Nobody but page fault should ask for creating the PDE,
00257              * Which imples that Process is the current one */
00258             ASSERT(Create == FALSE);
00259             
00260             PdeBase = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase[0]));
00261             if (PdeBase == NULL)
00262             {
00263                 KeBugCheck(MEMORY_MANAGEMENT);
00264             }
00265             PointerPde = PdeBase + PdeOffset;
00266             if (PointerPde->u.Hard.Valid == 0)
00267             {
00268                 MmDeleteHyperspaceMapping(PdeBase);
00269                 return NULL;
00270             }
00271             else
00272             {
00273                 Pfn = PointerPde->u.Hard.PageFrameNumber;
00274             }
00275             MmDeleteHyperspaceMapping(PdeBase);
00276             Pt = MmCreateHyperspaceMapping(Pfn);
00277             if (Pt == NULL)
00278             {
00279                 KeBugCheck(MEMORY_MANAGEMENT);
00280             }
00281             return Pt + MiAddressToPteOffset(Address);
00282         }
00283         /* This is for our process */
00284         PointerPde = MiAddressToPde(Address);
00285         Pt = (PULONG)MiAddressToPte(Address);
00286         if (PointerPde->u.Hard.Valid == 0)
00287         {
00288             NTSTATUS Status;
00289             if (Create == FALSE)
00290             {
00291                 return NULL;
00292             }
00293             ASSERT(PointerPde->u.Long == 0);
00294 
00295             MI_WRITE_INVALID_PTE(PointerPde, DemandZeroPde);
00296             Status = MiDispatchFault(TRUE,
00297                                      Pt,
00298                                      PointerPde,
00299                                      NULL,
00300                                      FALSE,
00301                                      PsGetCurrentProcess(),
00302                                      NULL,
00303                                      NULL);
00304             ASSERT(KeAreAllApcsDisabled() == TRUE);
00305             ASSERT(PointerPde->u.Hard.Valid == 1);
00306         }
00307         return (PULONG)MiAddressToPte(Address);
00308     }
00309 
00310     /* This is for kernel land address */
00311     ASSERT(Process == NULL);
00312     PointerPde = MiAddressToPde(Address);
00313     Pt = (PULONG)MiAddressToPte(Address);
00314     if (PointerPde->u.Hard.Valid == 0)
00315     {
00316         /* Let ARM3 synchronize the PDE */
00317         if(!MiSynchronizeSystemPde(PointerPde))
00318         {
00319             /* PDE (still) not valid, let ARM3 allocate one if asked */
00320             if(Create == FALSE)
00321                 return NULL;
00322             MiFillSystemPageDirectory(Address, PAGE_SIZE);
00323         }
00324     }
00325     return Pt;
00326 }
00327 
00328 BOOLEAN MmUnmapPageTable(PULONG Pt)
00329 {
00330     if (!IS_HYPERSPACE(Pt))
00331     {
00332         return TRUE;
00333     }
00334 
00335     if (Pt)
00336     {
00337         MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pt));
00338     }
00339     return FALSE;
00340 }
00341 
00342 static ULONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
00343 {
00344     ULONG Pte;
00345     PULONG Pt;
00346 
00347     Pt = MmGetPageTableForProcess(Process, Address, FALSE);
00348     if (Pt)
00349     {
00350         Pte = *Pt;
00351         MmUnmapPageTable(Pt);
00352         return Pte;
00353     }
00354     return 0;
00355 }
00356 
00357 PFN_NUMBER
00358 NTAPI
00359 MmGetPfnForProcess(PEPROCESS Process,
00360                    PVOID Address)
00361 {
00362     ULONG Entry;
00363     Entry = MmGetPageEntryForProcess(Process, Address);
00364     if (!(Entry & PA_PRESENT))
00365     {
00366         return 0;
00367     }
00368     return(PTE_TO_PFN(Entry));
00369 }
00370 
00371 VOID
00372 NTAPI
00373 MmDisableVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN* WasDirty, PPFN_NUMBER Page)
00374 /*
00375  * FUNCTION: Delete a virtual mapping
00376  */
00377 {
00378     BOOLEAN WasValid;
00379     ULONG Pte;
00380     PULONG Pt;
00381 
00382     Pt = MmGetPageTableForProcess(Process, Address, FALSE);
00383     if (Pt == NULL)
00384     {
00385         KeBugCheck(MEMORY_MANAGEMENT);
00386     }
00387 
00388     /*
00389      * Atomically disable the present bit and get the old value.
00390      */
00391     do
00392     {
00393         Pte = *Pt;
00394     } while (Pte != InterlockedCompareExchangePte(Pt, Pte & ~PA_PRESENT, Pte));
00395 
00396     MiFlushTlb(Pt, Address);
00397 
00398     WasValid = (Pte & PA_PRESENT);
00399     if (!WasValid)
00400     {
00401         KeBugCheck(MEMORY_MANAGEMENT);
00402     }
00403 
00404     /*
00405      * Return some information to the caller
00406      */
00407     if (WasDirty != NULL)
00408     {
00409         *WasDirty = Pte & PA_DIRTY;
00410     }
00411     if (Page != NULL)
00412     {
00413         *Page = PTE_TO_PFN(Pte);
00414     }
00415 }
00416 
00417 VOID
00418 NTAPI
00419 MmRawDeleteVirtualMapping(PVOID Address)
00420 {
00421     PULONG Pt;
00422 
00423     Pt = MmGetPageTableForProcess(NULL, Address, FALSE);
00424     if (Pt && *Pt)
00425     {
00426         /*
00427          * Set the entry to zero
00428          */
00429         InterlockedExchangePte(Pt, 0);
00430         MiFlushTlb(Pt, Address);
00431     }
00432 }
00433 
00434 VOID
00435 NTAPI
00436 MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN FreePage,
00437                        BOOLEAN* WasDirty, PPFN_NUMBER Page)
00438 /*
00439  * FUNCTION: Delete a virtual mapping
00440  */
00441 {
00442     BOOLEAN WasValid = FALSE;
00443     PFN_NUMBER Pfn;
00444     ULONG Pte;
00445     PULONG Pt;
00446 
00447     DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
00448            Process, Address, FreePage, WasDirty, Page);
00449 
00450     Pt = MmGetPageTableForProcess(Process, Address, FALSE);
00451 
00452     if (Pt == NULL)
00453     {
00454         if (WasDirty != NULL)
00455         {
00456             *WasDirty = FALSE;
00457         }
00458         if (Page != NULL)
00459         {
00460             *Page = 0;
00461         }
00462         return;
00463     }
00464 
00465     /*
00466      * Atomically set the entry to zero and get the old value.
00467      */
00468     Pte = InterlockedExchangePte(Pt, 0);
00469 
00470     WasValid = (Pte & PA_PRESENT);
00471     if (WasValid)
00472     {
00473         /* Flush the TLB since we transitioned this PTE
00474          * from valid to invalid so any stale translations
00475          * are removed from the cache */
00476         MiFlushTlb(Pt, Address);
00477 
00478         if (Address < MmSystemRangeStart)
00479         {
00480             /* Remove PDE reference */
00481             Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
00482             ASSERT(Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] < PTE_COUNT);
00483         }
00484 
00485         Pfn = PTE_TO_PFN(Pte);
00486 
00487         if (FreePage)
00488         {
00489             MmReleasePageMemoryConsumer(MC_SYSTEM, Pfn);
00490             Pfn = 0;
00491         }
00492     }
00493     else
00494     {
00495         MmUnmapPageTable(Pt);
00496         Pfn = 0;
00497     }
00498 
00499     /*
00500      * Return some information to the caller
00501      */
00502     if (WasDirty != NULL)
00503     {
00504         *WasDirty = ((Pte & PA_DIRTY) && (Pte & PA_PRESENT)) ? TRUE : FALSE;
00505     }
00506     if (Page != NULL)
00507     {
00508         *Page = Pfn;
00509     }
00510 }
00511 
00512 VOID
00513 NTAPI
00514 MmGetPageFileMapping(PEPROCESS Process, PVOID Address,
00515                      SWAPENTRY* SwapEntry)
00516 /*
00517  * FUNCTION: Get a page file mapping
00518  */
00519 {
00520     ULONG Entry = MmGetPageEntryForProcess(Process, Address);
00521     *SwapEntry = Entry >> 1;
00522 }
00523 
00524 VOID
00525 NTAPI
00526 MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
00527                         SWAPENTRY* SwapEntry)
00528 /*
00529  * FUNCTION: Delete a virtual mapping
00530  */
00531 {
00532     ULONG Pte;
00533     PULONG Pt;
00534 
00535     Pt = MmGetPageTableForProcess(Process, Address, FALSE);
00536 
00537     if (Pt == NULL)
00538     {
00539         *SwapEntry = 0;
00540         return;
00541     }
00542 
00543     /*
00544      * Atomically set the entry to zero and get the old value.
00545      */
00546     Pte = InterlockedExchangePte(Pt, 0);
00547 
00548     if (Address < MmSystemRangeStart)
00549     {
00550         /* Remove PDE reference */
00551         Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--;
00552         ASSERT(Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] < PTE_COUNT);
00553     }
00554 
00555     /* We don't need to flush here because page file entries
00556      * are invalid translations, so the processor won't cache them */
00557     MmUnmapPageTable(Pt);
00558 
00559     if ((Pte & PA_PRESENT) || !(Pte & 0x800))
00560     {
00561         DPRINT1("Pte %x (want not 1 and 0x800)\n", Pte);
00562         KeBugCheck(MEMORY_MANAGEMENT);
00563     }
00564 
00565     /*
00566      * Return some information to the caller
00567      */
00568     *SwapEntry = Pte >> 1;
00569 }
00570 
00571 BOOLEAN
00572 Mmi386MakeKernelPageTableGlobal(PVOID Address)
00573 {
00574     PMMPDE PointerPde = MiAddressToPde(Address);
00575     PMMPTE PointerPte = MiAddressToPte(Address);
00576     
00577     if (PointerPde->u.Hard.Valid == 0)
00578     {
00579         if(!MiSynchronizeSystemPde(PointerPde))
00580             return FALSE;
00581         return PointerPte->u.Hard.Valid != 0;
00582     }
00583     return FALSE;
00584 }
00585 
00586 BOOLEAN
00587 NTAPI
00588 MmIsDirtyPage(PEPROCESS Process, PVOID Address)
00589 {
00590     return MmGetPageEntryForProcess(Process, Address) & PA_DIRTY ? TRUE : FALSE;
00591 }
00592 
00593 VOID
00594 NTAPI
00595 MmSetCleanPage(PEPROCESS Process, PVOID Address)
00596 {
00597     PULONG Pt;
00598     ULONG Pte;
00599 
00600     if (Address < MmSystemRangeStart && Process == NULL)
00601     {
00602         DPRINT1("MmSetCleanPage is called for user space without a process.\n");
00603         KeBugCheck(MEMORY_MANAGEMENT);
00604     }
00605 
00606     Pt = MmGetPageTableForProcess(Process, Address, FALSE);
00607     if (Pt == NULL)
00608     {
00609         KeBugCheck(MEMORY_MANAGEMENT);
00610     }
00611 
00612     do
00613     {
00614         Pte = *Pt;
00615     } while (Pte != InterlockedCompareExchangePte(Pt, Pte & ~PA_DIRTY, Pte));
00616 
00617     if (!(Pte & PA_PRESENT))
00618     {
00619         KeBugCheck(MEMORY_MANAGEMENT);
00620     }
00621     else if (Pte & PA_DIRTY)
00622     {
00623         MiFlushTlb(Pt, Address);
00624     }
00625     else
00626     {
00627         MmUnmapPageTable(Pt);
00628     }
00629 }
00630 
00631 VOID
00632 NTAPI
00633 MmSetDirtyPage(PEPROCESS Process, PVOID Address)
00634 {
00635     PULONG Pt;
00636     ULONG Pte;
00637 
00638     if (Address < MmSystemRangeStart && Process == NULL)
00639     {
00640         DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
00641         KeBugCheck(MEMORY_MANAGEMENT);
00642     }
00643 
00644     Pt = MmGetPageTableForProcess(Process, Address, FALSE);
00645     if (Pt == NULL)
00646     {
00647         KeBugCheck(MEMORY_MANAGEMENT);
00648     }
00649 
00650     do
00651     {
00652         Pte = *Pt;
00653     } while (Pte != InterlockedCompareExchangePte(Pt, Pte | PA_DIRTY, Pte));
00654 
00655     if (!(Pte & PA_PRESENT))
00656     {
00657         KeBugCheck(MEMORY_MANAGEMENT);
00658     }
00659     else
00660     {
00661         /* The processor will never clear this bit itself, therefore
00662          * we do not need to flush the TLB here when setting it */
00663         MmUnmapPageTable(Pt);
00664     }
00665 }
00666 
00667 VOID
00668 NTAPI
00669 MmEnableVirtualMapping(PEPROCESS Process, PVOID Address)
00670 {
00671     PULONG Pt;
00672     ULONG Pte;
00673 
00674     Pt = MmGetPageTableForProcess(Process, Address, FALSE);
00675     if (Pt == NULL)
00676     {
00677         //HACK to get DPH working, waiting for MM rewrite :-/
00678         //KeBugCheck(MEMORY_MANAGEMENT);
00679         return;
00680     }
00681 
00682     /* Do not mark a 0 page as present */
00683     if(0 == InterlockedCompareExchangePte(Pt, 0, 0))
00684         return;
00685 
00686     do
00687     {
00688         Pte = *Pt;
00689     } while (Pte != InterlockedCompareExchangePte(Pt, Pte | PA_PRESENT, Pte));
00690 
00691     /* We don't need to flush the TLB here because it
00692      * won't cache translations for non-present pages */
00693     MmUnmapPageTable(Pt);
00694 }
00695 
00696 BOOLEAN
00697 NTAPI
00698 MmIsPagePresent(PEPROCESS Process, PVOID Address)
00699 {
00700     return MmGetPageEntryForProcess(Process, Address) & PA_PRESENT;
00701 }
00702 
00703 BOOLEAN
00704 NTAPI
00705 MmIsPageSwapEntry(PEPROCESS Process, PVOID Address)
00706 {
00707     ULONG Entry;
00708     Entry = MmGetPageEntryForProcess(Process, Address);
00709     return !(Entry & PA_PRESENT) && (Entry & 0x800);
00710 }
00711 
00712 NTSTATUS
00713 NTAPI
00714 MmCreatePageFileMapping(PEPROCESS Process,
00715                         PVOID Address,
00716                         SWAPENTRY SwapEntry)
00717 {
00718     PULONG Pt;
00719     ULONG Pte;
00720 
00721     if (Process == NULL && Address < MmSystemRangeStart)
00722     {
00723         DPRINT1("No process\n");
00724         KeBugCheck(MEMORY_MANAGEMENT);
00725     }
00726     if (Process != NULL && Address >= MmSystemRangeStart)
00727     {
00728         DPRINT1("Setting kernel address with process context\n");
00729         KeBugCheck(MEMORY_MANAGEMENT);
00730     }
00731 
00732     if (SwapEntry & (1 << 31))
00733     {
00734         KeBugCheck(MEMORY_MANAGEMENT);
00735     }
00736 
00737     Pt = MmGetPageTableForProcess(Process, Address, FALSE);
00738     if (Pt == NULL)
00739     {
00740         /* Nobody should page out an address that hasn't even been mapped */
00741         KeBugCheck(MEMORY_MANAGEMENT);
00742     }
00743     Pte = InterlockedExchangePte(Pt, SwapEntry << 1);
00744     if (Pte != 0)
00745     {
00746         KeBugCheck(MEMORY_MANAGEMENT);
00747     }
00748 
00749     if (Address < MmSystemRangeStart)
00750     {
00751         /* Add PDE reference */
00752         Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++;
00753         ASSERT(Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] <= PTE_COUNT);
00754     }
00755 
00756     /* We don't need to flush the TLB here because it
00757      * only caches valid translations and a zero PTE
00758      * is not a valid translation */
00759     MmUnmapPageTable(Pt);
00760 
00761     return(STATUS_SUCCESS);
00762 }
00763 
00764 
00765 NTSTATUS
00766 NTAPI
00767 MmCreateVirtualMappingUnsafe(PEPROCESS Process,
00768                              PVOID Address,
00769                              ULONG flProtect,
00770                              PPFN_NUMBER Pages,
00771                              ULONG PageCount)
00772 {
00773     ULONG Attributes;
00774     PVOID Addr;
00775     ULONG i;
00776     ULONG oldPdeOffset, PdeOffset;
00777     PULONG Pt = NULL;
00778     ULONG Pte;
00779     DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
00780            Process, Address, flProtect, Pages, *Pages, PageCount);
00781 
00782     ASSERT(((ULONG_PTR)Address % PAGE_SIZE) == 0);
00783 
00784     if (Process == NULL)
00785     {
00786         if (Address < MmSystemRangeStart)
00787         {
00788             DPRINT1("No process\n");
00789             KeBugCheck(MEMORY_MANAGEMENT);
00790         }
00791         if (PageCount > 0x10000 ||
00792             (ULONG_PTR) Address / PAGE_SIZE + PageCount > 0x100000)
00793         {
00794             DPRINT1("Page count too large\n");
00795             KeBugCheck(MEMORY_MANAGEMENT);
00796         }
00797     }
00798     else
00799     {
00800         if (Address >= MmSystemRangeStart)
00801         {
00802             DPRINT1("Setting kernel address with process context\n");
00803             KeBugCheck(MEMORY_MANAGEMENT);
00804         }
00805         if (PageCount > (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE ||
00806             (ULONG_PTR) Address / PAGE_SIZE + PageCount >
00807             (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE)
00808         {
00809             DPRINT1("Page Count too large\n");
00810             KeBugCheck(MEMORY_MANAGEMENT);
00811         }
00812     }
00813 
00814     Attributes = ProtectToPTE(flProtect);
00815     Attributes &= 0xfff;
00816     if (Address >= MmSystemRangeStart)
00817     {
00818         Attributes &= ~PA_USER;
00819     }
00820     else
00821     {
00822         Attributes |= PA_USER;
00823     }
00824 
00825     Addr = Address;
00826     /* MmGetPageTableForProcess should be called on the first run, so
00827      * let this trigger it */
00828     oldPdeOffset = ADDR_TO_PDE_OFFSET(Addr) + 1;
00829     for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE))
00830     {
00831         if (!(Attributes & PA_PRESENT) && Pages[i] != 0)
00832         {
00833             DPRINT1("Setting physical address but not allowing access at address "
00834                     "0x%.8X with attributes %x/%x.\n",
00835                     Addr, Attributes, flProtect);
00836             KeBugCheck(MEMORY_MANAGEMENT);
00837         }
00838         PdeOffset = ADDR_TO_PDE_OFFSET(Addr);
00839         if (oldPdeOffset != PdeOffset)
00840         {
00841             if(Pt) MmUnmapPageTable(Pt);
00842             Pt = MmGetPageTableForProcess(Process, Addr, TRUE);
00843             if (Pt == NULL)
00844             {
00845                 KeBugCheck(MEMORY_MANAGEMENT);
00846             }
00847         }
00848         else
00849         {
00850             Pt++;
00851         }
00852         oldPdeOffset = PdeOffset;
00853 
00854         Pte = InterlockedExchangePte(Pt, PFN_TO_PTE(Pages[i]) | Attributes);
00855 
00856         /* There should not be anything valid here */
00857         if (Pte != 0)
00858         {
00859             DPRINT1("Bad PTE %lx\n", Pte);
00860             KeBugCheck(MEMORY_MANAGEMENT);
00861         }
00862 
00863         /* We don't need to flush the TLB here because it only caches valid translations
00864          * and we're moving this PTE from invalid to valid so it can't be cached right now */
00865 
00866         if (Addr < MmSystemRangeStart)
00867         {
00868             /* Add PDE reference */
00869             Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Addr)]++;
00870             ASSERT(Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Addr)] <= PTE_COUNT);
00871         }
00872     }
00873 
00874     ASSERT(Addr > Address);
00875     MmUnmapPageTable(Pt);
00876 
00877     return(STATUS_SUCCESS);
00878 }
00879 
00880 NTSTATUS
00881 NTAPI
00882 MmCreateVirtualMapping(PEPROCESS Process,
00883                        PVOID Address,
00884                        ULONG flProtect,
00885                        PPFN_NUMBER Pages,
00886                        ULONG PageCount)
00887 {
00888     ULONG i;
00889 
00890     ASSERT((ULONG_PTR)Address % PAGE_SIZE == 0);
00891     for (i = 0; i < PageCount; i++)
00892     {
00893         if (!MmIsPageInUse(Pages[i]))
00894         {
00895             DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Pages[i]));
00896             KeBugCheck(MEMORY_MANAGEMENT);
00897         }
00898     }
00899 
00900     return(MmCreateVirtualMappingUnsafe(Process,
00901                                         Address,
00902                                         flProtect,
00903                                         Pages,
00904                                         PageCount));
00905 }
00906 
00907 ULONG
00908 NTAPI
00909 MmGetPageProtect(PEPROCESS Process, PVOID Address)
00910 {
00911     ULONG Entry;
00912     ULONG Protect;
00913 
00914     Entry = MmGetPageEntryForProcess(Process, Address);
00915 
00916 
00917     if (!(Entry & PA_PRESENT))
00918     {
00919         Protect = PAGE_NOACCESS;
00920     }
00921     else
00922     {
00923         if (Entry & PA_READWRITE)
00924         {
00925             Protect = PAGE_READWRITE;
00926         }
00927         else
00928         {
00929             Protect = PAGE_EXECUTE_READ;
00930         }
00931         if (Entry & PA_CD)
00932         {
00933             Protect |= PAGE_NOCACHE;
00934         }
00935         if (Entry & PA_WT)
00936         {
00937             Protect |= PAGE_WRITETHROUGH;
00938         }
00939         if (!(Entry & PA_USER))
00940         {
00941             Protect |= PAGE_SYSTEM;
00942         }
00943 
00944     }
00945     return(Protect);
00946 }
00947 
00948 VOID
00949 NTAPI
00950 MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
00951 {
00952     ULONG Attributes = 0;
00953     PULONG Pt;
00954     ULONG Pte;
00955 
00956     DPRINT("MmSetPageProtect(Process %x  Address %x  flProtect %x)\n",
00957            Process, Address, flProtect);
00958 
00959     Attributes = ProtectToPTE(flProtect);
00960 
00961     Attributes &= 0xfff;
00962     if (Address >= MmSystemRangeStart)
00963     {
00964         Attributes &= ~PA_USER;
00965     }
00966     else
00967     {
00968         Attributes |= PA_USER;
00969     }
00970 
00971     Pt = MmGetPageTableForProcess(Process, Address, FALSE);
00972     if (Pt == NULL)
00973     {
00974         KeBugCheck(MEMORY_MANAGEMENT);
00975     }
00976     Pte = InterlockedExchangePte(Pt, PAGE_MASK(*Pt) | Attributes | (*Pt & (PA_ACCESSED|PA_DIRTY)));
00977 
00978     if (!(Pte & PA_PRESENT))
00979     {
00980         DPRINT1("Invalid Pte %lx\n", Pte);
00981         KeBugCheck(MEMORY_MANAGEMENT);
00982     }
00983 
00984     if((Pte & Attributes) != Attributes)
00985         MiFlushTlb(Pt, Address);
00986     else
00987         MmUnmapPageTable(Pt);
00988 }
00989 
00990 /*
00991  * @implemented
00992  */
00993 PHYSICAL_ADDRESS NTAPI
00994 MmGetPhysicalAddress(PVOID vaddr)
00995 /*
00996  * FUNCTION: Returns the physical address corresponding to a virtual address
00997  */
00998 {
00999     PHYSICAL_ADDRESS p;
01000     ULONG Pte;
01001 
01002     DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr);
01003     Pte = MmGetPageEntryForProcess(NULL, vaddr);
01004     if (Pte != 0 && (Pte & PA_PRESENT))
01005     {
01006         p.QuadPart = PAGE_MASK(Pte);
01007         p.u.LowPart |= (ULONG_PTR)vaddr & (PAGE_SIZE - 1);
01008     }
01009     else
01010     {
01011         p.QuadPart = 0;
01012     }
01013     return p;
01014 }
01015 
01016 VOID
01017 INIT_FUNCTION
01018 NTAPI
01019 MmInitGlobalKernelPageDirectory(VOID)
01020 {
01021     /* Nothing to do here */
01022 }
01023 
01024 /* EOF */

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