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  * Revised for PowerPC by arty
00009  */
00010 
00011 /* INCLUDES ***************************************************************/
00012 
00013 #include <ntoskrnl.h>
00014 #include <ppcmmu/mmu.h>
00015 //#define NDEBUG
00016 #include <debug.h>
00017 
00018 #if defined (ALLOC_PRAGMA)
00019 #pragma alloc_text(INIT, MmInitGlobalKernelPageDirectory)
00020 #endif
00021 
00022 /* GLOBALS *****************************************************************/
00023 
00024 #define HYPERSPACE_PAGEDIR_PTR  ((PVOID)0xc0000000)
00025 
00026 #define PA_PRESENT (1ll<<63)
00027 #define PA_USER (1ll<<62)
00028 #define PA_ACCESSED 0x200
00029 #define PA_DIRTY 0x100
00030 #define PA_WT 0x20
00031 #define PA_CD 0x10
00032 #define PA_READWRITE 3
00033 
00034 #define HYPERSPACE              (0xc0400000)
00035 #define IS_HYPERSPACE(v)        (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000))
00036 
00037 #define PTE_TO_PFN(X)  ((X) >> PAGE_SHIFT)
00038 #define PFN_TO_PTE(X)  ((X) << PAGE_SHIFT)
00039 
00040 #if defined(__GNUC__)
00041 #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X)))
00042 #else
00043 __inline LARGE_INTEGER PTE_TO_PAGE(ULONG npage)
00044 {
00045    LARGE_INTEGER dummy;
00046    dummy.QuadPart = (LONGLONG)(PAGE_MASK(npage));
00047    return dummy;
00048 }
00049 #endif
00050 
00051 /* FUNCTIONS ***************************************************************/
00052 
00053 VOID
00054 NTAPI
00055 MiFlushTlbIpiRoutine(PVOID Address)
00056 {
00057    if (Address == (PVOID)0xffffffff)
00058    {
00059       __asm__("tlbsync");
00060    }
00061    else if (Address == (PVOID)0xfffffffe)
00062    {
00063       __asm__("tlbsync");
00064    }
00065    else
00066    {
00067       __asm__("tlbi %0" : "=r" (Address));
00068    }
00069 }
00070 
00071 VOID
00072 MiFlushTlb(PULONG Pt, PVOID Address)
00073 {
00074     __asm__("tlbi %0" : "=r" (Address));
00075 }
00076 
00077 static ULONG
00078 ProtectToFlags(ULONG flProtect)
00079 {
00080     return MMU_ALL_RW; // XXX hack
00081 }
00082 
00083 NTSTATUS
00084 NTAPI
00085 MmCopyMmInfo(PEPROCESS Src,
00086              PEPROCESS Dest,
00087              PPHYSICAL_ADDRESS DirectoryTableBase)
00088 {
00089     DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", Src, Dest);
00090 
00091     ASSERT(FALSE);
00092 
00093     return(STATUS_SUCCESS);
00094 }
00095 
00096 BOOLEAN
00097 NTAPI
00098 MmCreateProcessAddressSpace(IN ULONG MinWs,
00099                             IN PEPROCESS Process,
00100                             IN PLARGE_INTEGER DirectoryTableBase)
00101 {
00102     ASSERT(FALSE);
00103     return TRUE;
00104 }
00105 
00106 VOID
00107 NTAPI
00108 MmDeletePageTable(PEPROCESS Process, PVOID Address)
00109 {
00110     PEPROCESS CurrentProcess = PsGetCurrentProcess();
00111 
00112     DPRINT1("DeletePageTable: Process: %x CurrentProcess %x\n",
00113             Process, CurrentProcess);
00114 
00115     if (Process != NULL && Process != CurrentProcess)
00116     {
00117         KeAttachProcess(&Process->Pcb);
00118     }
00119 
00120     if (Process)
00121     {
00122         DPRINT1("Revoking VSID %d\n", (paddr_t)Process->UniqueProcessId);
00123         MmuRevokeVsid((paddr_t)Process->UniqueProcessId, -1);
00124     }
00125     else
00126     {
00127         DPRINT1("No vsid to revoke\n");
00128     }
00129 
00130     if (Process != NULL && Process != CurrentProcess)
00131     {
00132         KeDetachProcess();
00133     }
00134 }
00135 
00136 VOID
00137 NTAPI
00138 MmFreePageTable(PEPROCESS Process, PVOID Address)
00139 {
00140     MmDeletePageTable(Process, Address);
00141 }
00142 
00143 PVOID
00144 NTAPI
00145 MmGetPhysicalAddressProcess(PEPROCESS Process, PVOID Addr)
00146 {
00147     ppc_map_info_t info = { 0 };
00148     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00149     info.addr = (vaddr_t)Addr;
00150     MmuInqPage(&info, 1);
00151     return (PVOID)info.phys;
00152 }
00153 
00154 PFN_NUMBER
00155 NTAPI
00156 MmGetPfnForProcess(PEPROCESS Process,
00157                    PVOID Address)
00158 {
00159     return((PFN_NUMBER)MmGetPhysicalAddressProcess(Process, Address) >> PAGE_SHIFT);
00160 }
00161 
00162 VOID
00163 NTAPI
00164 MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address,
00165                        BOOLEAN* WasDirty, PPFN_NUMBER Page)
00166 /*
00167  * FUNCTION: Delete a virtual mapping
00168  */
00169 {
00170     ppc_map_info_t info = { 0 };
00171 
00172     DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
00173            Process, Address, WasDirty, Page);
00174 
00175     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00176     info.addr = (vaddr_t)Address;
00177     MmuInqPage(&info, 1);
00178 
00179     /*
00180      * Return some information to the caller
00181      */
00182     if (WasDirty != NULL)
00183     {
00184         *WasDirty = !!(info.flags & MMU_PAGE_DIRTY);
00185     }
00186     if (Page != NULL)
00187     {
00188         *Page = info.phys >> PAGE_SHIFT;
00189     }
00190 }
00191 
00192 VOID
00193 NTAPI
00194 MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
00195                         SWAPENTRY* SwapEntry)
00196 /*
00197  * FUNCTION: Delete a virtual mapping
00198  */
00199 {
00200     ppc_map_info_t info = { 0 };
00201     /*
00202      * Decrement the reference count for this page table.
00203      */
00204     if (Process != NULL &&
00205         ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
00206         Address < MmSystemRangeStart)
00207     {
00208         PUSHORT Ptrc;
00209 
00210         Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
00211         MmFreePageTable(Process, Address);
00212     }
00213 
00214     /*
00215      * Return some information to the caller
00216      */
00217     MmuInqPage(&info, 1);
00218     *SwapEntry = info.phys;
00219 }
00220 
00221 BOOLEAN
00222 NTAPI
00223 MmIsDirtyPage(PEPROCESS Process, PVOID Address)
00224 {
00225     ppc_map_info_t info = { 0 };
00226     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00227     info.addr = (vaddr_t)Address;
00228     MmuInqPage(&info, 1);
00229     return !!(info.flags & MMU_PAGE_DIRTY);
00230 }
00231 
00232 VOID
00233 NTAPI
00234 MmSetCleanPage(PEPROCESS Process, PVOID Address)
00235 {
00236 }
00237 
00238 VOID
00239 NTAPI
00240 MmSetDirtyPage(PEPROCESS Process, PVOID Address)
00241 {
00242 }
00243 
00244 BOOLEAN
00245 NTAPI
00246 MmIsPagePresent(PEPROCESS Process, PVOID Address)
00247 {
00248     ppc_map_info_t info = { 0 };
00249     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00250     info.addr = (vaddr_t)Address;
00251     MmuInqPage(&info, 1);
00252     return !!info.phys;
00253 }
00254 
00255 ULONGLONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
00256 {
00257     return 0; // XXX arty
00258 }
00259 
00260 BOOLEAN
00261 NTAPI
00262 MmIsPageSwapEntry(PEPROCESS Process, PVOID Address)
00263 {
00264     ULONG Entry;
00265     Entry = MmGetPageEntryForProcess(Process, Address);
00266     return !(Entry & PA_PRESENT) && Entry != 0 ? TRUE : FALSE;
00267 }
00268 
00269 NTSTATUS
00270 NTAPI
00271 MmCreatePageFileMapping(PEPROCESS Process,
00272                         PVOID Address,
00273                         SWAPENTRY SwapEntry)
00274 {
00275     if (Process == NULL && Address < MmSystemRangeStart)
00276     {
00277         DPRINT1("No process\n");
00278         ASSERT(FALSE);
00279     }
00280     if (Process != NULL && Address >= MmSystemRangeStart)
00281     {
00282         DPRINT1("Setting kernel address with process context\n");
00283         ASSERT(FALSE);
00284     }
00285     if (SwapEntry & (1 << 31))
00286     {
00287         ASSERT(FALSE);
00288     }
00289 
00290     // XXX arty
00291 
00292     return(STATUS_SUCCESS);
00293 }
00294 
00295 
00296 NTSTATUS
00297 NTAPI
00298 MmCreateVirtualMappingUnsafe(PEPROCESS Process,
00299                              PVOID Address,
00300                              ULONG flProtect,
00301                              PPFN_NUMBER Pages,
00302                              ULONG PageCount)
00303 {
00304     ULONG Attributes;
00305     PVOID Addr;
00306     ULONG i;
00307     ppc_map_info_t info = { 0 };
00308 
00309     DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
00310            Process, Address, flProtect, Pages, *Pages, PageCount);
00311 
00312     if (Process == NULL)
00313     {
00314         if (Address < MmSystemRangeStart)
00315         {
00316             DPRINT1("No process\n");
00317             ASSERT(FALSE);
00318         }
00319         if (PageCount > 0x10000 ||
00320             (ULONG_PTR) Address / PAGE_SIZE + PageCount > 0x100000)
00321         {
00322             DPRINT1("Page count to large\n");
00323             ASSERT(FALSE);
00324         }
00325     }
00326     else
00327     {
00328         if (Address >= MmSystemRangeStart)
00329         {
00330             DPRINT1("Setting kernel address with process context\n");
00331             ASSERT(FALSE);
00332         }
00333         if (PageCount > (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE ||
00334             (ULONG_PTR) Address / PAGE_SIZE + PageCount >
00335             (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE)
00336         {
00337             DPRINT1("Page Count to large\n");
00338             ASSERT(FALSE);
00339         }
00340     }
00341 
00342     Attributes = ProtectToFlags(flProtect);
00343     Addr = Address;
00344 
00345     for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE))
00346     {
00347         Process = PsGetCurrentProcess();
00348         info.proc = ((Addr < MmSystemRangeStart) && Process) ?
00349             (int)Process->UniqueProcessId : 0;
00350         info.addr = (vaddr_t)Addr;
00351         info.flags = Attributes;
00352         MmuMapPage(&info, 1);
00353         //(void)InterlockedExchangeUL(Pt, PFN_TO_PTE(Pages[i]) | Attributes);
00354         if (Address < MmSystemRangeStart &&
00355             ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
00356             Attributes & PA_PRESENT)
00357         {
00358 #if 0
00359             PUSHORT Ptrc;
00360 
00361             Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
00362 
00363             Ptrc[ADDR_TO_PAGE_TABLE(Addr)]++;
00364 #endif
00365         }
00366     }
00367     return(STATUS_SUCCESS);
00368 }
00369 
00370 NTSTATUS
00371 NTAPI
00372 MmCreateVirtualMapping(PEPROCESS Process,
00373                        PVOID Address,
00374                        ULONG flProtect,
00375                        PPFN_NUMBER Pages,
00376                        ULONG PageCount)
00377 {
00378    ULONG i;
00379 
00380    for (i = 0; i < PageCount; i++)
00381    {
00382       if (!MmIsUsablePage(Pages[i]))
00383       {
00384          DPRINT1("Page at address %x not usable\n", PFN_TO_PTE(Pages[i]));
00385          ASSERT(FALSE);
00386       }
00387    }
00388 
00389    return(MmCreateVirtualMappingUnsafe(Process,
00390                                        Address,
00391                                        flProtect,
00392                                        Pages,
00393                                        PageCount));
00394 }
00395 
00396 ULONG
00397 NTAPI
00398 MmGetPageProtect(PEPROCESS Process, PVOID Address)
00399 {
00400     ULONG Protect = 0;
00401     ppc_map_info_t info = { 0 };
00402 
00403     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00404     info.addr = (vaddr_t)Address;
00405     MmuInqPage(&info, 1);
00406 
00407     if (!info.phys) { return PAGE_NOACCESS; }
00408     if (!(info.flags & MMU_KMASK))
00409     {
00410         Protect |= PAGE_SYSTEM;
00411         if ((info.flags & MMU_KR) && (info.flags & MMU_KW))
00412             Protect = PAGE_READWRITE;
00413         else if (info.flags & MMU_KR)
00414             Protect = PAGE_EXECUTE_READ;
00415     }
00416     else
00417     {
00418         if ((info.flags & MMU_UR) && (info.flags & MMU_UW))
00419             Protect = PAGE_READWRITE;
00420         else
00421             Protect = PAGE_EXECUTE_READ;
00422     }
00423     return(Protect);
00424 }
00425 
00426 VOID
00427 NTAPI
00428 MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
00429 {
00430    //ULONG Attributes = 0;
00431 
00432    DPRINT("MmSetPageProtect(Process %x  Address %x  flProtect %x)\n",
00433           Process, Address, flProtect);
00434 
00435 #if 0
00436    Attributes = ProtectToPTE(flProtect);
00437 
00438    Pt = MmGetPageTableForProcess(Process, Address, FALSE);
00439    if (Pt == NULL)
00440    {
00441        ASSERT(FALSE);
00442    }
00443    InterlockedExchange((PLONG)Pt, PAGE_MASK(*Pt) | Attributes | (*Pt & (PA_ACCESSED|PA_DIRTY)));
00444    MiFlushTlb(Pt, Address);
00445 #endif
00446 }
00447 
00448 VOID
00449 INIT_FUNCTION
00450 NTAPI
00451 MmInitGlobalKernelPageDirectory(VOID)
00452 {
00453 }
00454 
00455 /* Create a simple, primitive mapping at the specified address on a new page */
00456 NTSTATUS MmPPCCreatePrimitiveMapping(ULONG_PTR PageAddr)
00457 {
00458     NTSTATUS result;
00459     ppc_map_info_t info = { 0 };
00460     info.flags = MMU_KRW;
00461     info.addr = (vaddr_t)PageAddr;
00462     result = MmuMapPage(&info, 1) ? STATUS_SUCCESS : STATUS_NO_MEMORY;
00463     return result;
00464 }
00465 
00466 /* Use our primitive allocator */
00467 PFN_NUMBER MmPPCPrimitiveAllocPage()
00468 {
00469     paddr_t Result = MmuGetPage();
00470     DbgPrint("Got Page %x\n", Result);
00471     return Result / PAGE_SIZE;
00472 }
00473 
00474 /* EOF */