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,
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, WasDirty, Page);
00183 
00184     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00185     info.addr = (vaddr_t)Address;
00186     MmuInqPage(&info, 1);
00187 
00188     /*
00189      * Return some information to the caller
00190      */
00191     if (WasDirty != NULL)
00192     {
00193         *WasDirty = !!(info.flags & MMU_PAGE_DIRTY);
00194     }
00195     if (Page != NULL)
00196     {
00197         *Page = info.phys >> PAGE_SHIFT;
00198     }
00199 }
00200 
00201 VOID
00202 NTAPI
00203 MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
00204                         SWAPENTRY* SwapEntry)
00205 /*
00206  * FUNCTION: Delete a virtual mapping
00207  */
00208 {
00209     ppc_map_info_t info = { 0 };
00210     /*
00211      * Decrement the reference count for this page table.
00212      */
00213     if (Process != NULL &&
00214         ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
00215         Address < MmSystemRangeStart)
00216     {
00217         PUSHORT Ptrc;
00218 
00219         Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
00220         MmFreePageTable(Process, Address);
00221     }
00222 
00223     /*
00224      * Return some information to the caller
00225      */
00226     MmuInqPage(&info, 1);
00227     *SwapEntry = info.phys;
00228 }
00229 
00230 BOOLEAN
00231 NTAPI
00232 MmIsDirtyPage(PEPROCESS Process, PVOID Address)
00233 {
00234     ppc_map_info_t info = { 0 };
00235     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00236     info.addr = (vaddr_t)Address;
00237     MmuInqPage(&info, 1);
00238     return !!(info.flags & MMU_PAGE_DIRTY);
00239 }
00240 
00241 VOID
00242 NTAPI
00243 MmSetCleanPage(PEPROCESS Process, PVOID Address)
00244 {
00245 }
00246 
00247 VOID
00248 NTAPI
00249 MmSetDirtyPage(PEPROCESS Process, PVOID Address)
00250 {
00251 }
00252 
00253 BOOLEAN
00254 NTAPI
00255 MmIsPagePresent(PEPROCESS Process, PVOID Address)
00256 {
00257     ppc_map_info_t info = { 0 };
00258     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00259     info.addr = (vaddr_t)Address;
00260     MmuInqPage(&info, 1);
00261     return !!info.phys;
00262 }
00263 
00264 ULONGLONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
00265 {
00266     return 0; // XXX arty
00267 }
00268 
00269 BOOLEAN
00270 NTAPI
00271 MmIsPageSwapEntry(PEPROCESS Process, PVOID Address)
00272 {
00273     ULONG Entry;
00274     Entry = MmGetPageEntryForProcess(Process, Address);
00275     return !(Entry & PA_PRESENT) && Entry != 0 ? TRUE : FALSE;
00276 }
00277 
00278 NTSTATUS
00279 NTAPI
00280 MmCreatePageFileMapping(PEPROCESS Process,
00281                         PVOID Address,
00282                         SWAPENTRY SwapEntry)
00283 {
00284     if (Process == NULL && Address < MmSystemRangeStart)
00285     {
00286         DPRINT1("No process\n");
00287         ASSERT(FALSE);
00288     }
00289     if (Process != NULL && Address >= MmSystemRangeStart)
00290     {
00291         DPRINT1("Setting kernel address with process context\n");
00292         ASSERT(FALSE);
00293     }
00294     if (SwapEntry & (1 << 31))
00295     {
00296         ASSERT(FALSE);
00297     }
00298 
00299     // XXX arty
00300 
00301     return(STATUS_SUCCESS);
00302 }
00303 
00304 
00305 NTSTATUS
00306 NTAPI
00307 MmCreateVirtualMappingUnsafe(PEPROCESS Process,
00308                              PVOID Address,
00309                              ULONG flProtect,
00310                              PPFN_NUMBER Pages,
00311                              ULONG PageCount)
00312 {
00313     ULONG Attributes;
00314     PVOID Addr;
00315     ULONG i;
00316     ppc_map_info_t info = { 0 };
00317 
00318     DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
00319            Process, Address, flProtect, Pages, *Pages, PageCount);
00320 
00321     if (Process == NULL)
00322     {
00323         if (Address < MmSystemRangeStart)
00324         {
00325             DPRINT1("No process\n");
00326             ASSERT(FALSE);
00327         }
00328         if (PageCount > 0x10000 ||
00329             (ULONG_PTR) Address / PAGE_SIZE + PageCount > 0x100000)
00330         {
00331             DPRINT1("Page count to large\n");
00332             ASSERT(FALSE);
00333         }
00334     }
00335     else
00336     {
00337         if (Address >= MmSystemRangeStart)
00338         {
00339             DPRINT1("Setting kernel address with process context\n");
00340             ASSERT(FALSE);
00341         }
00342         if (PageCount > (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE ||
00343             (ULONG_PTR) Address / PAGE_SIZE + PageCount >
00344             (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE)
00345         {
00346             DPRINT1("Page Count to large\n");
00347             ASSERT(FALSE);
00348         }
00349     }
00350 
00351     Attributes = ProtectToFlags(flProtect);
00352     Addr = Address;
00353 
00354     for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE))
00355     {
00356         Process = PsGetCurrentProcess();
00357         info.proc = ((Addr < MmSystemRangeStart) && Process) ?
00358             (int)Process->UniqueProcessId : 0;
00359         info.addr = (vaddr_t)Addr;
00360         info.flags = Attributes;
00361         MmuMapPage(&info, 1);
00362         //(void)InterlockedExchangeUL(Pt, PFN_TO_PTE(Pages[i]) | Attributes);
00363         if (Address < MmSystemRangeStart &&
00364             ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
00365             Attributes & PA_PRESENT)
00366         {
00367 #if 0
00368             PUSHORT Ptrc;
00369 
00370             Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
00371 
00372             Ptrc[ADDR_TO_PAGE_TABLE(Addr)]++;
00373 #endif
00374         }
00375     }
00376     return(STATUS_SUCCESS);
00377 }
00378 
00379 NTSTATUS
00380 NTAPI
00381 MmCreateVirtualMapping(PEPROCESS Process,
00382                        PVOID Address,
00383                        ULONG flProtect,
00384                        PPFN_NUMBER Pages,
00385                        ULONG PageCount)
00386 {
00387    ULONG i;
00388 
00389    for (i = 0; i < PageCount; i++)
00390    {
00391       if (!MmIsUsablePage(Pages[i]))
00392       {
00393          DPRINT1("Page at address %x not usable\n", PFN_TO_PTE(Pages[i]));
00394          ASSERT(FALSE);
00395       }
00396    }
00397 
00398    return(MmCreateVirtualMappingUnsafe(Process,
00399                                        Address,
00400                                        flProtect,
00401                                        Pages,
00402                                        PageCount));
00403 }
00404 
00405 ULONG
00406 NTAPI
00407 MmGetPageProtect(PEPROCESS Process, PVOID Address)
00408 {
00409     ULONG Protect = 0;
00410     ppc_map_info_t info = { 0 };
00411 
00412     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00413     info.addr = (vaddr_t)Address;
00414     MmuInqPage(&info, 1);
00415 
00416     if (!info.phys) { return PAGE_NOACCESS; }
00417     if (!(info.flags & MMU_KMASK))
00418     {
00419         Protect |= PAGE_SYSTEM;
00420         if ((info.flags & MMU_KR) && (info.flags & MMU_KW))
00421             Protect = PAGE_READWRITE;
00422         else if (info.flags & MMU_KR)
00423             Protect = PAGE_EXECUTE_READ;
00424     }
00425     else
00426     {
00427         if ((info.flags & MMU_UR) && (info.flags & MMU_UW))
00428             Protect = PAGE_READWRITE;
00429         else
00430             Protect = PAGE_EXECUTE_READ;
00431     }
00432     return(Protect);
00433 }
00434 
00435 VOID
00436 NTAPI
00437 MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
00438 {
00439    //ULONG Attributes = 0;
00440 
00441    DPRINT("MmSetPageProtect(Process %x  Address %x  flProtect %x)\n",
00442           Process, Address, flProtect);
00443 
00444 #if 0
00445    Attributes = ProtectToPTE(flProtect);
00446 
00447    Pt = MmGetPageTableForProcess(Process, Address, FALSE);
00448    if (Pt == NULL)
00449    {
00450        ASSERT(FALSE);
00451    }
00452    InterlockedExchange((PLONG)Pt, PAGE_MASK(*Pt) | Attributes | (*Pt & (PA_ACCESSED|PA_DIRTY)));
00453    MiFlushTlb(Pt, Address);
00454 #endif
00455 }
00456 
00457 PVOID
00458 NTAPI
00459 MmCreateHyperspaceMapping(PFN_NUMBER Page)
00460 {
00461     PVOID Address;
00462     ppc_map_info_t info = { 0 };
00463 
00464     Address = (PVOID)((ULONG_PTR)HYPERSPACE * PAGE_SIZE);
00465     info.proc = 0;
00466     info.addr = (vaddr_t)Address;
00467     info.flags = MMU_KRW;
00468     MmuMapPage(&info, 1);
00469 
00470     return Address;
00471 }
00472 
00473 PFN_NUMBER
00474 NTAPI
00475 MmDeleteHyperspaceMapping(PVOID Address)
00476 {
00477     ppc_map_info_t info = { 0 };
00478     ASSERT (IS_HYPERSPACE(Address));
00479 
00480     info.proc = 0;
00481     info.addr = (vaddr_t)Address;
00482 
00483     MmuUnmapPage(&info, 1);
00484 
00485     return (PFN_NUMBER)info.phys;
00486 }
00487 
00488 VOID
00489 INIT_FUNCTION
00490 NTAPI
00491 MmInitGlobalKernelPageDirectory(VOID)
00492 {
00493 }
00494 
00495 /* Create a simple, primitive mapping at the specified address on a new page */
00496 NTSTATUS MmPPCCreatePrimitiveMapping(ULONG_PTR PageAddr)
00497 {
00498     NTSTATUS result;
00499     ppc_map_info_t info = { 0 };
00500     info.flags = MMU_KRW;
00501     info.addr = (vaddr_t)PageAddr;
00502     result = MmuMapPage(&info, 1) ? STATUS_SUCCESS : STATUS_NO_MEMORY;
00503     return result;
00504 }
00505 
00506 /* Use our primitive allocator */
00507 PFN_NUMBER MmPPCPrimitiveAllocPage()
00508 {
00509     paddr_t Result = MmuGetPage();
00510     DbgPrint("Got Page %x\n", Result);
00511     return Result / PAGE_SIZE;
00512 }
00513 
00514 /* EOF */