00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <ntoskrnl.h>
00014 #include <ppcmmu/mmu.h>
00015
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
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
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;
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
00112 *DirectoryTableBase = PsGetCurrentProcess()->Pcb.DirectoryTableBase;
00113
00114
00115 MmInitializeAddressSpace(Process, (PMADDRESS_SPACE)&Process->VadRoot);
00116
00117
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
00182
00183 PHYSICAL_ADDRESS NTAPI
00184 MmGetPhysicalAddress(PVOID vaddr)
00185
00186
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
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
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
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
00262
00263 {
00264 ppc_map_info_t info = { 0 };
00265
00266
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
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 );
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;
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
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
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
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
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
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