Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpagepae.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 00016 #if defined (ALLOC_PRAGMA) 00017 #pragma alloc_text(INIT, MmInitGlobalKernelPageDirectory) 00018 #pragma alloc_text(INIT, MiInitPageDirectoryMap) 00019 #endif 00020 00021 00022 /* GLOBALS *****************************************************************/ 00023 00024 #define PA_BIT_PRESENT (0) 00025 #define PA_BIT_READWRITE (1) 00026 #define PA_BIT_USER (2) 00027 #define PA_BIT_WT (3) 00028 #define PA_BIT_CD (4) 00029 #define PA_BIT_ACCESSED (5) 00030 #define PA_BIT_DIRTY (6) 00031 #define PA_BIT_GLOBAL (8) 00032 00033 #define PA_PRESENT (1 << PA_BIT_PRESENT) 00034 #define PA_READWRITE (1 << PA_BIT_READWRITE) 00035 #define PA_USER (1 << PA_BIT_USER) 00036 #define PA_DIRTY (1 << PA_BIT_DIRTY) 00037 #define PA_WT (1 << PA_BIT_WT) 00038 #define PA_CD (1 << PA_BIT_CD) 00039 #define PA_ACCESSED (1 << PA_BIT_ACCESSED) 00040 #define PA_GLOBAL (1 << PA_BIT_GLOBAL) 00041 00042 #define PAGETABLE_MAP (0xc0000000) 00043 #define PAGEDIRECTORY_MAP (0xc0000000 + (PAGETABLE_MAP / (1024))) 00044 00045 #define PAE_PAGEDIRECTORY_MAP (0xc0000000 + (PAGETABLE_MAP / (512))) 00046 00047 #define HYPERSPACE (Ke386Pae ? 0xc0800000 : 0xc0400000) 00048 #define IS_HYPERSPACE(v) (((ULONG)(v) >= HYPERSPACE && (ULONG)(v) < HYPERSPACE + 0x400000)) 00049 00050 ULONG MmGlobalKernelPageDirectory[1024]; 00051 ULONGLONG MmGlobalKernelPageDirectoryForPAE[2048]; 00052 00053 #define PTE_TO_PFN(X) ((X) >> PAGE_SHIFT) 00054 #define PFN_TO_PTE(X) ((X) << PAGE_SHIFT) 00055 00056 #define PAE_PTE_TO_PFN(X) (PAE_PAGE_MASK(X) >> PAGE_SHIFT) 00057 #define PAE_PFN_TO_PTE(X) ((X) << PAGE_SHIFT) 00058 00059 #if defined(__GNUC__) 00060 #define PTE_TO_PAGE(X) ((LARGE_INTEGER)(LONGLONG)(PAGE_MASK(X))) 00061 #else 00062 __inline LARGE_INTEGER PTE_TO_PAGE(ULONG npage) 00063 { 00064 LARGE_INTEGER dummy; 00065 dummy.QuadPart = (LONGLONG)(PAGE_MASK(npage)); 00066 return dummy; 00067 } 00068 #endif 00069 00070 extern BOOLEAN Ke386Pae; 00071 extern BOOLEAN Ke386NoExecute; 00072 00073 /* FUNCTIONS ***************************************************************/ 00074 00075 BOOLEAN MmUnmapPageTable(PULONG Pt); 00076 00077 ULONG_PTR 00078 NTAPI 00079 MiFlushTlbIpiRoutine(ULONG_PTR Address) 00080 { 00081 if (Address == (ULONGLONG)-1) 00082 { 00083 KeFlushCurrentTb(); 00084 } 00085 else if (Address == (ULONGLONG)-2) 00086 { 00087 KeFlushCurrentTb(); 00088 } 00089 else 00090 { 00091 __invlpg((PVOID)Address); 00092 } 00093 return 0; 00094 } 00095 00096 VOID 00097 MiFlushTlb(PULONG Pt, PVOID Address) 00098 { 00099 #ifdef CONFIG_SMP 00100 if (Pt) 00101 { 00102 MmUnmapPageTable(Pt); 00103 } 00104 if (KeNumberProcessors > 1) 00105 { 00106 KeIpiGenericCall(MiFlushTlbIpiRoutine, (ULONG_PTR)Address); 00107 } 00108 else 00109 { 00110 MiFlushTlbIpiRoutine((ULONG_PTR)Address); 00111 } 00112 #else 00113 if ((Pt && MmUnmapPageTable(Pt)) || Address >= MmSystemRangeStart) 00114 { 00115 __invlpg(Address); 00116 } 00117 #endif 00118 } 00119 00120 00121 00122 PULONG 00123 MmGetPageDirectory(VOID) 00124 { 00125 return (PULONG)__readcr3(); 00126 } 00127 00128 static ULONG 00129 ProtectToPTE(ULONG flProtect) 00130 { 00131 ULONG Attributes = 0; 00132 00133 if (flProtect & (PAGE_NOACCESS|PAGE_GUARD)) 00134 { 00135 Attributes = 0; 00136 } 00137 else if (flProtect & PAGE_IS_WRITABLE) 00138 { 00139 Attributes = PA_PRESENT | PA_READWRITE; 00140 } 00141 else if (flProtect & (PAGE_IS_READABLE | PAGE_IS_EXECUTABLE)) 00142 { 00143 Attributes = PA_PRESENT; 00144 } 00145 else 00146 { 00147 DPRINT1("Unknown main protection type.\n"); 00148 ASSERT(FALSE); 00149 } 00150 if (Ke386NoExecute && 00151 !(flProtect & PAGE_IS_EXECUTABLE)) 00152 { 00153 Attributes = Attributes | 0x80000000; 00154 } 00155 00156 if (flProtect & PAGE_SYSTEM) 00157 { 00158 } 00159 else 00160 { 00161 Attributes = Attributes | PA_USER; 00162 } 00163 if (flProtect & PAGE_NOCACHE) 00164 { 00165 Attributes = Attributes | PA_CD; 00166 } 00167 if (flProtect & PAGE_WRITETHROUGH) 00168 { 00169 Attributes = Attributes | PA_WT; 00170 } 00171 return(Attributes); 00172 } 00173 00174 #define ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (1024 * PAGE_SIZE)) 00175 00176 #define ADDR_TO_PDE(v) (PULONG)(PAGEDIRECTORY_MAP + \ 00177 ((((ULONG)(v)) / (1024 * 1024))&(~0x3))) 00178 #define ADDR_TO_PTE(v) (PULONG)(PAGETABLE_MAP + ((((ULONG)(v) / 1024))&(~0x3))) 00179 00180 #define ADDR_TO_PDE_OFFSET(v) ((((ULONG)(v)) / (1024 * PAGE_SIZE))) 00181 00182 #define ADDR_TO_PTE_OFFSET(v) ((((ULONG)(v)) % (1024 * PAGE_SIZE)) / PAGE_SIZE) 00183 00184 00185 #define PAE_ADDR_TO_PAGE_TABLE(v) (((ULONG)(v)) / (512 * PAGE_SIZE)) 00186 00187 #define PAE_ADDR_TO_PDE(v) (PULONGLONG) (PAE_PAGEDIRECTORY_MAP + \ 00188 ((((ULONG_PTR)(v)) / (512 * 512))&(~0x7))) 00189 #define PAE_ADDR_TO_PTE(v) (PULONGLONG) (PAGETABLE_MAP + ((((ULONG_PTR)(v) / 512))&(~0x7))) 00190 00191 00192 #define PAE_ADDR_TO_PDTE_OFFSET(v) (((ULONG_PTR)(v)) / (512 * 512 * PAGE_SIZE)) 00193 00194 #define PAE_ADDR_TO_PDE_PAGE_OFFSET(v) ((((ULONG_PTR)(v)) % (512 * 512 * PAGE_SIZE)) / (512 * PAGE_SIZE)) 00195 00196 #define PAE_ADDR_TO_PDE_OFFSET(v) (((ULONG_PTR)(v))/ (512 * PAGE_SIZE)) 00197 00198 #define PAE_ADDR_TO_PTE_OFFSET(v) ((((ULONG_PTR)(v)) % (512 * PAGE_SIZE)) / PAGE_SIZE) 00199 00200 00201 NTSTATUS 00202 NTAPI 00203 Mmi386ReleaseMmInfo(PEPROCESS Process) 00204 { 00205 PUSHORT LdtDescriptor; 00206 ULONG LdtBase; 00207 ULONG i, j; 00208 00209 DPRINT("Mmi386ReleaseMmInfo(Process %x)\n",Process); 00210 00211 LdtDescriptor = (PUSHORT) &Process->Pcb.LdtDescriptor; 00212 LdtBase = LdtDescriptor[1] | 00213 ((LdtDescriptor[2] & 0xff) << 16) | 00214 ((LdtDescriptor[3] & ~0xff) << 16); 00215 00216 DPRINT("LdtBase: %x\n", LdtBase); 00217 00218 if (LdtBase) 00219 { 00220 ExFreePool((PVOID) LdtBase); 00221 } 00222 00223 if (Ke386Pae) 00224 { 00225 PULONGLONG PageDirTable; 00226 PULONGLONG PageDir; 00227 PULONGLONG Pde; 00228 ULONG k; 00229 00230 PageDirTable = (PULONGLONG)MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process->Pcb.DirectoryTableBase.QuadPart)); 00231 for (i = 0; i < 4; i++) 00232 { 00233 PageDir = (PULONGLONG)MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDirTable[i])); 00234 if (i < PAE_ADDR_TO_PDTE_OFFSET(MmSystemRangeStart)) 00235 { 00236 for (j = 0; j < 512; j++) 00237 { 00238 if (PageDir[j] != 0LL) 00239 { 00240 DPRINT1("ProcessId %d, Pde for %08x - %08x is not freed, RefCount %d\n", 00241 Process->UniqueProcessId, 00242 (i * 512 + j) * 512 * PAGE_SIZE, (i * 512 + j + 1) * 512 * PAGE_SIZE - 1, 00243 ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable[i*512 + j]); 00244 Pde = MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDir[j])); 00245 for (k = 0; k < 512; k++) 00246 { 00247 if(Pde[k] != 0) 00248 { 00249 if (Pde[k] & PA_PRESENT) 00250 { 00251 DPRINT1("Page at %08x is not freed\n", 00252 (i * 512 + j) * 512 * PAGE_SIZE + k * PAGE_SIZE); 00253 } 00254 else 00255 { 00256 DPRINT1("Swapentry %x at %x is not freed\n", 00257 (i * 512 + j) * 512 * PAGE_SIZE + k * PAGE_SIZE); 00258 } 00259 } 00260 } 00261 MmDeleteHyperspaceMapping(Pde); 00262 MmReleasePageMemoryConsumer(MC_NPPOOL, PAE_PTE_TO_PFN(PageDir[j])); 00263 } 00264 } 00265 } 00266 if (i == PAE_ADDR_TO_PDTE_OFFSET(HYPERSPACE)) 00267 { 00268 MmReleasePageMemoryConsumer(MC_NPPOOL, PAE_PTE_TO_PFN(PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE)])); 00269 MmReleasePageMemoryConsumer(MC_NPPOOL, PAE_PTE_TO_PFN(PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE)+1])); 00270 } 00271 MmDeleteHyperspaceMapping(PageDir); 00272 MmReleasePageMemoryConsumer(MC_NPPOOL, PAE_PTE_TO_PFN(PageDirTable[i])); 00273 } 00274 MmDeleteHyperspaceMapping((PVOID)PageDirTable); 00275 MmReleasePageMemoryConsumer(MC_NPPOOL, PAE_PTE_TO_PFN(Process->Pcb.DirectoryTableBase.QuadPart)); 00276 } 00277 else 00278 { 00279 PULONG Pde; 00280 PULONG PageDir; 00281 PageDir = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase.u.LowPart)); 00282 for (i = 0; i < ADDR_TO_PDE_OFFSET(MmSystemRangeStart); i++) 00283 { 00284 if (PageDir[i] != 0) 00285 { 00286 DPRINT1("Pde for %08x - %08x is not freed, RefCount %d\n", 00287 i * 4 * 1024 * 1024, (i + 1) * 4 * 1024 * 1024 - 1, 00288 ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable[i]); 00289 Pde = MmCreateHyperspaceMapping(PTE_TO_PFN(PageDir[i])); 00290 for (j = 0; j < 1024; j++) 00291 { 00292 if(Pde[j] != 0) 00293 { 00294 if (Pde[j] & PA_PRESENT) 00295 { 00296 DPRINT1("Page at %08x is not freed\n", 00297 i * 4 * 1024 * 1024 + j * PAGE_SIZE); 00298 } 00299 else 00300 { 00301 DPRINT1("Swapentry %x at %x is not freed\n", 00302 Pde[j], i * 4 * 1024 * 1024 + j * PAGE_SIZE); 00303 } 00304 } 00305 } 00306 MmDeleteHyperspaceMapping(Pde); 00307 MmReleasePageMemoryConsumer(MC_NPPOOL, PTE_TO_PFN(PageDir[i])); 00308 } 00309 } 00310 MmReleasePageMemoryConsumer(MC_NPPOOL, PTE_TO_PFN(PageDir[ADDR_TO_PDE_OFFSET(HYPERSPACE)])); 00311 MmDeleteHyperspaceMapping(PageDir); 00312 MmReleasePageMemoryConsumer(MC_NPPOOL, PTE_TO_PFN(Process->Pcb.DirectoryTableBase.u.LowPart)); 00313 } 00314 00315 #if defined(__GNUC__) 00316 00317 Process->Pcb.DirectoryTableBase.QuadPart = 0LL; 00318 #else 00319 00320 Process->Pcb.DirectoryTableBase.QuadPart = 0; 00321 #endif 00322 00323 DPRINT("Finished Mmi386ReleaseMmInfo()\n"); 00324 return(STATUS_SUCCESS); 00325 } 00326 00327 NTSTATUS 00328 NTAPI 00329 MmInitializeHandBuiltProcess(IN PEPROCESS Process, 00330 IN PLARGE_INTEGER DirectoryTableBase) 00331 { 00332 /* Share the directory base with the idle process */ 00333 *DirectoryTableBase = PsGetCurrentProcess()->Pcb.DirectoryTableBase; 00334 00335 /* Initialize the Addresss Space */ 00336 MmInitializeAddressSpace(Process, (PMADDRESS_SPACE)&Process->VadRoot); 00337 00338 /* The process now has an address space */ 00339 Process->HasAddressSpace = TRUE; 00340 return STATUS_SUCCESS; 00341 } 00342 00343 BOOLEAN 00344 NTAPI 00345 MmCreateProcessAddressSpace(IN ULONG MinWs, 00346 IN PEPROCESS Process, 00347 IN PLARGE_INTEGER DirectoryTableBase) 00348 { 00349 NTSTATUS Status; 00350 ULONG i, j; 00351 PFN_NUMBER Pfn[7]; 00352 ULONG Count; 00353 00354 DPRINT("MmCopyMmInfo(Src %x, Dest %x)\n", MinWs, Process); 00355 00356 Count = Ke386Pae ? 7 : 2; 00357 00358 for (i = 0; i < Count; i++) 00359 { 00360 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn[i]); 00361 if (!NT_SUCCESS(Status)) 00362 { 00363 for (j = 0; j < i; j++) 00364 { 00365 MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn[j]); 00366 } 00367 00368 return FALSE; 00369 } 00370 } 00371 00372 if (Ke386Pae) 00373 { 00374 PULONGLONG PageDirTable; 00375 PULONGLONG PageDir; 00376 00377 PageDirTable = MmCreateHyperspaceMapping(Pfn[0]); 00378 for (i = 0; i < 4; i++) 00379 { 00380 PageDirTable[i] = PAE_PFN_TO_PTE(Pfn[1+i]) | PA_PRESENT; 00381 } 00382 MmDeleteHyperspaceMapping(PageDirTable); 00383 for (i = PAE_ADDR_TO_PDTE_OFFSET(MmSystemRangeStart); i < 4; i++) 00384 { 00385 PageDir = (PULONGLONG)MmCreateHyperspaceMapping(Pfn[i+1]); 00386 memcpy(PageDir, &MmGlobalKernelPageDirectoryForPAE[i * 512], 512 * sizeof(ULONGLONG)); 00387 if (PAE_ADDR_TO_PDTE_OFFSET(PAGETABLE_MAP) == i) 00388 { 00389 for (j = 0; j < 4; j++) 00390 { 00391 PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(PAGETABLE_MAP) + j] = PAE_PFN_TO_PTE(Pfn[1+j]) | PA_PRESENT | PA_READWRITE; 00392 } 00393 } 00394 if (PAE_ADDR_TO_PDTE_OFFSET(HYPERSPACE) == i) 00395 { 00396 PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE)] = PAE_PFN_TO_PTE(Pfn[5]) | PA_PRESENT | PA_READWRITE; 00397 PageDir[PAE_ADDR_TO_PDE_PAGE_OFFSET(HYPERSPACE)+1] = PAE_PFN_TO_PTE(Pfn[6]) | PA_PRESENT | PA_READWRITE; 00398 } 00399 MmDeleteHyperspaceMapping(PageDir); 00400 } 00401 } 00402 else 00403 { 00404 PULONG PageDirectory; 00405 PageDirectory = MmCreateHyperspaceMapping(Pfn[0]); 00406 00407 memcpy(PageDirectory + ADDR_TO_PDE_OFFSET(MmSystemRangeStart), 00408 MmGlobalKernelPageDirectory + ADDR_TO_PDE_OFFSET(MmSystemRangeStart), 00409 (1024 - ADDR_TO_PDE_OFFSET(MmSystemRangeStart)) * sizeof(ULONG)); 00410 00411 DPRINT("Addr %x\n",ADDR_TO_PDE_OFFSET(PAGETABLE_MAP)); 00412 PageDirectory[ADDR_TO_PDE_OFFSET(PAGETABLE_MAP)] = PFN_TO_PTE(Pfn[0]) | PA_PRESENT | PA_READWRITE; 00413 PageDirectory[ADDR_TO_PDE_OFFSET(HYPERSPACE)] = PFN_TO_PTE(Pfn[1]) | PA_PRESENT | PA_READWRITE; 00414 00415 MmDeleteHyperspaceMapping(PageDirectory); 00416 } 00417 00418 DirectoryTableBase->QuadPart = PFN_TO_PTE(Pfn[0]); 00419 DPRINT("Finished MmCopyMmInfo(): %I64x\n", DirectoryTableBase->QuadPart); 00420 return TRUE; 00421 } 00422 00423 VOID 00424 NTAPI 00425 MmDeletePageTable(PEPROCESS Process, PVOID Address) 00426 { 00427 PEPROCESS CurrentProcess = PsGetCurrentProcess(); 00428 00429 if (Process != NULL && Process != CurrentProcess) 00430 { 00431 KeAttachProcess(&Process->Pcb); 00432 } 00433 00434 if (Ke386Pae) 00435 { 00436 ULONGLONG ZeroPde = 0LL; 00437 (void)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address), &ZeroPde); 00438 MiFlushTlb((PULONG)PAE_ADDR_TO_PDE(Address), PAE_ADDR_TO_PTE(Address)); 00439 } 00440 else 00441 { 00442 *(ADDR_TO_PDE(Address)) = 0; 00443 MiFlushTlb(ADDR_TO_PDE(Address), ADDR_TO_PTE(Address)); 00444 } 00445 if (Address >= MmSystemRangeStart) 00446 { 00447 ASSERT(FALSE); 00448 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0; 00449 } 00450 if (Process != NULL && Process != CurrentProcess) 00451 { 00452 KeDetachProcess(); 00453 } 00454 } 00455 00456 VOID 00457 NTAPI 00458 MmFreePageTable(PEPROCESS Process, PVOID Address) 00459 { 00460 PEPROCESS CurrentProcess = PsGetCurrentProcess(); 00461 ULONG i; 00462 PFN_NUMBER Pfn; 00463 00464 DPRINT("ProcessId %d, Address %x\n", Process->UniqueProcessId, Address); 00465 if (Process != NULL && Process != CurrentProcess) 00466 { 00467 KeAttachProcess(&Process->Pcb); 00468 } 00469 if (Ke386Pae) 00470 { 00471 PULONGLONG PageTable; 00472 ULONGLONG ZeroPte = 0LL; 00473 PageTable = (PULONGLONG)PAGE_ROUND_DOWN((PVOID)PAE_ADDR_TO_PTE(Address)); 00474 for (i = 0; i < 512; i++) 00475 { 00476 if (PageTable[i] != 0LL) 00477 { 00478 DbgPrint("Page table entry not clear at %x/%x (is %I64x)\n", 00479 ((ULONG)Address / (4*1024*1024)), i, PageTable[i]); 00480 ASSERT(FALSE); 00481 } 00482 } 00483 Pfn = PAE_PTE_TO_PFN(*(PAE_ADDR_TO_PDE(Address))); 00484 (void)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PDE(Address), &ZeroPte); 00485 MiFlushTlb((PULONG)PAE_ADDR_TO_PDE(Address), PAE_ADDR_TO_PTE(Address)); 00486 } 00487 else 00488 { 00489 PULONG PageTable; 00490 PageTable = (PULONG)PAGE_ROUND_DOWN((PVOID)ADDR_TO_PTE(Address)); 00491 for (i = 0; i < 1024; i++) 00492 { 00493 if (PageTable[i] != 0) 00494 { 00495 DbgPrint("Page table entry not clear at %x/%x (is %x)\n", 00496 ((ULONG)Address / (4*1024*1024)), i, PageTable[i]); 00497 ASSERT(FALSE); 00498 } 00499 } 00500 Pfn = PTE_TO_PFN(*(ADDR_TO_PDE(Address))); 00501 *(ADDR_TO_PDE(Address)) = 0; 00502 MiFlushTlb(ADDR_TO_PDE(Address), ADDR_TO_PTE(Address)); 00503 } 00504 00505 if (Address >= MmSystemRangeStart) 00506 { 00507 // MmGlobalKernelPageDirectory[ADDR_TO_PDE_OFFSET(Address)] = 0; 00508 ASSERT(FALSE); 00509 } 00510 else 00511 { 00512 MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn); 00513 } 00514 if (Process != NULL && Process != CurrentProcess) 00515 { 00516 KeDetachProcess(); 00517 } 00518 } 00519 00520 static PULONGLONG 00521 MmGetPageTableForProcessForPAE(PEPROCESS Process, PVOID Address, BOOLEAN Create) 00522 { 00523 NTSTATUS Status; 00524 PFN_NUMBER Pfn; 00525 ULONGLONG Entry; 00526 ULONGLONG ZeroEntry = 0LL; 00527 PULONGLONG Pt; 00528 PULONGLONG PageDir; 00529 PULONGLONG PageDirTable; 00530 00531 DPRINT("MmGetPageTableForProcessForPAE(%x %x %d)\n", 00532 Process, Address, Create); 00533 if (Address >= (PVOID)PAGETABLE_MAP && Address < (PVOID)((ULONG_PTR)PAGETABLE_MAP + 0x800000)) 00534 { 00535 ASSERT(FALSE); 00536 } 00537 if (Address < MmSystemRangeStart && Process && Process != PsGetCurrentProcess()) 00538 { 00539 PageDirTable = MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process->Pcb.DirectoryTableBase.QuadPart)); 00540 if (PageDirTable == NULL) 00541 { 00542 ASSERT(FALSE); 00543 } 00544 PageDir = MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(PageDirTable[PAE_ADDR_TO_PDTE_OFFSET(Address)])); 00545 MmDeleteHyperspaceMapping(PageDirTable); 00546 if (PageDir == NULL) 00547 { 00548 ASSERT(FALSE); 00549 } 00550 PageDir += PAE_ADDR_TO_PDE_PAGE_OFFSET(Address); 00551 Entry = ExfInterlockedCompareExchange64UL(PageDir, &ZeroEntry, &ZeroEntry); 00552 if (Entry == 0LL) 00553 { 00554 if (Create == FALSE) 00555 { 00556 MmDeleteHyperspaceMapping(PageDir); 00557 return NULL; 00558 } 00559 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn); 00560 if (!NT_SUCCESS(Status)) 00561 { 00562 ASSERT(FALSE); 00563 } 00564 Entry = PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER; 00565 Entry = ExfInterlockedCompareExchange64UL(PageDir, &Entry, &ZeroEntry); 00566 if (Entry != 0LL) 00567 { 00568 MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn); 00569 Pfn = PAE_PTE_TO_PFN(Entry); 00570 } 00571 } 00572 else 00573 { 00574 Pfn = PAE_PTE_TO_PFN(Entry); 00575 } 00576 MmDeleteHyperspaceMapping(PageDir); 00577 Pt = MmCreateHyperspaceMapping(Pfn); 00578 if (Pt == NULL) 00579 { 00580 ASSERT(FALSE); 00581 } 00582 return Pt + PAE_ADDR_TO_PTE_OFFSET(Address); 00583 } 00584 PageDir = PAE_ADDR_TO_PDE(Address); 00585 if (0LL == ExfInterlockedCompareExchange64UL(PageDir, &ZeroEntry, &ZeroEntry)) 00586 { 00587 if (Address >= MmSystemRangeStart) 00588 { 00589 if (MmGlobalKernelPageDirectoryForPAE[PAE_ADDR_TO_PDE_OFFSET(Address)] == 0LL) 00590 { 00591 if (Create == FALSE) 00592 { 00593 return NULL; 00594 } 00595 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn); 00596 if (!NT_SUCCESS(Status)) 00597 { 00598 ASSERT(FALSE); 00599 } 00600 Entry = PAE_PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE; 00601 if (Ke386GlobalPagesEnabled) 00602 { 00603 Entry |= PA_GLOBAL; 00604 } 00605 if (0LL != ExfInterlockedCompareExchange64UL(&MmGlobalKernelPageDirectoryForPAE[PAE_ADDR_TO_PDE_OFFSET(Address)], &Entry, &ZeroEntry)) 00606 { 00607 MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn); 00608 } 00609 } 00610 (void)ExfInterlockedCompareExchange64UL(PageDir, &MmGlobalKernelPageDirectoryForPAE[PAE_ADDR_TO_PDE_OFFSET(Address)], &ZeroEntry); 00611 } 00612 else 00613 { 00614 if (Create == FALSE) 00615 { 00616 return NULL; 00617 } 00618 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn); 00619 if (!NT_SUCCESS(Status)) 00620 { 00621 ASSERT(FALSE); 00622 } 00623 Entry = PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER; 00624 Entry = ExfInterlockedCompareExchange64UL(PageDir, &Entry, &ZeroEntry); 00625 if (Entry != 0LL) 00626 { 00627 MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn); 00628 } 00629 } 00630 } 00631 return (PULONGLONG)PAE_ADDR_TO_PTE(Address); 00632 } 00633 00634 static PULONG 00635 MmGetPageTableForProcess(PEPROCESS Process, PVOID Address, BOOLEAN Create) 00636 { 00637 ULONG PdeOffset = ADDR_TO_PDE_OFFSET(Address); 00638 NTSTATUS Status; 00639 PFN_NUMBER Pfn; 00640 ULONG Entry; 00641 PULONG Pt, PageDir; 00642 00643 if (Address < MmSystemRangeStart && Process && Process != PsGetCurrentProcess()) 00644 { 00645 PageDir = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase.LowPart)); 00646 if (PageDir == NULL) 00647 { 00648 ASSERT(FALSE); 00649 } 00650 if (0 == InterlockedCompareExchangeUL(&PageDir[PdeOffset], 0, 0)) 00651 { 00652 if (Create == FALSE) 00653 { 00654 MmDeleteHyperspaceMapping(PageDir); 00655 return NULL; 00656 } 00657 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn); 00658 if (!NT_SUCCESS(Status) || Pfn == 0) 00659 { 00660 ASSERT(FALSE); 00661 } 00662 Entry = InterlockedCompareExchangeUL(&PageDir[PdeOffset], PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER, 0); 00663 if (Entry != 0) 00664 { 00665 MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn); 00666 Pfn = PTE_TO_PFN(Entry); 00667 } 00668 } 00669 else 00670 { 00671 Pfn = PTE_TO_PFN(PageDir[PdeOffset]); 00672 } 00673 MmDeleteHyperspaceMapping(PageDir); 00674 Pt = MmCreateHyperspaceMapping(Pfn); 00675 if (Pt == NULL) 00676 { 00677 ASSERT(FALSE); 00678 } 00679 return Pt + ADDR_TO_PTE_OFFSET(Address); 00680 } 00681 PageDir = ADDR_TO_PDE(Address); 00682 if (0 == InterlockedCompareExchangeUL(PageDir, 0, 0)) 00683 { 00684 if (Address >= MmSystemRangeStart) 00685 { 00686 if (0 == InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory[PdeOffset], 0, 0)) 00687 { 00688 if (Create == FALSE) 00689 { 00690 return NULL; 00691 } 00692 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn); 00693 if (!NT_SUCCESS(Status) || Pfn == 0) 00694 { 00695 ASSERT(FALSE); 00696 } 00697 Entry = PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE; 00698 if (Ke386GlobalPagesEnabled) 00699 { 00700 Entry |= PA_GLOBAL; 00701 } 00702 if(0 != InterlockedCompareExchangeUL(&MmGlobalKernelPageDirectory[PdeOffset], Entry, 0)) 00703 { 00704 MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn); 00705 } 00706 } 00707 (void)InterlockedExchangeUL(PageDir, MmGlobalKernelPageDirectory[PdeOffset]); 00708 } 00709 else 00710 { 00711 if (Create == FALSE) 00712 { 00713 return NULL; 00714 } 00715 Status = MmRequestPageMemoryConsumer(MC_NPPOOL, FALSE, &Pfn); 00716 if (!NT_SUCCESS(Status) || Pfn == 0) 00717 { 00718 ASSERT(FALSE); 00719 } 00720 Entry = InterlockedCompareExchangeUL(PageDir, PFN_TO_PTE(Pfn) | PA_PRESENT | PA_READWRITE | PA_USER, 0); 00721 if (Entry != 0) 00722 { 00723 MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn); 00724 } 00725 } 00726 } 00727 return (PULONG)ADDR_TO_PTE(Address); 00728 } 00729 00730 BOOLEAN MmUnmapPageTable(PULONG Pt) 00731 { 00732 if (Ke386Pae) 00733 { 00734 if ((PULONGLONG)Pt >= (PULONGLONG)PAGETABLE_MAP && (PULONGLONG)Pt < (PULONGLONG)PAGETABLE_MAP + 4*512*512) 00735 { 00736 return TRUE; 00737 } 00738 } 00739 else 00740 { 00741 if (Pt >= (PULONG)PAGETABLE_MAP && Pt < (PULONG)PAGETABLE_MAP + 1024*1024) 00742 { 00743 return TRUE; 00744 } 00745 } 00746 if (Pt) 00747 { 00748 MmDeleteHyperspaceMapping((PVOID)PAGE_ROUND_DOWN(Pt)); 00749 } 00750 return FALSE; 00751 } 00752 00753 static ULONGLONG MmGetPageEntryForProcessForPAE(PEPROCESS Process, PVOID Address) 00754 { 00755 ULONGLONG Pte; 00756 PULONGLONG Pt; 00757 00758 Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE); 00759 if (Pt) 00760 { 00761 Pte = *Pt; 00762 MmUnmapPageTable((PULONG)Pt); 00763 return Pte; 00764 } 00765 return 0; 00766 } 00767 00768 static ULONG MmGetPageEntryForProcess(PEPROCESS Process, PVOID Address) 00769 { 00770 ULONG Pte; 00771 PULONG Pt; 00772 00773 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 00774 if (Pt) 00775 { 00776 Pte = *Pt; 00777 MmUnmapPageTable(Pt); 00778 return Pte; 00779 } 00780 return 0; 00781 } 00782 00783 PFN_NUMBER 00784 NTAPI 00785 MmGetPfnForProcess(PEPROCESS Process, 00786 PVOID Address) 00787 { 00788 00789 if (Ke386Pae) 00790 { 00791 ULONGLONG Entry; 00792 Entry = MmGetPageEntryForProcessForPAE(Process, Address); 00793 if (!(Entry & PA_PRESENT)) 00794 { 00795 return 0; 00796 } 00797 return(PAE_PTE_TO_PFN(Entry)); 00798 } 00799 else 00800 { 00801 ULONG Entry; 00802 Entry = MmGetPageEntryForProcess(Process, Address); 00803 if (!(Entry & PA_PRESENT)) 00804 { 00805 return 0; 00806 } 00807 return(PTE_TO_PFN(Entry)); 00808 } 00809 } 00810 00811 VOID 00812 NTAPI 00813 MmDisableVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN* WasDirty, PPFN_NUMBER Page) 00814 /* 00815 * FUNCTION: Delete a virtual mapping 00816 */ 00817 { 00818 BOOLEAN WasValid; 00819 if (Ke386Pae) 00820 { 00821 ULONGLONG Pte; 00822 ULONGLONG tmpPte; 00823 PULONGLONG Pt; 00824 00825 Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE); 00826 if (Pt == NULL) 00827 { 00828 ASSERT(FALSE); 00829 } 00830 /* 00831 * Atomically disable the present bit and get the old value. 00832 */ 00833 do 00834 { 00835 Pte = *Pt; 00836 tmpPte = Pte & ~PA_PRESENT; 00837 } while (Pte != ExfInterlockedCompareExchange64UL(Pt, &tmpPte, &Pte)); 00838 00839 MiFlushTlb((PULONG)Pt, Address); 00840 WasValid = PAE_PAGE_MASK(Pte) != 0LL ? TRUE : FALSE; 00841 if (!WasValid) 00842 { 00843 ASSERT(FALSE); 00844 } 00845 00846 /* 00847 * Return some information to the caller 00848 */ 00849 if (WasDirty != NULL) 00850 { 00851 *WasDirty = Pte & PA_DIRTY ? TRUE : FALSE; 00852 } 00853 if (Page != NULL) 00854 { 00855 *Page = PAE_PTE_TO_PFN(Pte); 00856 } 00857 } 00858 else 00859 { 00860 ULONG Pte; 00861 PULONG Pt; 00862 00863 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 00864 if (Pt == NULL) 00865 { 00866 ASSERT(FALSE); 00867 } 00868 /* 00869 * Atomically disable the present bit and get the old value. 00870 */ 00871 do 00872 { 00873 Pte = *Pt; 00874 } while (Pte != InterlockedCompareExchangeUL(Pt, Pte & ~PA_PRESENT, Pte)); 00875 00876 MiFlushTlb(Pt, Address); 00877 WasValid = (PAGE_MASK(Pte) != 0); 00878 if (!WasValid) 00879 { 00880 ASSERT(FALSE); 00881 } 00882 00883 /* 00884 * Return some information to the caller 00885 */ 00886 if (WasDirty != NULL) 00887 { 00888 *WasDirty = Pte & PA_DIRTY; 00889 } 00890 if (Page != NULL) 00891 { 00892 *Page = PTE_TO_PFN(Pte); 00893 } 00894 } 00895 } 00896 00897 VOID 00898 NTAPI 00899 MmRawDeleteVirtualMapping(PVOID Address) 00900 { 00901 if (Ke386Pae) 00902 { 00903 PULONGLONG Pt; 00904 ULONGLONG ZeroPte = 0LL; 00905 Pt = MmGetPageTableForProcessForPAE(NULL, Address, FALSE); 00906 if (Pt) 00907 { 00908 /* 00909 * Set the entry to zero 00910 */ 00911 (void)ExfpInterlockedExchange64UL(Pt, &ZeroPte); 00912 MiFlushTlb((PULONG)Pt, Address); 00913 } 00914 } 00915 else 00916 { 00917 PULONG Pt; 00918 00919 Pt = MmGetPageTableForProcess(NULL, Address, FALSE); 00920 if (Pt && *Pt) 00921 { 00922 /* 00923 * Set the entry to zero 00924 */ 00925 (void)InterlockedExchangeUL(Pt, 0); 00926 MiFlushTlb(Pt, Address); 00927 } 00928 } 00929 } 00930 00931 VOID 00932 NTAPI 00933 MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN FreePage, 00934 BOOLEAN* WasDirty, PPFN_NUMBER Page) 00935 /* 00936 * FUNCTION: Delete a virtual mapping 00937 */ 00938 { 00939 BOOLEAN WasValid = FALSE; 00940 PFN_NUMBER Pfn; 00941 00942 DPRINT("MmDeleteVirtualMapping(%x, %x, %d, %x, %x)\n", 00943 Process, Address, FreePage, WasDirty, Page); 00944 if (Ke386Pae) 00945 { 00946 ULONGLONG Pte; 00947 PULONGLONG Pt; 00948 00949 Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE); 00950 if (Pt == NULL) 00951 { 00952 if (WasDirty != NULL) 00953 { 00954 *WasDirty = FALSE; 00955 } 00956 if (Page != NULL) 00957 { 00958 *Page = 0; 00959 } 00960 return; 00961 } 00962 00963 /* 00964 * Atomically set the entry to zero and get the old value. 00965 */ 00966 Pte = 0LL; 00967 Pte = ExfpInterlockedExchange64UL(Pt, &Pte); 00968 00969 MiFlushTlb((PULONG)Pt, Address); 00970 00971 WasValid = PAE_PAGE_MASK(Pte) != 0 ? TRUE : FALSE; 00972 if (WasValid) 00973 { 00974 Pfn = PAE_PTE_TO_PFN(Pte); 00975 MmMarkPageUnmapped(Pfn); 00976 } 00977 else 00978 { 00979 Pfn = 0; 00980 } 00981 00982 if (FreePage && WasValid) 00983 { 00984 MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn); 00985 } 00986 00987 /* 00988 * Return some information to the caller 00989 */ 00990 if (WasDirty != NULL) 00991 { 00992 *WasDirty = Pte & PA_DIRTY ? TRUE : FALSE; 00993 } 00994 if (Page != NULL) 00995 { 00996 *Page = Pfn; 00997 } 00998 } 00999 else 01000 { 01001 ULONG Pte; 01002 PULONG Pt; 01003 01004 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 01005 01006 if (Pt == NULL) 01007 { 01008 if (WasDirty != NULL) 01009 { 01010 *WasDirty = FALSE; 01011 } 01012 if (Page != NULL) 01013 { 01014 *Page = 0; 01015 } 01016 return; 01017 } 01018 01019 /* 01020 * Atomically set the entry to zero and get the old value. 01021 */ 01022 Pte = InterlockedExchangeUL(Pt, 0); 01023 01024 MiFlushTlb(Pt, Address); 01025 01026 WasValid = (PAGE_MASK(Pte) != 0); 01027 if (WasValid) 01028 { 01029 Pfn = PTE_TO_PFN(Pte); 01030 MmMarkPageUnmapped(Pfn); 01031 } 01032 else 01033 { 01034 Pfn = 0; 01035 } 01036 01037 if (FreePage && WasValid) 01038 { 01039 MmReleasePageMemoryConsumer(MC_NPPOOL, Pfn); 01040 } 01041 01042 /* 01043 * Return some information to the caller 01044 */ 01045 if (WasDirty != NULL) 01046 { 01047 *WasDirty = Pte & PA_DIRTY ? TRUE : FALSE; 01048 } 01049 if (Page != NULL) 01050 { 01051 *Page = Pfn; 01052 } 01053 } 01054 /* 01055 * Decrement the reference count for this page table. 01056 */ 01057 if (Process != NULL && WasValid && 01058 ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL && 01059 Address < MmSystemRangeStart) 01060 { 01061 PUSHORT Ptrc; 01062 ULONG Idx; 01063 01064 Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable; 01065 Idx = Ke386Pae ? PAE_ADDR_TO_PAGE_TABLE(Address) : ADDR_TO_PAGE_TABLE(Address); 01066 01067 Ptrc[Idx]--; 01068 if (Ptrc[Idx] == 0) 01069 { 01070 MmFreePageTable(Process, Address); 01071 } 01072 } 01073 } 01074 01075 VOID 01076 NTAPI 01077 MmDeletePageFileMapping(PEPROCESS Process, PVOID Address, 01078 SWAPENTRY* SwapEntry) 01079 /* 01080 * FUNCTION: Delete a virtual mapping 01081 */ 01082 { 01083 if (Ke386Pae) 01084 { 01085 ULONGLONG Pte; 01086 PULONGLONG Pt; 01087 01088 Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE); 01089 if (Pt == NULL) 01090 { 01091 *SwapEntry = 0; 01092 return; 01093 } 01094 01095 /* 01096 * Atomically set the entry to zero and get the old value. 01097 */ 01098 Pte = 0LL; 01099 Pte = ExfpInterlockedExchange64UL(Pt, &Pte); 01100 01101 MiFlushTlb((PULONG)Pt, Address); 01102 01103 /* 01104 * Decrement the reference count for this page table. 01105 */ 01106 if (Process != NULL && Pte && 01107 ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL && 01108 Address < MmSystemRangeStart) 01109 { 01110 PUSHORT Ptrc; 01111 01112 Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable; 01113 01114 Ptrc[PAE_ADDR_TO_PAGE_TABLE(Address)]--; 01115 if (Ptrc[PAE_ADDR_TO_PAGE_TABLE(Address)] == 0) 01116 { 01117 MmFreePageTable(Process, Address); 01118 } 01119 } 01120 01121 01122 /* 01123 * Return some information to the caller 01124 */ 01125 *SwapEntry = Pte >> 1; 01126 } 01127 else 01128 { 01129 ULONG Pte; 01130 PULONG Pt; 01131 01132 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 01133 01134 if (Pt == NULL) 01135 { 01136 *SwapEntry = 0; 01137 return; 01138 } 01139 01140 /* 01141 * Atomically set the entry to zero and get the old value. 01142 */ 01143 Pte = InterlockedExchangeUL(Pt, 0); 01144 01145 MiFlushTlb(Pt, Address); 01146 01147 /* 01148 * Decrement the reference count for this page table. 01149 */ 01150 if (Process != NULL && Pte && 01151 ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL && 01152 Address < MmSystemRangeStart) 01153 { 01154 PUSHORT Ptrc; 01155 01156 Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable; 01157 01158 Ptrc[ADDR_TO_PAGE_TABLE(Address)]--; 01159 if (Ptrc[ADDR_TO_PAGE_TABLE(Address)] == 0) 01160 { 01161 MmFreePageTable(Process, Address); 01162 } 01163 } 01164 01165 01166 /* 01167 * Return some information to the caller 01168 */ 01169 *SwapEntry = Pte >> 1; 01170 } 01171 } 01172 01173 BOOLEAN 01174 Mmi386MakeKernelPageTableGlobal(PVOID PAddress) 01175 { 01176 if (Ke386Pae) 01177 { 01178 PULONGLONG Pt; 01179 PULONGLONG Pde; 01180 Pde = PAE_ADDR_TO_PDE(PAddress); 01181 if (*Pde == 0LL) 01182 { 01183 Pt = MmGetPageTableForProcessForPAE(NULL, PAddress, FALSE); 01184 #if 0 01185 /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */ 01186 FLASH_TLB_ONE(PAddress); 01187 #endif 01188 if (Pt != NULL) 01189 { 01190 return TRUE; 01191 } 01192 } 01193 } 01194 else 01195 { 01196 PULONG Pt, Pde; 01197 Pde = ADDR_TO_PDE(PAddress); 01198 if (*Pde == 0) 01199 { 01200 Pt = MmGetPageTableForProcess(NULL, PAddress, FALSE); 01201 #if 0 01202 /* Non existing mappings are not cached within the tlb. We must not invalidate this entry */ 01203 FLASH_TLB_ONE(PAddress); 01204 #endif 01205 if (Pt != NULL) 01206 { 01207 return TRUE; 01208 } 01209 } 01210 } 01211 return(FALSE); 01212 } 01213 01214 BOOLEAN 01215 NTAPI 01216 MmIsDirtyPage(PEPROCESS Process, PVOID Address) 01217 { 01218 if (Ke386Pae) 01219 { 01220 return MmGetPageEntryForProcessForPAE(Process, Address) & PA_DIRTY ? TRUE : FALSE; 01221 } 01222 else 01223 { 01224 return MmGetPageEntryForProcess(Process, Address) & PA_DIRTY ? TRUE : FALSE; 01225 } 01226 } 01227 01228 BOOLEAN 01229 NTAPI 01230 MmIsAccessedAndResetAccessPage(PEPROCESS Process, PVOID Address) 01231 { 01232 if (Address < MmSystemRangeStart && Process == NULL) 01233 { 01234 DPRINT1("MmIsAccessedAndResetAccessPage is called for user space without a process.\n"); 01235 ASSERT(FALSE); 01236 } 01237 if (Ke386Pae) 01238 { 01239 PULONGLONG Pt; 01240 ULONGLONG Pte; 01241 ULONGLONG tmpPte; 01242 01243 Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE); 01244 if (Pt == NULL) 01245 { 01246 ASSERT(FALSE); 01247 } 01248 01249 do 01250 { 01251 Pte = *Pt; 01252 tmpPte = Pte & ~PA_ACCESSED; 01253 } while (Pte != ExfInterlockedCompareExchange64UL(Pt, &tmpPte, &Pte)); 01254 01255 if (Pte & PA_ACCESSED) 01256 { 01257 MiFlushTlb((PULONG)Pt, Address); 01258 return TRUE; 01259 } 01260 else 01261 { 01262 MmUnmapPageTable((PULONG)Pt); 01263 return FALSE; 01264 } 01265 } 01266 else 01267 { 01268 PULONG Pt; 01269 ULONG Pte; 01270 01271 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 01272 if (Pt == NULL) 01273 { 01274 ASSERT(FALSE); 01275 } 01276 01277 do 01278 { 01279 Pte = *Pt; 01280 } while (Pte != InterlockedCompareExchangeUL(Pt, Pte & ~PA_ACCESSED, Pte)); 01281 01282 if (Pte & PA_ACCESSED) 01283 { 01284 MiFlushTlb(Pt, Address); 01285 return TRUE; 01286 } 01287 else 01288 { 01289 MmUnmapPageTable(Pt); 01290 return FALSE; 01291 } 01292 } 01293 } 01294 01295 VOID 01296 NTAPI 01297 MmSetCleanPage(PEPROCESS Process, PVOID Address) 01298 { 01299 if (Address < MmSystemRangeStart && Process == NULL) 01300 { 01301 DPRINT1("MmSetCleanPage is called for user space without a process.\n"); 01302 ASSERT(FALSE); 01303 } 01304 if (Ke386Pae) 01305 { 01306 PULONGLONG Pt; 01307 ULONGLONG Pte; 01308 ULONGLONG tmpPte; 01309 01310 Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE); 01311 01312 if (Pt == NULL) 01313 { 01314 ASSERT(FALSE); 01315 } 01316 01317 do 01318 { 01319 Pte = *Pt; 01320 tmpPte = Pte & ~PA_DIRTY; 01321 } while (Pte != ExfInterlockedCompareExchange64UL(Pt, &tmpPte, &Pte)); 01322 01323 if (Pte & PA_DIRTY) 01324 { 01325 MiFlushTlb((PULONG)Pt, Address); 01326 } 01327 else 01328 { 01329 MmUnmapPageTable((PULONG)Pt); 01330 } 01331 } 01332 else 01333 { 01334 PULONG Pt; 01335 ULONG Pte; 01336 01337 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 01338 01339 if (Pt == NULL) 01340 { 01341 ASSERT(FALSE); 01342 } 01343 01344 do 01345 { 01346 Pte = *Pt; 01347 } while (Pte != InterlockedCompareExchangeUL(Pt, Pte & ~PA_DIRTY, Pte)); 01348 01349 if (Pte & PA_DIRTY) 01350 { 01351 MiFlushTlb(Pt, Address); 01352 } 01353 else 01354 { 01355 MmUnmapPageTable(Pt); 01356 } 01357 } 01358 } 01359 01360 VOID 01361 NTAPI 01362 MmSetDirtyPage(PEPROCESS Process, PVOID Address) 01363 { 01364 if (Address < MmSystemRangeStart && Process == NULL) 01365 { 01366 DPRINT1("MmSetDirtyPage is called for user space without a process.\n"); 01367 ASSERT(FALSE); 01368 } 01369 if (Ke386Pae) 01370 { 01371 PULONGLONG Pt; 01372 ULONGLONG Pte; 01373 ULONGLONG tmpPte; 01374 01375 Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE); 01376 if (Pt == NULL) 01377 { 01378 ASSERT(FALSE); 01379 } 01380 01381 do 01382 { 01383 Pte = *Pt; 01384 tmpPte = Pte | PA_DIRTY; 01385 } while (Pte != ExfInterlockedCompareExchange64UL(Pt, &tmpPte, &Pte)); 01386 if (!(Pte & PA_DIRTY)) 01387 { 01388 MiFlushTlb((PULONG)Pt, Address); 01389 } 01390 else 01391 { 01392 MmUnmapPageTable((PULONG)Pt); 01393 } 01394 } 01395 else 01396 { 01397 PULONG Pt; 01398 ULONG Pte; 01399 01400 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 01401 if (Pt == NULL) 01402 { 01403 ASSERT(FALSE); 01404 } 01405 01406 do 01407 { 01408 Pte = *Pt; 01409 } while (Pte != InterlockedCompareExchangeUL(Pt, Pte | PA_DIRTY, Pte)); 01410 if (!(Pte & PA_DIRTY)) 01411 { 01412 MiFlushTlb(Pt, Address); 01413 } 01414 else 01415 { 01416 MmUnmapPageTable(Pt); 01417 } 01418 } 01419 } 01420 01421 VOID 01422 NTAPI 01423 MmEnableVirtualMapping(PEPROCESS Process, PVOID Address) 01424 { 01425 if (Ke386Pae) 01426 { 01427 PULONGLONG Pt; 01428 ULONGLONG Pte; 01429 ULONGLONG tmpPte; 01430 01431 Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE); 01432 if (Pt == NULL) 01433 { 01434 ASSERT(FALSE); 01435 } 01436 01437 do 01438 { 01439 Pte = *Pt; 01440 tmpPte = Pte | PA_PRESENT; 01441 } while (Pte != ExfInterlockedCompareExchange64UL(Pt, &tmpPte, &Pte)); 01442 if (!(Pte & PA_PRESENT)) 01443 { 01444 MiFlushTlb((PULONG)Pt, Address); 01445 } 01446 else 01447 { 01448 MmUnmapPageTable((PULONG)Pt); 01449 } 01450 } 01451 else 01452 { 01453 PULONG Pt; 01454 ULONG Pte; 01455 01456 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 01457 if (Pt == NULL) 01458 { 01459 ASSERT(FALSE); 01460 } 01461 01462 do 01463 { 01464 Pte = *Pt; 01465 } while (Pte != InterlockedCompareExchangeUL(Pt, Pte | PA_PRESENT, Pte)); 01466 if (!(Pte & PA_PRESENT)) 01467 { 01468 MiFlushTlb(Pt, Address); 01469 } 01470 else 01471 { 01472 MmUnmapPageTable(Pt); 01473 } 01474 } 01475 } 01476 01477 BOOLEAN 01478 NTAPI 01479 MmIsPagePresent(PEPROCESS Process, PVOID Address) 01480 { 01481 if (Ke386Pae) 01482 { 01483 return MmGetPageEntryForProcessForPAE(Process, Address) & PA_PRESENT ? TRUE : FALSE; 01484 } 01485 else 01486 { 01487 return MmGetPageEntryForProcess(Process, Address) & PA_PRESENT ? TRUE : FALSE; 01488 } 01489 } 01490 01491 BOOLEAN 01492 NTAPI 01493 MmIsPageSwapEntry(PEPROCESS Process, PVOID Address) 01494 { 01495 if (Ke386Pae) 01496 { 01497 ULONGLONG Entry; 01498 Entry = MmGetPageEntryForProcessForPAE(Process, Address); 01499 return !(Entry & PA_PRESENT) && Entry != 0 ? TRUE : FALSE; 01500 } 01501 else 01502 { 01503 ULONG Entry; 01504 Entry = MmGetPageEntryForProcess(Process, Address); 01505 return !(Entry & PA_PRESENT) && Entry != 0 ? TRUE : FALSE; 01506 } 01507 } 01508 01509 NTSTATUS 01510 NTAPI 01511 MmCreateVirtualMappingForKernel(PVOID Address, 01512 ULONG flProtect, 01513 PPFN_NUMBER Pages, 01514 ULONG PageCount) 01515 { 01516 ULONG Attributes; 01517 ULONG i; 01518 PVOID Addr; 01519 ULONG PdeOffset, oldPdeOffset; 01520 BOOLEAN NoExecute = FALSE; 01521 01522 DPRINT("MmCreateVirtualMappingForKernel(%x, %x, %x, %d)\n", 01523 Address, flProtect, Pages, PageCount); 01524 01525 if (Address < MmSystemRangeStart) 01526 { 01527 DPRINT1("MmCreateVirtualMappingForKernel is called for user space\n"); 01528 ASSERT(FALSE); 01529 } 01530 01531 Attributes = ProtectToPTE(flProtect); 01532 if (Attributes & 0x80000000) 01533 { 01534 NoExecute = TRUE; 01535 } 01536 Attributes &= 0xfff; 01537 if (Ke386GlobalPagesEnabled) 01538 { 01539 Attributes |= PA_GLOBAL; 01540 } 01541 01542 Addr = Address; 01543 01544 if (Ke386Pae) 01545 { 01546 PULONGLONG Pt = NULL; 01547 ULONGLONG Pte; 01548 01549 oldPdeOffset = PAE_ADDR_TO_PDE_OFFSET(Addr) + 1; 01550 for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE)) 01551 { 01552 if (!(Attributes & PA_PRESENT) && Pages[i] != 0) 01553 { 01554 DPRINT1("Setting physical address but not allowing access at address " 01555 "0x%.8X with attributes %x/%x.\n", 01556 Addr, Attributes, flProtect); 01557 ASSERT(FALSE); 01558 } 01559 01560 PdeOffset = PAE_ADDR_TO_PDE_OFFSET(Addr); 01561 if (oldPdeOffset != PdeOffset) 01562 { 01563 Pt = MmGetPageTableForProcessForPAE(NULL, Addr, TRUE); 01564 if (Pt == NULL) 01565 { 01566 ASSERT(FALSE); 01567 } 01568 } 01569 else 01570 { 01571 Pt++; 01572 } 01573 oldPdeOffset = PdeOffset; 01574 01575 Pte = PFN_TO_PTE(Pages[i]) | Attributes; 01576 if (NoExecute) 01577 { 01578 Pte |= 0x8000000000000000LL; 01579 } 01580 Pte = ExfpInterlockedExchange64UL(Pt, &Pte); 01581 if (Pte != 0LL) 01582 { 01583 ASSERT(FALSE); 01584 } 01585 } 01586 } 01587 else 01588 { 01589 PULONG Pt; 01590 ULONG Pte; 01591 01592 oldPdeOffset = ADDR_TO_PDE_OFFSET(Addr); 01593 Pt = MmGetPageTableForProcess(NULL, Addr, TRUE); 01594 if (Pt == NULL) 01595 { 01596 ASSERT(FALSE); 01597 } 01598 Pt--; 01599 01600 for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE)) 01601 { 01602 if (!(Attributes & PA_PRESENT) && Pages[i] != 0) 01603 { 01604 DPRINT1("Setting physical address but not allowing access at address " 01605 "0x%.8X with attributes %x/%x.\n", 01606 Addr, Attributes, flProtect); 01607 ASSERT(FALSE); 01608 } 01609 01610 PdeOffset = ADDR_TO_PDE_OFFSET(Addr); 01611 if (oldPdeOffset != PdeOffset) 01612 { 01613 Pt = MmGetPageTableForProcess(NULL, Addr, TRUE); 01614 if (Pt == NULL) 01615 { 01616 ASSERT(FALSE); 01617 } 01618 } 01619 else 01620 { 01621 Pt++; 01622 } 01623 oldPdeOffset = PdeOffset; 01624 01625 Pte = *Pt; 01626 if (Pte != 0) 01627 { 01628 ASSERT(FALSE); 01629 } 01630 (void)InterlockedExchangeUL(Pt, PFN_TO_PTE(Pages[i]) | Attributes); 01631 } 01632 } 01633 01634 return(STATUS_SUCCESS); 01635 } 01636 01637 NTSTATUS 01638 NTAPI 01639 MmCreatePageFileMapping(PEPROCESS Process, 01640 PVOID Address, 01641 SWAPENTRY SwapEntry) 01642 { 01643 if (Process == NULL && Address < MmSystemRangeStart) 01644 { 01645 DPRINT1("No process\n"); 01646 ASSERT(FALSE); 01647 } 01648 if (Process != NULL && Address >= MmSystemRangeStart) 01649 { 01650 DPRINT1("Setting kernel address with process context\n"); 01651 ASSERT(FALSE); 01652 } 01653 if (SwapEntry & (1 << 31)) 01654 { 01655 ASSERT(FALSE); 01656 } 01657 01658 if (Ke386Pae) 01659 { 01660 PULONGLONG Pt; 01661 ULONGLONG Pte; 01662 ULONGLONG tmpPte; 01663 01664 Pt = MmGetPageTableForProcessForPAE(Process, Address, TRUE); 01665 if (Pt == NULL) 01666 { 01667 ASSERT(FALSE); 01668 } 01669 tmpPte = SwapEntry << 1; 01670 Pte = ExfpInterlockedExchange64UL(Pt, &tmpPte); 01671 if (PAE_PAGE_MASK((Pte)) != 0) 01672 { 01673 MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte))); 01674 } 01675 01676 if (Pte != 0) 01677 { 01678 MiFlushTlb((PULONG)Pt, Address); 01679 } 01680 else 01681 { 01682 MmUnmapPageTable((PULONG)Pt); 01683 } 01684 } 01685 else 01686 { 01687 PULONG Pt; 01688 ULONG Pte; 01689 01690 Pt = MmGetPageTableForProcess(Process, Address, TRUE); 01691 if (Pt == NULL) 01692 { 01693 ASSERT(FALSE); 01694 } 01695 Pte = *Pt; 01696 if (PAGE_MASK((Pte)) != 0) 01697 { 01698 MmMarkPageUnmapped(PTE_TO_PFN((Pte))); 01699 } 01700 (void)InterlockedExchangeUL(Pt, SwapEntry << 1); 01701 if (Pte != 0) 01702 { 01703 MiFlushTlb(Pt, Address); 01704 } 01705 else 01706 { 01707 MmUnmapPageTable(Pt); 01708 } 01709 } 01710 if (Process != NULL && 01711 ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL && 01712 Address < MmSystemRangeStart) 01713 { 01714 PUSHORT Ptrc; 01715 ULONG Idx; 01716 01717 Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable; 01718 Idx = Ke386Pae ? PAE_ADDR_TO_PAGE_TABLE(Address) : ADDR_TO_PAGE_TABLE(Address); 01719 Ptrc[Idx]++; 01720 } 01721 return(STATUS_SUCCESS); 01722 } 01723 01724 01725 NTSTATUS 01726 NTAPI 01727 MmCreateVirtualMappingUnsafe(PEPROCESS Process, 01728 PVOID Address, 01729 ULONG flProtect, 01730 PPFN_NUMBER Pages, 01731 ULONG PageCount) 01732 { 01733 ULONG Attributes; 01734 PVOID Addr; 01735 ULONG i; 01736 ULONG oldPdeOffset, PdeOffset; 01737 BOOLEAN NoExecute = FALSE; 01738 01739 DPRINT("MmCreateVirtualMappingUnsafe(%x, %x, %x, %x (%x), %d)\n", 01740 Process, Address, flProtect, Pages, *Pages, PageCount); 01741 01742 if (Process == NULL) 01743 { 01744 if (Address < MmSystemRangeStart) 01745 { 01746 DPRINT1("No process\n"); 01747 ASSERT(FALSE); 01748 } 01749 if (PageCount > 0x10000 || 01750 (ULONG_PTR) Address / PAGE_SIZE + PageCount > 0x100000) 01751 { 01752 DPRINT1("Page count to large\n"); 01753 ASSERT(FALSE); 01754 } 01755 } 01756 else 01757 { 01758 if (Address >= MmSystemRangeStart) 01759 { 01760 DPRINT1("Setting kernel address with process context\n"); 01761 ASSERT(FALSE); 01762 } 01763 if (PageCount > (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE || 01764 (ULONG_PTR) Address / PAGE_SIZE + PageCount > 01765 (ULONG_PTR)MmSystemRangeStart / PAGE_SIZE) 01766 { 01767 DPRINT1("Page Count to large\n"); 01768 ASSERT(FALSE); 01769 } 01770 } 01771 01772 Attributes = ProtectToPTE(flProtect); 01773 if (Attributes & 0x80000000) 01774 { 01775 NoExecute = TRUE; 01776 } 01777 Attributes &= 0xfff; 01778 if (Address >= MmSystemRangeStart) 01779 { 01780 Attributes &= ~PA_USER; 01781 if (Ke386GlobalPagesEnabled) 01782 { 01783 Attributes |= PA_GLOBAL; 01784 } 01785 } 01786 else 01787 { 01788 Attributes |= PA_USER; 01789 } 01790 01791 Addr = Address; 01792 01793 if (Ke386Pae) 01794 { 01795 ULONGLONG Pte, tmpPte; 01796 PULONGLONG Pt = NULL; 01797 01798 oldPdeOffset = PAE_ADDR_TO_PDE_OFFSET(Addr) + 1; 01799 for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE)) 01800 { 01801 if (!(Attributes & PA_PRESENT) && Pages[i] != 0) 01802 { 01803 DPRINT1("Setting physical address but not allowing access at address " 01804 "0x%.8X with attributes %x/%x.\n", 01805 Addr, Attributes, flProtect); 01806 ASSERT(FALSE); 01807 } 01808 PdeOffset = PAE_ADDR_TO_PDE_OFFSET(Addr); 01809 if (oldPdeOffset != PdeOffset) 01810 { 01811 MmUnmapPageTable((PULONG)Pt); 01812 Pt = MmGetPageTableForProcessForPAE(Process, Addr, TRUE); 01813 if (Pt == NULL) 01814 { 01815 ASSERT(FALSE); 01816 } 01817 } 01818 else 01819 { 01820 Pt++; 01821 } 01822 oldPdeOffset = PdeOffset; 01823 01824 MmMarkPageMapped(Pages[i]); 01825 tmpPte = PAE_PFN_TO_PTE(Pages[i]) | Attributes; 01826 if (NoExecute) 01827 { 01828 tmpPte |= 0x8000000000000000LL; 01829 } 01830 Pte = ExfpInterlockedExchange64UL(Pt, &tmpPte); 01831 if (PAE_PAGE_MASK((Pte)) != 0LL && !((Pte) & PA_PRESENT)) 01832 { 01833 ASSERT(FALSE); 01834 } 01835 if (PAE_PAGE_MASK((Pte)) != 0LL) 01836 { 01837 MmMarkPageUnmapped(PAE_PTE_TO_PFN((Pte))); 01838 } 01839 if (Address < MmSystemRangeStart && 01840 ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL && 01841 Attributes & PA_PRESENT) 01842 { 01843 PUSHORT Ptrc; 01844 01845 Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable; 01846 01847 Ptrc[PAE_ADDR_TO_PAGE_TABLE(Addr)]++; 01848 } 01849 if (Pte != 0LL) 01850 { 01851 if (Address > MmSystemRangeStart || 01852 (Pt >= (PULONGLONG)PAGETABLE_MAP && Pt < (PULONGLONG)PAGETABLE_MAP + 4*512*512)) 01853 { 01854 MiFlushTlb((PULONG)Pt, Address); 01855 } 01856 } 01857 } 01858 if (Addr > Address) 01859 { 01860 MmUnmapPageTable((PULONG)Pt); 01861 } 01862 } 01863 else 01864 { 01865 PULONG Pt = NULL; 01866 ULONG Pte; 01867 oldPdeOffset = ADDR_TO_PDE_OFFSET(Addr) + 1; 01868 for (i = 0; i < PageCount; i++, Addr = (PVOID)((ULONG_PTR)Addr + PAGE_SIZE)) 01869 { 01870 if (!(Attributes & PA_PRESENT) && Pages[i] != 0) 01871 { 01872 DPRINT1("Setting physical address but not allowing access at address " 01873 "0x%.8X with attributes %x/%x.\n", 01874 Addr, Attributes, flProtect); 01875 ASSERT(FALSE); 01876 } 01877 PdeOffset = ADDR_TO_PDE_OFFSET(Addr); 01878 if (oldPdeOffset != PdeOffset) 01879 { 01880 MmUnmapPageTable(Pt); 01881 Pt = MmGetPageTableForProcess(Process, Addr, TRUE); 01882 if (Pt == NULL) 01883 { 01884 ASSERT(FALSE); 01885 } 01886 } 01887 else 01888 { 01889 Pt++; 01890 } 01891 oldPdeOffset = PdeOffset; 01892 01893 Pte = *Pt; 01894 MmMarkPageMapped(Pages[i]); 01895 if (PAGE_MASK((Pte)) != 0 && !((Pte) & PA_PRESENT)) 01896 { 01897 ASSERT(FALSE); 01898 } 01899 if (PAGE_MASK((Pte)) != 0) 01900 { 01901 MmMarkPageUnmapped(PTE_TO_PFN((Pte))); 01902 } 01903 (void)InterlockedExchangeUL(Pt, PFN_TO_PTE(Pages[i]) | Attributes); 01904 if (Address < MmSystemRangeStart && 01905 ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable != NULL && 01906 Attributes & PA_PRESENT) 01907 { 01908 PUSHORT Ptrc; 01909 01910 Ptrc = ((PMADDRESS_SPACE)&Process->VadRoot)->PageTableRefCountTable; 01911 01912 Ptrc[ADDR_TO_PAGE_TABLE(Addr)]++; 01913 } 01914 if (Pte != 0) 01915 { 01916 if (Address > MmSystemRangeStart || 01917 (Pt >= (PULONG)PAGETABLE_MAP && Pt < (PULONG)PAGETABLE_MAP + 1024*1024)) 01918 { 01919 MiFlushTlb(Pt, Address); 01920 } 01921 } 01922 } 01923 if (Addr > Address) 01924 { 01925 MmUnmapPageTable(Pt); 01926 } 01927 } 01928 return(STATUS_SUCCESS); 01929 } 01930 01931 NTSTATUS 01932 NTAPI 01933 MmCreateVirtualMapping(PEPROCESS Process, 01934 PVOID Address, 01935 ULONG flProtect, 01936 PPFN_NUMBER Pages, 01937 ULONG PageCount) 01938 { 01939 ULONG i; 01940 01941 for (i = 0; i < PageCount; i++) 01942 { 01943 if (!MmIsPageInUse(Pages[i])) 01944 { 01945 DPRINT1("Page at address %x not in use\n", PFN_TO_PTE(Pages[i])); 01946 ASSERT(FALSE); 01947 } 01948 } 01949 01950 return(MmCreateVirtualMappingUnsafe(Process, 01951 Address, 01952 flProtect, 01953 Pages, 01954 PageCount)); 01955 } 01956 01957 ULONG 01958 NTAPI 01959 MmGetPageProtect(PEPROCESS Process, PVOID Address) 01960 { 01961 ULONG Entry; 01962 ULONG Protect; 01963 if (Ke386Pae) 01964 { 01965 Entry = MmGetPageEntryForProcessForPAE(Process, Address); 01966 } 01967 else 01968 { 01969 Entry = MmGetPageEntryForProcess(Process, Address); 01970 } 01971 01972 if (!(Entry & PA_PRESENT)) 01973 { 01974 Protect = PAGE_NOACCESS; 01975 } 01976 else 01977 { 01978 if (Entry & PA_READWRITE) 01979 { 01980 Protect = PAGE_READWRITE; 01981 } 01982 else 01983 { 01984 Protect = PAGE_EXECUTE_READ; 01985 } 01986 if (Entry & PA_CD) 01987 { 01988 Protect |= PAGE_NOCACHE; 01989 } 01990 if (Entry & PA_WT) 01991 { 01992 Protect |= PAGE_WRITETHROUGH; 01993 } 01994 if (!(Entry & PA_USER)) 01995 { 01996 Protect |= PAGE_SYSTEM; 01997 } 01998 01999 } 02000 return(Protect); 02001 } 02002 02003 VOID 02004 NTAPI 02005 MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect) 02006 { 02007 ULONG Attributes = 0; 02008 BOOLEAN NoExecute = FALSE; 02009 02010 DPRINT("MmSetPageProtect(Process %x Address %x flProtect %x)\n", 02011 Process, Address, flProtect); 02012 02013 Attributes = ProtectToPTE(flProtect); 02014 if (Attributes & 0x80000000) 02015 { 02016 NoExecute = TRUE; 02017 } 02018 Attributes &= 0xfff; 02019 if (Address >= MmSystemRangeStart) 02020 { 02021 Attributes &= ~PA_USER; 02022 if (Ke386GlobalPagesEnabled) 02023 { 02024 Attributes |= PA_GLOBAL; 02025 } 02026 } 02027 else 02028 { 02029 Attributes |= PA_USER; 02030 } 02031 if (Ke386Pae) 02032 { 02033 PULONGLONG Pt; 02034 ULONGLONG tmpPte, Pte; 02035 02036 Pt = MmGetPageTableForProcessForPAE(Process, Address, FALSE); 02037 if (Pt == NULL) 02038 { 02039 DPRINT1("Address %x\n", Address); 02040 ASSERT(FALSE); 02041 } 02042 do 02043 { 02044 Pte = *Pt; 02045 tmpPte = PAE_PAGE_MASK(Pte) | Attributes | (Pte & (PA_ACCESSED|PA_DIRTY)); 02046 if (NoExecute) 02047 { 02048 tmpPte |= 0x8000000000000000LL; 02049 } 02050 else 02051 { 02052 tmpPte &= ~0x8000000000000000LL; 02053 } 02054 } while (Pte != ExfInterlockedCompareExchange64UL(Pt, &tmpPte, &Pte)); 02055 02056 MiFlushTlb((PULONG)Pt, Address); 02057 } 02058 else 02059 { 02060 PULONG Pt; 02061 02062 Pt = MmGetPageTableForProcess(Process, Address, FALSE); 02063 if (Pt == NULL) 02064 { 02065 ASSERT(FALSE); 02066 } 02067 InterlockedExchange((PLONG)Pt, PAGE_MASK(*Pt) | Attributes | (*Pt & (PA_ACCESSED|PA_DIRTY))); 02068 MiFlushTlb(Pt, Address); 02069 } 02070 } 02071 02072 /* 02073 * @implemented 02074 */ 02075 PHYSICAL_ADDRESS NTAPI 02076 MmGetPhysicalAddress(PVOID vaddr) 02077 /* 02078 * FUNCTION: Returns the physical address corresponding to a virtual address 02079 */ 02080 { 02081 PHYSICAL_ADDRESS p; 02082 02083 DPRINT("MmGetPhysicalAddress(vaddr %x)\n", vaddr); 02084 if (Ke386Pae) 02085 { 02086 ULONGLONG Pte; 02087 Pte = MmGetPageEntryForProcessForPAE(NULL, vaddr); 02088 if (Pte != 0 && Pte & PA_PRESENT) 02089 { 02090 p.QuadPart = PAE_PAGE_MASK(Pte); 02091 p.u.LowPart |= (ULONG_PTR)vaddr & (PAGE_SIZE - 1); 02092 } 02093 else 02094 { 02095 p.QuadPart = 0; 02096 } 02097 } 02098 else 02099 { 02100 ULONG Pte; 02101 Pte = MmGetPageEntryForProcess(NULL, vaddr); 02102 if (Pte != 0 && Pte & PA_PRESENT) 02103 { 02104 p.QuadPart = PAGE_MASK(Pte); 02105 p.u.LowPart |= (ULONG_PTR)vaddr & (PAGE_SIZE - 1); 02106 } 02107 else 02108 { 02109 p.QuadPart = 0; 02110 } 02111 } 02112 return p; 02113 } 02114 02115 PVOID 02116 NTAPI 02117 MmCreateHyperspaceMapping(PFN_NUMBER Page) 02118 { 02119 PVOID Address; 02120 ULONG i; 02121 02122 if (Ke386Pae) 02123 { 02124 ULONGLONG Entry; 02125 ULONGLONG ZeroEntry = 0LL; 02126 PULONGLONG Pte; 02127 02128 Entry = PFN_TO_PTE(Page) | PA_PRESENT | PA_READWRITE; 02129 Pte = PAE_ADDR_TO_PTE(HYPERSPACE) + Page % 1024; 02130 02131 if (Page & 1024) 02132 { 02133 for (i = Page %1024; i < 1024; i++, Pte++) 02134 { 02135 if (0LL == ExfInterlockedCompareExchange64UL(Pte, &Entry, &ZeroEntry)) 02136 { 02137 break; 02138 } 02139 } 02140 if (i >= 1024) 02141 { 02142 Pte = PAE_ADDR_TO_PTE(HYPERSPACE); 02143 for (i = 0; i < Page % 1024; i++, Pte++) 02144 { 02145 if (0LL == ExfInterlockedCompareExchange64UL(Pte, &Entry, &ZeroEntry)) 02146 { 02147 break; 02148 } 02149 } 02150 if (i >= Page % 1024) 02151 { 02152 ASSERT(FALSE); 02153 } 02154 } 02155 } 02156 else 02157 { 02158 for (i = Page %1024; (LONG)i >= 0; i--, Pte--) 02159 { 02160 if (0LL == ExfInterlockedCompareExchange64UL(Pte, &Entry, &ZeroEntry)) 02161 { 02162 break; 02163 } 02164 } 02165 if ((LONG)i < 0) 02166 { 02167 Pte = PAE_ADDR_TO_PTE(HYPERSPACE) + 1023; 02168 for (i = 1023; i > Page % 1024; i--, Pte--) 02169 { 02170 if (0LL == ExfInterlockedCompareExchange64UL(Pte, &Entry, &ZeroEntry)) 02171 { 02172 break; 02173 } 02174 } 02175 if (i <= Page % 1024) 02176 { 02177 ASSERT(FALSE); 02178 } 02179 } 02180 } 02181 } 02182 else 02183 { 02184 ULONG Entry; 02185 PULONG Pte; 02186 Entry = PFN_TO_PTE(Page) | PA_PRESENT | PA_READWRITE; 02187 Pte = ADDR_TO_PTE(HYPERSPACE) + Page % 1024; 02188 if (Page & 1024) 02189 { 02190 for (i = Page % 1024; i < 1024; i++, Pte++) 02191 { 02192 if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0)) 02193 { 02194 break; 02195 } 02196 } 02197 if (i >= 1024) 02198 { 02199 Pte = ADDR_TO_PTE(HYPERSPACE); 02200 for (i = 0; i < Page % 1024; i++, Pte++) 02201 { 02202 if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0)) 02203 { 02204 break; 02205 } 02206 } 02207 if (i >= Page % 1024) 02208 { 02209 ASSERT(FALSE); 02210 } 02211 } 02212 } 02213 else 02214 { 02215 for (i = Page % 1024; (LONG)i >= 0; i--, Pte--) 02216 { 02217 if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0)) 02218 { 02219 break; 02220 } 02221 } 02222 if ((LONG)i < 0) 02223 { 02224 Pte = ADDR_TO_PTE(HYPERSPACE) + 1023; 02225 for (i = 1023; i > Page % 1024; i--, Pte--) 02226 { 02227 if (0 == InterlockedCompareExchange((PLONG)Pte, (LONG)Entry, 0)) 02228 { 02229 break; 02230 } 02231 } 02232 if (i <= Page % 1024) 02233 { 02234 ASSERT(FALSE); 02235 } 02236 } 02237 } 02238 } 02239 Address = (PVOID)((ULONG_PTR)HYPERSPACE + i * PAGE_SIZE); 02240 __invlpg(Address); 02241 return Address; 02242 } 02243 02244 PFN_NUMBER 02245 NTAPI 02246 MmChangeHyperspaceMapping(PVOID Address, PFN_NUMBER NewPage) 02247 { 02248 PFN_NUMBER Pfn; 02249 ASSERT (IS_HYPERSPACE(Address)); 02250 if (Ke386Pae) 02251 { 02252 ULONGLONG Entry = PAE_PFN_TO_PTE(NewPage) | PA_PRESENT | PA_READWRITE; 02253 Entry = (ULONG)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PTE(Address), &Entry); 02254 Pfn = PAE_PTE_TO_PFN(Entry); 02255 } 02256 else 02257 { 02258 ULONG Entry; 02259 Entry = InterlockedExchange((PLONG)ADDR_TO_PTE(Address), PFN_TO_PTE(NewPage) | PA_PRESENT | PA_READWRITE); 02260 Pfn = PTE_TO_PFN(Entry); 02261 } 02262 __invlpg(Address); 02263 return Pfn; 02264 } 02265 02266 PFN_NUMBER 02267 NTAPI 02268 MmDeleteHyperspaceMapping(PVOID Address) 02269 { 02270 PFN_NUMBER Pfn; 02271 ASSERT (IS_HYPERSPACE(Address)); 02272 if (Ke386Pae) 02273 { 02274 ULONGLONG Entry = 0LL; 02275 Entry = (ULONG)ExfpInterlockedExchange64UL(PAE_ADDR_TO_PTE(Address), &Entry); 02276 Pfn = PAE_PTE_TO_PFN(Entry); 02277 } 02278 else 02279 { 02280 ULONG Entry; 02281 Entry = InterlockedExchange((PLONG)ADDR_TO_PTE(Address), 0); 02282 Pfn = PTE_TO_PFN(Entry); 02283 } 02284 __invlpg(Address); 02285 return Pfn; 02286 } 02287 02288 VOID 02289 NTAPI 02290 MmUpdatePageDir(PEPROCESS Process, PVOID Address, ULONG Size) 02291 { 02292 ULONG StartOffset, EndOffset, Offset; 02293 02294 if (Address < MmSystemRangeStart) 02295 { 02296 ASSERT(FALSE); 02297 } 02298 if (Ke386Pae) 02299 { 02300 PULONGLONG PageDirTable; 02301 PULONGLONG Pde; 02302 ULONGLONG ZeroPde = 0LL; 02303 ULONG i; 02304 02305 for (i = PAE_ADDR_TO_PDTE_OFFSET(Address); i <= PAE_ADDR_TO_PDTE_OFFSET((PVOID)((ULONG_PTR)Address + Size)); i++) 02306 { 02307 if (i == PAE_ADDR_TO_PDTE_OFFSET(Address)) 02308 { 02309 StartOffset = PAE_ADDR_TO_PDE_PAGE_OFFSET(Address); 02310 } 02311 else 02312 { 02313 StartOffset = 0; 02314 } 02315 if (i == PAE_ADDR_TO_PDTE_OFFSET((PVOID)((ULONG_PTR)Address + Size))) 02316 { 02317 EndOffset = PAE_ADDR_TO_PDE_PAGE_OFFSET((PVOID)((ULONG_PTR)Address + Size)); 02318 } 02319 else 02320 { 02321 EndOffset = 511; 02322 } 02323 02324 if (Process != NULL && Process != PsGetCurrentProcess()) 02325 { 02326 PageDirTable = MmCreateHyperspaceMapping(PAE_PTE_TO_PFN(Process->Pcb.DirectoryTableBase.QuadPart)); 02327 Pde = (PULONGLONG)MmCreateHyperspaceMapping(PTE_TO_PFN(PageDirTable[i])); 02328 MmDeleteHyperspaceMapping(PageDirTable); 02329 } 02330 else 02331 { 02332 Pde = (PULONGLONG)PAE_PAGEDIRECTORY_MAP + i*512; 02333 } 02334 02335 for (Offset = StartOffset; Offset <= EndOffset; Offset++) 02336 { 02337 if (i * 512 + Offset < PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP) || i * 512 + Offset >= PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP)+4) 02338 { 02339 (void)ExfInterlockedCompareExchange64UL(&Pde[Offset], &MmGlobalKernelPageDirectoryForPAE[i*512 + Offset], &ZeroPde); 02340 } 02341 } 02342 MmUnmapPageTable((PULONG)Pde); 02343 } 02344 } 02345 else 02346 { 02347 PULONG Pde; 02348 StartOffset = ADDR_TO_PDE_OFFSET(Address); 02349 EndOffset = ADDR_TO_PDE_OFFSET((PVOID)((ULONG_PTR)Address + Size)); 02350 02351 if (Process != NULL && Process != PsGetCurrentProcess()) 02352 { 02353 Pde = MmCreateHyperspaceMapping(PTE_TO_PFN(Process->Pcb.DirectoryTableBase.u.LowPart)); 02354 } 02355 else 02356 { 02357 Pde = (PULONG)PAGEDIRECTORY_MAP; 02358 } 02359 for (Offset = StartOffset; Offset <= EndOffset; Offset++) 02360 { 02361 if (Offset != ADDR_TO_PDE_OFFSET(PAGETABLE_MAP)) 02362 { 02363 (void)InterlockedCompareExchangeUL(&Pde[Offset], MmGlobalKernelPageDirectory[Offset], 0); 02364 } 02365 } 02366 if (Pde != (PULONG)PAGEDIRECTORY_MAP) 02367 { 02368 MmDeleteHyperspaceMapping(Pde); 02369 } 02370 } 02371 } 02372 02373 VOID 02374 INIT_FUNCTION 02375 NTAPI 02376 MmInitGlobalKernelPageDirectory(VOID) 02377 { 02378 ULONG i; 02379 02380 DPRINT("MmInitGlobalKernelPageDirectory()\n"); 02381 02382 if (Ke386Pae) 02383 { 02384 PULONGLONG CurrentPageDirectory = (PULONGLONG)PAE_PAGEDIRECTORY_MAP; 02385 for (i = PAE_ADDR_TO_PDE_OFFSET(MmSystemRangeStart); i < 4 * 512; i++) 02386 { 02387 if (!(i >= PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP) && i < PAE_ADDR_TO_PDE_OFFSET(PAGETABLE_MAP) + 4) && 02388 !(i >= PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE) && i < PAE_ADDR_TO_PDE_OFFSET(HYPERSPACE) + 2) && 02389 0LL == MmGlobalKernelPageDirectoryForPAE[i] && 0LL != CurrentPageDirectory[i]) 02390 { 02391 (void)ExfpInterlockedExchange64UL(&MmGlobalKernelPageDirectoryForPAE[i], &CurrentPageDirectory[i]); 02392 if (Ke386GlobalPagesEnabled) 02393 { 02394 MmGlobalKernelPageDirectoryForPAE[i] |= PA_GLOBAL; 02395 CurrentPageDirectory[i] |= PA_GLOBAL; 02396 } 02397 } 02398 } 02399 } 02400 else 02401 { 02402 PULONG CurrentPageDirectory = (PULONG)PAGEDIRECTORY_MAP; 02403 for (i = ADDR_TO_PDE_OFFSET(MmSystemRangeStart); i < 1024; i++) 02404 { 02405 if (i != ADDR_TO_PDE_OFFSET(PAGETABLE_MAP) && 02406 i != ADDR_TO_PDE_OFFSET(HYPERSPACE) && 02407 0 == MmGlobalKernelPageDirectory[i] && 0 != CurrentPageDirectory[i]) 02408 { 02409 MmGlobalKernelPageDirectory[i] = CurrentPageDirectory[i]; 02410 if (Ke386GlobalPagesEnabled) 02411 { 02412 MmGlobalKernelPageDirectory[i] |= PA_GLOBAL; 02413 CurrentPageDirectory[i] |= PA_GLOBAL; 02414 } 02415 } 02416 } 02417 } 02418 } 02419 02420 ULONG 02421 NTAPI 02422 MiGetUserPageDirectoryCount(VOID) 02423 { 02424 return Ke386Pae ? PAE_ADDR_TO_PDE_OFFSET(MmSystemRangeStart) : ADDR_TO_PDE_OFFSET(MmSystemRangeStart); 02425 } 02426 02427 VOID 02428 INIT_FUNCTION 02429 NTAPI 02430 MiInitPageDirectoryMap(VOID) 02431 { 02432 MEMORY_AREA* kernel_map_desc = NULL; 02433 MEMORY_AREA* hyperspace_desc = NULL; 02434 PHYSICAL_ADDRESS BoundaryAddressMultiple; 02435 PVOID BaseAddress; 02436 NTSTATUS Status; 02437 02438 DPRINT("MiInitPageDirectoryMap()\n"); 02439 02440 BoundaryAddressMultiple.QuadPart = 0; 02441 BaseAddress = (PVOID)PAGETABLE_MAP; 02442 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(), 02443 MEMORY_AREA_SYSTEM, 02444 &BaseAddress, 02445 Ke386Pae ? 0x800000 : 0x400000, 02446 PAGE_READWRITE, 02447 &kernel_map_desc, 02448 TRUE, 02449 0, 02450 BoundaryAddressMultiple); 02451 if (!NT_SUCCESS(Status)) 02452 { 02453 ASSERT(FALSE); 02454 } 02455 BaseAddress = (PVOID)HYPERSPACE; 02456 Status = MmCreateMemoryArea(MmGetKernelAddressSpace(), 02457 MEMORY_AREA_SYSTEM, 02458 &BaseAddress, 02459 0x400000, 02460 PAGE_READWRITE, 02461 &hyperspace_desc, 02462 TRUE, 02463 0, 02464 BoundaryAddressMultiple); 02465 if (!NT_SUCCESS(Status)) 02466 { 02467 ASSERT(FALSE); 02468 } 02469 } 02470 02471 /* EOF */ Generated on Sat May 26 2012 04:36:30 for ReactOS by
1.7.6.1
|