Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpage.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 */ 00009 00010 /* INCLUDES ***************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 #include "../ARM3/miarm.h" 00016 00017 #if defined (ALLOC_PRAGMA) 00018 #pragma alloc_text(INIT, MmInitGlobalKernelPageDirectory) 00019 #pragma alloc_text(INIT, MiInitPageDirectoryMap) 00020 #endif 00021 00022 00023 /* GLOBALS *****************************************************************/ 00024 00025 #define PA_BIT_PRESENT (0) 00026 #define PA_BIT_READWRITE (1) 00027 #define PA_BIT_USER (2) 00028 #define PA_BIT_WT (3) 00029 #define PA_BIT_CD (4) 00030 #define PA_BIT_ACCESSED (5) 00031 #define PA_BIT_DIRTY (6) 00032 #define PA_BIT_GLOBAL (8) 00033 00034 #define PA_PRESENT (1 << PA_BIT_PRESENT) 00035 #define PA_READWRITE (1 << PA_BIT_READWRITE) 00036 #define PA_USER (1 << PA_BIT_USER) 00037 #define PA_DIRTY (1 << PA_BIT_DIRTY) 00038 #define PA_WT (1 << PA_BIT_WT) 00039 #define PA_CD (1 << PA_BIT_CD) 00040 #define PA_ACCESSED (1 << PA_BIT_ACCESSED) 00041 #define PA_GLOBAL (1 << PA_BIT_GLOBAL) 00042 00043 #define HYPERSPACE (0xc0400000) 00044 #define IS_HYPERSPACE(v) (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000)) 00045 00046 #define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT) 00047 #define PFN_TO_PTE(X) ((X) << PAGE_SHIFT) 00048 00049 #if defined(__GNUC__) 00050 #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X))) 00051 #else 00052 __inline LARGE_INTEGER PTE_TO_PAGE(ULONG npage) 00053 { 00054 LARGE_INTEGER dummy; 00055 dummy.QuadPart = (LONGLONG)(PAGE_MASK(npage)); 00056 return dummy; 00057 } 00058 #endif 00059 00060 const 00061 ULONG 00062 MmProtectToPteMask[32] = 00063 { 00064 // 00065 // These are the base MM_ protection flags 00066 // 00067 0, 00068 PTE_READONLY | PTE_ENABLE_CACHE, 00069 PTE_EXECUTE | PTE_ENABLE_CACHE, 00070 PTE_EXECUTE_READ | PTE_ENABLE_CACHE, 00071 PTE_READWRITE | PTE_ENABLE_CACHE, 00072 PTE_WRITECOPY | PTE_ENABLE_CACHE, 00073 PTE_EXECUTE_READWRITE | PTE_ENABLE_CACHE, 00074 PTE_EXECUTE_WRITECOPY | PTE_ENABLE_CACHE, 00075 // 00076 // These OR in the MM_NOCACHE flag 00077 // 00078 0, 00079 PTE_READONLY | PTE_DISABLE_CACHE, 00080 PTE_EXECUTE | PTE_DISABLE_CACHE, 00081 PTE_EXECUTE_READ | PTE_DISABLE_CACHE, 00082 PTE_READWRITE | PTE_DISABLE_CACHE, 00083 PTE_WRITECOPY | PTE_DISABLE_CACHE, 00084 PTE_EXECUTE_READWRITE | PTE_DISABLE_CACHE, 00085 PTE_EXECUTE_WRITECOPY | PTE_DISABLE_CACHE, 00086 // 00087 // These OR in the MM_DECOMMIT flag, which doesn't seem supported on x86/64/ARM 00088 // 00089 0, 00090 PTE_READONLY | PTE_ENABLE_CACHE, 00091 PTE_EXECUTE | PTE_ENABLE_CACHE, 00092 PTE_EXECUTE_READ | PTE_ENABLE_CACHE, 00093 PTE_READWRITE | PTE_ENABLE_CACHE, 00094 PTE_WRITECOPY | PTE_ENABLE_CACHE, 00095 PTE_EXECUTE_READWRITE | PTE_ENABLE_CACHE, 00096 PTE_EXECUTE_WRITECOPY | PTE_ENABLE_CACHE, 00097 // 00098 // These OR in the MM_NOACCESS flag, which seems to enable WriteCombining? 00099 // 00100 0, 00101 PTE_READONLY | PTE_WRITECOMBINED_CACHE, 00102 PTE_EXECUTE | PTE_WRITECOMBINED_CACHE, 00103 PTE_EXECUTE_READ | PTE_WRITECOMBINED_CACHE, 00104 PTE_READWRITE | PTE_WRITECOMBINED_CACHE, 00105 PTE_WRITECOPY | PTE_WRITECOMBINED_CACHE, 00106 PTE_EXECUTE_READWRITE | PTE_WRITECOMBINED_CACHE, 00107 PTE_EXECUTE_WRITECOPY | PTE_WRITECOMBINED_CACHE, 00108 }; 00109 00110 const 00111 ULONG MmProtectToValue[32] = 00112 { 00113 PAGE_NOACCESS, 00114 PAGE_READONLY, 00115 PAGE_EXECUTE, 00116 PAGE_EXECUTE_READ, 00117 PAGE_READWRITE, 00118 PAGE_WRITECOPY, 00119 PAGE_EXECUTE_READWRITE, 00120 PAGE_EXECUTE_WRITECOPY, 00121 PAGE_NOACCESS, 00122 PAGE_NOCACHE | PAGE_READONLY, 00123 PAGE_NOCACHE | PAGE_EXECUTE, 00124 PAGE_NOCACHE | PAGE_EXECUTE_READ, 00125 PAGE_NOCACHE | PAGE_READWRITE, 00126 PAGE_NOCACHE | PAGE_WRITECOPY, 00127 PAGE_NOCACHE | PAGE_EXECUTE_READWRITE, 00128 PAGE_NOCACHE | PAGE_EXECUTE_WRITECOPY, 00129 PAGE_NOACCESS, 00130 PAGE_GUARD | PAGE_READONLY, 00131 PAGE_GUARD | PAGE_EXECUTE, 00132 PAGE_GUARD | PAGE_EXECUTE_READ, 00133 PAGE_GUARD | PAGE_READWRITE, 00134 PAGE_GUARD | PAGE_WRITECOPY, 00135 PAGE_GUARD | PAGE_EXECUTE_READWRITE, 00136 PAGE_GUARD | PAGE_EXECUTE_WRITECOPY, 00137 PAGE_NOACCESS, 00138 PAGE_WRITECOMBINE | PAGE_READONLY, 00139 PAGE_WRITECOMBINE | PAGE_EXECUTE, 00140 PAGE_WRITECOMBINE | PAGE_EXECUTE_READ, 00141 PAGE_WRITECOMBINE | PAGE_READWRITE, 00142 PAGE_WRITECOMBINE | PAGE_WRITECOPY, 00143 PAGE_WRITECOMBINE | PAGE_EXECUTE_READWRITE, 00144 PAGE_WRITECOMBINE | PAGE_EXECUTE_WRITECOPY 00145 }; 00146 00147 /* FUNCTIONS ***************************************************************/ 00148 00149 BOOLEAN MmUnmapPageTable(PULONG Pt); 00150 00151 VOID 00152 MiFlushTlb(PULONG Pt, PVOID Address) 00153 { 00154 if ((Pt && MmUnmapPageTable(Pt)) || Address >= MmSystemRangeStart) 00155 { 00156 KeInvalidateTlbEntry(Address); 00157 } 00158 } 00159 00160 static ULONG 00161 ProtectToPTE(ULONG flProtect) 00162 { 00163 ULONG Attributes = 0; 00164 00165 if (flProtect & (PAGE_NOACCESS|PAGE_GUARD)) 00166 { 00167 Attributes = 0; 00168 } 00169 else if (flProtect & PAGE_IS_WRITABLE) 00170 { 00171 Attributes = PA_PRESENT | PA_READWRITE; 00172 } 00173 else if (flProtect & (PAGE_IS_READABLE | PAGE_IS_EXECUTABLE)) 00174 { 00175 Attributes = PA_PRESENT; 00176 } 00177 else 00178 { 00179 DPRINT1("Unknown main protection type.\n"); 00180 KeBugCheck(MEMORY_MANAGEMENT); 00181 } 00182 00183 if (flProtect & PAGE_SYSTEM) 00184 { 00185 } 00186 else 00187 { 00188 Attributes = Attributes | PA_USER; 00189 } 00190 if (flProtect & PAGE_NOCACHE) 00191 { 00192 Attributes = Attributes | PA_CD; 00193 } 00194 if (flProtect & PAGE_WRITETHROUGH) 00195 { 00196 Attributes = Attributes | PA_WT; 00197 } 00198 return(Attributes); 00199 } 00200 00201 /* Taken from ARM3/pagfault.c */ 00202 BOOLEAN 00203 FORCEINLINE 00204 MiSynchronizeSystemPde(PMMPDE PointerPde) 00205 { 00206 MMPDE SystemPde; 00207 ULONG Index; 00208 00209 /* Get the Index from the PDE */ 00210 Index = ((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE); 00211 00212 /* Copy the PDE from the double-mapped system page directory */ 00213 SystemPde = MmSystemPagePtes[Index]; 00214 *PointerPde = SystemPde; 00215 00216 /* Make sure we re-read the PDE and PTE */ 00217 KeMemoryBarrierWithoutFence(); 00218 00219 /* Return, if we had success */ 00220 return SystemPde.u.Hard.Valid != 0; 00221 } 00222 00223 NTSTATUS 00224 NTAPI 00225 MiDispatchFault(IN BOOLEAN StoreInstruction, 00226 IN PVOID Address, 00227 IN PMMPTE PointerPte, 00228 IN PMMPTE PointerProtoPte, 00229 IN BOOLEAN Recursive, 00230 IN PEPROCESS Process, 00231 IN PVOID TrapInformation, 00232 IN PVOID Vad); 00233 00234 NTSTATUS 00235 NTAPI 00236 MiFillSystemPageDirectory(IN PVOID Base, 00237 IN SIZE_T NumberOfBytes); 00238 00239 static PULONG 00240 MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create) 00241 { 00242 PFN_NUMBER Pfn; 00243 PULONG Pt; 00244 PMMPDE PointerPde; 00245 00246 if (Address < MmSystemRangeStart) 00247 { 00248 /* We should have a process for user land addresses */ 00249 ASSERT(Process != NULL); 00250 00251 if(Process != PsGetCurrentProcess()) 00252 { 00253 PMMPDE PdeBase; 00254 ULONG PdeOffset = MiGetPdeOffset(Address); 00255 00256 /* Nobody but page fault should ask for creating the PDE, 00257 * Which imples that Process is the current one */ 00258 ASSERT(Create == FALSE); 00259 00260 PdeBase = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase[0])); 00261 if (PdeBase == NULL) 00262 { 00263 KeBugCheck(MEMORY_MANAGEMENT); 00264 } 00265 PointerPde = PdeBase + PdeOffset; 00266 if (PointerPde->u.Hard.Valid == 0) 00267 { 00268 MmDeleteHyperspaceMapping(PdeBase); 00269 return NULL; 00270 } 00271 else 00272 { 00273 Pfn = PointerPde->u.Hard.PageFrameNumber; 00274 } 00275 MmDeleteHyperspaceMapping(PdeBase); 00276 Pt = MmCreateHyperspaceMapping(Pfn); 00277 if (Pt == NULL) 00278 { 00279 KeBugCheck(MEMORY_MANAGEMENT); 00280 } 00281 return Pt + MiAddressToPteOffset(Address); 00282 } 00283 /* This is for our process */ 00284 PointerPde = MiAddressToPde(Address); 00285 Pt = (PULONG)MiAddressToPte(Address); 00286 if (PointerPde->u.Hard.Valid == 0) 00287 { 00288 NTSTATUS Status; 00289 if (Create == FALSE) 00290 { 00291 return NULL; 00292 } 00293 ASSERT(PointerPde->u.Long == 0); 00294 00295 MI_WRITE_INVALID_PTE(PointerPde, DemandZeroPde); 00296 Status = MiDispatchFault(TRUE, 00297 Pt, 00298 PointerPde, 00299 NULL, 00300 FALSE, 00301 PsGetCurrentProcess(), 00302 NULL, 00303 NULL); 00304 ASSERT(KeAreAllApcsDisabled() == TRUE); 00305 ASSERT(PointerPde->u.Hard.Valid == 1); 00306 } 00307 return (PULONG)MiAddressToPte(Address); 00308 } 00309 00310 /* This is for kernel land address */ 00311 ASSERT(Process == NULL); 00312 PointerPde = MiAddressToPde(Address); 00313 Pt = (PULONG)MiAddressToPte(Address); 00314 if (PointerPde->u.Hard.Valid == 0) 00315 { 00316 /* Let ARM3 synchronize the PDE */ 00317 if(!MiSynchronizeSystemPde(PointerPde)) 00318 { 00319 /* PDE (still) not valid, let ARM3 allocate one if asked */ 00320 if(Create == FALSE) 00321 return NULL; 00322 MiFillSystemPageDirectory(Address, PAGE_SIZE); 00323 } 00324 } 00325 return Pt; 00326 } 00327 00328 BOOLEAN MmUnmapPageTable(PULONG Pt) 00329 { 00330 if (!IS_HYPERSPACE(Pt)) 00331 { 00332 return TRUE; 00333 } 00334 00335 if (Pt) 00336 { 00337 MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pt)); 00338 } 00339 return FALSE; 00340 } 00341 00342 static ULONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address) 00343 { 00344 ULONG Pte; 00345 PULONG Pt; 00346 00347 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 00348 if (Pt) 00349 { 00350 Pte = *Pt; 00351 MmUnmapPageTable(Pt); 00352 return Pte; 00353 } 00354 return 0; 00355 } 00356 00357 PFN_NUMBER 00358 NTAPI 00359 MmGetPfnForProcess(PEPROCESS Process, 00360 PVOID Address) 00361 { 00362 ULONG Entry; 00363 Entry = MmGetPageEntryForProcess(Process, Address); 00364 if (!(Entry & PA_PRESENT)) 00365 { 00366 return 0; 00367 } 00368 return(PTE_TO_PFN(Entry)); 00369 } 00370 00371 VOID 00372 NTAPI 00373 MmDisableVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN* WasDirty, PPFN_NUMBER Page) 00374 /* 00375 * FUNCTION: Delete a virtual mapping 00376 */ 00377 { 00378 BOOLEAN WasValid; 00379 ULONG Pte; 00380 PULONG Pt; 00381 00382 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 00383 if (Pt == NULL) 00384 { 00385 KeBugCheck(MEMORY_MANAGEMENT); 00386 } 00387 00388 /* 00389 * Atomically disable the present bit and get the old value. 00390 */ 00391 do 00392 { 00393 Pte = *Pt; 00394 } while (Pte != InterlockedCompareExchangePte(Pt, Pte & ~PA_PRESENT, Pte)); 00395 00396 MiFlushTlb(Pt, Address); 00397 00398 WasValid = (Pte & PA_PRESENT); 00399 if (!WasValid) 00400 { 00401 KeBugCheck(MEMORY_MANAGEMENT); 00402 } 00403 00404 /* 00405 * Return some information to the caller 00406 */ 00407 if (WasDirty != NULL) 00408 { 00409 *WasDirty = Pte & PA_DIRTY; 00410 } 00411 if (Page != NULL) 00412 { 00413 *Page = PTE_TO_PFN(Pte); 00414 } 00415 } 00416 00417 VOID 00418 NTAPI 00419 MmRawDeleteVirtualMapping(PVOID Address) 00420 { 00421 PULONG Pt; 00422 00423 Pt = MmGetPageTableForProcess(NULL, Address, FALSE); 00424 if (Pt && *Pt) 00425 { 00426 /* 00427 * Set the entry to zero 00428 */ 00429 InterlockedExchangePte(Pt, 0); 00430 MiFlushTlb(Pt, Address); 00431 } 00432 } 00433 00434 VOID 00435 NTAPI 00436 MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN FreePage, 00437 BOOLEAN* WasDirty, PPFN_NUMBER Page) 00438 /* 00439 * FUNCTION: Delete a virtual mapping 00440 */ 00441 { 00442 BOOLEAN WasValid = FALSE; 00443 PFN_NUMBER Pfn; 00444 ULONG Pte; 00445 PULONG Pt; 00446 00447 DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n", 00448 Process, Address, FreePage, WasDirty, Page); 00449 00450 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 00451 00452 if (Pt == NULL) 00453 { 00454 if (WasDirty != NULL) 00455 { 00456 *WasDirty = FALSE; 00457 } 00458 if (Page != NULL) 00459 { 00460 *Page = 0; 00461 } 00462 return; 00463 } 00464 00465 /* 00466 * Atomically set the entry to zero and get the old value. 00467 */ 00468 Pte = InterlockedExchangePte(Pt, 0); 00469 00470 WasValid = (Pte & PA_PRESENT); 00471 if (WasValid) 00472 { 00473 /* Flush the TLB since we transitioned this PTE 00474 * from valid to invalid so any stale translations 00475 * are removed from the cache */ 00476 MiFlushTlb(Pt, Address); 00477 00478 if (Address < MmSystemRangeStart) 00479 { 00480 /* Remove PDE reference */ 00481 Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--; 00482 ASSERT(Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] < PTE_COUNT); 00483 } 00484 00485 Pfn = PTE_TO_PFN(Pte); 00486 00487 if (FreePage) 00488 { 00489 MmReleasePageMemoryConsumer(MC_SYSTEM, Pfn); 00490 Pfn = 0; 00491 } 00492 } 00493 else 00494 { 00495 MmUnmapPageTable(Pt); 00496 Pfn = 0; 00497 } 00498 00499 /* 00500 * Return some information to the caller 00501 */ 00502 if (WasDirty != NULL) 00503 { 00504 *WasDirty = ((Pte & PA_DIRTY) && (Pte & PA_PRESENT)) ? TRUE : FALSE; 00505 } 00506 if (Page != NULL) 00507 { 00508 *Page = Pfn; 00509 } 00510 } 00511 00512 VOID 00513 NTAPI 00514 MmGetPageFileMapping(PEPROCESS Process, PVOID Address, 00515 SWAPENTRY* SwapEntry) 00516 /* 00517 * FUNCTION: Get a page file mapping 00518 */ 00519 { 00520 ULONG Entry = MmGetPageEntryForProcess(Process, Address); 00521 *SwapEntry = Entry >> 1; 00522 } 00523 00524 VOID 00525 NTAPI 00526 MmDeletePageFileMapping(PEPROCESS Process, PVOID Address, 00527 SWAPENTRY* SwapEntry) 00528 /* 00529 * FUNCTION: Delete a virtual mapping 00530 */ 00531 { 00532 ULONG Pte; 00533 PULONG Pt; 00534 00535 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 00536 00537 if (Pt == NULL) 00538 { 00539 *SwapEntry = 0; 00540 return; 00541 } 00542 00543 /* 00544 * Atomically set the entry to zero and get the old value. 00545 */ 00546 Pte = InterlockedExchangePte(Pt, 0); 00547 00548 if (Address < MmSystemRangeStart) 00549 { 00550 /* Remove PDE reference */ 00551 Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]--; 00552 ASSERT(Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] < PTE_COUNT); 00553 } 00554 00555 /* We don't need to flush here because page file entries 00556 * are invalid translations, so the processor won't cache them */ 00557 MmUnmapPageTable(Pt); 00558 00559 if ((Pte & PA_PRESENT) || !(Pte & 0x800)) 00560 { 00561 DPRINT1("Pte %x (want not 1 and 0x800)\n", Pte); 00562 KeBugCheck(MEMORY_MANAGEMENT); 00563 } 00564 00565 /* 00566 * Return some information to the caller 00567 */ 00568 *SwapEntry = Pte >> 1; 00569 } 00570 00571 BOOLEAN 00572 Mmi386MakeKernelPageTableGlobal(PVOID Address) 00573 { 00574 PMMPDE PointerPde = MiAddressToPde(Address); 00575 PMMPTE PointerPte = MiAddressToPte(Address); 00576 00577 if (PointerPde->u.Hard.Valid == 0) 00578 { 00579 if(!MiSynchronizeSystemPde(PointerPde)) 00580 return FALSE; 00581 return PointerPte->u.Hard.Valid != 0; 00582 } 00583 return FALSE; 00584 } 00585 00586 BOOLEAN 00587 NTAPI 00588 MmIsDirtyPage(PEPROCESS Process, PVOID Address) 00589 { 00590 return MmGetPageEntryForProcess(Process, Address) & PA_DIRTY ? TRUE : FALSE; 00591 } 00592 00593 VOID 00594 NTAPI 00595 MmSetCleanPage(PEPROCESS Process, PVOID Address) 00596 { 00597 PULONG Pt; 00598 ULONG Pte; 00599 00600 if (Address < MmSystemRangeStart && Process == NULL) 00601 { 00602 DPRINT1("MmSetCleanPage is called for user space without a process.\n"); 00603 KeBugCheck(MEMORY_MANAGEMENT); 00604 } 00605 00606 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 00607 if (Pt == NULL) 00608 { 00609 KeBugCheck(MEMORY_MANAGEMENT); 00610 } 00611 00612 do 00613 { 00614 Pte = *Pt; 00615 } while (Pte != InterlockedCompareExchangePte(Pt, Pte & ~PA_DIRTY, Pte)); 00616 00617 if (!(Pte & PA_PRESENT)) 00618 { 00619 KeBugCheck(MEMORY_MANAGEMENT); 00620 } 00621 else if (Pte & PA_DIRTY) 00622 { 00623 MiFlushTlb(Pt, Address); 00624 } 00625 else 00626 { 00627 MmUnmapPageTable(Pt); 00628 } 00629 } 00630 00631 VOID 00632 NTAPI 00633 MmSetDirtyPage(PEPROCESS Process, PVOID Address) 00634 { 00635 PULONG Pt; 00636 ULONG Pte; 00637 00638 if (Address < MmSystemRangeStart && Process == NULL) 00639 { 00640 DPRINT1("MmSetDirtyPage is called for user space without a process.\n"); 00641 KeBugCheck(MEMORY_MANAGEMENT); 00642 } 00643 00644 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 00645 if (Pt == NULL) 00646 { 00647 KeBugCheck(MEMORY_MANAGEMENT); 00648 } 00649 00650 do 00651 { 00652 Pte = *Pt; 00653 } while (Pte != InterlockedCompareExchangePte(Pt, Pte | PA_DIRTY, Pte)); 00654 00655 if (!(Pte & PA_PRESENT)) 00656 { 00657 KeBugCheck(MEMORY_MANAGEMENT); 00658 } 00659 else 00660 { 00661 /* The processor will never clear this bit itself, therefore 00662 * we do not need to flush the TLB here when setting it */ 00663 MmUnmapPageTable(Pt); 00664 } 00665 } 00666 00667 VOID 00668 NTAPI 00669 MmEnableVirtualMapping(PEPROCESS Process, PVOID Address) 00670 { 00671 PULONG Pt; 00672 ULONG Pte; 00673 00674 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 00675 if (Pt == NULL) 00676 { 00677 //HACK to get DPH working, waiting for MM rewrite :-/ 00678 //KeBugCheck(MEMORY_MANAGEMENT); 00679 return; 00680 } 00681 00682 /* Do not mark a 0 page as present */ 00683 if(0 == InterlockedCompareExchangePte(Pt, 0, 0)) 00684 return; 00685 00686 do 00687 { 00688 Pte = *Pt; 00689 } while (Pte != InterlockedCompareExchangePte(Pt, Pte | PA_PRESENT, Pte)); 00690 00691 /* We don't need to flush the TLB here because it 00692 * won't cache translations for non-present pages */ 00693 MmUnmapPageTable(Pt); 00694 } 00695 00696 BOOLEAN 00697 NTAPI 00698 MmIsPagePresent(PEPROCESS Process, PVOID Address) 00699 { 00700 return MmGetPageEntryForProcess(Process, Address) & PA_PRESENT; 00701 } 00702 00703 BOOLEAN 00704 NTAPI 00705 MmIsPageSwapEntry(PEPROCESS Process, PVOID Address) 00706 { 00707 ULONG Entry; 00708 Entry = MmGetPageEntryForProcess(Process, Address); 00709 return !(Entry & PA_PRESENT) && (Entry & 0x800); 00710 } 00711 00712 NTSTATUS 00713 NTAPI 00714 MmCreatePageFileMapping(PEPROCESS Process, 00715 PVOID Address, 00716 SWAPENTRY SwapEntry) 00717 { 00718 PULONG Pt; 00719 ULONG Pte; 00720 00721 if (Process == NULL && Address < MmSystemRangeStart) 00722 { 00723 DPRINT1("No process\n"); 00724 KeBugCheck(MEMORY_MANAGEMENT); 00725 } 00726 if (Process != NULL && Address >= MmSystemRangeStart) 00727 { 00728 DPRINT1("Setting kernel address with process context\n"); 00729 KeBugCheck(MEMORY_MANAGEMENT); 00730 } 00731 00732 if (SwapEntry & (1 << 31)) 00733 { 00734 KeBugCheck(MEMORY_MANAGEMENT); 00735 } 00736 00737 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 00738 if (Pt == NULL) 00739 { 00740 /* Nobody should page out an address that hasn't even been mapped */ 00741 KeBugCheck(MEMORY_MANAGEMENT); 00742 } 00743 Pte = InterlockedExchangePte(Pt, SwapEntry << 1); 00744 if (Pte != 0) 00745 { 00746 KeBugCheck(MEMORY_MANAGEMENT); 00747 } 00748 00749 if (Address < MmSystemRangeStart) 00750 { 00751 /* Add PDE reference */ 00752 Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)]++; 00753 ASSERT(Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] <= PTE_COUNT); 00754 } 00755 00756 /* We don't need to flush the TLB here because it 00757 * only caches valid translations and a zero PTE 00758 * is not a valid translation */ 00759 MmUnmapPageTable(Pt); 00760 00761 return(STATUS_SUCCESS); 00762 } 00763 00764 00765 NTSTATUS 00766 NTAPI 00767 MmCreateVirtualMappingUnsafe(PEPROCESS Process, 00768 PVOID Address, 00769 ULONG flProtect, 00770 PPFN_NUMBER Pages, 00771 ULONG PageCount) 00772 { 00773 ULONG Attributes; 00774 PVOID Addr; 00775 ULONG i; 00776 ULONG oldPdeOffset, PdeOffset; 00777 PULONG Pt = NULL; 00778 ULONG Pte; 00779 DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n", 00780 Process, Address, flProtect, Pages, *Pages, PageCount); 00781 00782 ASSERT(((ULONG_PTR)Address % PAGE_SIZE) == 0); 00783 00784 if (Process == NULL) 00785 { 00786 if (Address < MmSystemRangeStart) 00787 { 00788 DPRINT1("No process\n"); 00789 KeBugCheck(MEMORY_MANAGEMENT); 00790 } 00791 if (PageCount > 0x10000 || 00792 (ULONG_PTR) Address / PAGE_SIZE + PageCount > 0x100000) 00793 { 00794 DPRINT1("Page count too large\n"); 00795 KeBugCheck(MEMORY_MANAGEMENT); 00796 } 00797 } 00798 else 00799 { 00800 if (Address >= MmSystemRangeStart) 00801 { 00802 DPRINT1("Setting kernel address with process context\n"); 00803 KeBugCheck(MEMORY_MANAGEMENT); 00804 } 00805 if (PageCount > (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE || 00806 (ULONG_PTR) Address / PAGE_SIZE + PageCount > 00807 (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE) 00808 { 00809 DPRINT1("Page Count too large\n"); 00810 KeBugCheck(MEMORY_MANAGEMENT); 00811 } 00812 } 00813 00814 Attributes = ProtectToPTE(flProtect); 00815 Attributes &= 0xfff; 00816 if (Address >= MmSystemRangeStart) 00817 { 00818 Attributes &= ~PA_USER; 00819 } 00820 else 00821 { 00822 Attributes |= PA_USER; 00823 } 00824 00825 Addr = Address; 00826 /* MmGetPageTableForProcess should be called on the first run, so 00827 * let this trigger it */ 00828 oldPdeOffset = ADDR_TO_PDE_OFFSET(Addr) + 1; 00829 for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE)) 00830 { 00831 if (!(Attributes & PA_PRESENT) && Pages[i] != 0) 00832 { 00833 DPRINT1("Setting physical address but not allowing access at address " 00834 "0x%.8X with attributes %x/%x.\n", 00835 Addr, Attributes, flProtect); 00836 KeBugCheck(MEMORY_MANAGEMENT); 00837 } 00838 PdeOffset = ADDR_TO_PDE_OFFSET(Addr); 00839 if (oldPdeOffset != PdeOffset) 00840 { 00841 if(Pt) MmUnmapPageTable(Pt); 00842 Pt = MmGetPageTableForProcess(Process, Addr, TRUE); 00843 if (Pt == NULL) 00844 { 00845 KeBugCheck(MEMORY_MANAGEMENT); 00846 } 00847 } 00848 else 00849 { 00850 Pt++; 00851 } 00852 oldPdeOffset = PdeOffset; 00853 00854 Pte = InterlockedExchangePte(Pt, PFN_TO_PTE(Pages[i]) | Attributes); 00855 00856 /* There should not be anything valid here */ 00857 if (Pte != 0) 00858 { 00859 DPRINT1("Bad PTE %lx\n", Pte); 00860 KeBugCheck(MEMORY_MANAGEMENT); 00861 } 00862 00863 /* We don't need to flush the TLB here because it only caches valid translations 00864 * and we're moving this PTE from invalid to valid so it can't be cached right now */ 00865 00866 if (Addr < MmSystemRangeStart) 00867 { 00868 /* Add PDE reference */ 00869 Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Addr)]++; 00870 ASSERT(Process->Vm.VmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Addr)] <= PTE_COUNT); 00871 } 00872 } 00873 00874 ASSERT(Addr > Address); 00875 MmUnmapPageTable(Pt); 00876 00877 return(STATUS_SUCCESS); 00878 } 00879 00880 NTSTATUS 00881 NTAPI 00882 MmCreateVirtualMapping(PEPROCESS Process, 00883 PVOID Address, 00884 ULONG flProtect, 00885 PPFN_NUMBER Pages, 00886 ULONG PageCount) 00887 { 00888 ULONG i; 00889 00890 ASSERT((ULONG_PTR)Address % PAGE_SIZE == 0); 00891 for (i = 0; i < PageCount; i++) 00892 { 00893 if (!MmIsPageInUse(Pages[i])) 00894 { 00895 DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Pages[i])); 00896 KeBugCheck(MEMORY_MANAGEMENT); 00897 } 00898 } 00899 00900 return(MmCreateVirtualMappingUnsafe(Process, 00901 Address, 00902 flProtect, 00903 Pages, 00904 PageCount)); 00905 } 00906 00907 ULONG 00908 NTAPI 00909 MmGetPageProtect(PEPROCESS Process, PVOID Address) 00910 { 00911 ULONG Entry; 00912 ULONG Protect; 00913 00914 Entry = MmGetPageEntryForProcess(Process, Address); 00915 00916 00917 if (!(Entry & PA_PRESENT)) 00918 { 00919 Protect = PAGE_NOACCESS; 00920 } 00921 else 00922 { 00923 if (Entry & PA_READWRITE) 00924 { 00925 Protect = PAGE_READWRITE; 00926 } 00927 else 00928 { 00929 Protect = PAGE_EXECUTE_READ; 00930 } 00931 if (Entry & PA_CD) 00932 { 00933 Protect |= PAGE_NOCACHE; 00934 } 00935 if (Entry & PA_WT) 00936 { 00937 Protect |= PAGE_WRITETHROUGH; 00938 } 00939 if (!(Entry & PA_USER)) 00940 { 00941 Protect |= PAGE_SYSTEM; 00942 } 00943 00944 } 00945 return(Protect); 00946 } 00947 00948 VOID 00949 NTAPI 00950 MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect) 00951 { 00952 ULONG Attributes = 0; 00953 PULONG Pt; 00954 ULONG Pte; 00955 00956 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n", 00957 Process, Address, flProtect); 00958 00959 Attributes = ProtectToPTE(flProtect); 00960 00961 Attributes &= 0xfff; 00962 if (Address >= MmSystemRangeStart) 00963 { 00964 Attributes &= ~PA_USER; 00965 } 00966 else 00967 { 00968 Attributes |= PA_USER; 00969 } 00970 00971 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 00972 if (Pt == NULL) 00973 { 00974 KeBugCheck(MEMORY_MANAGEMENT); 00975 } 00976 Pte = InterlockedExchangePte(Pt, PAGE_MASK(*Pt) | Attributes | (*Pt & (PA_ACCESSED|PA_DIRTY))); 00977 00978 if (!(Pte & PA_PRESENT)) 00979 { 00980 DPRINT1("Invalid Pte %lx\n", Pte); 00981 KeBugCheck(MEMORY_MANAGEMENT); 00982 } 00983 00984 if((Pte & Attributes) != Attributes) 00985 MiFlushTlb(Pt, Address); 00986 else 00987 MmUnmapPageTable(Pt); 00988 } 00989 00990 /* 00991 * @implemented 00992 */ 00993 PHYSICAL_ADDRESS NTAPI 00994 MmGetPhysicalAddress(PVOID vaddr) 00995 /* 00996 * FUNCTION: Returns the physical address corresponding to a virtual address 00997 */ 00998 { 00999 PHYSICAL_ADDRESS p; 01000 ULONG Pte; 01001 01002 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr); 01003 Pte = MmGetPageEntryForProcess(NULL, vaddr); 01004 if (Pte != 0 && (Pte & PA_PRESENT)) 01005 { 01006 p.QuadPart = PAGE_MASK(Pte); 01007 p.u.LowPart |= (ULONG_PTR)vaddr & (PAGE_SIZE - 1); 01008 } 01009 else 01010 { 01011 p.QuadPart = 0; 01012 } 01013 return p; 01014 } 01015 01016 VOID 01017 INIT_FUNCTION 01018 NTAPI 01019 MmInitGlobalKernelPageDirectory(VOID) 01020 { 01021 /* Nothing to do here */ 01022 } 01023 01024 /* EOF */ Generated on Sun May 27 2012 04:27:04 for ReactOS by
1.7.6.1
|