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 #pragma alloc_text(INIT, MiInitPageDirectoryMap)
00021 #endif
00022 
00023 /* GLOBALS *****************************************************************/
00024 
00025 #define HYPERSPACE_PAGEDIR_PTR  ((PVOID)0xc0000000)
00026 
00027 #define PA_PRESENT (1ll<<63)
00028 #define PA_USER (1ll<<62)
00029 #define PA_ACCESSED 0x200
00030 #define PA_DIRTY 0x100
00031 #define PA_WT 0x20
00032 #define PA_CD 0x10
00033 #define PA_READWRITE 3
00034 
00035 #define HYPERSPACE              (0xc0400000)
00036 #define IS_HYPERSPACE(v)        (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000))
00037 
00038 #define PTE_TO_PFN(X)  ((X) >> PAGE_SHIFT)
00039 #define PFN_TO_PTE(X)  ((X) << PAGE_SHIFT)
00040 
00041 #if defined(__GNUC__)
00042 #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X)))
00043 #else
00044 __inline LARGE_INTEGER PTE_TO_PAGE(ULONG npage)
00045 {
00046    LARGE_INTEGER dummy;
00047    dummy.QuadPart = (LONGLONG)(PAGE_MASK(npage));
00048    return dummy;
00049 }
00050 #endif
00051 
00052 /* FUNCTIONS ***************************************************************/
00053 
00054 VOID
00055 NTAPI
00056 MiFlushTlbIpiRoutine(PVOID Address)
00057 {
00058    if (Address == (PVOID)0xffffffff)
00059    {
00060       __asm__("tlbsync");
00061    }
00062    else if (Address == (PVOID)0xfffffffe)
00063    {
00064       __asm__("tlbsync");
00065    }
00066    else
00067    {
00068       __asm__("tlbi %0" : "=r" (Address));
00069    }
00070 }
00071 
00072 VOID
00073 MiFlushTlb(PULONG Pt, PVOID Address)
00074 {
00075     __asm__("tlbi %0" : "=r" (Address));
00076 }
00077 
00078 
00079 
00080 PULONG
00081 MmGetPageDirectory(VOID)
00082 {
00083    unsigned int page_dir=0;
00084    return((PULONG)page_dir);
00085 }
00086 
00087 static ULONG
00088 ProtectToFlags(ULONG flProtect)
00089 {
00090     return MMU_ALL_RW; // XXX hack
00091 }
00092 
00093 NTSTATUS
00094 NTAPI
00095 MmCopyMmInfo(PEPROCESS Src,
00096              PEPROCESS Dest,
00097              PPHYSICAL_ADDRESS DirectoryTableBase)
00098 {
00099     DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", Src, Dest);
00100 
00101     ASSERT(FALSE);
00102 
00103     return(STATUS_SUCCESS);
00104 }
00105 
00106 NTSTATUS
00107 NTAPI
00108 MmInitializeHandBuiltProcess(IN PEPROCESS Process,
00109                              IN PLARGE_INTEGER DirectoryTableBase)
00110 {
00111     /* Share the directory base with the idle process */
00112     *DirectoryTableBase = PsGetCurrentProcess()->Pcb.DirectoryTableBase;
00113 
00114     /* Initialize the Addresss Space */
00115     MmInitializeAddressSpace(Process, (PMADDRESS_SPACE)&Process->VadRoot);
00116 
00117     /* The process now has an address space */
00118     Process->HasAddressSpace = TRUE;
00119     return STATUS_SUCCESS;
00120 }
00121 
00122 BOOLEAN
00123 NTAPI
00124 MmCreateProcessAddressSpace(IN ULONG MinWs,
00125                             IN PEPROCESS Process,
00126                             IN PLARGE_INTEGER DirectoryTableBase)
00127 {
00128     ASSERT(FALSE);
00129     return TRUE;
00130 }
00131 
00132 VOID
00133 NTAPI
00134 MmDeletePageTable(PEPROCESS Process, PVOID Address)
00135 {
00136     PEPROCESS CurrentProcess = PsGetCurrentProcess();
00137 
00138     DPRINT1("DeletePageTable: Process: %x CurrentProcess %x\n",
00139             Process, CurrentProcess);
00140 
00141     if (Process != NULL && Process != CurrentProcess)
00142     {
00143         KeAttachProcess(&Process->Pcb);
00144     }
00145 
00146     if (Process)
00147     {
00148         DPRINT1("Revoking VSID %d\n", (paddr_t)Process->UniqueProcessId);
00149         MmuRevokeVsid((paddr_t)Process->UniqueProcessId, -1);
00150     }
00151     else
00152     {
00153         DPRINT1("No vsid to revoke\n");
00154     }
00155 
00156     if (Process != NULL && Process != CurrentProcess)
00157     {
00158         KeDetachProcess();
00159     }
00160 }
00161 
00162 VOID
00163 NTAPI
00164 MmFreePageTable(PEPROCESS Process, PVOID Address)
00165 {
00166     MmDeletePageTable(Process, Address);
00167 }
00168 
00169 PVOID
00170 NTAPI
00171 MmGetPhysicalAddressProcess(PEPROCESS Process, PVOID Addr)
00172 {
00173     ppc_map_info_t info = { 0 };
00174     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00175     info.addr = (vaddr_t)Addr;
00176     MmuInqPage(&info, 1);
00177     return (PVOID)info.phys;
00178 }
00179 
00180 /*
00181  * @implemented
00182  */
00183 PHYSICAL_ADDRESS NTAPI
00184 MmGetPhysicalAddress(PVOID vaddr)
00185 /*
00186  * FUNCTION: Returns the physical address corresponding to a virtual address
00187  */
00188 {
00189     PHYSICAL_ADDRESS Addr;
00190     Addr.QuadPart = (ULONG)MmGetPhysicalAddressProcess(PsGetCurrentProcess()->UniqueProcessId, vaddr);
00191     return Addr;
00192 }
00193 
00194 PFN_NUMBER
00195 NTAPI
00196 MmGetPfnForProcess(PEPROCESS Process,
00197                    PVOID Address)
00198 {
00199     return((PFN_NUMBER)MmGetPhysicalAddressProcess(Process, Address) >> PAGE_SHIFT);
00200 }
00201 
00202 VOID
00203 NTAPI
00204 MmDisableVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN* WasDirty, PPFN_NUMBER Page)
00205 /*
00206  * FUNCTION: Delete a virtual mapping
00207  */
00208 {
00209     ppc_map_info_t info = { 0 };
00210     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00211     info.addr = (vaddr_t)Address;
00212     MmuUnmapPage(&info, 1);
00213 }
00214 
00215 VOID
00216 NTAPI
00217 MmRawDeleteVirtualMapping(PVOID Address)
00218 {
00219 }
00220 
00221 VOID
00222 NTAPI
00223 MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN FreePage,
00224                        BOOLEAN* WasDirty, PPFN_NUMBER Page)
00225 /*
00226  * FUNCTION: Delete a virtual mapping
00227  */
00228 {
00229     ppc_map_info_t info = { 0 };
00230 
00231     DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n",
00232            Process, Address, FreePage, WasDirty, Page);
00233 
00234     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00235     info.addr = (vaddr_t)Address;
00236     MmuInqPage(&info, 1);
00237 
00238     if (FreePage && info.phys)
00239     {
00240         MmReleasePageMemoryConsumer(MC_NPPOOL, info.phys >> PAGE_SHIFT);
00241     }
00242 
00243     /*
00244      * Return some information to the caller
00245      */
00246     if (WasDirty != NULL)
00247     {
00248         *WasDirty = !!(info.flags & MMU_PAGE_DIRTY);
00249     }
00250     if (Page != NULL)
00251     {
00252         *Page = info.phys >> PAGE_SHIFT;
00253     }
00254 }
00255 
00256 VOID
00257 NTAPI
00258 MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
00259                         SWAPENTRY* SwapEntry)
00260 /*
00261  * FUNCTION: Delete a virtual mapping
00262  */
00263 {
00264     ppc_map_info_t info = { 0 };
00265     /*
00266      * Decrement the reference count for this page table.
00267      */
00268     if (Process != NULL &&
00269         ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
00270         Address < MmSystemRangeStart)
00271     {
00272         PUSHORT Ptrc;
00273 
00274         Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
00275         MmFreePageTable(Process, Address);
00276     }
00277 
00278     /*
00279      * Return some information to the caller
00280      */
00281     MmuInqPage(&info, 1);
00282     *SwapEntry = info.phys;
00283 }
00284 
00285 BOOLEAN
00286 NTAPI
00287 MmIsDirtyPage(PEPROCESS Process, PVOID Address)
00288 {
00289     ppc_map_info_t info = { 0 };
00290     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00291     info.addr = (vaddr_t)Address;
00292     MmuInqPage(&info, 1);
00293     return !!(info.flags & MMU_PAGE_DIRTY);
00294 }
00295 
00296 BOOLEAN
00297 NTAPI
00298 MmIsAccessedAndResetAccessPage(PEPROCESS Process, PVOID Address)
00299 {
00300     ppc_map_info_t info = { 0 };
00301 
00302     if (Address < MmSystemRangeStart && Process == NULL)
00303     {
00304         DPRINT1("MmIsAccessedAndResetAccessPage is called for user space without a process.\n");
00305         ASSERT(FALSE);
00306     }
00307 
00308     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00309     info.addr = (vaddr_t)Address;
00310     MmuInqPage(&info, 1);
00311     return !!(info.flags /*& MMU_PAGE_ACCESS*/);
00312 }
00313 
00314 VOID
00315 NTAPI
00316 MmSetCleanPage(PEPROCESS Process, PVOID Address)
00317 {
00318 }
00319 
00320 VOID
00321 NTAPI
00322 MmSetDirtyPage(PEPROCESS Process, PVOID Address)
00323 {
00324 }
00325 
00326 VOID
00327 NTAPI
00328 MmEnableVirtualMapping(PEPROCESS Process, PVOID Address)
00329 {
00330 }
00331 
00332 BOOLEAN
00333 NTAPI
00334 MmIsPagePresent(PEPROCESS Process, PVOID Address)
00335 {
00336     ppc_map_info_t info = { 0 };
00337     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00338     info.addr = (vaddr_t)Address;
00339     MmuInqPage(&info, 1);
00340     return !!info.phys;
00341 }
00342 
00343 ULONGLONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address)
00344 {
00345     return 0; // XXX arty
00346 }
00347 
00348 BOOLEAN
00349 NTAPI
00350 MmIsPageSwapEntry(PEPROCESS Process, PVOID Address)
00351 {
00352     ULONG Entry;
00353     Entry = MmGetPageEntryForProcess(Process, Address);
00354     return !(Entry & PA_PRESENT) && Entry != 0 ? TRUE : FALSE;
00355 }
00356 
00357 NTSTATUS
00358 NTAPI
00359 MmCreateVirtualMappingForKernel(PVOID Address,
00360                                 ULONG flProtect,
00361                                 PPFN_NUMBER Pages,
00362                                 ULONG PageCount)
00363 {
00364     ULONG i;
00365     PVOID Addr;
00366 
00367     DPRINT("MmCreateVirtualMappingForKernel(%x, %x, %x, %d)\n",
00368            Address, flProtect, Pages, PageCount);
00369 
00370     if (Address < MmSystemRangeStart)
00371     {
00372         DPRINT1("MmCreateVirtualMappingForKernel is called for user space\n");
00373         ASSERT(FALSE);
00374     }
00375 
00376     Addr = Address;
00377 
00378     for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE))
00379     {
00380 #if 0
00381         if (!(Attributes & PA_PRESENT) && Pages[i] != 0)
00382         {
00383             DPRINT1("Setting physical address but not allowing access at address "
00384                     "0x%.8X with attributes %x/%x.\n",
00385                     Addr, Attributes, flProtect);
00386             ASSERT(FALSE);
00387         }
00388         (void)InterlockedExchangeUL(Pt, PFN_TO_PTE(Pages[i]) | Attributes);
00389 #endif
00390     }
00391 
00392     return(STATUS_SUCCESS);
00393 }
00394 
00395 NTSTATUS
00396 NTAPI
00397 MmCreatePageFileMapping(PEPROCESS Process,
00398                         PVOID Address,
00399                         SWAPENTRY SwapEntry)
00400 {
00401     if (Process == NULL && Address < MmSystemRangeStart)
00402     {
00403         DPRINT1("No process\n");
00404         ASSERT(FALSE);
00405     }
00406     if (Process != NULL && Address >= MmSystemRangeStart)
00407     {
00408         DPRINT1("Setting kernel address with process context\n");
00409         ASSERT(FALSE);
00410     }
00411     if (SwapEntry & (1 << 31))
00412     {
00413         ASSERT(FALSE);
00414     }
00415 
00416     // XXX arty
00417 
00418     return(STATUS_SUCCESS);
00419 }
00420 
00421 
00422 NTSTATUS
00423 NTAPI
00424 MmCreateVirtualMappingUnsafe(PEPROCESS Process,
00425                              PVOID Address,
00426                              ULONG flProtect,
00427                              PPFN_NUMBER Pages,
00428                              ULONG PageCount)
00429 {
00430     ULONG Attributes;
00431     PVOID Addr;
00432     ULONG i;
00433     ppc_map_info_t info = { 0 };
00434 
00435     DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n",
00436            Process, Address, flProtect, Pages, *Pages, PageCount);
00437 
00438     if (Process == NULL)
00439     {
00440         if (Address < MmSystemRangeStart)
00441         {
00442             DPRINT1("No process\n");
00443             ASSERT(FALSE);
00444         }
00445         if (PageCount > 0x10000 ||
00446             (ULONG_PTR) Address / PAGE_SIZE + PageCount > 0x100000)
00447         {
00448             DPRINT1("Page count to large\n");
00449             ASSERT(FALSE);
00450         }
00451     }
00452     else
00453     {
00454         if (Address >= MmSystemRangeStart)
00455         {
00456             DPRINT1("Setting kernel address with process context\n");
00457             ASSERT(FALSE);
00458         }
00459         if (PageCount > (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE ||
00460             (ULONG_PTR) Address / PAGE_SIZE + PageCount >
00461             (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE)
00462         {
00463             DPRINT1("Page Count to large\n");
00464             ASSERT(FALSE);
00465         }
00466     }
00467 
00468     Attributes = ProtectToFlags(flProtect);
00469     Addr = Address;
00470 
00471     for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE))
00472     {
00473         Process = PsGetCurrentProcess();
00474         info.proc = ((Addr < MmSystemRangeStart) && Process) ?
00475             (int)Process->UniqueProcessId : 0;
00476         info.addr = (vaddr_t)Addr;
00477         info.flags = Attributes;
00478         MmuMapPage(&info, 1);
00479         //(void)InterlockedExchangeUL(Pt, PFN_TO_PTE(Pages[i]) | Attributes);
00480         if (Address < MmSystemRangeStart &&
00481             ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL &&
00482             Attributes & PA_PRESENT)
00483         {
00484 #if 0
00485             PUSHORT Ptrc;
00486 
00487             Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable;
00488 
00489             Ptrc[ADDR_TO_PAGE_TABLE(Addr)]++;
00490 #endif
00491         }
00492     }
00493     return(STATUS_SUCCESS);
00494 }
00495 
00496 NTSTATUS
00497 NTAPI
00498 MmCreateVirtualMapping(PEPROCESS Process,
00499                        PVOID Address,
00500                        ULONG flProtect,
00501                        PPFN_NUMBER Pages,
00502                        ULONG PageCount)
00503 {
00504    ULONG i;
00505 
00506    for (i = 0; i < PageCount; i++)
00507    {
00508       if (!MmIsUsablePage(Pages[i]))
00509       {
00510          DPRINT1("Page at address %x not usable\n", PFN_TO_PTE(Pages[i]));
00511          ASSERT(FALSE);
00512       }
00513    }
00514 
00515    return(MmCreateVirtualMappingUnsafe(Process,
00516                                        Address,
00517                                        flProtect,
00518                                        Pages,
00519                                        PageCount));
00520 }
00521 
00522 ULONG
00523 NTAPI
00524 MmGetPageProtect(PEPROCESS Process, PVOID Address)
00525 {
00526     ULONG Protect = 0;
00527     ppc_map_info_t info = { 0 };
00528 
00529     info.proc = Process ? (int)Process->UniqueProcessId : 0;
00530     info.addr = (vaddr_t)Address;
00531     MmuInqPage(&info, 1);
00532 
00533     if (!info.phys) { return PAGE_NOACCESS; }
00534     if (!(info.flags & MMU_KMASK))
00535     {
00536         Protect |= PAGE_SYSTEM;
00537         if ((info.flags & MMU_KR) && (info.flags & MMU_KW))
00538             Protect = PAGE_READWRITE;
00539         else if (info.flags & MMU_KR)
00540             Protect = PAGE_EXECUTE_READ;
00541     }
00542     else
00543     {
00544         if ((info.flags & MMU_UR) && (info.flags & MMU_UW))
00545             Protect = PAGE_READWRITE;
00546         else
00547             Protect = PAGE_EXECUTE_READ;
00548     }
00549     return(Protect);
00550 }
00551 
00552 VOID
00553 NTAPI
00554 MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
00555 {
00556    //ULONG Attributes = 0;
00557 
00558    DPRINT("MmSetPageProtect(Process %x  Address %x  flProtect %x)\n",
00559           Process, Address, flProtect);
00560 
00561 #if 0
00562    Attributes = ProtectToPTE(flProtect);
00563 
00564    Pt = MmGetPageTableForProcess(Process, Address, FALSE);
00565    if (Pt == NULL)
00566    {
00567        ASSERT(FALSE);
00568    }
00569    InterlockedExchange((PLONG)Pt, PAGE_MASK(*Pt) | Attributes | (*Pt & (PA_ACCESSED|PA_DIRTY)));
00570    MiFlushTlb(Pt, Address);
00571 #endif
00572 }
00573 
00574 PVOID
00575 NTAPI
00576 MmCreateHyperspaceMapping(PFN_NUMBER Page)
00577 {
00578     PVOID Address;
00579     ppc_map_info_t info = { 0 };
00580 
00581     Address = (PVOID)((ULONG_PTR)HYPERSPACE * PAGE_SIZE);
00582     info.proc = 0;
00583     info.addr = (vaddr_t)Address;
00584     info.flags = MMU_KRW;
00585     MmuMapPage(&info, 1);
00586 
00587     return Address;
00588 }
00589 
00590 PFN_NUMBER
00591 NTAPI
00592 MmChangeHyperspaceMapping(PVOID Address, PFN_NUMBER NewPage)
00593 {
00594     PFN_NUMBER OldPage;
00595     ppc_map_info_t info = { 0 };
00596 
00597     info.proc = 0;
00598     info.addr = (vaddr_t)Address;
00599     MmuUnmapPage(&info, 1);
00600     OldPage = info.phys;
00601     info.phys = (paddr_t)NewPage;
00602     MmuMapPage(&info, 1);
00603 
00604     return NewPage;
00605 }
00606 
00607 PFN_NUMBER
00608 NTAPI
00609 MmDeleteHyperspaceMapping(PVOID Address)
00610 {
00611     ppc_map_info_t info = { 0 };
00612     ASSERT (IS_HYPERSPACE(Address));
00613 
00614     info.proc = 0;
00615     info.addr = (vaddr_t)Address;
00616 
00617     MmuUnmapPage(&info, 1);
00618 
00619     return (PFN_NUMBER)info.phys;
00620 }
00621 
00622 VOID
00623 INIT_FUNCTION
00624 NTAPI
00625 MmInitGlobalKernelPageDirectory(VOID)
00626 {
00627 }
00628 
00629 VOID
00630 INIT_FUNCTION
00631 NTAPI
00632 MiInitPageDirectoryMap(VOID)
00633 {
00634 }
00635 
00636 ULONG
00637 NTAPI
00638 MiGetUserPageDirectoryCount(VOID)
00639 {
00640     return 0;
00641 }
00642 
00643 VOID
00644 NTAPI
00645 MmUpdatePageDir(PEPROCESS Process, PVOID Address, ULONG Size)
00646 {
00647 }
00648 
00649 /* Create a simple, primitive mapping at the specified address on a new page */
00650 NTSTATUS MmPPCCreatePrimitiveMapping(ULONG_PTR PageAddr)
00651 {
00652     NTSTATUS result;
00653     ppc_map_info_t info = { 0 };
00654     info.flags = MMU_KRW;
00655     info.addr = (vaddr_t)PageAddr;
00656     result = MmuMapPage(&info, 1) ? STATUS_SUCCESS : STATUS_NO_MEMORY;
00657     return result;
00658 }
00659 
00660 /* Use our primitive allocator */
00661 PFN_NUMBER MmPPCPrimitiveAllocPage()
00662 {
00663     paddr_t Result = MmuGetPage();
00664     DbgPrint("Got Page %x\n", Result);
00665     return Result / PAGE_SIZE;
00666 }
00667 
00668 /* EOF */