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

pagepae.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 
00016 #if defined (ALLOC_PRAGMA)
00017 #pragma alloc_text(INIT, MmInitGlobalKernelPageDirectory)
00018 #pragma alloc_text(INIT, MiInitPageDirectoryMap)
00019 #endif
00020 
00021 
00022 /* GLOBALS *****************************************************************/
00023 
00024 #define PA_BIT_PRESENT   (0)
00025 #define PA_BIT_READWRITE (1)
00026 #define PA_BIT_USER      (2)
00027 #define PA_BIT_WT        (3)
00028 #define PA_BIT_CD        (4)
00029 #define PA_BIT_ACCESSED  (5)
00030 #define PA_BIT_DIRTY     (6)
00031 #define PA_BIT_GLOBAL    (8)
00032 
00033 #define PA_PRESENT   (1 << PA_BIT_PRESENT)
00034 #define PA_READWRITE (1 << PA_BIT_READWRITE)
00035 #define PA_USER      (1 << PA_BIT_USER)
00036 #define PA_DIRTY     (1 << PA_BIT_DIRTY)
00037 #define PA_WT        (1 << PA_BIT_WT)
00038 #define PA_CD        (1 << PA_BIT_CD)
00039 #define PA_ACCESSED  (1 << PA_BIT_ACCESSED)
00040 #define PA_GLOBAL    (1 << PA_BIT_GLOBAL)
00041 
00042 #define PAGETABLE_MAP           (0xc0000000)
00043 #define PAGEDIRECTORY_MAP       (0xc0000000 + (PAGETABLE_MAP / (1024)))
00044 
00045 #define PAE_PAGEDIRECTORY_MAP   (0xc0000000 + (PAGETABLE_MAP / (512)))
00046 
00047 #define HYPERSPACE              (Ke386Pae ? 0xc0800000 : 0xc0400000)
00048 #define IS_HYPERSPACE(v)        (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000))
00049 
00050 ULONG MmGlobalKernelPageDirectory[1024];
00051 ULONGLONG MmGlobalKernelPageDirectoryForPAE[2048];
00052 
00053 #define PTE_TO_PFN(X)  ((X) >> PAGE_SHIFT)
00054 #define PFN_TO_PTE(X)  ((X) << PAGE_SHIFT)
00055 
00056 #define PAE_PTE_TO_PFN(X)   (PAE_PAGE_MASK(X) >> PAGE_SHIFT)
00057 #define PAE_PFN_TO_PTE(X)   ((X) << PAGE_SHIFT)
00058 
00059 #if defined(__GNUC__)
00060 #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X)))
00061 #else
00062 __inline LARGE_INTEGER PTE_TO_PAGE(ULONG npage)
00063 {
00064    LARGE_INTEGER dummy;
00065    dummy.QuadPart = (LONGLONG)(PAGE_MASK(npage));
00066    return dummy;
00067 }
00068 #endif
00069 
00070 extern BOOLEAN Ke386Pae;
00071 extern BOOLEAN Ke386NoExecute;
00072 
00073 /* FUNCTIONS ***************************************************************/
00074 
00075 BOOLEAN MmUnmapPageTable(PULONG Pt);
00076 
00077 ULONG_PTR
00078 NTAPI
00079 MiFlushTlbIpiRoutine(ULONG_PTR Address)
00080 {
00081    if (Address == (ULONGLONG)-1)
00082    {
00083       KeFlushCurrentTb();
00084    }
00085    else if (Address == (ULONGLONG)-2)
00086    {
00087       KeFlushCurrentTb();
00088    }
00089    else
00090    {
00091        __invlpg((PVOID)Address);
00092    }
00093    return 0;
00094 }
00095 
00096 VOID
00097 MiFlushTlb(PULONG Pt, PVOID Address)
00098 {
00099 #ifdef CONFIG_SMP
00100    if (Pt)
00101    {
00102       MmUnmapPageTable(Pt);
00103    }
00104    if (KeNumberProcessors > 1)
00105    {
00106       KeIpiGenericCall(MiFlushTlbIpiRoutine, (ULONG_PTR)Address);
00107    }
00108    else
00109    {
00110       MiFlushTlbIpiRoutine((ULONG_PTR)Address);
00111    }
00112 #else
00113    if ((Pt && MmUnmapPageTable(Pt)) || Address >= MmSystemRangeStart)
00114    {
00115       __invlpg(Address);
00116    }
00117 #endif
00118 }
00119 
00120 
00121 
00122 PULONG
00123 MmGetPageDirectory(VOID)
00124 {
00125    return (PULONG)__readcr3();
00126 }
00127 
00128 static ULONG
00129 ProtectToPTE(ULONG flProtect)
00130 {
00131    ULONG Attributes = 0;
00132 
00133    if (flProtect & (PAGE_NOACCESS|PAGE_GUARD))
00134    {
00135       Attributes = 0;
00136    }
00137    else if (flProtect & PAGE_IS_WRITABLE)
00138    {
00139       Attributes = PA_PRESENT | PA_READWRITE;
00140    }
00141    else if (flProtect & (PAGE_IS_READABLE | PAGE_IS_EXECUTABLE))
00142    {
00143       Attributes = PA_PRESENT;
00144    }
00145    else
00146    {
00147       DPRINT1("Unknown main protection type.\n");
00148       ASSERT(FALSE);
00149    }
00150    if (Ke386NoExecute &&
00151        !(flProtect & PAGE_IS_EXECUTABLE))
00152    {
00153       Attributes = Attributes | 0x80000000;
00154    }
00155 
00156    if (flProtect & PAGE_SYSTEM)
00157    {
00158    }
00159    else
00160    {
00161       Attributes = Attributes | PA_USER;
00162    }
00163    if (flProtect & PAGE_NOCACHE)
00164    {
00165       Attributes = Attributes | PA_CD;
00166    }
00167    if (flProtect & PAGE_WRITETHROUGH)
00168    {
00169       Attributes = Attributes | PA_WT;
00170    }
00171    return(Attributes);
00172 }
00173 
00174 #define ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (1024 * PAGE_SIZE))
00175 
00176 #define ADDR_TO_PDE(v) (PULONG)(PAGEDIRECTORY_MAP + \
00177                                 ((((ULONG)(v)) / (1024 * 1024))&(~0x3)))
00178 #define ADDR_TO_PTE(v) (PULONG)(PAGETABLE_MAP + ((((ULONG)(v) / 1024))&(~0x3)))
00179 
00180 #define ADDR_TO_PDE_OFFSET(v) ((((ULONG)(v)) / (1024 * PAGE_SIZE)))
00181 
00182 #define ADDR_TO_PTE_OFFSET(v)  ((((ULONG)(v)) % (1024 * PAGE_SIZE)) / PAGE_SIZE)
00183 
00184 
00185 #define PAE_ADDR_TO_PAGE_TABLE(v)   (((ULONG)(v)) / (512 * PAGE_SIZE))
00186 
00187 #define PAE_ADDR_TO_PDE(v)          (PULONGLONG) (PAE_PAGEDIRECTORY_MAP + \
00188                                                   ((((ULONG_PTR)(v)) / (512 * 512))&(~0x7)))
00189 #define PAE_ADDR_TO_PTE(v)          (PULONGLONG) (PAGETABLE_MAP + ((((ULONG_PTR)(v) / 512))&(~0x7)))
00190 
00191 
00192 #define PAE_ADDR_TO_PDTE_OFFSET(v)  (((ULONG_PTR)(v)) / (512 * 512 * PAGE_SIZE))
00193 
00194 #define PAE_ADDR_TO_PDE_PAGE_OFFSET(v)   ((((ULONG_PTR)(v)) % (512 * 512 * PAGE_SIZE)) / (512 * PAGE_SIZE))
00195 
00196 #define PAE_ADDR_TO_PDE_OFFSET(v)   (((ULONG_PTR)(v))/ (512 * PAGE_SIZE))
00197 
00198 #define PAE_ADDR_TO_PTE_OFFSET(v)   ((((ULONG_PTR)(v)) % (512 * PAGE_SIZE)) / PAGE_SIZE)
00199 
00200 
00201 NTSTATUS
00202 NTAPI
00203 Mmi386ReleaseMmInfo(PEPROCESS Process)
00204 {
00205    PUSHORT LdtDescriptor;
00206    ULONG LdtBase;
00207    ULONG i, j;
00208 
00209    DPRINT("Mmi386ReleaseMmInfo(Process %x)\n",Process);
00210 
00211    LdtDescriptor = (PUSHORT) &Process->Pcb.LdtDescriptor;
00212    LdtBase = LdtDescriptor[1] |
00213              ((LdtDescriptor[2] & 0xff) << 16) |
00214              ((LdtDescriptor[3] & ~0xff) << 16);
00215 
00216    DPRINT("LdtBase: %x\n", LdtBase);
00217 
00218    if (LdtBase)
00219    {
00220       ExFreePool((PVOID) LdtBase);
00221    }
00222 
00223    if (Ke386Pae)
00224    {
00225       PULONGLONG PageDirTable;
00226       PULONGLONG PageDir;
00227       PULONGLONG Pde;
00228       ULONG k;
00229 
00230       PageDirTable = (PULONGLONG)MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process->Pcb.DirectoryTableBase.QuadPart));
00231       for (i = 0; i < 4; i++)
00232       {
00233          PageDir = (PULONGLONG)MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDirTable[i]));
00234          if (i < PAE_ADDR_TO_PDTE_OFFSET(MmSystemRangeStart))
00235          {
00236             for (j = 0; j < 512; j++)
00237             {
00238                if (PageDir[j] != 0LL)
00239                {
00240                   DPRINT1("ProcessId %d, Pde for %08x - %08x is not freed, RefCount %d\n",
00241                           Process->UniqueProcessId,
00242                           (i * 512 + j) * 512 * PAGE_SIZE, (i * 512 + j + 1) * 512 * PAGE_SIZE - 1,
00243                           ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable[i*512 + j]);
00244                   Pde = MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDir[j]));
00245                   for (k = 0; k < 512; k++)
00246                   {
00247                      if(Pde[k] != 0)
00248                      {
00249                         if (Pde[k] & PA_PRESENT)
00250                         {
00251                            DPRINT1("Page at %08x is not freed\n",
00252                                    (i * 512 + j) * 512 * PAGE_SIZE + k * PAGE_SIZE);
00253                         }
00254                         else
00255                         {
00256                            DPRINT1("Swapentry %x at %x is not freed\n",
00257                                    (i * 512 + j) * 512 * PAGE_SIZE + k * PAGE_SIZE);
00258                         }
00259                      }
00260                   }
00261                   MmDeleteHyperspaceMapping(Pde);
00262                   MmReleasePageMemoryConsumer(MC_NPPOOL, PAE_PTE_TO_PFN(PageDir[j]));
00263                }
00264             }
00265          }
00266          if (i == PAE_ADDR_TO_PDTE_OFFSET(HYPERSPACE))
00267          {
00268             MmReleasePageMemoryConsumer(MC_NPPOOL, PAE_PTE_TO_PFN(PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE)]));
00269             MmReleasePageMemoryConsumer(MC_NPPOOL, PAE_PTE_TO_PFN(PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE)+1]));
00270          }
00271          MmDeleteHyperspaceMapping(PageDir);
00272          MmReleasePageMemoryConsumer(MC_NPPOOL, PAE_PTE_TO_PFN(PageDirTable[i]));
00273       }
00274       MmDeleteHyperspaceMapping((PVOID)PageDirTable);
00275       MmReleasePageMemoryConsumer(MC_NPPOOL, PAE_PTE_TO_PFN(Process->Pcb.DirectoryTableBase.QuadPart));
00276    }
00277    else
00278    {
00279       PULONG Pde;
00280       PULONG PageDir;
00281       PageDir = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase.u.LowPart));
00282       for (i = 0; i < ADDR_TO_PDE_OFFSET(MmSystemRangeStart); i++)
00283       {
00284          if (PageDir[i] != 0)
00285          {
00286             DPRINT1("Pde for %08x - %08x is not freed, RefCount %d\n",
00287                     i * 4 * 1024 * 1024, (i + 1) * 4 * 1024 * 1024 - 1,
00288                     ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable[i]);
00289             Pde = MmCreateHyperspaceMapping(PTE_TO_PFN(PageDir[i]));
00290             for (j = 0; j < 1024; j++)
00291             {
00292                if(Pde[j] != 0)
00293                {
00294                   if (Pde[j] & PA_PRESENT)
00295                   {
00296                      DPRINT1("Page at %08x is not freed\n",
00297                              i * 4 * 1024 * 1024 + j * PAGE_SIZE);
00298                   }
00299                   else
00300                   {
00301                      DPRINT1("Swapentry %x at %x is not freed\n",
00302                              Pde[j], i * 4 * 1024 * 1024 + j * PAGE_SIZE);
00303                   }
00304                }
00305             }
00306             MmDeleteHyperspaceMapping(Pde);
00307             MmReleasePageMemoryConsumer(MC_NPPOOL, PTE_TO_PFN(PageDir[i]));
00308          }
00309       }
00310       MmReleasePageMemoryConsumer(MC_NPPOOL, PTE_TO_PFN(PageDir[ADDR_TO_PDE_OFFSET(HYPERSPACE)]));
00311       MmDeleteHyperspaceMapping(PageDir);
00312       MmReleasePageMemoryConsumer(MC_NPPOOL, PTE_TO_PFN(Process->Pcb.DirectoryTableBase.u.LowPart));
00313    }
00314 
00315 #if defined(__GNUC__)
00316 
00317    Process->Pcb.DirectoryTableBase.QuadPart = 0LL;
00318 #else
00319 
00320    Process->Pcb.DirectoryTableBase.QuadPart = 0;
00321 #endif
00322 
00323    DPRINT("Finished Mmi386ReleaseMmInfo()\n");
00324    return(STATUS_SUCCESS);
00325 }
00326 
00327 NTSTATUS
00328 NTAPI
00329 MmInitializeHandBuiltProcess(IN PEPROCESS Process,
00330                              IN PLARGE_INTEGER DirectoryTableBase)
00331 {
00332     /* Share the directory base with the idle process */
00333     *DirectoryTableBase = PsGetCurrentProcess()->Pcb.DirectoryTableBase;
00334 
00335     /* Initialize the Addresss Space */
00336     MmInitializeAddressSpace(Process, (PMADDRESS_SPACE)&Process->VadRoot);
00337 
00338     /* The process now has an address space */
00339     Process->HasAddressSpace = TRUE;
00340     return STATUS_SUCCESS;
00341 }
00342 
00343 BOOLEAN
00344 NTAPI
00345 MmCreateProcessAddressSpace(IN ULONG MinWs,
00346                             IN PEPROCESS Process,
00347                             IN PLARGE_INTEGER DirectoryTableBase)
00348 {
00349    NTSTATUS Status;
00350    ULONG i, j;
00351    PFN_NUMBER Pfn[7];
00352    ULONG Count;
00353 
00354    DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", MinWs, Process);
00355 
00356    Count = Ke386Pae ? 7 : 2;
00357 
00358    for (i = 0; i < Count; i++)
00359    {
00360       Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn[i]);
00361       if (!NT_SUCCESS(Status))
00362       {
00363           for (j = 0; j < i; j++)
00364           {
00365               MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn[j]);
00366           }
00367 
00368           return FALSE;
00369       }
00370    }
00371 
00372    if (Ke386Pae)
00373    {
00374       PULONGLONG PageDirTable;
00375       PULONGLONG PageDir;
00376 
00377       PageDirTable = MmCreateHyperspaceMapping(Pfn[0]);
00378       for (i = 0; i < 4; i++)
00379       {
00380          PageDirTable[i] = PAE_PFN_TO_PTE(Pfn[1+i]) | PA_PRESENT;
00381       }
00382       MmDeleteHyperspaceMapping(PageDirTable);
00383       for (i = PAE_ADDR_TO_PDTE_OFFSET(MmSystemRangeStart); i < 4; i++)
00384       {
00385          PageDir = (PULONGLONG)MmCreateHyperspaceMapping(Pfn[i+1]);
00386          memcpy(PageDir, &MmGlobalKernelPageDirectoryForPAE[i * 512], 512 * sizeof(ULONGLONG));
00387          if (PAE_ADDR_TO_PDTE_OFFSET(PAGETABLE_MAP) == i)
00388          {
00389             for (j = 0; j < 4; j++)
00390             {
00391                PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(PAGETABLE_MAP) + j] = PAE_PFN_TO_PTE(Pfn[1+j]) | PA_PRESENT | PA_READWRITE;
00392             }
00393          }
00394          if (PAE_ADDR_TO_PDTE_OFFSET(HYPERSPACE) == i)
00395          {
00396             PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE)] = PAE_PFN_TO_PTE(Pfn[5]) | PA_PRESENT | PA_READWRITE;
00397             PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE)+1] = PAE_PFN_TO_PTE(Pfn[6]) | PA_PRESENT | PA_READWRITE;
00398          }
00399          MmDeleteHyperspaceMapping(PageDir);
00400       }
00401    }
00402    else
00403    {
00404       PULONG PageDirectory;
00405       PageDirectory = MmCreateHyperspaceMapping(Pfn[0]);
00406 
00407       memcpy(PageDirectory + ADDR_TO_PDE_OFFSET(MmSystemRangeStart),
00408              MmGlobalKernelPageDirectory + ADDR_TO_PDE_OFFSET(MmSystemRangeStart),
00409              (1024 - ADDR_TO_PDE_OFFSET(MmSystemRangeStart)) * sizeof(ULONG));
00410 
00411       DPRINT("Addr %x\n",ADDR_TO_PDE_OFFSET(PAGETABLE_MAP));
00412       PageDirectory[ADDR_TO_PDE_OFFSET(PAGETABLE_MAP)] = PFN_TO_PTE(Pfn[0]) | PA_PRESENT | PA_READWRITE;
00413       PageDirectory[ADDR_TO_PDE_OFFSET(HYPERSPACE)] = PFN_TO_PTE(Pfn[1]) | PA_PRESENT | PA_READWRITE;
00414 
00415       MmDeleteHyperspaceMapping(PageDirectory);
00416    }
00417 
00418    DirectoryTableBase->QuadPart = PFN_TO_PTE(Pfn[0]);
00419    DPRINT("Finished MmCopyMmInfo(): %I64x\n", DirectoryTableBase->QuadPart);
00420    return TRUE;
00421 }
00422 
00423 VOID
00424 NTAPI
00425 MmDeletePageTable(PEPROCESS Process, PVOID Address)
00426 {
00427    PEPROCESS CurrentProcess = PsGetCurrentProcess();
00428 
00429    if (Process != NULL && Process != CurrentProcess)
00430    {
00431       KeAttachProcess(&Process->Pcb);
00432    }
00433 
00434    if (Ke386Pae)
00435    {
00436       ULONGLONG ZeroPde = 0LL;
00437       (void)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address), &ZeroPde);
00438       MiFlushTlb((PULONG)PAE_ADDR_TO_PDE(Address), PAE_ADDR_TO_PTE(Address));
00439    }
00440    else
00441    {
00442       *(ADDR_TO_PDE(Address)) = 0;
00443       MiFlushTlb(ADDR_TO_PDE(Address), ADDR_TO_PTE(Address));
00444    }
00445    if (Address >= MmSystemRangeStart)
00446    {
00447       ASSERT(FALSE);
00448       //       MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
00449    }
00450    if (Process != NULL && Process != CurrentProcess)
00451    {
00452       KeDetachProcess();
00453    }
00454 }
00455 
00456 VOID
00457 NTAPI
00458 MmFreePageTable(PEPROCESS Process, PVOID Address)
00459 {
00460    PEPROCESS CurrentProcess = PsGetCurrentProcess();
00461    ULONG i;
00462    PFN_NUMBER Pfn;
00463 
00464    DPRINT("ProcessId %d, Address %x\n", Process->UniqueProcessId, Address);
00465    if (Process != NULL && Process != CurrentProcess)
00466    {
00467       KeAttachProcess(&Process->Pcb);
00468    }
00469    if (Ke386Pae)
00470    {
00471       PULONGLONG PageTable;
00472       ULONGLONG ZeroPte = 0LL;
00473       PageTable = (PULONGLONG)PAGE_ROUND_DOWN((PVOID)PAE_ADDR_TO_PTE(Address));
00474       for (i = 0; i < 512; i++)
00475       {
00476          if (PageTable[i] != 0LL)
00477          {
00478             DbgPrint("Page table entry not clear at %x/%x (is %I64x)\n",
00479                      ((ULONG)Address / (4*1024*1024)), i, PageTable[i]);
00480             ASSERT(FALSE);
00481          }
00482       }
00483       Pfn = PAE_PTE_TO_PFN(*(PAE_ADDR_TO_PDE(Address)));
00484       (void)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address), &ZeroPte);
00485       MiFlushTlb((PULONG)PAE_ADDR_TO_PDE(Address), PAE_ADDR_TO_PTE(Address));
00486    }
00487    else
00488    {
00489       PULONG PageTable;
00490       PageTable = (PULONG)PAGE_ROUND_DOWN((PVOID)ADDR_TO_PTE(Address));
00491       for (i = 0; i < 1024; i++)
00492       {
00493          if (PageTable[i] != 0)
00494          {
00495             DbgPrint("Page table entry not clear at %x/%x (is %x)\n",
00496                      ((ULONG)Address / (4*1024*1024)), i, PageTable[i]);
00497             ASSERT(FALSE);
00498          }
00499       }
00500       Pfn = PTE_TO_PFN(*(ADDR_TO_PDE(Address)));
00501       *(ADDR_TO_PDE(Address)) = 0;
00502       MiFlushTlb(ADDR_TO_PDE(Address), ADDR_TO_PTE(Address));
00503    }
00504 
00505    if (Address >= MmSystemRangeStart)
00506    {
00507       //    MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0;
00508       ASSERT(FALSE);
00509    }
00510    else
00511    {
00512       MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
00513    }
00514    if (Process != NULL && Process != CurrentProcess)
00515    {
00516       KeDetachProcess();
00517    }
00518 }
00519 
00520 static PULONGLONG
00521 MmGetPageTableForProcessForPAE(PEPROCESS Process, PVOID Address, BOOLEAN Create)
00522 {
00523    NTSTATUS Status;
00524    PFN_NUMBER Pfn;
00525    ULONGLONG Entry;
00526    ULONGLONG ZeroEntry = 0LL;
00527    PULONGLONG Pt;
00528    PULONGLONG PageDir;
00529    PULONGLONG PageDirTable;
00530 
00531    DPRINT("MmGetPageTableForProcessForPAE(%x %x %d)\n",
00532           Process, Address, Create);
00533    if (Address >= (PVOID)PAGETABLE_MAP && Address < (PVOID)((ULONG_PTR)PAGETABLE_MAP + 0x800000))
00534    {
00535       ASSERT(FALSE);
00536    }
00537    if (Address < MmSystemRangeStart && Process && Process != PsGetCurrentProcess())
00538    {
00539       PageDirTable = MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process->Pcb.DirectoryTableBase.QuadPart));
00540       if (PageDirTable == NULL)
00541       {
00542          ASSERT(FALSE);
00543       }
00544       PageDir = MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDirTable[PAE_ADDR_TO_PDTE_OFFSET(Address)]));
00545       MmDeleteHyperspaceMapping(PageDirTable);
00546       if (PageDir == NULL)
00547       {
00548          ASSERT(FALSE);
00549       }
00550       PageDir += PAE_ADDR_TO_PDE_PAGE_OFFSET(Address);
00551       Entry = ExfInterlockedCompareExchange64UL(PageDir, &ZeroEntry, &ZeroEntry);
00552       if (Entry == 0LL)
00553       {
00554          if (Create == FALSE)
00555          {
00556             MmDeleteHyperspaceMapping(PageDir);
00557             return NULL;
00558          }
00559          Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
00560          if (!NT_SUCCESS(Status))
00561          {
00562             ASSERT(FALSE);
00563          }
00564          Entry = PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER;
00565          Entry = ExfInterlockedCompareExchange64UL(PageDir, &Entry, &ZeroEntry);
00566          if (Entry != 0LL)
00567          {
00568             MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
00569             Pfn = PAE_PTE_TO_PFN(Entry);
00570          }
00571       }
00572       else
00573       {
00574          Pfn = PAE_PTE_TO_PFN(Entry);
00575       }
00576       MmDeleteHyperspaceMapping(PageDir);
00577       Pt = MmCreateHyperspaceMapping(Pfn);
00578       if (Pt == NULL)
00579       {
00580          ASSERT(FALSE);
00581       }
00582       return Pt + PAE_ADDR_TO_PTE_OFFSET(Address);
00583    }
00584    PageDir = PAE_ADDR_TO_PDE(Address);
00585    if (0LL == ExfInterlockedCompareExchange64UL(PageDir, &ZeroEntry, &ZeroEntry))
00586    {
00587       if (Address >= MmSystemRangeStart)
00588       {
00589          if (MmGlobalKernelPageDirectoryForPAE[PAE_ADDR_TO_PDE_OFFSET(Address)] == 0LL)
00590          {
00591             if (Create == FALSE)
00592             {
00593                return NULL;
00594             }
00595             Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
00596             if (!NT_SUCCESS(Status))
00597             {
00598                ASSERT(FALSE);
00599             }
00600             Entry = PAE_PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE;
00601             if (Ke386GlobalPagesEnabled)
00602             {
00603                Entry |= PA_GLOBAL;
00604             }
00605             if (0LL != ExfInterlockedCompareExchange64UL(&MmGlobalKernelPageDirectoryForPAE[PAE_ADDR_TO_PDE_OFFSET(Address)], &Entry, &ZeroEntry))
00606             {
00607                MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
00608             }
00609          }
00610          (void)ExfInterlockedCompareExchange64UL(PageDir, &MmGlobalKernelPageDirectoryForPAE[PAE_ADDR_TO_PDE_OFFSET(Address)], &ZeroEntry);
00611       }
00612       else
00613       {
00614          if (Create == FALSE)
00615          {
00616             return NULL;
00617          }
00618          Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
00619          if (!NT_SUCCESS(Status))
00620          {
00621             ASSERT(FALSE);
00622          }
00623          Entry = PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER;
00624          Entry = ExfInterlockedCompareExchange64UL(PageDir, &Entry, &ZeroEntry);
00625          if (Entry != 0LL)
00626          {
00627             MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
00628          }
00629       }
00630    }
00631    return (PULONGLONG)PAE_ADDR_TO_PTE(Address);
00632 }
00633 
00634 static PULONG
00635 MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create)
00636 {
00637    ULONG PdeOffset = ADDR_TO_PDE_OFFSET(Address);
00638    NTSTATUS Status;
00639    PFN_NUMBER Pfn;
00640    ULONG Entry;
00641    PULONG Pt, PageDir;
00642 
00643    if (Address < MmSystemRangeStart && Process && Process != PsGetCurrentProcess())
00644    {
00645       PageDir = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase.LowPart));
00646       if (PageDir == NULL)
00647       {
00648          ASSERT(FALSE);
00649       }
00650       if (0 == InterlockedCompareExchangeUL(&PageDir[PdeOffset], 0, 0))
00651       {
00652          if (Create == FALSE)
00653          {
00654             MmDeleteHyperspaceMapping(PageDir);
00655             return NULL;
00656          }
00657          Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
00658          if (!NT_SUCCESS(Status) || Pfn == 0)
00659          {
00660             ASSERT(FALSE);
00661          }
00662          Entry = InterlockedCompareExchangeUL(&PageDir[PdeOffset], PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER, 0);
00663          if (Entry != 0)
00664          {
00665             MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
00666             Pfn = PTE_TO_PFN(Entry);
00667          }
00668       }
00669       else
00670       {
00671          Pfn = PTE_TO_PFN(PageDir[PdeOffset]);
00672       }
00673       MmDeleteHyperspaceMapping(PageDir);
00674       Pt = MmCreateHyperspaceMapping(Pfn);
00675       if (Pt == NULL)
00676       {
00677          ASSERT(FALSE);
00678       }
00679       return Pt + ADDR_TO_PTE_OFFSET(Address);
00680    }
00681    PageDir = ADDR_TO_PDE(Address);
00682    if (0 == InterlockedCompareExchangeUL(PageDir, 0, 0))
00683    {
00684       if (Address >= MmSystemRangeStart)
00685       {
00686          if (0 == InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory[PdeOffset], 0, 0))
00687          {
00688             if (Create == FALSE)
00689             {
00690                return NULL;
00691             }
00692             Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
00693             if (!NT_SUCCESS(Status) || Pfn == 0)
00694             {
00695                ASSERT(FALSE);
00696             }
00697             Entry = PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE;
00698             if (Ke386GlobalPagesEnabled)
00699             {
00700                Entry |= PA_GLOBAL;
00701             }
00702             if(0 != InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory[PdeOffset], Entry, 0))
00703             {
00704                MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
00705             }
00706          }
00707          (void)InterlockedExchangeUL(PageDir, MmGlobalKernelPageDirectory[PdeOffset]);
00708       }
00709       else
00710       {
00711          if (Create == FALSE)
00712          {
00713             return NULL;
00714          }
00715          Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn);
00716          if (!NT_SUCCESS(Status) || Pfn == 0)
00717          {
00718             ASSERT(FALSE);
00719          }
00720          Entry = InterlockedCompareExchangeUL(PageDir, PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER, 0);
00721          if (Entry != 0)
00722          {
00723             MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
00724          }
00725       }
00726    }
00727    return (PULONG)ADDR_TO_PTE(Address);
00728 }
00729 
00730 BOOLEAN MmUnmapPageTable(PULONG Pt)
00731 {
00732    if (Ke386Pae)
00733    {
00734       if ((PULONGLONG)Pt >= (PULONGLONG)PAGETABLE_MAP && (PULONGLONG)Pt < (PULONGLONG)PAGETABLE_MAP + 4*512*512)
00735       {
00736          return TRUE;
00737       }
00738    }
00739    else
00740    {
00741       if (Pt >= (PULONG)PAGETABLE_MAP && Pt < (PULONG)PAGETABLE_MAP + 1024*1024)
00742       {
00743          return TRUE;
00744       }
00745    }
00746    if (Pt)
00747    {
00748       MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pt));
00749    }
00750    return FALSE;
00751 }
00752 
00753 static ULONGLONG MmGetPageEntryForProcessForPAE(PEPROCESS Process, PVOID Address)
00754 {
00755    ULONGLONG Pte;
00756    PULONGLONG Pt;
00757 
00758    Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE);
00759    if (Pt)
00760    {
00761       Pte = *Pt;
00762       MmUnmapPageTable((PULONG)Pt);
00763       return Pte;
00764    }
00765    return 0;
00766 }
00767 
00768 static ULONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
00769 {
00770    ULONG Pte;
00771    PULONG Pt;
00772 
00773    Pt = MmGetPageTableForProcess(Process, Address, FALSE);
00774    if (Pt)
00775    {
00776       Pte = *Pt;
00777       MmUnmapPageTable(Pt);
00778       return Pte;
00779    }
00780    return 0;
00781 }
00782 
00783 PFN_NUMBER
00784 NTAPI
00785 MmGetPfnForProcess(PEPROCESS Process,
00786                    PVOID Address)
00787 {
00788 
00789    if (Ke386Pae)
00790    {
00791       ULONGLONG Entry;
00792       Entry = MmGetPageEntryForProcessForPAE(Process, Address);
00793       if (!(Entry & PA_PRESENT))
00794       {
00795          return 0;
00796       }
00797       return(PAE_PTE_TO_PFN(Entry));
00798    }
00799    else
00800    {
00801       ULONG Entry;
00802       Entry = MmGetPageEntryForProcess(Process, Address);
00803       if (!(Entry & PA_PRESENT))
00804       {
00805          return 0;
00806       }
00807       return(PTE_TO_PFN(Entry));
00808    }
00809 }
00810 
00811 VOID
00812 NTAPI
00813 MmDisableVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN* WasDirty, PPFN_NUMBER Page)
00814 /*
00815  * FUNCTION: Delete a virtual mapping
00816  */
00817 {
00818    BOOLEAN WasValid;
00819    if (Ke386Pae)
00820    {
00821       ULONGLONG Pte;
00822       ULONGLONG tmpPte;
00823       PULONGLONG Pt;
00824 
00825       Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE);
00826       if (Pt == NULL)
00827       {
00828          ASSERT(FALSE);
00829       }
00830       /*
00831        * Atomically disable the present bit and get the old value.
00832        */
00833       do
00834       {
00835          Pte = *Pt;
00836          tmpPte = Pte & ~PA_PRESENT;
00837       } while (Pte != ExfInterlockedCompareExchange64UL(Pt, &tmpPte, &Pte));
00838 
00839       MiFlushTlb((PULONG)Pt, Address);
00840       WasValid = PAE_PAGE_MASK(Pte) != 0LL ? TRUE : FALSE;
00841       if (!WasValid)
00842       {
00843          ASSERT(FALSE);
00844       }
00845 
00846       /*
00847        * Return some information to the caller
00848        */
00849       if (WasDirty != NULL)
00850       {
00851          *WasDirty = Pte & PA_DIRTY ? TRUE : FALSE;
00852       }
00853       if (Page != NULL)
00854       {
00855          *Page = PAE_PTE_TO_PFN(Pte);
00856       }
00857    }
00858    else
00859    {
00860       ULONG Pte;
00861       PULONG Pt;
00862 
00863       Pt = MmGetPageTableForProcess(Process, Address, FALSE);
00864       if (Pt == NULL)
00865       {
00866          ASSERT(FALSE);
00867       }
00868       /*
00869        * Atomically disable the present bit and get the old value.
00870        */
00871       do
00872       {
00873         Pte = *Pt;
00874       } while (Pte != InterlockedCompareExchangeUL(Pt, Pte & ~PA_PRESENT, Pte));
00875 
00876       MiFlushTlb(Pt, Address);
00877       WasValid = (PAGE_MASK(Pte) != 0);
00878       if (!WasValid)
00879       {
00880          ASSERT(FALSE);
00881       }
00882 
00883       /*
00884        * Return some information to the caller
00885        */
00886       if (WasDirty != NULL)
00887       {
00888          *WasDirty = Pte & PA_DIRTY;
00889       }
00890       if (Page != NULL)
00891       {
00892          *Page = PTE_TO_PFN(Pte);
00893       }
00894    }
00895 }
00896 
00897 VOID
00898 NTAPI
00899 MmRawDeleteVirtualMapping(PVOID Address)
00900 {
00901    if (Ke386Pae)
00902    {
00903       PULONGLONG Pt;
00904       ULONGLONG ZeroPte = 0LL;
00905       Pt = MmGetPageTableForProcessForPAE(NULL, Address, FALSE);
00906       if (Pt)
00907       {
00908          /*
00909           * Set the entry to zero
00910           */
00911          (void)ExfpInterlockedExchange64UL(Pt, &ZeroPte);
00912          MiFlushTlb((PULONG)Pt, Address);
00913       }
00914    }
00915    else
00916    {
00917       PULONG Pt;
00918 
00919       Pt = MmGetPageTableForProcess(NULL, Address, FALSE);
00920       if (Pt && *Pt)
00921       {
00922          /*
00923           * Set the entry to zero
00924           */
00925          (void)InterlockedExchangeUL(Pt, 0);
00926          MiFlushTlb(Pt, Address);
00927       }
00928    }
00929 }
00930 
00931 VOID
00932 NTAPI
00933 MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN FreePage,
00934                        BOOLEAN* WasDirty, PPFN_NUMBER Page)
00935 /*
00936  * FUNCTION: Delete a virtual mapping
00937  */
00938 {
00939    BOOLEAN WasValid = FALSE;
00940    PFN_NUMBER Pfn;
00941 
00942    DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
00943           Process, Address, FreePage, WasDirty, Page);
00944    if (Ke386Pae)
00945    {
00946       ULONGLONG Pte;
00947       PULONGLONG Pt;
00948 
00949       Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE);
00950       if (Pt == NULL)
00951       {
00952          if (WasDirty != NULL)
00953          {
00954             *WasDirty = FALSE;
00955          }
00956          if (Page != NULL)
00957          {
00958             *Page = 0;
00959          }
00960          return;
00961       }
00962 
00963       /*
00964        * Atomically set the entry to zero and get the old value.
00965        */
00966       Pte = 0LL;
00967       Pte = ExfpInterlockedExchange64UL(Pt, &Pte);
00968 
00969       MiFlushTlb((PULONG)Pt, Address);
00970 
00971       WasValid = PAE_PAGE_MASK(Pte) != 0 ? TRUE : FALSE;
00972       if (WasValid)
00973       {
00974          Pfn = PAE_PTE_TO_PFN(Pte);
00975          MmMarkPageUnmapped(Pfn);
00976       }
00977       else
00978       {
00979          Pfn = 0;
00980       }
00981 
00982       if (FreePage && WasValid)
00983       {
00984          MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
00985       }
00986 
00987       /*
00988        * Return some information to the caller
00989        */
00990       if (WasDirty != NULL)
00991       {
00992          *WasDirty = Pte & PA_DIRTY ? TRUE : FALSE;
00993       }
00994       if (Page != NULL)
00995       {
00996          *Page = Pfn;
00997       }
00998    }
00999    else
01000    {
01001       ULONG Pte;
01002       PULONG Pt;
01003 
01004       Pt = MmGetPageTableForProcess(Process, Address, FALSE);
01005 
01006       if (Pt == NULL)
01007       {
01008          if (WasDirty != NULL)
01009          {
01010             *WasDirty = FALSE;
01011          }
01012          if (Page != NULL)
01013          {
01014             *Page = 0;
01015          }
01016          return;
01017       }
01018 
01019       /*
01020        * Atomically set the entry to zero and get the old value.
01021        */
01022       Pte = InterlockedExchangeUL(Pt, 0);
01023 
01024       MiFlushTlb(Pt, Address);
01025 
01026       WasValid = (PAGE_MASK(Pte) != 0);
01027       if (WasValid)
01028       {
01029          Pfn = PTE_TO_PFN(Pte);
01030          MmMarkPageUnmapped(Pfn);
01031       }
01032       else
01033       {
01034          Pfn = 0;
01035       }
01036 
01037       if (FreePage && WasValid)
01038       {
01039          MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn);
01040       }
01041 
01042       /*
01043        * Return some information to the caller
01044        */
01045       if (WasDirty != NULL)
01046       {
01047          *WasDirty = Pte & PA_DIRTY ? TRUE : FALSE;
01048       }
01049       if (Page != NULL)
01050       {
01051          *Page = Pfn;
01052       }
01053    }
01054    /*
01055     * Decrement the reference count for this page table.
01056     */
01057    if (Process != NULL && WasValid &&
01058        ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
01059        Address < MmSystemRangeStart)
01060    {
01061       PUSHORT Ptrc;
01062       ULONG Idx;
01063 
01064       Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
01065       Idx = Ke386Pae ? PAE_ADDR_TO_PAGE_TABLE(Address) : ADDR_TO_PAGE_TABLE(Address);
01066 
01067       Ptrc[Idx]--;
01068       if (Ptrc[Idx] == 0)
01069       {
01070          MmFreePageTable(Process, Address);
01071       }
01072    }
01073 }
01074 
01075 VOID
01076 NTAPI
01077 MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
01078                         SWAPENTRY* SwapEntry)
01079 /*
01080  * FUNCTION: Delete a virtual mapping
01081  */
01082 {
01083    if (Ke386Pae)
01084    {
01085       ULONGLONG Pte;
01086       PULONGLONG Pt;
01087 
01088       Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE);
01089       if (Pt == NULL)
01090       {
01091          *SwapEntry = 0;
01092          return;
01093       }
01094 
01095       /*
01096        * Atomically set the entry to zero and get the old value.
01097        */
01098       Pte = 0LL;
01099       Pte = ExfpInterlockedExchange64UL(Pt, &Pte);
01100 
01101       MiFlushTlb((PULONG)Pt, Address);
01102 
01103       /*
01104        * Decrement the reference count for this page table.
01105        */
01106       if (Process != NULL && Pte &&
01107           ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
01108           Address < MmSystemRangeStart)
01109       {
01110          PUSHORT Ptrc;
01111 
01112          Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
01113 
01114          Ptrc[PAE_ADDR_TO_PAGE_TABLE(Address)]--;
01115          if (Ptrc[PAE_ADDR_TO_PAGE_TABLE(Address)] == 0)
01116          {
01117             MmFreePageTable(Process, Address);
01118          }
01119       }
01120 
01121 
01122       /*
01123        * Return some information to the caller
01124        */
01125       *SwapEntry = Pte >> 1;
01126    }
01127    else
01128    {
01129       ULONG Pte;
01130       PULONG Pt;
01131 
01132       Pt = MmGetPageTableForProcess(Process, Address, FALSE);
01133 
01134       if (Pt == NULL)
01135       {
01136          *SwapEntry = 0;
01137          return;
01138       }
01139 
01140       /*
01141        * Atomically set the entry to zero and get the old value.
01142        */
01143       Pte = InterlockedExchangeUL(Pt, 0);
01144 
01145       MiFlushTlb(Pt, Address);
01146 
01147       /*
01148        * Decrement the reference count for this page table.
01149        */
01150       if (Process != NULL && Pte &&
01151           ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
01152           Address < MmSystemRangeStart)
01153       {
01154          PUSHORT Ptrc;
01155 
01156          Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
01157 
01158          Ptrc[ADDR_TO_PAGE_TABLE(Address)]--;
01159          if (Ptrc[ADDR_TO_PAGE_TABLE(Address)] == 0)
01160          {
01161             MmFreePageTable(Process, Address);
01162          }
01163       }
01164 
01165 
01166       /*
01167        * Return some information to the caller
01168        */
01169       *SwapEntry = Pte >> 1;
01170    }
01171 }
01172 
01173 BOOLEAN
01174 Mmi386MakeKernelPageTableGlobal(PVOID PAddress)
01175 {
01176    if (Ke386Pae)
01177    {
01178       PULONGLONG Pt;
01179       PULONGLONG Pde;
01180       Pde = PAE_ADDR_TO_PDE(PAddress);
01181       if (*Pde == 0LL)
01182       {
01183          Pt = MmGetPageTableForProcessForPAE(NULL, PAddress, FALSE);
01184 #if 0
01185          /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
01186          FLASH_TLB_ONE(PAddress);
01187 #endif
01188          if (Pt != NULL)
01189          {
01190             return TRUE;
01191          }
01192       }
01193    }
01194    else
01195    {
01196       PULONG Pt, Pde;
01197       Pde = ADDR_TO_PDE(PAddress);
01198       if (*Pde == 0)
01199       {
01200          Pt = MmGetPageTableForProcess(NULL, PAddress, FALSE);
01201 #if 0
01202          /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */
01203          FLASH_TLB_ONE(PAddress);
01204 #endif
01205          if (Pt != NULL)
01206          {
01207             return TRUE;
01208          }
01209       }
01210    }
01211    return(FALSE);
01212 }
01213 
01214 BOOLEAN
01215 NTAPI
01216 MmIsDirtyPage(PEPROCESS Process, PVOID Address)
01217 {
01218    if (Ke386Pae)
01219    {
01220       return MmGetPageEntryForProcessForPAE(Process, Address) & PA_DIRTY ? TRUE : FALSE;
01221    }
01222    else
01223    {
01224       return MmGetPageEntryForProcess(Process, Address) & PA_DIRTY ? TRUE : FALSE;
01225    }
01226 }
01227 
01228 BOOLEAN
01229 NTAPI
01230 MmIsAccessedAndResetAccessPage(PEPROCESS Process, PVOID Address)
01231 {
01232    if (Address < MmSystemRangeStart && Process == NULL)
01233    {
01234       DPRINT1("MmIsAccessedAndResetAccessPage is called for user space without a process.\n");
01235       ASSERT(FALSE);
01236    }
01237    if (Ke386Pae)
01238    {
01239       PULONGLONG Pt;
01240       ULONGLONG Pte;
01241       ULONGLONG tmpPte;
01242 
01243       Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE);
01244       if (Pt == NULL)
01245       {
01246          ASSERT(FALSE);
01247       }
01248 
01249       do
01250       {
01251          Pte = *Pt;
01252          tmpPte = Pte & ~PA_ACCESSED;
01253       } while (Pte != ExfInterlockedCompareExchange64UL(Pt, &tmpPte, &Pte));
01254 
01255       if (Pte & PA_ACCESSED)
01256       {
01257          MiFlushTlb((PULONG)Pt, Address);
01258          return TRUE;
01259       }
01260       else
01261       {
01262          MmUnmapPageTable((PULONG)Pt);
01263          return FALSE;
01264       }
01265    }
01266    else
01267    {
01268       PULONG Pt;
01269       ULONG Pte;
01270 
01271       Pt = MmGetPageTableForProcess(Process, Address, FALSE);
01272       if (Pt == NULL)
01273       {
01274          ASSERT(FALSE);
01275       }
01276 
01277       do
01278       {
01279          Pte = *Pt;
01280       } while (Pte != InterlockedCompareExchangeUL(Pt, Pte & ~PA_ACCESSED, Pte));
01281 
01282       if (Pte & PA_ACCESSED)
01283       {
01284          MiFlushTlb(Pt, Address);
01285          return TRUE;
01286       }
01287       else
01288       {
01289          MmUnmapPageTable(Pt);
01290          return FALSE;
01291       }
01292    }
01293 }
01294 
01295 VOID
01296 NTAPI
01297 MmSetCleanPage(PEPROCESS Process, PVOID Address)
01298 {
01299    if (Address < MmSystemRangeStart && Process == NULL)
01300    {
01301       DPRINT1("MmSetCleanPage is called for user space without a process.\n");
01302       ASSERT(FALSE);
01303    }
01304    if (Ke386Pae)
01305    {
01306       PULONGLONG Pt;
01307       ULONGLONG Pte;
01308       ULONGLONG tmpPte;
01309 
01310       Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE);
01311 
01312       if (Pt == NULL)
01313       {
01314          ASSERT(FALSE);
01315       }
01316 
01317       do
01318       {
01319          Pte = *Pt;
01320          tmpPte = Pte & ~PA_DIRTY;
01321       } while (Pte != ExfInterlockedCompareExchange64UL(Pt, &tmpPte, &Pte));
01322 
01323       if (Pte & PA_DIRTY)
01324       {
01325          MiFlushTlb((PULONG)Pt, Address);
01326       }
01327       else
01328       {
01329          MmUnmapPageTable((PULONG)Pt);
01330       }
01331    }
01332    else
01333    {
01334       PULONG Pt;
01335       ULONG Pte;
01336 
01337       Pt = MmGetPageTableForProcess(Process, Address, FALSE);
01338 
01339       if (Pt == NULL)
01340       {
01341          ASSERT(FALSE);
01342       }
01343 
01344       do
01345       {
01346          Pte = *Pt;
01347       } while (Pte != InterlockedCompareExchangeUL(Pt, Pte & ~PA_DIRTY, Pte));
01348 
01349       if (Pte & PA_DIRTY)
01350       {
01351          MiFlushTlb(Pt, Address);
01352       }
01353       else
01354       {
01355          MmUnmapPageTable(Pt);
01356       }
01357    }
01358 }
01359 
01360 VOID
01361 NTAPI
01362 MmSetDirtyPage(PEPROCESS Process, PVOID Address)
01363 {
01364    if (Address < MmSystemRangeStart && Process == NULL)
01365    {
01366       DPRINT1("MmSetDirtyPage is called for user space without a process.\n");
01367       ASSERT(FALSE);
01368    }
01369    if (Ke386Pae)
01370    {
01371       PULONGLONG Pt;
01372       ULONGLONG Pte;
01373       ULONGLONG tmpPte;
01374 
01375       Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE);
01376       if (Pt == NULL)
01377       {
01378          ASSERT(FALSE);
01379       }
01380 
01381       do
01382       {
01383          Pte = *Pt;
01384          tmpPte = Pte | PA_DIRTY;
01385       } while (Pte != ExfInterlockedCompareExchange64UL(Pt, &tmpPte, &Pte));
01386       if (!(Pte & PA_DIRTY))
01387       {
01388          MiFlushTlb((PULONG)Pt, Address);
01389       }
01390       else
01391       {
01392          MmUnmapPageTable((PULONG)Pt);
01393       }
01394    }
01395    else
01396    {
01397       PULONG Pt;
01398       ULONG Pte;
01399 
01400       Pt = MmGetPageTableForProcess(Process, Address, FALSE);
01401       if (Pt == NULL)
01402       {
01403          ASSERT(FALSE);
01404       }
01405 
01406       do
01407       {
01408          Pte = *Pt;
01409       } while (Pte != InterlockedCompareExchangeUL(Pt, Pte | PA_DIRTY, Pte));
01410       if (!(Pte & PA_DIRTY))
01411       {
01412          MiFlushTlb(Pt, Address);
01413       }
01414       else
01415       {
01416          MmUnmapPageTable(Pt);
01417       }
01418    }
01419 }
01420 
01421 VOID
01422 NTAPI
01423 MmEnableVirtualMapping(PEPROCESS Process, PVOID Address)
01424 {
01425    if (Ke386Pae)
01426    {
01427       PULONGLONG Pt;
01428       ULONGLONG Pte;
01429       ULONGLONG tmpPte;
01430 
01431       Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE);
01432       if (Pt == NULL)
01433       {
01434          ASSERT(FALSE);
01435       }
01436 
01437       do
01438       {
01439          Pte = *Pt;
01440          tmpPte = Pte | PA_PRESENT;
01441       } while (Pte != ExfInterlockedCompareExchange64UL(Pt, &tmpPte, &Pte));
01442       if (!(Pte & PA_PRESENT))
01443       {
01444          MiFlushTlb((PULONG)Pt, Address);
01445       }
01446       else
01447       {
01448          MmUnmapPageTable((PULONG)Pt);
01449       }
01450    }
01451    else
01452    {
01453       PULONG Pt;
01454       ULONG Pte;
01455 
01456       Pt = MmGetPageTableForProcess(Process, Address, FALSE);
01457       if (Pt == NULL)
01458       {
01459          ASSERT(FALSE);
01460       }
01461 
01462       do
01463       {
01464          Pte = *Pt;
01465       } while (Pte != InterlockedCompareExchangeUL(Pt, Pte | PA_PRESENT, Pte));
01466       if (!(Pte & PA_PRESENT))
01467       {
01468          MiFlushTlb(Pt, Address);
01469       }
01470       else
01471       {
01472          MmUnmapPageTable(Pt);
01473       }
01474    }
01475 }
01476 
01477 BOOLEAN
01478 NTAPI
01479 MmIsPagePresent(PEPROCESS Process, PVOID Address)
01480 {
01481    if (Ke386Pae)
01482    {
01483       return MmGetPageEntryForProcessForPAE(Process, Address) & PA_PRESENT ? TRUE : FALSE;
01484    }
01485    else
01486    {
01487       return MmGetPageEntryForProcess(Process, Address) & PA_PRESENT ? TRUE : FALSE;
01488    }
01489 }
01490 
01491 BOOLEAN
01492 NTAPI
01493 MmIsPageSwapEntry(PEPROCESS Process, PVOID Address)
01494 {
01495    if (Ke386Pae)
01496    {
01497       ULONGLONG Entry;
01498       Entry = MmGetPageEntryForProcessForPAE(Process, Address);
01499       return !(Entry & PA_PRESENT) && Entry != 0 ? TRUE : FALSE;
01500    }
01501    else
01502    {
01503       ULONG Entry;
01504       Entry = MmGetPageEntryForProcess(Process, Address);
01505       return !(Entry & PA_PRESENT) && Entry != 0 ? TRUE : FALSE;
01506    }
01507 }
01508 
01509 NTSTATUS
01510 NTAPI
01511 MmCreateVirtualMappingForKernel(PVOID Address,
01512                                 ULONG flProtect,
01513                                 PPFN_NUMBER Pages,
01514                                 ULONG PageCount)
01515 {
01516    ULONG Attributes;
01517    ULONG i;
01518    PVOID Addr;
01519    ULONG PdeOffset, oldPdeOffset;
01520    BOOLEAN NoExecute = FALSE;
01521 
01522    DPRINT("MmCreateVirtualMappingForKernel(%x, %x, %x, %d)\n",
01523            Address, flProtect, Pages, PageCount);
01524 
01525    if (Address < MmSystemRangeStart)
01526    {
01527       DPRINT1("MmCreateVirtualMappingForKernel is called for user space\n");
01528       ASSERT(FALSE);
01529    }
01530 
01531    Attributes = ProtectToPTE(flProtect);
01532    if (Attributes & 0x80000000)
01533    {
01534       NoExecute = TRUE;
01535    }
01536    Attributes &= 0xfff;
01537    if (Ke386GlobalPagesEnabled)
01538    {
01539       Attributes |= PA_GLOBAL;
01540    }
01541 
01542    Addr = Address;
01543 
01544    if (Ke386Pae)
01545    {
01546       PULONGLONG Pt = NULL;
01547       ULONGLONG Pte;
01548 
01549       oldPdeOffset = PAE_ADDR_TO_PDE_OFFSET(Addr) + 1;
01550       for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE))
01551       {
01552          if (!(Attributes & PA_PRESENT) && Pages[i] != 0)
01553          {
01554             DPRINT1("Setting physical address but not allowing access at address "
01555                     "0x%.8X with attributes %x/%x.\n",
01556                     Addr, Attributes, flProtect);
01557             ASSERT(FALSE);
01558          }
01559 
01560          PdeOffset = PAE_ADDR_TO_PDE_OFFSET(Addr);
01561          if (oldPdeOffset != PdeOffset)
01562          {
01563             Pt = MmGetPageTableForProcessForPAE(NULL, Addr, TRUE);
01564             if (Pt == NULL)
01565             {
01566                ASSERT(FALSE);
01567             }
01568          }
01569          else
01570          {
01571             Pt++;
01572          }
01573          oldPdeOffset = PdeOffset;
01574 
01575          Pte = PFN_TO_PTE(Pages[i]) | Attributes;
01576          if (NoExecute)
01577          {
01578             Pte |= 0x8000000000000000LL;
01579          }
01580          Pte = ExfpInterlockedExchange64UL(Pt, &Pte);
01581          if (Pte != 0LL)
01582          {
01583             ASSERT(FALSE);
01584          }
01585       }
01586    }
01587    else
01588    {
01589       PULONG Pt;
01590       ULONG Pte;
01591 
01592       oldPdeOffset = ADDR_TO_PDE_OFFSET(Addr);
01593       Pt = MmGetPageTableForProcess(NULL, Addr, TRUE);
01594       if (Pt == NULL)
01595       {
01596          ASSERT(FALSE);
01597       }
01598       Pt--;
01599 
01600       for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE))
01601       {
01602          if (!(Attributes & PA_PRESENT) && Pages[i] != 0)
01603          {
01604             DPRINT1("Setting physical address but not allowing access at address "
01605                     "0x%.8X with attributes %x/%x.\n",
01606                     Addr, Attributes, flProtect);
01607             ASSERT(FALSE);
01608          }
01609 
01610          PdeOffset = ADDR_TO_PDE_OFFSET(Addr);
01611          if (oldPdeOffset != PdeOffset)
01612          {
01613             Pt = MmGetPageTableForProcess(NULL, Addr, TRUE);
01614             if (Pt == NULL)
01615             {
01616                ASSERT(FALSE);
01617             }
01618          }
01619          else
01620          {
01621             Pt++;
01622          }
01623          oldPdeOffset = PdeOffset;
01624 
01625          Pte = *Pt;
01626          if (Pte != 0)
01627          {
01628             ASSERT(FALSE);
01629          }
01630          (void)InterlockedExchangeUL(Pt, PFN_TO_PTE(Pages[i]) | Attributes);
01631       }
01632    }
01633 
01634    return(STATUS_SUCCESS);
01635 }
01636 
01637 NTSTATUS
01638 NTAPI
01639 MmCreatePageFileMapping(PEPROCESS Process,
01640                         PVOID Address,
01641                         SWAPENTRY SwapEntry)
01642 {
01643    if (Process == NULL && Address < MmSystemRangeStart)
01644    {
01645       DPRINT1("No process\n");
01646       ASSERT(FALSE);
01647    }
01648    if (Process != NULL && Address >= MmSystemRangeStart)
01649    {
01650       DPRINT1("Setting kernel address with process context\n");
01651       ASSERT(FALSE);
01652    }
01653    if (SwapEntry & (1 << 31))
01654    {
01655       ASSERT(FALSE);
01656    }
01657 
01658    if (Ke386Pae)
01659    {
01660       PULONGLONG Pt;
01661       ULONGLONG Pte;
01662       ULONGLONG tmpPte;
01663 
01664       Pt = MmGetPageTableForProcessForPAE(Process, Address, TRUE);
01665       if (Pt == NULL)
01666       {
01667          ASSERT(FALSE);
01668       }
01669       tmpPte = SwapEntry << 1;
01670       Pte = ExfpInterlockedExchange64UL(Pt, &tmpPte);
01671       if (PAE_PAGE_MASK((Pte)) != 0)
01672       {
01673          MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte)));
01674       }
01675 
01676       if (Pte != 0)
01677       {
01678          MiFlushTlb((PULONG)Pt, Address);
01679       }
01680       else
01681       {
01682          MmUnmapPageTable((PULONG)Pt);
01683       }
01684    }
01685    else
01686    {
01687       PULONG Pt;
01688       ULONG Pte;
01689 
01690       Pt = MmGetPageTableForProcess(Process, Address, TRUE);
01691       if (Pt == NULL)
01692       {
01693          ASSERT(FALSE);
01694       }
01695       Pte = *Pt;
01696       if (PAGE_MASK((Pte)) != 0)
01697       {
01698          MmMarkPageUnmapped(PTE_TO_PFN((Pte)));
01699       }
01700       (void)InterlockedExchangeUL(Pt, SwapEntry << 1);
01701       if (Pte != 0)
01702       {
01703          MiFlushTlb(Pt, Address);
01704       }
01705       else
01706       {
01707          MmUnmapPageTable(Pt);
01708       }
01709    }
01710    if (Process != NULL &&
01711        ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
01712        Address < MmSystemRangeStart)
01713    {
01714      PUSHORT Ptrc;
01715      ULONG Idx;
01716 
01717      Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
01718      Idx = Ke386Pae ? PAE_ADDR_TO_PAGE_TABLE(Address) : ADDR_TO_PAGE_TABLE(Address);
01719      Ptrc[Idx]++;
01720    }
01721    return(STATUS_SUCCESS);
01722 }
01723 
01724 
01725 NTSTATUS
01726 NTAPI
01727 MmCreateVirtualMappingUnsafe(PEPROCESS Process,
01728                              PVOID Address,
01729                              ULONG flProtect,
01730                              PPFN_NUMBER Pages,
01731                              ULONG PageCount)
01732 {
01733    ULONG Attributes;
01734    PVOID Addr;
01735    ULONG i;
01736    ULONG oldPdeOffset, PdeOffset;
01737    BOOLEAN NoExecute = FALSE;
01738 
01739    DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
01740           Process, Address, flProtect, Pages, *Pages, PageCount);
01741 
01742    if (Process == NULL)
01743    {
01744       if (Address < MmSystemRangeStart)
01745       {
01746          DPRINT1("No process\n");
01747          ASSERT(FALSE);
01748       }
01749       if (PageCount > 0x10000 ||
01750           (ULONG_PTR) Address / PAGE_SIZE + PageCount > 0x100000)
01751       {
01752          DPRINT1("Page count to large\n");
01753          ASSERT(FALSE);
01754       }
01755    }
01756    else
01757    {
01758       if (Address >= MmSystemRangeStart)
01759       {
01760          DPRINT1("Setting kernel address with process context\n");
01761          ASSERT(FALSE);
01762       }
01763       if (PageCount > (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE ||
01764           (ULONG_PTR) Address / PAGE_SIZE + PageCount >
01765           (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE)
01766       {
01767          DPRINT1("Page Count to large\n");
01768          ASSERT(FALSE);
01769       }
01770    }
01771 
01772    Attributes = ProtectToPTE(flProtect);
01773    if (Attributes & 0x80000000)
01774    {
01775       NoExecute = TRUE;
01776    }
01777    Attributes &= 0xfff;
01778    if (Address >= MmSystemRangeStart)
01779    {
01780       Attributes &= ~PA_USER;
01781       if (Ke386GlobalPagesEnabled)
01782       {
01783          Attributes |= PA_GLOBAL;
01784       }
01785    }
01786    else
01787    {
01788       Attributes |= PA_USER;
01789    }
01790 
01791    Addr = Address;
01792 
01793    if (Ke386Pae)
01794    {
01795       ULONGLONG Pte, tmpPte;
01796       PULONGLONG Pt = NULL;
01797 
01798       oldPdeOffset = PAE_ADDR_TO_PDE_OFFSET(Addr) + 1;
01799       for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE))
01800       {
01801          if (!(Attributes & PA_PRESENT) && Pages[i] != 0)
01802          {
01803             DPRINT1("Setting physical address but not allowing access at address "
01804                     "0x%.8X with attributes %x/%x.\n",
01805                     Addr, Attributes, flProtect);
01806             ASSERT(FALSE);
01807          }
01808          PdeOffset = PAE_ADDR_TO_PDE_OFFSET(Addr);
01809          if (oldPdeOffset != PdeOffset)
01810          {
01811             MmUnmapPageTable((PULONG)Pt);
01812             Pt = MmGetPageTableForProcessForPAE(Process, Addr, TRUE);
01813             if (Pt == NULL)
01814             {
01815                ASSERT(FALSE);
01816             }
01817          }
01818          else
01819          {
01820             Pt++;
01821          }
01822          oldPdeOffset = PdeOffset;
01823 
01824          MmMarkPageMapped(Pages[i]);
01825          tmpPte = PAE_PFN_TO_PTE(Pages[i]) | Attributes;
01826          if (NoExecute)
01827          {
01828             tmpPte |= 0x8000000000000000LL;
01829          }
01830          Pte = ExfpInterlockedExchange64UL(Pt, &tmpPte);
01831          if (PAE_PAGE_MASK((Pte)) != 0LL && !((Pte) & PA_PRESENT))
01832          {
01833             ASSERT(FALSE);
01834          }
01835          if (PAE_PAGE_MASK((Pte)) != 0LL)
01836          {
01837             MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte)));
01838          }
01839          if (Address < MmSystemRangeStart &&
01840              ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
01841              Attributes & PA_PRESENT)
01842          {
01843             PUSHORT Ptrc;
01844 
01845             Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
01846 
01847             Ptrc[PAE_ADDR_TO_PAGE_TABLE(Addr)]++;
01848          }
01849          if (Pte != 0LL)
01850          {
01851             if (Address > MmSystemRangeStart ||
01852                 (Pt >= (PULONGLONG)PAGETABLE_MAP && Pt < (PULONGLONG)PAGETABLE_MAP + 4*512*512))
01853             {
01854               MiFlushTlb((PULONG)Pt, Address);
01855             }
01856          }
01857       }
01858       if (Addr > Address)
01859       {
01860          MmUnmapPageTable((PULONG)Pt);
01861       }
01862    }
01863    else
01864    {
01865       PULONG Pt = NULL;
01866       ULONG Pte;
01867       oldPdeOffset = ADDR_TO_PDE_OFFSET(Addr) + 1;
01868       for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE))
01869       {
01870          if (!(Attributes & PA_PRESENT) && Pages[i] != 0)
01871          {
01872             DPRINT1("Setting physical address but not allowing access at address "
01873                     "0x%.8X with attributes %x/%x.\n",
01874                     Addr, Attributes, flProtect);
01875             ASSERT(FALSE);
01876          }
01877          PdeOffset = ADDR_TO_PDE_OFFSET(Addr);
01878          if (oldPdeOffset != PdeOffset)
01879          {
01880             MmUnmapPageTable(Pt);
01881             Pt = MmGetPageTableForProcess(Process, Addr, TRUE);
01882             if (Pt == NULL)
01883             {
01884                ASSERT(FALSE);
01885             }
01886          }
01887          else
01888          {
01889             Pt++;
01890          }
01891          oldPdeOffset = PdeOffset;
01892 
01893          Pte = *Pt;
01894          MmMarkPageMapped(Pages[i]);
01895          if (PAGE_MASK((Pte)) != 0 && !((Pte) & PA_PRESENT))
01896          {
01897             ASSERT(FALSE);
01898          }
01899          if (PAGE_MASK((Pte)) != 0)
01900          {
01901             MmMarkPageUnmapped(PTE_TO_PFN((Pte)));
01902          }
01903          (void)InterlockedExchangeUL(Pt, PFN_TO_PTE(Pages[i]) | Attributes);
01904          if (Address < MmSystemRangeStart &&
01905              ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
01906              Attributes & PA_PRESENT)
01907          {
01908             PUSHORT Ptrc;
01909 
01910             Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
01911 
01912             Ptrc[ADDR_TO_PAGE_TABLE(Addr)]++;
01913          }
01914          if (Pte != 0)
01915          {
01916             if (Address > MmSystemRangeStart ||
01917                 (Pt >= (PULONG)PAGETABLE_MAP && Pt < (PULONG)PAGETABLE_MAP + 1024*1024))
01918             {
01919                MiFlushTlb(Pt, Address);
01920             }
01921          }
01922       }
01923       if (Addr > Address)
01924       {
01925          MmUnmapPageTable(Pt);
01926       }
01927    }
01928    return(STATUS_SUCCESS);
01929 }
01930 
01931 NTSTATUS
01932 NTAPI
01933 MmCreateVirtualMapping(PEPROCESS Process,
01934                        PVOID Address,
01935                        ULONG flProtect,
01936                        PPFN_NUMBER Pages,
01937                        ULONG PageCount)
01938 {
01939    ULONG i;
01940 
01941    for (i = 0; i < PageCount; i++)
01942    {
01943       if (!MmIsPageInUse(Pages[i]))
01944       {
01945          DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Pages[i]));
01946          ASSERT(FALSE);
01947       }
01948    }
01949 
01950    return(MmCreateVirtualMappingUnsafe(Process,
01951                                        Address,
01952                                        flProtect,
01953                                        Pages,
01954                                        PageCount));
01955 }
01956 
01957 ULONG
01958 NTAPI
01959 MmGetPageProtect(PEPROCESS Process, PVOID Address)
01960 {
01961    ULONG Entry;
01962    ULONG Protect;
01963    if (Ke386Pae)
01964    {
01965       Entry = MmGetPageEntryForProcessForPAE(Process, Address);
01966    }
01967    else
01968    {
01969       Entry = MmGetPageEntryForProcess(Process, Address);
01970    }
01971 
01972    if (!(Entry & PA_PRESENT))
01973    {
01974       Protect = PAGE_NOACCESS;
01975    }
01976    else
01977    {
01978       if (Entry & PA_READWRITE)
01979       {
01980          Protect = PAGE_READWRITE;
01981       }
01982       else
01983       {
01984          Protect = PAGE_EXECUTE_READ;
01985       }
01986       if (Entry & PA_CD)
01987       {
01988          Protect |= PAGE_NOCACHE;
01989       }
01990       if (Entry & PA_WT)
01991       {
01992          Protect |= PAGE_WRITETHROUGH;
01993       }
01994       if (!(Entry & PA_USER))
01995       {
01996          Protect |= PAGE_SYSTEM;
01997       }
01998 
01999    }
02000    return(Protect);
02001 }
02002 
02003 VOID
02004 NTAPI
02005 MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
02006 {
02007    ULONG Attributes = 0;
02008    BOOLEAN NoExecute = FALSE;
02009 
02010    DPRINT("MmSetPageProtect(Process %x  Address %x  flProtect %x)\n",
02011           Process, Address, flProtect);
02012 
02013    Attributes = ProtectToPTE(flProtect);
02014    if (Attributes & 0x80000000)
02015    {
02016       NoExecute = TRUE;
02017    }
02018    Attributes &= 0xfff;
02019    if (Address >= MmSystemRangeStart)
02020    {
02021       Attributes &= ~PA_USER;
02022       if (Ke386GlobalPagesEnabled)
02023       {
02024          Attributes |= PA_GLOBAL;
02025       }
02026    }
02027    else
02028    {
02029       Attributes |= PA_USER;
02030    }
02031    if (Ke386Pae)
02032    {
02033       PULONGLONG Pt;
02034       ULONGLONG tmpPte, Pte;
02035 
02036       Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE);
02037       if (Pt == NULL)
02038       {
02039          DPRINT1("Address %x\n", Address);
02040          ASSERT(FALSE);
02041       }
02042       do
02043       {
02044         Pte = *Pt;
02045         tmpPte = PAE_PAGE_MASK(Pte) | Attributes | (Pte & (PA_ACCESSED|PA_DIRTY));
02046         if (NoExecute)
02047         {
02048            tmpPte |= 0x8000000000000000LL;
02049         }
02050         else
02051         {
02052            tmpPte &= ~0x8000000000000000LL;
02053         }
02054       } while (Pte != ExfInterlockedCompareExchange64UL(Pt, &tmpPte, &Pte));
02055 
02056       MiFlushTlb((PULONG)Pt, Address);
02057    }
02058    else
02059    {
02060       PULONG Pt;
02061 
02062       Pt = MmGetPageTableForProcess(Process, Address, FALSE);
02063       if (Pt == NULL)
02064       {
02065          ASSERT(FALSE);
02066       }
02067       InterlockedExchange((PLONG)Pt, PAGE_MASK(*Pt) | Attributes | (*Pt & (PA_ACCESSED|PA_DIRTY)));
02068       MiFlushTlb(Pt, Address);
02069    }
02070 }
02071 
02072 /*
02073  * @implemented
02074  */
02075 PHYSICAL_ADDRESS NTAPI
02076 MmGetPhysicalAddress(PVOID vaddr)
02077 /*
02078  * FUNCTION: Returns the physical address corresponding to a virtual address
02079  */
02080 {
02081    PHYSICAL_ADDRESS p;
02082 
02083    DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr);
02084    if (Ke386Pae)
02085    {
02086       ULONGLONG Pte;
02087       Pte = MmGetPageEntryForProcessForPAE(NULL, vaddr);
02088       if (Pte != 0 && Pte & PA_PRESENT)
02089       {
02090          p.QuadPart = PAE_PAGE_MASK(Pte);
02091          p.u.LowPart |= (ULONG_PTR)vaddr & (PAGE_SIZE - 1);
02092       }
02093       else
02094       {
02095          p.QuadPart = 0;
02096       }
02097    }
02098    else
02099    {
02100       ULONG Pte;
02101       Pte = MmGetPageEntryForProcess(NULL, vaddr);
02102       if (Pte != 0 && Pte & PA_PRESENT)
02103       {
02104          p.QuadPart = PAGE_MASK(Pte);
02105          p.u.LowPart |= (ULONG_PTR)vaddr & (PAGE_SIZE - 1);
02106       }
02107       else
02108       {
02109          p.QuadPart = 0;
02110       }
02111    }
02112    return p;
02113 }
02114 
02115 PVOID
02116 NTAPI
02117 MmCreateHyperspaceMapping(PFN_NUMBER Page)
02118 {
02119    PVOID Address;
02120    ULONG i;
02121 
02122    if (Ke386Pae)
02123    {
02124       ULONGLONG Entry;
02125       ULONGLONG ZeroEntry = 0LL;
02126       PULONGLONG Pte;
02127 
02128       Entry = PFN_TO_PTE(Page) | PA_PRESENT | PA_READWRITE;
02129       Pte = PAE_ADDR_TO_PTE(HYPERSPACE) + Page % 1024;
02130 
02131       if (Page & 1024)
02132       {
02133          for (i = Page %1024; i < 1024; i++, Pte++)
02134          {
02135             if (0LL == ExfInterlockedCompareExchange64UL(Pte, &Entry, &ZeroEntry))
02136             {
02137                break;
02138             }
02139          }
02140          if (i >= 1024)
02141          {
02142             Pte = PAE_ADDR_TO_PTE(HYPERSPACE);
02143             for (i = 0; i < Page % 1024; i++, Pte++)
02144             {
02145                if (0LL == ExfInterlockedCompareExchange64UL(Pte, &Entry, &ZeroEntry))
02146                {
02147                   break;
02148                }
02149             }
02150             if (i >= Page % 1024)
02151             {
02152                ASSERT(FALSE);
02153             }
02154          }
02155       }
02156       else
02157       {
02158          for (i = Page %1024; (LONG)i >= 0; i--, Pte--)
02159          {
02160             if (0LL == ExfInterlockedCompareExchange64UL(Pte, &Entry, &ZeroEntry))
02161             {
02162                break;
02163             }
02164          }
02165          if ((LONG)i < 0)
02166          {
02167             Pte = PAE_ADDR_TO_PTE(HYPERSPACE) + 1023;
02168             for (i = 1023; i > Page % 1024; i--, Pte--)
02169             {
02170                if (0LL == ExfInterlockedCompareExchange64UL(Pte, &Entry, &ZeroEntry))
02171                {
02172                   break;
02173                }
02174             }
02175             if (i <= Page % 1024)
02176             {
02177                ASSERT(FALSE);
02178             }
02179          }
02180       }
02181    }
02182    else
02183    {
02184       ULONG Entry;
02185       PULONG Pte;
02186       Entry = PFN_TO_PTE(Page) | PA_PRESENT | PA_READWRITE;
02187       Pte = ADDR_TO_PTE(HYPERSPACE) + Page % 1024;
02188       if (Page & 1024)
02189       {
02190          for (i = Page % 1024; i < 1024; i++, Pte++)
02191          {
02192             if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0))
02193             {
02194                break;
02195             }
02196          }
02197          if (i >= 1024)
02198          {
02199             Pte = ADDR_TO_PTE(HYPERSPACE);
02200             for (i = 0; i < Page % 1024; i++, Pte++)
02201             {
02202                if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0))
02203                {
02204                   break;
02205                }
02206             }
02207             if (i >= Page % 1024)
02208             {
02209                ASSERT(FALSE);
02210             }
02211          }
02212       }
02213       else
02214       {
02215          for (i = Page % 1024; (LONG)i >= 0; i--, Pte--)
02216          {
02217             if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0))
02218             {
02219                break;
02220             }
02221          }
02222          if ((LONG)i < 0)
02223          {
02224             Pte = ADDR_TO_PTE(HYPERSPACE) + 1023;
02225             for (i = 1023; i > Page % 1024; i--, Pte--)
02226             {
02227                if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0))
02228                {
02229                   break;
02230                }
02231             }
02232             if (i <= Page % 1024)
02233             {
02234                ASSERT(FALSE);
02235             }
02236          }
02237       }
02238    }
02239    Address = (PVOID)((ULONG_PTR)HYPERSPACE + i * PAGE_SIZE);
02240    __invlpg(Address);
02241    return Address;
02242 }
02243 
02244 PFN_NUMBER
02245 NTAPI
02246 MmChangeHyperspaceMapping(PVOID Address, PFN_NUMBER NewPage)
02247 {
02248    PFN_NUMBER Pfn;
02249    ASSERT (IS_HYPERSPACE(Address));
02250    if (Ke386Pae)
02251    {
02252       ULONGLONG Entry = PAE_PFN_TO_PTE(NewPage) | PA_PRESENT | PA_READWRITE;
02253       Entry = (ULONG)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PTE(Address), &Entry);
02254       Pfn = PAE_PTE_TO_PFN(Entry);
02255    }
02256    else
02257    {
02258       ULONG Entry;
02259       Entry = InterlockedExchange((PLONG)ADDR_TO_PTE(Address), PFN_TO_PTE(NewPage) | PA_PRESENT | PA_READWRITE);
02260       Pfn = PTE_TO_PFN(Entry);
02261    }
02262    __invlpg(Address);
02263    return Pfn;
02264 }
02265 
02266 PFN_NUMBER
02267 NTAPI
02268 MmDeleteHyperspaceMapping(PVOID Address)
02269 {
02270    PFN_NUMBER Pfn;
02271    ASSERT (IS_HYPERSPACE(Address));
02272    if (Ke386Pae)
02273    {
02274       ULONGLONG Entry = 0LL;
02275       Entry = (ULONG)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PTE(Address), &Entry);
02276       Pfn = PAE_PTE_TO_PFN(Entry);
02277    }
02278    else
02279    {
02280       ULONG Entry;
02281       Entry = InterlockedExchange((PLONG)ADDR_TO_PTE(Address), 0);
02282       Pfn = PTE_TO_PFN(Entry);
02283    }
02284    __invlpg(Address);
02285    return Pfn;
02286 }
02287 
02288 VOID
02289 NTAPI
02290 MmUpdatePageDir(PEPROCESS Process, PVOID Address, ULONG Size)
02291 {
02292    ULONG StartOffset, EndOffset, Offset;
02293 
02294    if (Address < MmSystemRangeStart)
02295    {
02296       ASSERT(FALSE);
02297    }
02298    if (Ke386Pae)
02299    {
02300       PULONGLONG PageDirTable;
02301       PULONGLONG Pde;
02302       ULONGLONG ZeroPde = 0LL;
02303       ULONG i;
02304 
02305       for (i = PAE_ADDR_TO_PDTE_OFFSET(Address); i <= PAE_ADDR_TO_PDTE_OFFSET((PVOID)((ULONG_PTR)Address + Size)); i++)
02306       {
02307          if (i == PAE_ADDR_TO_PDTE_OFFSET(Address))
02308          {
02309             StartOffset = PAE_ADDR_TO_PDE_PAGE_OFFSET(Address);
02310          }
02311          else
02312          {
02313             StartOffset = 0;
02314          }
02315          if (i == PAE_ADDR_TO_PDTE_OFFSET((PVOID)((ULONG_PTR)Address + Size)))
02316          {
02317             EndOffset = PAE_ADDR_TO_PDE_PAGE_OFFSET((PVOID)((ULONG_PTR)Address + Size));
02318          }
02319          else
02320          {
02321             EndOffset = 511;
02322          }
02323 
02324          if (Process != NULL && Process != PsGetCurrentProcess())
02325          {
02326             PageDirTable = MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process->Pcb.DirectoryTableBase.QuadPart));
02327             Pde = (PULONGLONG)MmCreateHyperspaceMapping(PTE_TO_PFN(PageDirTable[i]));
02328             MmDeleteHyperspaceMapping(PageDirTable);
02329          }
02330          else
02331          {
02332             Pde = (PULONGLONG)PAE_PAGEDIRECTORY_MAP + i*512;
02333          }
02334 
02335          for (Offset = StartOffset; Offset <= EndOffset; Offset++)
02336          {
02337             if (i * 512 + Offset < PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP) || i * 512 + Offset >= PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP)+4)
02338             {
02339                (void)ExfInterlockedCompareExchange64UL(&Pde[Offset], &MmGlobalKernelPageDirectoryForPAE[i*512 + Offset], &ZeroPde);
02340             }
02341          }
02342          MmUnmapPageTable((PULONG)Pde);
02343       }
02344    }
02345    else
02346    {
02347       PULONG Pde;
02348       StartOffset = ADDR_TO_PDE_OFFSET(Address);
02349       EndOffset = ADDR_TO_PDE_OFFSET((PVOID)((ULONG_PTR)Address + Size));
02350 
02351       if (Process != NULL && Process != PsGetCurrentProcess())
02352       {
02353          Pde = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase.u.LowPart));
02354       }
02355       else
02356       {
02357          Pde = (PULONG)PAGEDIRECTORY_MAP;
02358       }
02359       for (Offset = StartOffset; Offset <= EndOffset; Offset++)
02360       {
02361          if (Offset != ADDR_TO_PDE_OFFSET(PAGETABLE_MAP))
02362          {
02363             (void)InterlockedCompareExchangeUL(&Pde[Offset], MmGlobalKernelPageDirectory[Offset], 0);
02364          }
02365       }
02366       if (Pde != (PULONG)PAGEDIRECTORY_MAP)
02367       {
02368          MmDeleteHyperspaceMapping(Pde);
02369       }
02370    }
02371 }
02372 
02373 VOID
02374 INIT_FUNCTION
02375 NTAPI
02376 MmInitGlobalKernelPageDirectory(VOID)
02377 {
02378    ULONG i;
02379 
02380    DPRINT("MmInitGlobalKernelPageDirectory()\n");
02381 
02382    if (Ke386Pae)
02383    {
02384       PULONGLONG CurrentPageDirectory = (PULONGLONG)PAE_PAGEDIRECTORY_MAP;
02385       for (i = PAE_ADDR_TO_PDE_OFFSET(MmSystemRangeStart); i < 4 * 512; i++)
02386       {
02387          if (!(i >= PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP) && i < PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP) + 4) &&
02388              !(i >= PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE) && i < PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE) + 2) &&
02389              0LL == MmGlobalKernelPageDirectoryForPAE[i] && 0LL != CurrentPageDirectory[i])
02390          {
02391             (void)ExfpInterlockedExchange64UL(&MmGlobalKernelPageDirectoryForPAE[i], &CurrentPageDirectory[i]);
02392             if (Ke386GlobalPagesEnabled)
02393             {
02394                MmGlobalKernelPageDirectoryForPAE[i] |= PA_GLOBAL;
02395                CurrentPageDirectory[i] |= PA_GLOBAL;
02396             }
02397          }
02398       }
02399    }
02400    else
02401    {
02402       PULONG CurrentPageDirectory = (PULONG)PAGEDIRECTORY_MAP;
02403       for (i = ADDR_TO_PDE_OFFSET(MmSystemRangeStart); i < 1024; i++)
02404       {
02405          if (i != ADDR_TO_PDE_OFFSET(PAGETABLE_MAP) &&
02406              i != ADDR_TO_PDE_OFFSET(HYPERSPACE) &&
02407              0 == MmGlobalKernelPageDirectory[i] && 0 != CurrentPageDirectory[i])
02408          {
02409             MmGlobalKernelPageDirectory[i] = CurrentPageDirectory[i];
02410             if (Ke386GlobalPagesEnabled)
02411             {
02412                MmGlobalKernelPageDirectory[i] |= PA_GLOBAL;
02413                CurrentPageDirectory[i] |= PA_GLOBAL;
02414             }
02415          }
02416       }
02417    }
02418 }
02419 
02420 ULONG
02421 NTAPI
02422 MiGetUserPageDirectoryCount(VOID)
02423 {
02424    return Ke386Pae ? PAE_ADDR_TO_PDE_OFFSET(MmSystemRangeStart) : ADDR_TO_PDE_OFFSET(MmSystemRangeStart);
02425 }
02426 
02427 VOID
02428 INIT_FUNCTION
02429 NTAPI
02430 MiInitPageDirectoryMap(VOID)
02431 {
02432    MEMORY_AREA* kernel_map_desc = NULL;
02433    MEMORY_AREA* hyperspace_desc = NULL;
02434    PHYSICAL_ADDRESS BoundaryAddressMultiple;
02435    PVOID BaseAddress;
02436    NTSTATUS Status;
02437 
02438    DPRINT("MiInitPageDirectoryMap()\n");
02439 
02440    BoundaryAddressMultiple.QuadPart = 0;
02441    BaseAddress = (PVOID)PAGETABLE_MAP;
02442    Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
02443                                MEMORY_AREA_SYSTEM,
02444                                &BaseAddress,
02445                                Ke386Pae ? 0x800000 : 0x400000,
02446                                PAGE_READWRITE,
02447                                &kernel_map_desc,
02448                                TRUE,
02449                                0,
02450                                BoundaryAddressMultiple);
02451    if (!NT_SUCCESS(Status))
02452    {
02453       ASSERT(FALSE);
02454    }
02455    BaseAddress = (PVOID)HYPERSPACE;
02456    Status = MmCreateMemoryArea(MmGetKernelAddressSpace(),
02457                                MEMORY_AREA_SYSTEM,
02458                                &BaseAddress,
02459                                0x400000,
02460                                PAGE_READWRITE,
02461                                &hyperspace_desc,
02462                                TRUE,
02463                                0,
02464                                BoundaryAddressMultiple);
02465    if (!NT_SUCCESS(Status))
02466    {
02467       ASSERT(FALSE);
02468    }
02469 }
02470 
02471 /* EOF */

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