/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/mm/powerpc/page.c * PURPOSE: Low level memory managment manipulation * * PROGRAMMERS: David Welch (welch@cwcom.net) * Revised for PowerPC by arty */ /* INCLUDES ***************************************************************/ #include #include //#define NDEBUG #include #if defined (ALLOC_PRAGMA) #pragma alloc_text(INIT, MmInitGlobalKernelPageDirectory) #endif /* GLOBALS *****************************************************************/ #define HYPERSPACE_PAGEDIR_PTR ((PVOID)0xc0000000) #define PA_PRESENT (1ll<<63) #define PA_USER (1ll<<62) #define PA_ACCESSED 0x200 #define PA_DIRTY 0x100 #define PA_WT 0x20 #define PA_CD 0x10 #define PA_READWRITE 3 #define HYPERSPACE (0xc0400000) #define IS_HYPERSPACE(v) (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000)) #define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT) #define PFN_TO_PTE(X) ((X) << PAGE_SHIFT) #if defined(__GNUC__) #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X))) #else __inline LARGE_INTEGER PTE_TO_PAGE(ULONG npage) { LARGE_INTEGER dummy; dummy.QuadPart = (LONGLONG)(PAGE_MASK(npage)); return dummy; } #endif /* FUNCTIONS ***************************************************************/ VOID NTAPI MiFlushTlbIpiRoutine(PVOID Address) { if (Address == (PVOID)0xffffffff) { __asm__("tlbsync"); } else if (Address == (PVOID)0xfffffffe) { __asm__("tlbsync"); } else { __asm__("tlbi %0" : "=r" (Address)); } } VOID MiFlushTlb(PULONG Pt, PVOID Address) { __asm__("tlbi %0" : "=r" (Address)); } static ULONG ProtectToFlags(ULONG flProtect) { return MMU_ALL_RW; // XXX hack } NTSTATUS NTAPI MmCopyMmInfo(PEPROCESS Src, PEPROCESS Dest, PPHYSICAL_ADDRESS DirectoryTableBase) { DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", Src, Dest); ASSERT(FALSE); return(STATUS_SUCCESS); } BOOLEAN NTAPI MmCreateProcessAddressSpace(IN ULONG MinWs, IN PEPROCESS Process, IN PLARGE_INTEGER DirectoryTableBase) { ASSERT(FALSE); return TRUE; } VOID NTAPI MmDeletePageTable(PEPROCESS Process, PVOID Address) { PEPROCESS CurrentProcess = PsGetCurrentProcess(); DPRINT1("DeletePageTable: Process: %x CurrentProcess %x\n", Process, CurrentProcess); if (Process != NULL && Process != CurrentProcess) { KeAttachProcess(&Process->Pcb); } if (Process) { DPRINT1("Revoking VSID %d\n", (paddr_t)Process->UniqueProcessId); MmuRevokeVsid((paddr_t)Process->UniqueProcessId, -1); } else { DPRINT1("No vsid to revoke\n"); } if (Process != NULL && Process != CurrentProcess) { KeDetachProcess(); } } VOID NTAPI MmFreePageTable(PEPROCESS Process, PVOID Address) { MmDeletePageTable(Process, Address); } PVOID NTAPI MmGetPhysicalAddressProcess(PEPROCESS Process, PVOID Addr) { ppc_map_info_t info = { 0 }; info.proc = Process ? (int)Process->UniqueProcessId : 0; info.addr = (vaddr_t)Addr; MmuInqPage(&info, 1); return (PVOID)info.phys; } PFN_NUMBER NTAPI MmGetPfnForProcess(PEPROCESS Process, PVOID Address) { return((PFN_NUMBER)MmGetPhysicalAddressProcess(Process, Address) >> PAGE_SHIFT); } VOID NTAPI MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN* WasDirty, PPFN_NUMBER Page) /* * FUNCTION: Delete a virtual mapping */ { ppc_map_info_t info = { 0 }; DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n", Process, Address, WasDirty, Page); info.proc = Process ? (int)Process->UniqueProcessId : 0; info.addr = (vaddr_t)Address; MmuInqPage(&info, 1); /* * Return some information to the caller */ if (WasDirty != NULL) { *WasDirty = !!(info.flags & MMU_PAGE_DIRTY); } if (Page != NULL) { *Page = info.phys >> PAGE_SHIFT; } } VOID NTAPI MmDeletePageFileMapping(PEPROCESS Process, PVOID Address, SWAPENTRY* SwapEntry) /* * FUNCTION: Delete a virtual mapping */ { ppc_map_info_t info = { 0 }; /* * Decrement the reference count for this page table. */ if (Process != NULL && ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL && Address < MmSystemRangeStart) { PUSHORT Ptrc; Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable; MmFreePageTable(Process, Address); } /* * Return some information to the caller */ MmuInqPage(&info, 1); *SwapEntry = info.phys; } BOOLEAN NTAPI MmIsDirtyPage(PEPROCESS Process, PVOID Address) { ppc_map_info_t info = { 0 }; info.proc = Process ? (int)Process->UniqueProcessId : 0; info.addr = (vaddr_t)Address; MmuInqPage(&info, 1); return !!(info.flags & MMU_PAGE_DIRTY); } VOID NTAPI MmSetCleanPage(PEPROCESS Process, PVOID Address) { } VOID NTAPI MmSetDirtyPage(PEPROCESS Process, PVOID Address) { } BOOLEAN NTAPI MmIsPagePresent(PEPROCESS Process, PVOID Address) { ppc_map_info_t info = { 0 }; info.proc = Process ? (int)Process->UniqueProcessId : 0; info.addr = (vaddr_t)Address; MmuInqPage(&info, 1); return !!info.phys; } ULONGLONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address) { return 0; // XXX arty } BOOLEAN NTAPI MmIsPageSwapEntry(PEPROCESS Process, PVOID Address) { ULONG Entry; Entry = MmGetPageEntryForProcess(Process, Address); return !(Entry & PA_PRESENT) && Entry != 0 ? TRUE : FALSE; } NTSTATUS NTAPI MmCreatePageFileMapping(PEPROCESS Process, PVOID Address, SWAPENTRY SwapEntry) { if (Process == NULL && Address < MmSystemRangeStart) { DPRINT1("No process\n"); ASSERT(FALSE); } if (Process != NULL && Address >= MmSystemRangeStart) { DPRINT1("Setting kernel address with process context\n"); ASSERT(FALSE); } if (SwapEntry & (1 << 31)) { ASSERT(FALSE); } // XXX arty return(STATUS_SUCCESS); } NTSTATUS NTAPI MmCreateVirtualMappingUnsafe(PEPROCESS Process, PVOID Address, ULONG flProtect, PPFN_NUMBER Pages, ULONG PageCount) { ULONG Attributes; PVOID Addr; ULONG i; ppc_map_info_t info = { 0 }; DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n", Process, Address, flProtect, Pages, *Pages, PageCount); if (Process == NULL) { if (Address < MmSystemRangeStart) { DPRINT1("No process\n"); ASSERT(FALSE); } if (PageCount > 0x10000 || (ULONG_PTR) Address / PAGE_SIZE + PageCount > 0x100000) { DPRINT1("Page count to large\n"); ASSERT(FALSE); } } else { if (Address >= MmSystemRangeStart) { DPRINT1("Setting kernel address with process context\n"); ASSERT(FALSE); } if (PageCount > (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE || (ULONG_PTR) Address / PAGE_SIZE + PageCount > (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE) { DPRINT1("Page Count to large\n"); ASSERT(FALSE); } } Attributes = ProtectToFlags(flProtect); Addr = Address; for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE)) { Process = PsGetCurrentProcess(); info.proc = ((Addr < MmSystemRangeStart) && Process) ? (int)Process->UniqueProcessId : 0; info.addr = (vaddr_t)Addr; info.flags = Attributes; MmuMapPage(&info, 1); //(void)InterlockedExchangeUL(Pt, PFN_TO_PTE(Pages[i]) | Attributes); if (Address < MmSystemRangeStart && ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL && Attributes & PA_PRESENT) { #if 0 PUSHORT Ptrc; Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable; Ptrc[ADDR_TO_PAGE_TABLE(Addr)]++; #endif } } return(STATUS_SUCCESS); } NTSTATUS NTAPI MmCreateVirtualMapping(PEPROCESS Process, PVOID Address, ULONG flProtect, PPFN_NUMBER Pages, ULONG PageCount) { ULONG i; for (i = 0; i < PageCount; i++) { if (!MmIsUsablePage(Pages[i])) { DPRINT1("Page at address %x not usable\n", PFN_TO_PTE(Pages[i])); ASSERT(FALSE); } } return(MmCreateVirtualMappingUnsafe(Process, Address, flProtect, Pages, PageCount)); } ULONG NTAPI MmGetPageProtect(PEPROCESS Process, PVOID Address) { ULONG Protect = 0; ppc_map_info_t info = { 0 }; info.proc = Process ? (int)Process->UniqueProcessId : 0; info.addr = (vaddr_t)Address; MmuInqPage(&info, 1); if (!info.phys) { return PAGE_NOACCESS; } if (!(info.flags & MMU_KMASK)) { Protect |= PAGE_SYSTEM; if ((info.flags & MMU_KR) && (info.flags & MMU_KW)) Protect = PAGE_READWRITE; else if (info.flags & MMU_KR) Protect = PAGE_EXECUTE_READ; } else { if ((info.flags & MMU_UR) && (info.flags & MMU_UW)) Protect = PAGE_READWRITE; else Protect = PAGE_EXECUTE_READ; } return(Protect); } VOID NTAPI MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect) { //ULONG Attributes = 0; DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n", Process, Address, flProtect); #if 0 Attributes = ProtectToPTE(flProtect); Pt = MmGetPageTableForProcess(Process, Address, FALSE); if (Pt == NULL) { ASSERT(FALSE); } InterlockedExchange((PLONG)Pt, PAGE_MASK(*Pt) | Attributes | (*Pt & (PA_ACCESSED|PA_DIRTY))); MiFlushTlb(Pt, Address); #endif } VOID INIT_FUNCTION NTAPI MmInitGlobalKernelPageDirectory(VOID) { } /* Create a simple, primitive mapping at the specified address on a new page */ NTSTATUS MmPPCCreatePrimitiveMapping(ULONG_PTR PageAddr) { NTSTATUS result; ppc_map_info_t info = { 0 }; info.flags = MMU_KRW; info.addr = (vaddr_t)PageAddr; result = MmuMapPage(&info, 1) ? STATUS_SUCCESS : STATUS_NO_MEMORY; return result; } /* Use our primitive allocator */ PFN_NUMBER MmPPCPrimitiveAllocPage() { paddr_t Result = MmuGetPage(); DbgPrint("Got Page %x\n", Result); return Result / PAGE_SIZE; } /* EOF */