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 
00078 
00079 PULONG
00080 MmGetPageDirectory(VOID)
00081 {
00082    unsigned int page_dir=0;
00083    return((PULONG)page_dir);
00084 }
00085 
00086 static ULONG
00087 ProtectToFlags(ULONG flProtect)
00088 {
00089     return MMU_ALL_RW; // XXX hack
00090 }
00091 
00092 NTSTATUS
00093 NTAPI
00094 MmCopyMmInfo(PEPROCESS Src,
00095              PEPROCESS Dest,
00096              PPHYSICAL_ADDRESS DirectoryTableBase)
00097 {
00098     DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", Src, Dest);
00099 
00100     ASSERT(FALSE);
00101 
00102     return(STATUS_SUCCESS);
00103 }
00104 
00105 BOOLEAN
00106 NTAPI
00107 MmCreateProcessAddressSpace(IN ULONG MinWs,
00108                             IN PEPROCESS Process,
00109                             IN PLARGE_INTEGER DirectoryTableBase)
00110 {
00111     ASSERT(FALSE);
00112     return TRUE;
00113 }
00114 
00115 VOID
00116 NTAPI
00117 MmDeletePageTable(PEPROCESS Process, PVOID Address)
00118 {
00119     PEPROCESS CurrentProcess = PsGetCurrentProcess();
00120 
00121     DPRINT1("DeletePageTable: Process: %x CurrentProcess %x\n",
00122             Process, CurrentProcess);
00123 
00124     if (Process != NULL && Process != CurrentProcess)
00125     {
00126         KeAttachProcess(&Process->Pcb);
00127     }
00128 
00129     if (Process)
00130     {
00131         DPRINT1("Revoking VSID %d\n", (paddr_t)Process->UniqueProcessId);
00132         MmuRevokeVsid((paddr_t)Process->UniqueProcessId, -1);
00133     }
00134     else
00135     {
00136         DPRINT1("No vsid to revoke\n");
00137     }
00138 
00139     if (Process != NULL && Process != CurrentProcess)
00140     {
00141         KeDetachProcess();
00142     }
00143 }
00144 
00145 VOID
00146 NTAPI
00147 MmFreePageTable(PEPROCESS Process, PVOID Address)
00148 {
00149     MmDeletePageTable(Process, Address);
00150 }
00151 
00152 PVOID
00153 NTAPI
00154 MmGetPhysicalAddressProcess(PEPROCESS Process, PVOID Addr)
00155 {
00156     ppc_map_info_t info = { 0 };
00157     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00158     info.addr = (vaddr_t)Addr;
00159     MmuInqPage(&info, 1);
00160     return (PVOID)info.phys;
00161 }
00162 
00163 PFN_NUMBER
00164 NTAPI
00165 MmGetPfnForProcess(PEPROCESS Process,
00166                    PVOID Address)
00167 {
00168     return((PFN_NUMBER)MmGetPhysicalAddressProcess(Process, Address) >> PAGE_SHIFT);
00169 }
00170 
00171 VOID
00172 NTAPI
00173 MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN FreePage,
00174                        BOOLEAN* WasDirty, PPFN_NUMBER Page)
00175 /*
00176  * FUNCTION: Delete a virtual mapping
00177  */
00178 {
00179     ppc_map_info_t info = { 0 };
00180 
00181     DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
00182            Process, Address, FreePage, WasDirty, Page);
00183 
00184     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00185     info.addr = (vaddr_t)Address;
00186     MmuInqPage(&info, 1);
00187 
00188     if (FreePage && info.phys)
00189     {
00190         MmReleasePageMemoryConsumer(MC_NPPOOL, info.phys >> PAGE_SHIFT);
00191     }
00192 
00193     /*
00194      * Return some information to the caller
00195      */
00196     if (WasDirty != NULL)
00197     {
00198         *WasDirty = !!(info.flags & MMU_PAGE_DIRTY);
00199     }
00200     if (Page != NULL)
00201     {
00202         *Page = info.phys >> PAGE_SHIFT;
00203     }
00204 }
00205 
00206 VOID
00207 NTAPI
00208 MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
00209                         SWAPENTRY* SwapEntry)
00210 /*
00211  * FUNCTION: Delete a virtual mapping
00212  */
00213 {
00214     ppc_map_info_t info = { 0 };
00215     /*
00216      * Decrement the reference count for this page table.
00217      */
00218     if (Process != NULL &&
00219         ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
00220         Address < MmSystemRangeStart)
00221     {
00222         PUSHORT Ptrc;
00223 
00224         Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
00225         MmFreePageTable(Process, Address);
00226     }
00227 
00228     /*
00229      * Return some information to the caller
00230      */
00231     MmuInqPage(&info, 1);
00232     *SwapEntry = info.phys;
00233 }
00234 
00235 BOOLEAN
00236 NTAPI
00237 MmIsDirtyPage(PEPROCESS Process, PVOID Address)
00238 {
00239     ppc_map_info_t info = { 0 };
00240     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00241     info.addr = (vaddr_t)Address;
00242     MmuInqPage(&info, 1);
00243     return !!(info.flags & MMU_PAGE_DIRTY);
00244 }
00245 
00246 VOID
00247 NTAPI
00248 MmSetCleanPage(PEPROCESS Process, PVOID Address)
00249 {
00250 }
00251 
00252 VOID
00253 NTAPI
00254 MmSetDirtyPage(PEPROCESS Process, PVOID Address)
00255 {
00256 }
00257 
00258 BOOLEAN
00259 NTAPI
00260 MmIsPagePresent(PEPROCESS Process, PVOID Address)
00261 {
00262     ppc_map_info_t info = { 0 };
00263     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00264     info.addr = (vaddr_t)Address;
00265     MmuInqPage(&info, 1);
00266     return !!info.phys;
00267 }
00268 
00269 ULONGLONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
00270 {
00271     return 0; // XXX arty
00272 }
00273 
00274 BOOLEAN
00275 NTAPI
00276 MmIsPageSwapEntry(PEPROCESS Process, PVOID Address)
00277 {
00278     ULONG Entry;
00279     Entry = MmGetPageEntryForProcess(Process, Address);
00280     return !(Entry & PA_PRESENT) && Entry != 0 ? TRUE : FALSE;
00281 }
00282 
00283 NTSTATUS
00284 NTAPI
00285 MmCreatePageFileMapping(PEPROCESS Process,
00286                         PVOID Address,
00287                         SWAPENTRY SwapEntry)
00288 {
00289     if (Process == NULL && Address < MmSystemRangeStart)
00290     {
00291         DPRINT1("No process\n");
00292         ASSERT(FALSE);
00293     }
00294     if (Process != NULL && Address >= MmSystemRangeStart)
00295     {
00296         DPRINT1("Setting kernel address with process context\n");
00297         ASSERT(FALSE);
00298     }
00299     if (SwapEntry & (1 << 31))
00300     {
00301         ASSERT(FALSE);
00302     }
00303 
00304     // XXX arty
00305 
00306     return(STATUS_SUCCESS);
00307 }
00308 
00309 
00310 NTSTATUS
00311 NTAPI
00312 MmCreateVirtualMappingUnsafe(PEPROCESS Process,
00313                              PVOID Address,
00314                              ULONG flProtect,
00315                              PPFN_NUMBER Pages,
00316                              ULONG PageCount)
00317 {
00318     ULONG Attributes;
00319     PVOID Addr;
00320     ULONG i;
00321     ppc_map_info_t info = { 0 };
00322 
00323     DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
00324            Process, Address, flProtect, Pages, *Pages, PageCount);
00325 
00326     if (Process == NULL)
00327     {
00328         if (Address < MmSystemRangeStart)
00329         {
00330             DPRINT1("No process\n");
00331             ASSERT(FALSE);
00332         }
00333         if (PageCount > 0x10000 ||
00334             (ULONG_PTR) Address / PAGE_SIZE + PageCount > 0x100000)
00335         {
00336             DPRINT1("Page count to large\n");
00337             ASSERT(FALSE);
00338         }
00339     }
00340     else
00341     {
00342         if (Address >= MmSystemRangeStart)
00343         {
00344             DPRINT1("Setting kernel address with process context\n");
00345             ASSERT(FALSE);
00346         }
00347         if (PageCount > (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE ||
00348             (ULONG_PTR) Address / PAGE_SIZE + PageCount >
00349             (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE)
00350         {
00351             DPRINT1("Page Count to large\n");
00352             ASSERT(FALSE);
00353         }
00354     }
00355 
00356     Attributes = ProtectToFlags(flProtect);
00357     Addr = Address;
00358 
00359     for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE))
00360     {
00361         Process = PsGetCurrentProcess();
00362         info.proc = ((Addr < MmSystemRangeStart) && Process) ?
00363             (int)Process->UniqueProcessId : 0;
00364         info.addr = (vaddr_t)Addr;
00365         info.flags = Attributes;
00366         MmuMapPage(&info, 1);
00367         //(void)InterlockedExchangeUL(Pt, PFN_TO_PTE(Pages[i]) | Attributes);
00368         if (Address < MmSystemRangeStart &&
00369             ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
00370             Attributes & PA_PRESENT)
00371         {
00372 #if 0
00373             PUSHORT Ptrc;
00374 
00375             Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
00376 
00377             Ptrc[ADDR_TO_PAGE_TABLE(Addr)]++;
00378 #endif
00379         }
00380     }
00381     return(STATUS_SUCCESS);
00382 }
00383 
00384 NTSTATUS
00385 NTAPI
00386 MmCreateVirtualMapping(PEPROCESS Process,
00387                        PVOID Address,
00388                        ULONG flProtect,
00389                        PPFN_NUMBER Pages,
00390                        ULONG PageCount)
00391 {
00392    ULONG i;
00393 
00394    for (i = 0; i < PageCount; i++)
00395    {
00396       if (!MmIsUsablePage(Pages[i]))
00397       {
00398          DPRINT1("Page at address %x not usable\n", PFN_TO_PTE(Pages[i]));
00399          ASSERT(FALSE);
00400       }
00401    }
00402 
00403    return(MmCreateVirtualMappingUnsafe(Process,
00404                                        Address,
00405                                        flProtect,
00406                                        Pages,
00407                                        PageCount));
00408 }
00409 
00410 ULONG
00411 NTAPI
00412 MmGetPageProtect(PEPROCESS Process, PVOID Address)
00413 {
00414     ULONG Protect = 0;
00415     ppc_map_info_t info = { 0 };
00416 
00417     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00418     info.addr = (vaddr_t)Address;
00419     MmuInqPage(&info, 1);
00420 
00421     if (!info.phys) { return PAGE_NOACCESS; }
00422     if (!(info.flags & MMU_KMASK))
00423     {
00424         Protect |= PAGE_SYSTEM;
00425         if ((info.flags & MMU_KR) && (info.flags & MMU_KW))
00426             Protect = PAGE_READWRITE;
00427         else if (info.flags & MMU_KR)
00428             Protect = PAGE_EXECUTE_READ;
00429     }
00430     else
00431     {
00432         if ((info.flags & MMU_UR) && (info.flags & MMU_UW))
00433             Protect = PAGE_READWRITE;
00434         else
00435             Protect = PAGE_EXECUTE_READ;
00436     }
00437     return(Protect);
00438 }
00439 
00440 VOID
00441 NTAPI
00442 MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
00443 {
00444    //ULONG Attributes = 0;
00445 
00446    DPRINT("MmSetPageProtect(Process %x  Address %x  flProtect %x)\n",
00447           Process, Address, flProtect);
00448 
00449 #if 0
00450    Attributes = ProtectToPTE(flProtect);
00451 
00452    Pt = MmGetPageTableForProcess(Process, Address, FALSE);
00453    if (Pt == NULL)
00454    {
00455        ASSERT(FALSE);
00456    }
00457    InterlockedExchange((PLONG)Pt, PAGE_MASK(*Pt) | Attributes | (*Pt & (PA_ACCESSED|PA_DIRTY)));
00458    MiFlushTlb(Pt, Address);
00459 #endif
00460 }
00461 
00462 PVOID
00463 NTAPI
00464 MmCreateHyperspaceMapping(PFN_NUMBER Page)
00465 {
00466     PVOID Address;
00467     ppc_map_info_t info = { 0 };
00468 
00469     Address = (PVOID)((ULONG_PTR)HYPERSPACE * PAGE_SIZE);
00470     info.proc = 0;
00471     info.addr = (vaddr_t)Address;
00472     info.flags = MMU_KRW;
00473     MmuMapPage(&info, 1);
00474 
00475     return Address;
00476 }
00477 
00478 PFN_NUMBER
00479 NTAPI
00480 MmDeleteHyperspaceMapping(PVOID Address)
00481 {
00482     ppc_map_info_t info = { 0 };
00483     ASSERT (IS_HYPERSPACE(Address));
00484 
00485     info.proc = 0;
00486     info.addr = (vaddr_t)Address;
00487 
00488     MmuUnmapPage(&info, 1);
00489 
00490     return (PFN_NUMBER)info.phys;
00491 }
00492 
00493 VOID
00494 INIT_FUNCTION
00495 NTAPI
00496 MmInitGlobalKernelPageDirectory(VOID)
00497 {
00498 }
00499 
00500 /* Create a simple, primitive mapping at the specified address on a new page */
00501 NTSTATUS MmPPCCreatePrimitiveMapping(ULONG_PTR PageAddr)
00502 {
00503     NTSTATUS result;
00504     ppc_map_info_t info = { 0 };
00505     info.flags = MMU_KRW;
00506     info.addr = (vaddr_t)PageAddr;
00507     result = MmuMapPage(&info, 1) ? STATUS_SUCCESS : STATUS_NO_MEMORY;
00508     return result;
00509 }
00510 
00511 /* Use our primitive allocator */
00512 PFN_NUMBER MmPPCPrimitiveAllocPage()
00513 {
00514     paddr_t Result = MmuGetPage();
00515     DbgPrint("Got Page %x\n", Result);
00516     return Result / PAGE_SIZE;
00517 }
00518 
00519 /* EOF */