Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpage.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: GPL, See COPYING in the top level directory 00003 * PROJECT: ReactOS kernel 00004 * FILE: ntoskrnl/mm/amd64/page.c 00005 * PURPOSE: Low level memory managment manipulation 00006 * 00007 * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) 00008 * ReactOS Portable Systems Group 00009 */ 00010 00011 /* INCLUDES ***************************************************************/ 00012 00013 #include <ntoskrnl.h> 00014 #define NDEBUG 00015 #include <debug.h> 00016 #include "../ARM3/miarm.h" 00017 00018 #undef InterlockedExchangePte 00019 #define InterlockedExchangePte(pte1, pte2) \ 00020 InterlockedExchange64((LONG64*)&pte1->u.Long, pte2.u.Long) 00021 00022 #define PAGE_EXECUTE_ANY (PAGE_EXECUTE|PAGE_EXECUTE_READ|PAGE_EXECUTE_READWRITE|PAGE_EXECUTE_WRITECOPY) 00023 #define PAGE_WRITE_ANY (PAGE_EXECUTE_READWRITE|PAGE_READWRITE|PAGE_EXECUTE_WRITECOPY|PAGE_WRITECOPY) 00024 #define PAGE_WRITECOPY_ANY (PAGE_EXECUTE_WRITECOPY|PAGE_WRITECOPY) 00025 00026 extern MMPTE HyperTemplatePte; 00027 00028 /* GLOBALS *****************************************************************/ 00029 00030 const 00031 ULONG64 00032 MmProtectToPteMask[32] = 00033 { 00034 // 00035 // These are the base MM_ protection flags 00036 // 00037 0, 00038 PTE_READONLY | PTE_ENABLE_CACHE, 00039 PTE_EXECUTE | PTE_ENABLE_CACHE, 00040 PTE_EXECUTE_READ | PTE_ENABLE_CACHE, 00041 PTE_READWRITE | PTE_ENABLE_CACHE, 00042 PTE_WRITECOPY | PTE_ENABLE_CACHE, 00043 PTE_EXECUTE_READWRITE | PTE_ENABLE_CACHE, 00044 PTE_EXECUTE_WRITECOPY | PTE_ENABLE_CACHE, 00045 // 00046 // These OR in the MM_NOCACHE flag 00047 // 00048 0, 00049 PTE_READONLY | PTE_DISABLE_CACHE, 00050 PTE_EXECUTE | PTE_DISABLE_CACHE, 00051 PTE_EXECUTE_READ | PTE_DISABLE_CACHE, 00052 PTE_READWRITE | PTE_DISABLE_CACHE, 00053 PTE_WRITECOPY | PTE_DISABLE_CACHE, 00054 PTE_EXECUTE_READWRITE | PTE_DISABLE_CACHE, 00055 PTE_EXECUTE_WRITECOPY | PTE_DISABLE_CACHE, 00056 // 00057 // These OR in the MM_DECOMMIT flag, which doesn't seem supported on x86/64/ARM 00058 // 00059 0, 00060 PTE_READONLY | PTE_ENABLE_CACHE, 00061 PTE_EXECUTE | PTE_ENABLE_CACHE, 00062 PTE_EXECUTE_READ | PTE_ENABLE_CACHE, 00063 PTE_READWRITE | PTE_ENABLE_CACHE, 00064 PTE_WRITECOPY | PTE_ENABLE_CACHE, 00065 PTE_EXECUTE_READWRITE | PTE_ENABLE_CACHE, 00066 PTE_EXECUTE_WRITECOPY | PTE_ENABLE_CACHE, 00067 // 00068 // These OR in the MM_NOACCESS flag, which seems to enable WriteCombining? 00069 // 00070 0, 00071 PTE_READONLY | PTE_WRITECOMBINED_CACHE, 00072 PTE_EXECUTE | PTE_WRITECOMBINED_CACHE, 00073 PTE_EXECUTE_READ | PTE_WRITECOMBINED_CACHE, 00074 PTE_READWRITE | PTE_WRITECOMBINED_CACHE, 00075 PTE_WRITECOPY | PTE_WRITECOMBINED_CACHE, 00076 PTE_EXECUTE_READWRITE | PTE_WRITECOMBINED_CACHE, 00077 PTE_EXECUTE_WRITECOPY | PTE_WRITECOMBINED_CACHE, 00078 }; 00079 00080 const 00081 ULONG MmProtectToValue[32] = 00082 { 00083 PAGE_NOACCESS, 00084 PAGE_READONLY, 00085 PAGE_EXECUTE, 00086 PAGE_EXECUTE_READ, 00087 PAGE_READWRITE, 00088 PAGE_WRITECOPY, 00089 PAGE_EXECUTE_READWRITE, 00090 PAGE_EXECUTE_WRITECOPY, 00091 PAGE_NOACCESS, 00092 PAGE_NOCACHE | PAGE_READONLY, 00093 PAGE_NOCACHE | PAGE_EXECUTE, 00094 PAGE_NOCACHE | PAGE_EXECUTE_READ, 00095 PAGE_NOCACHE | PAGE_READWRITE, 00096 PAGE_NOCACHE | PAGE_WRITECOPY, 00097 PAGE_NOCACHE | PAGE_EXECUTE_READWRITE, 00098 PAGE_NOCACHE | PAGE_EXECUTE_WRITECOPY, 00099 PAGE_NOACCESS, 00100 PAGE_GUARD | PAGE_READONLY, 00101 PAGE_GUARD | PAGE_EXECUTE, 00102 PAGE_GUARD | PAGE_EXECUTE_READ, 00103 PAGE_GUARD | PAGE_READWRITE, 00104 PAGE_GUARD | PAGE_WRITECOPY, 00105 PAGE_GUARD | PAGE_EXECUTE_READWRITE, 00106 PAGE_GUARD | PAGE_EXECUTE_WRITECOPY, 00107 PAGE_NOACCESS, 00108 PAGE_WRITECOMBINE | PAGE_READONLY, 00109 PAGE_WRITECOMBINE | PAGE_EXECUTE, 00110 PAGE_WRITECOMBINE | PAGE_EXECUTE_READ, 00111 PAGE_WRITECOMBINE | PAGE_READWRITE, 00112 PAGE_WRITECOMBINE | PAGE_WRITECOPY, 00113 PAGE_WRITECOMBINE | PAGE_EXECUTE_READWRITE, 00114 PAGE_WRITECOMBINE | PAGE_EXECUTE_WRITECOPY 00115 }; 00116 00117 /* PRIVATE FUNCTIONS *******************************************************/ 00118 00119 BOOLEAN 00120 FORCEINLINE 00121 MiIsHyperspaceAddress(PVOID Address) 00122 { 00123 return ((ULONG64)Address >= HYPER_SPACE && 00124 (ULONG64)Address <= HYPER_SPACE_END); 00125 } 00126 00127 VOID 00128 MiFlushTlb(PMMPTE Pte, PVOID Address) 00129 { 00130 if (MiIsHyperspaceAddress(Pte)) 00131 { 00132 MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pte)); 00133 } 00134 else 00135 { 00136 __invlpg(Address); 00137 } 00138 } 00139 00140 static 00141 VOID 00142 MmDeletePageTablePfn(PFN_NUMBER PageFrameNumber, ULONG Level) 00143 { 00144 PMMPTE PageTable; 00145 KIRQL OldIrql; 00146 PMMPFN PfnEntry; 00147 ULONG i, NumberEntries; 00148 00149 /* Check if this is a page table */ 00150 if (Level > 0) 00151 { 00152 NumberEntries = (Level == 4) ? MiAddressToPxi(MmHighestUserAddress)+1 : 512; 00153 00154 /* Map the page table in hyperspace */ 00155 PageTable = (PMMPTE)MmCreateHyperspaceMapping(PageFrameNumber); 00156 00157 /* Loop all page table entries */ 00158 for (i = 0; i < NumberEntries; i++) 00159 { 00160 /* Check if the entry is valid */ 00161 if (PageTable[i].u.Hard.Valid) 00162 { 00163 /* Recursively free the page that backs it */ 00164 MmDeletePageTablePfn(PageTable[i].u.Hard.PageFrameNumber, Level - 1); 00165 } 00166 } 00167 00168 /* Delete the hyperspace mapping */ 00169 MmDeleteHyperspaceMapping(PageTable); 00170 } 00171 00172 /* Check if this is a legacy allocation */ 00173 PfnEntry = MiGetPfnEntry(PageFrameNumber); 00174 if (MI_IS_ROS_PFN(PfnEntry)) 00175 { 00176 /* Free it using the legacy API */ 00177 MmReleasePageMemoryConsumer(MC_SYSTEM, PageFrameNumber); 00178 } 00179 else 00180 { 00181 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 00182 00183 /* Free it using the ARM3 API */ 00184 MI_SET_PFN_DELETED(PfnEntry); 00185 MiDecrementShareCount(PfnEntry, PageFrameNumber); 00186 00187 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 00188 } 00189 } 00190 00191 static 00192 PMMPTE 00193 MiGetPteForProcess( 00194 PEPROCESS Process, 00195 PVOID Address, 00196 BOOLEAN Create) 00197 { 00198 MMPTE TmplPte, *Pte; 00199 00200 /* Check if we need hypersapce mapping */ 00201 if (Address < MmSystemRangeStart && 00202 Process && Process != PsGetCurrentProcess()) 00203 { 00204 UNIMPLEMENTED; 00205 __debugbreak(); 00206 return NULL; 00207 } 00208 else if (Create) 00209 { 00210 KIRQL OldIrql; 00211 TmplPte.u.Long = 0; 00212 TmplPte.u.Flush.Valid = 1; 00213 TmplPte.u.Flush.Write = 1; 00214 00215 /* All page table levels of user pages are user owned */ 00216 TmplPte.u.Flush.Owner = (Address < MmHighestUserAddress) ? 1 : 0; 00217 00218 /* Lock the PFN database */ 00219 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 00220 00221 /* Get the PXE */ 00222 Pte = MiAddressToPxe(Address); 00223 if (!Pte->u.Hard.Valid) 00224 { 00225 TmplPte.u.Hard.PageFrameNumber = MiRemoveZeroPage(0); 00226 MI_WRITE_VALID_PTE(Pte, TmplPte); 00227 } 00228 00229 /* Get the PPE */ 00230 Pte = MiAddressToPpe(Address); 00231 if (!Pte->u.Hard.Valid) 00232 { 00233 TmplPte.u.Hard.PageFrameNumber = MiRemoveZeroPage(1); 00234 MI_WRITE_VALID_PTE(Pte, TmplPte); 00235 } 00236 00237 /* Get the PDE */ 00238 Pte = MiAddressToPde(Address); 00239 if (!Pte->u.Hard.Valid) 00240 { 00241 TmplPte.u.Hard.PageFrameNumber = MiRemoveZeroPage(2); 00242 MI_WRITE_VALID_PTE(Pte, TmplPte); 00243 } 00244 00245 /* Unlock PFN database */ 00246 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 00247 } 00248 else 00249 { 00250 /* Get the PXE */ 00251 Pte = MiAddressToPxe(Address); 00252 if (!Pte->u.Hard.Valid) 00253 return NULL; 00254 00255 /* Get the PPE */ 00256 Pte = MiAddressToPpe(Address); 00257 if (!Pte->u.Hard.Valid) 00258 return NULL; 00259 00260 /* Get the PDE */ 00261 Pte = MiAddressToPde(Address); 00262 if (!Pte->u.Hard.Valid) 00263 return NULL; 00264 } 00265 00266 return MiAddressToPte(Address); 00267 } 00268 00269 static 00270 ULONG64 00271 MiGetPteValueForProcess( 00272 PEPROCESS Process, 00273 PVOID Address) 00274 { 00275 PMMPTE Pte; 00276 ULONG64 PteValue; 00277 00278 Pte = MiGetPteForProcess(Process, Address, FALSE); 00279 PteValue = Pte ? Pte->u.Long : 0; 00280 00281 if (MiIsHyperspaceAddress(Pte)) 00282 MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pte)); 00283 00284 return PteValue; 00285 } 00286 00287 ULONG 00288 NTAPI 00289 MiGetPteProtection(MMPTE Pte) 00290 { 00291 ULONG Protect; 00292 00293 if (!Pte.u.Flush.Valid) 00294 { 00295 Protect = PAGE_NOACCESS; 00296 } 00297 else if (Pte.u.Flush.NoExecute) 00298 { 00299 if (Pte.u.Flush.CopyOnWrite) 00300 Protect = PAGE_WRITECOPY; 00301 else if (Pte.u.Flush.Write) 00302 Protect = PAGE_READWRITE; 00303 else 00304 Protect = PAGE_READONLY; 00305 } 00306 else 00307 { 00308 if (Pte.u.Flush.CopyOnWrite) 00309 Protect = PAGE_EXECUTE_WRITECOPY; 00310 else if (Pte.u.Flush.Write) 00311 Protect = PAGE_EXECUTE_READWRITE; 00312 else 00313 Protect = PAGE_EXECUTE_READ; 00314 } 00315 00316 if (Pte.u.Flush.CacheDisable) 00317 Protect |= PAGE_NOCACHE; 00318 00319 if (Pte.u.Flush.WriteThrough) 00320 Protect |= PAGE_WRITETHROUGH; 00321 00322 // PAGE_GUARD ? 00323 return Protect; 00324 } 00325 00326 VOID 00327 NTAPI 00328 MiSetPteProtection(PMMPTE Pte, ULONG Protection) 00329 { 00330 Pte->u.Flush.CopyOnWrite = (Protection & PAGE_WRITECOPY_ANY) ? 1 : 0; 00331 Pte->u.Flush.Write = (Protection & PAGE_WRITE_ANY) ? 1 : 0; 00332 Pte->u.Flush.CacheDisable = (Protection & PAGE_NOCACHE) ? 1 : 0; 00333 Pte->u.Flush.WriteThrough = (Protection & PAGE_WRITETHROUGH) ? 1 : 0; 00334 00335 // FIXME: This doesn't work. Why? 00336 // Pte->u.Flush.NoExecute = (Protection & PAGE_EXECUTE_ANY) ? 0 : 1; 00337 } 00338 00339 /* FUNCTIONS ***************************************************************/ 00340 00341 PFN_NUMBER 00342 NTAPI 00343 MmGetPfnForProcess(PEPROCESS Process, 00344 PVOID Address) 00345 { 00346 MMPTE Pte; 00347 Pte.u.Long = MiGetPteValueForProcess(Process, Address); 00348 return Pte.u.Hard.Valid ? Pte.u.Hard.PageFrameNumber : 0; 00349 } 00350 00351 PHYSICAL_ADDRESS 00352 NTAPI 00353 MmGetPhysicalAddress(PVOID Address) 00354 { 00355 PHYSICAL_ADDRESS p; 00356 MMPTE Pte; 00357 00358 Pte.u.Long = MiGetPteValueForProcess(NULL, Address); 00359 if (Pte.u.Hard.Valid) 00360 { 00361 p.QuadPart = Pte.u.Hard.PageFrameNumber * PAGE_SIZE; 00362 p.u.LowPart |= (ULONG_PTR)Address & (PAGE_SIZE - 1); 00363 } 00364 else 00365 { 00366 p.QuadPart = 0; 00367 } 00368 00369 return p; 00370 } 00371 00372 BOOLEAN 00373 NTAPI 00374 MmIsPagePresent(PEPROCESS Process, PVOID Address) 00375 { 00376 MMPTE Pte; 00377 Pte.u.Long = MiGetPteValueForProcess(Process, Address); 00378 return (BOOLEAN)Pte.u.Hard.Valid; 00379 } 00380 00381 BOOLEAN 00382 NTAPI 00383 MmIsPageSwapEntry(PEPROCESS Process, PVOID Address) 00384 { 00385 MMPTE Pte; 00386 Pte.u.Long = MiGetPteValueForProcess(Process, Address); 00387 return Pte.u.Hard.Valid && Pte.u.Soft.Transition; 00388 } 00389 00390 static PMMPTE 00391 MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create) 00392 { 00393 __debugbreak(); 00394 return 0; 00395 } 00396 00397 BOOLEAN MmUnmapPageTable(PMMPTE Pt) 00398 { 00399 ASSERT(FALSE); 00400 return 0; 00401 } 00402 00403 static ULONG64 MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address) 00404 { 00405 MMPTE Pte, *PointerPte; 00406 00407 PointerPte = MmGetPageTableForProcess(Process, Address, FALSE); 00408 if (PointerPte) 00409 { 00410 Pte = *PointerPte; 00411 MmUnmapPageTable(PointerPte); 00412 return Pte.u.Long; 00413 } 00414 return 0; 00415 } 00416 00417 VOID 00418 NTAPI 00419 MmGetPageFileMapping( 00420 PEPROCESS Process, 00421 PVOID Address, 00422 SWAPENTRY* SwapEntry) 00423 { 00424 ULONG64 Entry = MmGetPageEntryForProcess(Process, Address); 00425 *SwapEntry = Entry >> 1; 00426 } 00427 00428 BOOLEAN 00429 NTAPI 00430 MmIsDirtyPage(PEPROCESS Process, PVOID Address) 00431 { 00432 MMPTE Pte; 00433 Pte.u.Long = MiGetPteValueForProcess(Process, Address); 00434 return Pte.u.Hard.Valid && Pte.u.Hard.Dirty; 00435 } 00436 00437 ULONG 00438 NTAPI 00439 MmGetPageProtect(PEPROCESS Process, PVOID Address) 00440 { 00441 MMPTE Pte; 00442 00443 Pte.u.Long = MiGetPteValueForProcess(Process, Address); 00444 00445 return MiGetPteProtection(Pte); 00446 } 00447 00448 VOID 00449 NTAPI 00450 MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect) 00451 { 00452 PMMPTE Pte; 00453 MMPTE NewPte; 00454 00455 Pte = MiGetPteForProcess(Process, Address, FALSE); 00456 ASSERT(Pte != NULL); 00457 00458 NewPte = *Pte; 00459 00460 MiSetPteProtection(&NewPte, flProtect); 00461 00462 InterlockedExchangePte(Pte, NewPte); 00463 00464 MiFlushTlb(Pte, Address); 00465 } 00466 00467 VOID 00468 NTAPI 00469 MmSetCleanPage(PEPROCESS Process, PVOID Address) 00470 { 00471 PMMPTE Pte; 00472 00473 Pte = MiGetPteForProcess(Process, Address, FALSE); 00474 if (!Pte) 00475 { 00476 KeBugCheckEx(MEMORY_MANAGEMENT, 0x1234, (ULONG64)Address, 0, 0); 00477 } 00478 00479 /* Ckear the dirty bit */ 00480 if (InterlockedBitTestAndReset64((PVOID)Pte, 6)) 00481 { 00482 if (!MiIsHyperspaceAddress(Pte)) 00483 __invlpg(Address); 00484 } 00485 00486 MiFlushTlb(Pte, Address); 00487 } 00488 00489 VOID 00490 NTAPI 00491 MmSetDirtyPage(PEPROCESS Process, PVOID Address) 00492 { 00493 PMMPTE Pte; 00494 00495 Pte = MiGetPteForProcess(Process, Address, FALSE); 00496 if (!Pte) 00497 { 00498 KeBugCheckEx(MEMORY_MANAGEMENT, 0x1234, (ULONG64)Address, 0, 0); 00499 } 00500 00501 /* Ckear the dirty bit */ 00502 if (InterlockedBitTestAndSet64((PVOID)Pte, 6)) 00503 { 00504 if (!MiIsHyperspaceAddress(Pte)) 00505 __invlpg(Address); 00506 } 00507 00508 MiFlushTlb(Pte, Address); 00509 } 00510 00511 00512 NTSTATUS 00513 NTAPI 00514 Mmi386ReleaseMmInfo(PEPROCESS Process) 00515 { 00516 UNIMPLEMENTED; 00517 return STATUS_UNSUCCESSFUL; 00518 } 00519 00520 VOID 00521 NTAPI 00522 MmDisableVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN* WasDirty, PPFN_NUMBER Page) 00523 { 00524 UNIMPLEMENTED; 00525 } 00526 00527 VOID 00528 NTAPI 00529 MmRawDeleteVirtualMapping(PVOID Address) 00530 { 00531 UNIMPLEMENTED; 00532 } 00533 00534 VOID 00535 NTAPI 00536 MmDeleteVirtualMapping( 00537 PEPROCESS Process, 00538 PVOID Address, 00539 BOOLEAN FreePage, 00540 BOOLEAN* WasDirty, 00541 PPFN_NUMBER Page) 00542 { 00543 PFN_NUMBER Pfn; 00544 PMMPTE Pte; 00545 MMPTE OldPte; 00546 00547 Pte = MiGetPteForProcess(Process, Address, FALSE); 00548 00549 if (Pte) 00550 { 00551 /* Atomically set the entry to zero and get the old value. */ 00552 OldPte.u.Long = InterlockedExchange64((LONG64*)&Pte->u.Long, 0); 00553 00554 if (OldPte.u.Hard.Valid) 00555 { 00556 Pfn = OldPte.u.Hard.PageFrameNumber; 00557 00558 //if (FreePage) 00559 //MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn); 00560 } 00561 else 00562 Pfn = 0; 00563 } 00564 else 00565 { 00566 OldPte.u.Long = 0; 00567 Pfn = 0; 00568 } 00569 00570 /* Return information to the caller */ 00571 if (WasDirty) 00572 *WasDirty = (BOOLEAN)OldPte.u.Hard.Dirty;; 00573 00574 if (Page) 00575 *Page = Pfn; 00576 00577 MiFlushTlb(Pte, Address); 00578 } 00579 00580 VOID 00581 NTAPI 00582 MmDeletePageFileMapping(PEPROCESS Process, PVOID Address, 00583 SWAPENTRY* SwapEntry) 00584 { 00585 UNIMPLEMENTED; 00586 } 00587 00588 00589 VOID 00590 NTAPI 00591 MmEnableVirtualMapping(PEPROCESS Process, PVOID Address) 00592 { 00593 UNIMPLEMENTED; 00594 } 00595 00596 00597 NTSTATUS 00598 NTAPI 00599 MmCreatePageFileMapping(PEPROCESS Process, 00600 PVOID Address, 00601 SWAPENTRY SwapEntry) 00602 { 00603 UNIMPLEMENTED; 00604 return STATUS_UNSUCCESSFUL; 00605 } 00606 00607 00608 NTSTATUS 00609 NTAPI 00610 MmCreateVirtualMappingUnsafe( 00611 PEPROCESS Process, 00612 PVOID Address, 00613 ULONG PageProtection, 00614 PPFN_NUMBER Pages, 00615 ULONG PageCount) 00616 { 00617 ULONG i; 00618 MMPTE TmplPte, *Pte; 00619 00620 ASSERT((ULONG_PTR)Address % PAGE_SIZE == 0); 00621 00622 /* Check if the range is valid */ 00623 if ((Process == NULL && Address < MmSystemRangeStart) || 00624 (Process != NULL && Address > MmHighestUserAddress)) 00625 { 00626 DPRINT1("Address 0x%p is invalid for process %p\n", Address, Process); 00627 ASSERT(FALSE); 00628 } 00629 00630 TmplPte.u.Long = 0; 00631 TmplPte.u.Hard.Valid = 1; 00632 MiSetPteProtection(&TmplPte, PageProtection); 00633 00634 TmplPte.u.Flush.Owner = (Address < MmHighestUserAddress) ? 1 : 0; 00635 00636 //__debugbreak(); 00637 00638 for (i = 0; i < PageCount; i++) 00639 { 00640 TmplPte.u.Hard.PageFrameNumber = Pages[i]; 00641 00642 Pte = MiGetPteForProcess(Process, Address, TRUE); 00643 00644 DPRINT("MmCreateVirtualMappingUnsafe, Address=%p, TmplPte=%p, Pte=%p\n", 00645 Address, TmplPte.u.Long, Pte); 00646 00647 if (InterlockedExchangePte(Pte, TmplPte)) 00648 { 00649 KeInvalidateTlbEntry(Address); 00650 } 00651 00652 if (MiIsHyperspaceAddress(Pte)) 00653 MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pte)); 00654 00655 Address = (PVOID)((ULONG64)Address + PAGE_SIZE); 00656 } 00657 00658 00659 return STATUS_SUCCESS; 00660 } 00661 00662 NTSTATUS 00663 NTAPI 00664 MmCreateVirtualMapping(PEPROCESS Process, 00665 PVOID Address, 00666 ULONG Protect, 00667 PPFN_NUMBER Pages, 00668 ULONG PageCount) 00669 { 00670 ULONG i; 00671 00672 ASSERT((ULONG_PTR)Address % PAGE_SIZE == 0); 00673 00674 for (i = 0; i < PageCount; i++) 00675 { 00676 if (!MmIsPageInUse(Pages[i])) 00677 { 00678 DPRINT1("Page %x not in use\n", Pages[i]); 00679 KeBugCheck(MEMORY_MANAGEMENT); 00680 } 00681 } 00682 00683 return MmCreateVirtualMappingUnsafe(Process, Address, Protect, Pages, PageCount); 00684 } 00685 00686 BOOLEAN 00687 NTAPI 00688 MmCreateProcessAddressSpace(IN ULONG MinWs, 00689 IN PEPROCESS Process, 00690 OUT PULONG_PTR DirectoryTableBase) 00691 { 00692 KIRQL OldIrql; 00693 PFN_NUMBER TableBasePfn, HyperPfn, HyperPdPfn, HyperPtPfn, WorkingSetPfn; 00694 PMMPTE SystemPte; 00695 MMPTE TempPte, PdePte; 00696 ULONG TableIndex; 00697 PMMPTE PageTablePointer; 00698 00699 /* Make sure we don't already have a page directory setup */ 00700 ASSERT(Process->Pcb.DirectoryTableBase[0] == 0); 00701 ASSERT(Process->Pcb.DirectoryTableBase[1] == 0); 00702 ASSERT(Process->WorkingSetPage == 0); 00703 00704 /* Choose a process color */ 00705 Process->NextPageColor = (USHORT)RtlRandom(&MmProcessColorSeed); 00706 00707 /* Setup the hyperspace lock */ 00708 KeInitializeSpinLock(&Process->HyperSpaceLock); 00709 00710 /* Lock PFN database */ 00711 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 00712 00713 /* Get a page for the table base and one for hyper space. The PFNs for 00714 these pages will be initialized in MmInitializeProcessAddressSpace, 00715 when we are already attached to the process. */ 00716 TableBasePfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process)); 00717 HyperPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process)); 00718 HyperPdPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process)); 00719 HyperPtPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process)); 00720 WorkingSetPfn = MiRemoveAnyPage(MI_GET_NEXT_PROCESS_COLOR(Process)); 00721 00722 /* Release PFN lock */ 00723 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 00724 00725 /* Zero pages */ 00726 MiZeroPhysicalPage(HyperPfn); 00727 MiZeroPhysicalPage(WorkingSetPfn); 00728 00729 /* Set the base directory pointers */ 00730 Process->WorkingSetPage = WorkingSetPfn; 00731 DirectoryTableBase[0] = TableBasePfn << PAGE_SHIFT; 00732 DirectoryTableBase[1] = HyperPfn << PAGE_SHIFT; 00733 00734 /* Get a PTE to map the page directory */ 00735 SystemPte = MiReserveSystemPtes(1, SystemPteSpace); 00736 ASSERT(SystemPte != NULL); 00737 00738 /* Get its address */ 00739 PageTablePointer = MiPteToAddress(SystemPte); 00740 00741 /* Build the PTE for the page directory and map it */ 00742 PdePte = ValidKernelPte; 00743 PdePte.u.Hard.PageFrameNumber = TableBasePfn; 00744 *SystemPte = PdePte; 00745 00747 //MiInitializePageDirectoryForProcess( 00748 00749 /* Copy the kernel mappings and zero out the rest */ 00750 TableIndex = PXE_PER_PAGE / 2; 00751 RtlZeroMemory(PageTablePointer, TableIndex * sizeof(MMPTE)); 00752 RtlCopyMemory(PageTablePointer + TableIndex, 00753 MiAddressToPxe(0) + TableIndex, 00754 PAGE_SIZE - TableIndex * sizeof(MMPTE)); 00755 00756 /* Sanity check */ 00757 ASSERT(MiAddressToPxi(MmHyperSpaceEnd) >= TableIndex); 00758 00759 /* Setup a PTE for the page directory mappings */ 00760 TempPte = ValidKernelPte; 00761 00762 /* Update the self mapping of the PML4 */ 00763 TableIndex = MiAddressToPxi((PVOID)PXE_SELFMAP); 00764 TempPte.u.Hard.PageFrameNumber = TableBasePfn; 00765 PageTablePointer[TableIndex] = TempPte; 00766 00767 /* Write the PML4 entry for hyperspace */ 00768 TableIndex = MiAddressToPxi((PVOID)HYPER_SPACE); 00769 TempPte.u.Hard.PageFrameNumber = HyperPfn; 00770 PageTablePointer[TableIndex] = TempPte; 00771 00772 /* Map the hyperspace PDPT to the system PTE */ 00773 PdePte.u.Hard.PageFrameNumber = HyperPfn; 00774 *SystemPte = PdePte; 00775 __invlpg(PageTablePointer); 00776 00777 /* Write the hyperspace entry for the first PD */ 00778 TempPte.u.Hard.PageFrameNumber = HyperPdPfn; 00779 PageTablePointer[0] = TempPte; 00780 00781 /* Map the hyperspace PD to the system PTE */ 00782 PdePte.u.Hard.PageFrameNumber = HyperPdPfn; 00783 *SystemPte = PdePte; 00784 __invlpg(PageTablePointer); 00785 00786 /* Write the hyperspace entry for the first PT */ 00787 TempPte.u.Hard.PageFrameNumber = HyperPtPfn; 00788 PageTablePointer[0] = TempPte; 00789 00790 /* Map the hyperspace PT to the system PTE */ 00791 PdePte.u.Hard.PageFrameNumber = HyperPtPfn; 00792 *SystemPte = PdePte; 00793 __invlpg(PageTablePointer); 00794 00795 /* Write the hyperspace PTE for the working set list index */ 00796 TempPte.u.Hard.PageFrameNumber = WorkingSetPfn; 00797 TableIndex = MiAddressToPti(MmWorkingSetList); 00798 PageTablePointer[TableIndex] = TempPte; 00799 00801 00802 /* Release the system PTE */ 00803 MiReleaseSystemPtes(SystemPte, 1, SystemPteSpace); 00804 00805 /* Switch to phase 1 initialization */ 00806 ASSERT(Process->AddressSpaceInitialized == 0); 00807 Process->AddressSpaceInitialized = 1; 00808 00809 return TRUE; 00810 } 00811 00812 /* EOF */ Generated on Sat May 26 2012 04:25:34 for ReactOS by
1.7.6.1
|