Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmdlsup.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: BSD - See COPYING.ARM in the top level directory 00004 * FILE: ntoskrnl/mm/ARM3/mdlsup.c 00005 * PURPOSE: ARM Memory Manager Memory Descriptor List (MDL) Management 00006 * PROGRAMMERS: ReactOS Portable Systems Group 00007 */ 00008 00009 /* INCLUDES *******************************************************************/ 00010 00011 #include <ntoskrnl.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 #define MODULE_INVOLVED_IN_ARM3 00016 #include "../ARM3/miarm.h" 00017 00018 /* GLOBALS ********************************************************************/ 00019 00020 BOOLEAN MmTrackPtes; 00021 BOOLEAN MmTrackLockedPages; 00022 SIZE_T MmSystemLockPagesCount; 00023 00024 /* PUBLIC FUNCTIONS ***********************************************************/ 00025 00026 /* 00027 * @implemented 00028 */ 00029 PMDL 00030 NTAPI 00031 MmCreateMdl(IN PMDL Mdl, 00032 IN PVOID Base, 00033 IN SIZE_T Length) 00034 { 00035 SIZE_T Size; 00036 00037 // 00038 // Check if we don't have an MDL built 00039 // 00040 if (!Mdl) 00041 { 00042 // 00043 // Calculate the size we'll need and allocate the MDL 00044 // 00045 Size = MmSizeOfMdl(Base, Length); 00046 Mdl = ExAllocatePoolWithTag(NonPagedPool, Size, TAG_MDL); 00047 if (!Mdl) return NULL; 00048 } 00049 00050 // 00051 // Initialize it 00052 // 00053 MmInitializeMdl(Mdl, Base, Length); 00054 return Mdl; 00055 } 00056 00057 /* 00058 * @implemented 00059 */ 00060 SIZE_T 00061 NTAPI 00062 MmSizeOfMdl(IN PVOID Base, 00063 IN SIZE_T Length) 00064 { 00065 // 00066 // Return the MDL size 00067 // 00068 return sizeof(MDL) + 00069 (ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base, Length) * sizeof(PFN_NUMBER)); 00070 } 00071 00072 /* 00073 * @implemented 00074 */ 00075 VOID 00076 NTAPI 00077 MmBuildMdlForNonPagedPool(IN PMDL Mdl) 00078 { 00079 PPFN_NUMBER MdlPages, EndPage; 00080 PFN_NUMBER Pfn, PageCount; 00081 PVOID Base; 00082 PMMPTE PointerPte; 00083 00084 // 00085 // Sanity checks 00086 // 00087 ASSERT(Mdl->ByteCount != 0); 00088 ASSERT((Mdl->MdlFlags & (MDL_PAGES_LOCKED | 00089 MDL_MAPPED_TO_SYSTEM_VA | 00090 MDL_SOURCE_IS_NONPAGED_POOL | 00091 MDL_PARTIAL)) == 0); 00092 00093 // 00094 // We know the MDL isn't associated to a process now 00095 // 00096 Mdl->Process = NULL; 00097 00098 // 00099 // Get page and VA information 00100 // 00101 MdlPages = (PPFN_NUMBER)(Mdl + 1); 00102 Base = Mdl->StartVa; 00103 00104 // 00105 // Set the system address and now get the page count 00106 // 00107 Mdl->MappedSystemVa = (PVOID)((ULONG_PTR)Base + Mdl->ByteOffset); 00108 PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Mdl->MappedSystemVa, 00109 Mdl->ByteCount); 00110 ASSERT(PageCount != 0); 00111 EndPage = MdlPages + PageCount; 00112 00113 // 00114 // Loop the PTEs 00115 // 00116 PointerPte = MiAddressToPte(Base); 00117 do 00118 { 00119 // 00120 // Write the PFN 00121 // 00122 Pfn = PFN_FROM_PTE(PointerPte++); 00123 *MdlPages++ = Pfn; 00124 } while (MdlPages < EndPage); 00125 00126 // 00127 // Set the nonpaged pool flag 00128 // 00129 Mdl->MdlFlags |= MDL_SOURCE_IS_NONPAGED_POOL; 00130 00131 // 00132 // Check if this is an I/O mapping 00133 // 00134 if (!MiGetPfnEntry(Pfn)) Mdl->MdlFlags |= MDL_IO_SPACE; 00135 } 00136 00137 /* 00138 * @implemented 00139 */ 00140 PMDL 00141 NTAPI 00142 MmAllocatePagesForMdl(IN PHYSICAL_ADDRESS LowAddress, 00143 IN PHYSICAL_ADDRESS HighAddress, 00144 IN PHYSICAL_ADDRESS SkipBytes, 00145 IN SIZE_T TotalBytes) 00146 { 00147 // 00148 // Call the internal routine 00149 // 00150 return MiAllocatePagesForMdl(LowAddress, 00151 HighAddress, 00152 SkipBytes, 00153 TotalBytes, 00154 MiNotMapped, 00155 0); 00156 } 00157 00158 /* 00159 * @implemented 00160 */ 00161 PMDL 00162 NTAPI 00163 MmAllocatePagesForMdlEx(IN PHYSICAL_ADDRESS LowAddress, 00164 IN PHYSICAL_ADDRESS HighAddress, 00165 IN PHYSICAL_ADDRESS SkipBytes, 00166 IN SIZE_T TotalBytes, 00167 IN MEMORY_CACHING_TYPE CacheType, 00168 IN ULONG Flags) 00169 { 00170 MI_PFN_CACHE_ATTRIBUTE CacheAttribute; 00171 00172 // 00173 // Check for invalid cache type 00174 // 00175 if (CacheType > MmWriteCombined) 00176 { 00177 // 00178 // Normalize to default 00179 // 00180 CacheAttribute = MiNotMapped; 00181 } 00182 else 00183 { 00184 // 00185 // Conver to internal caching attribute 00186 // 00187 CacheAttribute = MiPlatformCacheAttributes[FALSE][CacheType]; 00188 } 00189 00190 // 00191 // Only these flags are allowed 00192 // 00193 if (Flags & ~(MM_DONT_ZERO_ALLOCATION | MM_ALLOCATE_FROM_LOCAL_NODE_ONLY)) 00194 { 00195 // 00196 // Silently fail 00197 // 00198 return NULL; 00199 } 00200 00201 // 00202 // Call the internal routine 00203 // 00204 return MiAllocatePagesForMdl(LowAddress, 00205 HighAddress, 00206 SkipBytes, 00207 TotalBytes, 00208 CacheAttribute, 00209 Flags); 00210 } 00211 00212 /* 00213 * @implemented 00214 */ 00215 VOID 00216 NTAPI 00217 MmFreePagesFromMdl(IN PMDL Mdl) 00218 { 00219 PVOID Base; 00220 PPFN_NUMBER Pages; 00221 LONG NumberOfPages; 00222 PMMPFN Pfn1; 00223 KIRQL OldIrql; 00224 DPRINT("Freeing MDL: %p\n", Mdl); 00225 00226 // 00227 // Sanity checks 00228 // 00229 ASSERT(KeGetCurrentIrql() <= APC_LEVEL); 00230 ASSERT((Mdl->MdlFlags & MDL_IO_SPACE) == 0); 00231 ASSERT(((ULONG_PTR)Mdl->StartVa & (PAGE_SIZE - 1)) == 0); 00232 00233 // 00234 // Get address and page information 00235 // 00236 Base = (PVOID)((ULONG_PTR)Mdl->StartVa + Mdl->ByteOffset); 00237 NumberOfPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base, Mdl->ByteCount); 00238 00239 // 00240 // Acquire PFN lock 00241 // 00242 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 00243 00244 // 00245 // Loop all the MDL pages 00246 // 00247 Pages = (PPFN_NUMBER)(Mdl + 1); 00248 do 00249 { 00250 // 00251 // Reached the last page 00252 // 00253 if (*Pages == LIST_HEAD) break; 00254 00255 // 00256 // Get the page entry 00257 // 00258 Pfn1 = MiGetPfnEntry(*Pages); 00259 ASSERT(Pfn1); 00260 ASSERT(Pfn1->u2.ShareCount == 1); 00261 ASSERT(MI_IS_PFN_DELETED(Pfn1) == TRUE); 00262 if (Pfn1->u4.PteFrame != 0x1FFEDCB) 00263 { 00264 /* Corrupted PFN entry or invalid free */ 00265 KeBugCheckEx(MEMORY_MANAGEMENT, 0x1236, (ULONG_PTR)Mdl, (ULONG_PTR)Pages, *Pages); 00266 } 00267 00268 // 00269 // Clear it 00270 // 00271 Pfn1->u3.e1.StartOfAllocation = 0; 00272 Pfn1->u3.e1.EndOfAllocation = 0; 00273 Pfn1->u2.ShareCount = 0; 00274 00275 // 00276 // Dereference it 00277 // 00278 ASSERT(Pfn1->u3.e2.ReferenceCount != 0); 00279 if (Pfn1->u3.e2.ReferenceCount != 1) 00280 { 00281 /* Just take off one reference */ 00282 InterlockedDecrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount); 00283 } 00284 else 00285 { 00286 /* We'll be nuking the whole page */ 00287 MiDecrementReferenceCount(Pfn1, *Pages); 00288 } 00289 00290 // 00291 // Clear this page and move on 00292 // 00293 *Pages++ = LIST_HEAD; 00294 } while (--NumberOfPages != 0); 00295 00296 // 00297 // Release the lock 00298 // 00299 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 00300 00301 // 00302 // Remove the pages locked flag 00303 // 00304 Mdl->MdlFlags &= ~MDL_PAGES_LOCKED; 00305 } 00306 00307 /* 00308 * @implemented 00309 */ 00310 PVOID 00311 NTAPI 00312 MmMapLockedPagesSpecifyCache(IN PMDL Mdl, 00313 IN KPROCESSOR_MODE AccessMode, 00314 IN MEMORY_CACHING_TYPE CacheType, 00315 IN PVOID BaseAddress, 00316 IN ULONG BugCheckOnFailure, 00317 IN MM_PAGE_PRIORITY Priority) 00318 { 00319 PVOID Base; 00320 PPFN_NUMBER MdlPages, LastPage; 00321 PFN_COUNT PageCount; 00322 BOOLEAN IsIoMapping; 00323 MI_PFN_CACHE_ATTRIBUTE CacheAttribute; 00324 PMMPTE PointerPte; 00325 MMPTE TempPte; 00326 00327 // 00328 // Sanity check 00329 // 00330 ASSERT(Mdl->ByteCount != 0); 00331 00332 // 00333 // Get the base 00334 // 00335 Base = (PVOID)((ULONG_PTR)Mdl->StartVa + Mdl->ByteOffset); 00336 00337 // 00338 // Handle kernel case first 00339 // 00340 if (AccessMode == KernelMode) 00341 { 00342 // 00343 // Get the list of pages and count 00344 // 00345 MdlPages = (PPFN_NUMBER)(Mdl + 1); 00346 PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base, Mdl->ByteCount); 00347 LastPage = MdlPages + PageCount; 00348 00349 // 00350 // Sanity checks 00351 // 00352 ASSERT((Mdl->MdlFlags & (MDL_MAPPED_TO_SYSTEM_VA | 00353 MDL_SOURCE_IS_NONPAGED_POOL | 00354 MDL_PARTIAL_HAS_BEEN_MAPPED)) == 0); 00355 ASSERT((Mdl->MdlFlags & (MDL_PAGES_LOCKED | MDL_PARTIAL)) != 0); 00356 00357 // 00358 // Get the correct cache type 00359 // 00360 IsIoMapping = (Mdl->MdlFlags & MDL_IO_SPACE) != 0; 00361 CacheAttribute = MiPlatformCacheAttributes[IsIoMapping][CacheType]; 00362 00363 // 00364 // Reserve the PTEs 00365 // 00366 PointerPte = MiReserveSystemPtes(PageCount, SystemPteSpace); 00367 if (!PointerPte) 00368 { 00369 // 00370 // If it can fail, return NULL 00371 // 00372 if (Mdl->MdlFlags & MDL_MAPPING_CAN_FAIL) return NULL; 00373 00374 // 00375 // Should we bugcheck? 00376 // 00377 if (!BugCheckOnFailure) return NULL; 00378 00379 // 00380 // Yes, crash the system 00381 // 00382 KeBugCheckEx(NO_MORE_SYSTEM_PTES, 0, PageCount, 0, 0); 00383 } 00384 00385 // 00386 // Get the mapped address 00387 // 00388 Base = (PVOID)((ULONG_PTR)MiPteToAddress(PointerPte) + Mdl->ByteOffset); 00389 00390 // 00391 // Get the template 00392 // 00393 TempPte = ValidKernelPte; 00394 switch (CacheAttribute) 00395 { 00396 case MiNonCached: 00397 00398 // 00399 // Disable caching 00400 // 00401 MI_PAGE_DISABLE_CACHE(&TempPte); 00402 MI_PAGE_WRITE_THROUGH(&TempPte); 00403 break; 00404 00405 case MiWriteCombined: 00406 00407 // 00408 // Enable write combining 00409 // 00410 MI_PAGE_DISABLE_CACHE(&TempPte); 00411 MI_PAGE_WRITE_COMBINED(&TempPte); 00412 break; 00413 00414 default: 00415 // 00416 // Nothing to do 00417 // 00418 break; 00419 } 00420 00421 // 00422 // Loop all PTEs 00423 // 00424 do 00425 { 00426 // 00427 // We're done here 00428 // 00429 if (*MdlPages == LIST_HEAD) break; 00430 00431 // 00432 // Write the PTE 00433 // 00434 TempPte.u.Hard.PageFrameNumber = *MdlPages; 00435 MI_WRITE_VALID_PTE(PointerPte++, TempPte); 00436 } while (++MdlPages < LastPage); 00437 00438 // 00439 // Mark it as mapped 00440 // 00441 ASSERT((Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) == 0); 00442 Mdl->MappedSystemVa = Base; 00443 Mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA; 00444 00445 // 00446 // Check if it was partial 00447 // 00448 if (Mdl->MdlFlags & MDL_PARTIAL) 00449 { 00450 // 00451 // Write the appropriate flag here too 00452 // 00453 Mdl->MdlFlags |= MDL_PARTIAL_HAS_BEEN_MAPPED; 00454 } 00455 00456 // 00457 // Return the mapped address 00458 // 00459 return Base; 00460 } 00461 00462 UNIMPLEMENTED; 00463 return NULL; 00464 } 00465 00466 /* 00467 * @implemented 00468 */ 00469 PVOID 00470 NTAPI 00471 MmMapLockedPages(IN PMDL Mdl, 00472 IN KPROCESSOR_MODE AccessMode) 00473 { 00474 // 00475 // Call the extended version 00476 // 00477 return MmMapLockedPagesSpecifyCache(Mdl, 00478 AccessMode, 00479 MmCached, 00480 NULL, 00481 TRUE, 00482 HighPagePriority); 00483 } 00484 00485 /* 00486 * @implemented 00487 */ 00488 VOID 00489 NTAPI 00490 MmUnmapLockedPages(IN PVOID BaseAddress, 00491 IN PMDL Mdl) 00492 { 00493 PVOID Base; 00494 PFN_COUNT PageCount, ExtraPageCount; 00495 PPFN_NUMBER MdlPages; 00496 PMMPTE PointerPte; 00497 00498 // 00499 // Sanity check 00500 // 00501 ASSERT(Mdl->ByteCount != 0); 00502 00503 // 00504 // Check if this is a kernel request 00505 // 00506 if (BaseAddress > MM_HIGHEST_USER_ADDRESS) 00507 { 00508 // 00509 // Get base and count information 00510 // 00511 Base = (PVOID)((ULONG_PTR)Mdl->StartVa + Mdl->ByteOffset); 00512 PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base, Mdl->ByteCount); 00513 00514 // 00515 // Sanity checks 00516 // 00517 ASSERT((Mdl->MdlFlags & MDL_PARENT_MAPPED_SYSTEM_VA) == 0); 00518 ASSERT(PageCount != 0); 00519 ASSERT(Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA); 00520 00521 // 00522 // Get the PTE 00523 // 00524 PointerPte = MiAddressToPte(BaseAddress); 00525 00526 // 00527 // This should be a resident system PTE 00528 // 00529 ASSERT(PointerPte >= MmSystemPtesStart[SystemPteSpace]); 00530 ASSERT(PointerPte <= MmSystemPtesEnd[SystemPteSpace]); 00531 ASSERT(PointerPte->u.Hard.Valid == 1); 00532 00533 // 00534 // Check if the caller wants us to free advanced pages 00535 // 00536 if (Mdl->MdlFlags & MDL_FREE_EXTRA_PTES) 00537 { 00538 // 00539 // Get the MDL page array 00540 // 00541 MdlPages = MmGetMdlPfnArray(Mdl); 00542 00543 /* Number of extra pages stored after the PFN array */ 00544 ExtraPageCount = (PFN_COUNT)*(MdlPages + PageCount); 00545 00546 // 00547 // Do the math 00548 // 00549 PageCount += ExtraPageCount; 00550 PointerPte -= ExtraPageCount; 00551 ASSERT(PointerPte >= MmSystemPtesStart[SystemPteSpace]); 00552 ASSERT(PointerPte <= MmSystemPtesEnd[SystemPteSpace]); 00553 00554 // 00555 // Get the new base address 00556 // 00557 BaseAddress = (PVOID)((ULONG_PTR)BaseAddress - 00558 (ExtraPageCount << PAGE_SHIFT)); 00559 } 00560 00561 // 00562 // Remove flags 00563 // 00564 Mdl->MdlFlags &= ~(MDL_MAPPED_TO_SYSTEM_VA | 00565 MDL_PARTIAL_HAS_BEEN_MAPPED | 00566 MDL_FREE_EXTRA_PTES); 00567 00568 // 00569 // Release the system PTEs 00570 // 00571 MiReleaseSystemPtes(PointerPte, PageCount, SystemPteSpace); 00572 } 00573 else 00574 { 00575 UNIMPLEMENTED; 00576 } 00577 } 00578 00579 /* 00580 * @implemented 00581 */ 00582 VOID 00583 NTAPI 00584 MmProbeAndLockPages(IN PMDL Mdl, 00585 IN KPROCESSOR_MODE AccessMode, 00586 IN LOCK_OPERATION Operation) 00587 { 00588 PPFN_NUMBER MdlPages; 00589 PVOID Base, Address, LastAddress, StartAddress; 00590 ULONG LockPages, TotalPages; 00591 NTSTATUS Status = STATUS_SUCCESS; 00592 PEPROCESS CurrentProcess; 00593 NTSTATUS ProbeStatus; 00594 PMMPTE PointerPte, LastPte; 00595 PMMPDE PointerPde; 00596 #if (_MI_PAGING_LEVELS >= 3) 00597 PMMPDE PointerPpe; 00598 #endif 00599 #if (_MI_PAGING_LEVELS == 4) 00600 PMMPDE PointerPxe; 00601 #endif 00602 PFN_NUMBER PageFrameIndex; 00603 BOOLEAN UsePfnLock; 00604 KIRQL OldIrql; 00605 USHORT OldRefCount, RefCount; 00606 PMMPFN Pfn1; 00607 DPRINT("Probing MDL: %p\n", Mdl); 00608 00609 // 00610 // Sanity checks 00611 // 00612 ASSERT(Mdl->ByteCount != 0); 00613 ASSERT(((ULONG)Mdl->ByteOffset & ~(PAGE_SIZE - 1)) == 0); 00614 ASSERT(((ULONG_PTR)Mdl->StartVa & (PAGE_SIZE - 1)) == 0); 00615 ASSERT((Mdl->MdlFlags & (MDL_PAGES_LOCKED | 00616 MDL_MAPPED_TO_SYSTEM_VA | 00617 MDL_SOURCE_IS_NONPAGED_POOL | 00618 MDL_PARTIAL | 00619 MDL_IO_SPACE)) == 0); 00620 00621 // 00622 // Get page and base information 00623 // 00624 MdlPages = (PPFN_NUMBER)(Mdl + 1); 00625 Base = Mdl->StartVa; 00626 00627 // 00628 // Get the addresses and how many pages we span (and need to lock) 00629 // 00630 Address = (PVOID)((ULONG_PTR)Base + Mdl->ByteOffset); 00631 LastAddress = (PVOID)((ULONG_PTR)Address + Mdl->ByteCount); 00632 LockPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Address, Mdl->ByteCount); 00633 ASSERT(LockPages != 0); 00634 00635 /* Block invalid access */ 00636 if ((AccessMode != KernelMode) && 00637 ((LastAddress > (PVOID)MM_USER_PROBE_ADDRESS) || (Address >= LastAddress))) 00638 { 00639 /* Caller should be in SEH, raise the error */ 00640 *MdlPages = LIST_HEAD; 00641 ExRaiseStatus(STATUS_ACCESS_VIOLATION); 00642 } 00643 00644 // 00645 // Get the process 00646 // 00647 if (Address <= MM_HIGHEST_USER_ADDRESS) 00648 { 00649 // 00650 // Get the process 00651 // 00652 CurrentProcess = PsGetCurrentProcess(); 00653 } 00654 else 00655 { 00656 // 00657 // No process 00658 // 00659 CurrentProcess = NULL; 00660 } 00661 00662 // 00663 // Save the number of pages we'll have to lock, and the start address 00664 // 00665 TotalPages = LockPages; 00666 StartAddress = Address; 00667 00668 /* Large pages not supported */ 00669 ASSERT(!MI_IS_PHYSICAL_ADDRESS(Address)); 00670 00671 // 00672 // Now probe them 00673 // 00674 ProbeStatus = STATUS_SUCCESS; 00675 _SEH2_TRY 00676 { 00677 // 00678 // Enter probe loop 00679 // 00680 do 00681 { 00682 // 00683 // Assume failure 00684 // 00685 *MdlPages = LIST_HEAD; 00686 00687 // 00688 // Read 00689 // 00690 *(volatile CHAR*)Address; 00691 00692 // 00693 // Check if this is write access (only probe for user-mode) 00694 // 00695 if ((Operation != IoReadAccess) && 00696 (Address <= MM_HIGHEST_USER_ADDRESS)) 00697 { 00698 // 00699 // Probe for write too 00700 // 00701 ProbeForWriteChar(Address); 00702 } 00703 00704 // 00705 // Next address... 00706 // 00707 Address = PAGE_ALIGN((ULONG_PTR)Address + PAGE_SIZE); 00708 00709 // 00710 // Next page... 00711 // 00712 LockPages--; 00713 MdlPages++; 00714 } while (Address < LastAddress); 00715 00716 // 00717 // Reset back to the original page 00718 // 00719 ASSERT(LockPages == 0); 00720 MdlPages = (PPFN_NUMBER)(Mdl + 1); 00721 } 00722 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00723 { 00724 // 00725 // Oops :( 00726 // 00727 ProbeStatus = _SEH2_GetExceptionCode(); 00728 } 00729 _SEH2_END; 00730 00731 // 00732 // So how did that go? 00733 // 00734 if (ProbeStatus != STATUS_SUCCESS) 00735 { 00736 // 00737 // Fail 00738 // 00739 DPRINT1("MDL PROBE FAILED!\n"); 00740 Mdl->Process = NULL; 00741 ExRaiseStatus(ProbeStatus); 00742 } 00743 00744 // 00745 // Get the PTE and PDE 00746 // 00747 PointerPte = MiAddressToPte(StartAddress); 00748 PointerPde = MiAddressToPde(StartAddress); 00749 #if (_MI_PAGING_LEVELS >= 3) 00750 PointerPpe = MiAddressToPpe(StartAddress); 00751 #endif 00752 #if (_MI_PAGING_LEVELS == 4) 00753 PointerPxe = MiAddressToPxe(StartAddress); 00754 #endif 00755 00756 // 00757 // Sanity check 00758 // 00759 ASSERT(MdlPages == (PPFN_NUMBER)(Mdl + 1)); 00760 00761 // 00762 // Check what kind of operation this is 00763 // 00764 if (Operation != IoReadAccess) 00765 { 00766 // 00767 // Set the write flag 00768 // 00769 Mdl->MdlFlags |= MDL_WRITE_OPERATION; 00770 } 00771 else 00772 { 00773 // 00774 // Remove the write flag 00775 // 00776 Mdl->MdlFlags &= ~(MDL_WRITE_OPERATION); 00777 } 00778 00779 // 00780 // Mark the MDL as locked *now* 00781 // 00782 Mdl->MdlFlags |= MDL_PAGES_LOCKED; 00783 00784 // 00785 // Check if this came from kernel mode 00786 // 00787 if (Base > MM_HIGHEST_USER_ADDRESS) 00788 { 00789 // 00790 // We should not have a process 00791 // 00792 ASSERT(CurrentProcess == NULL); 00793 Mdl->Process = NULL; 00794 00795 // 00796 // In kernel mode, we don't need to check for write access 00797 // 00798 Operation = IoReadAccess; 00799 00800 // 00801 // Use the PFN lock 00802 // 00803 UsePfnLock = TRUE; 00804 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 00805 } 00806 else 00807 { 00808 // 00809 // Sanity checks 00810 // 00811 ASSERT(TotalPages != 0); 00812 ASSERT(CurrentProcess == PsGetCurrentProcess()); 00813 00814 // 00815 // Track locked pages 00816 // 00817 InterlockedExchangeAddSizeT(&CurrentProcess->NumberOfLockedPages, 00818 TotalPages); 00819 00820 // 00821 // Save the process 00822 // 00823 Mdl->Process = CurrentProcess; 00824 00825 /* Lock the process working set */ 00826 MiLockProcessWorkingSet(CurrentProcess, PsGetCurrentThread()); 00827 UsePfnLock = FALSE; 00828 OldIrql = MM_NOIRQL; 00829 } 00830 00831 // 00832 // Get the last PTE 00833 // 00834 LastPte = MiAddressToPte((PVOID)((ULONG_PTR)LastAddress - 1)); 00835 00836 // 00837 // Loop the pages 00838 // 00839 do 00840 { 00841 // 00842 // Assume failure and check for non-mapped pages 00843 // 00844 *MdlPages = LIST_HEAD; 00845 while ( 00846 #if (_MI_PAGING_LEVELS == 4) 00847 (PointerPxe->u.Hard.Valid == 0) || 00848 #endif 00849 #if (_MI_PAGING_LEVELS >= 3) 00850 (PointerPpe->u.Hard.Valid == 0) || 00851 #endif 00852 (PointerPde->u.Hard.Valid == 0) || 00853 (PointerPte->u.Hard.Valid == 0)) 00854 { 00855 // 00856 // What kind of lock were we using? 00857 // 00858 if (UsePfnLock) 00859 { 00860 // 00861 // Release PFN lock 00862 // 00863 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 00864 } 00865 else 00866 { 00867 /* Release process working set */ 00868 MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread()); 00869 } 00870 00871 // 00872 // Access the page 00873 // 00874 Address = MiPteToAddress(PointerPte); 00875 00876 //HACK: Pass a placeholder TrapInformation so the fault handler knows we're unlocked 00877 Status = MmAccessFault(FALSE, Address, KernelMode, (PVOID)0xBADBADA3); 00878 if (!NT_SUCCESS(Status)) 00879 { 00880 // 00881 // Fail 00882 // 00883 DPRINT1("Access fault failed\n"); 00884 goto Cleanup; 00885 } 00886 00887 // 00888 // What lock should we use? 00889 // 00890 if (UsePfnLock) 00891 { 00892 // 00893 // Grab the PFN lock 00894 // 00895 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 00896 } 00897 else 00898 { 00899 /* Lock the process working set */ 00900 MiLockProcessWorkingSet(CurrentProcess, PsGetCurrentThread()); 00901 } 00902 } 00903 00904 // 00905 // Check if this was a write or modify 00906 // 00907 if (Operation != IoReadAccess) 00908 { 00909 // 00910 // Check if the PTE is not writable 00911 // 00912 if (MI_IS_PAGE_WRITEABLE(PointerPte) == FALSE) 00913 { 00914 // 00915 // Check if it's copy on write 00916 // 00917 if (MI_IS_PAGE_COPY_ON_WRITE(PointerPte)) 00918 { 00919 // 00920 // Get the base address and allow a change for user-mode 00921 // 00922 Address = MiPteToAddress(PointerPte); 00923 if (Address <= MM_HIGHEST_USER_ADDRESS) 00924 { 00925 // 00926 // What kind of lock were we using? 00927 // 00928 if (UsePfnLock) 00929 { 00930 // 00931 // Release PFN lock 00932 // 00933 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 00934 } 00935 else 00936 { 00937 /* Release process working set */ 00938 MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread()); 00939 } 00940 00941 // 00942 // Access the page 00943 // 00944 00945 //HACK: Pass a placeholder TrapInformation so the fault handler knows we're unlocked 00946 Status = MmAccessFault(TRUE, Address, KernelMode, (PVOID)0xBADBADA3); 00947 if (!NT_SUCCESS(Status)) 00948 { 00949 // 00950 // Fail 00951 // 00952 DPRINT1("Access fault failed\n"); 00953 goto Cleanup; 00954 } 00955 00956 // 00957 // Re-acquire the lock 00958 // 00959 if (UsePfnLock) 00960 { 00961 // 00962 // Grab the PFN lock 00963 // 00964 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 00965 } 00966 else 00967 { 00968 /* Lock the process working set */ 00969 MiLockProcessWorkingSet(CurrentProcess, PsGetCurrentThread()); 00970 } 00971 00972 // 00973 // Start over 00974 // 00975 continue; 00976 } 00977 } 00978 00979 // 00980 // Fail, since we won't allow this 00981 // 00982 Status = STATUS_ACCESS_VIOLATION; 00983 goto CleanupWithLock; 00984 } 00985 } 00986 00987 // 00988 // Grab the PFN 00989 // 00990 PageFrameIndex = PFN_FROM_PTE(PointerPte); 00991 Pfn1 = MiGetPfnEntry(PageFrameIndex); 00992 if (Pfn1) 00993 { 00994 /* Either this is for kernel-mode, or the working set is held */ 00995 ASSERT((CurrentProcess == NULL) || (UsePfnLock == FALSE)); 00996 00997 /* No Physical VADs supported yet */ 00998 if (CurrentProcess) ASSERT(CurrentProcess->PhysicalVadRoot == NULL); 00999 01000 /* This address should already exist and be fully valid */ 01001 ASSERT(Pfn1->u3.e2.ReferenceCount != 0); 01002 if (MI_IS_ROS_PFN(Pfn1)) 01003 { 01004 /* ReactOS Mm doesn't track share count */ 01005 ASSERT(Pfn1->u3.e1.PageLocation == ActiveAndValid); 01006 } 01007 else 01008 { 01009 /* On ARM3 pages, we should see a valid share count */ 01010 ASSERT((Pfn1->u2.ShareCount != 0) && (Pfn1->u3.e1.PageLocation == ActiveAndValid)); 01011 01012 /* We don't support mapping a prototype page yet */ 01013 ASSERT((Pfn1->u3.e1.PrototypePte == 0) && (Pfn1->OriginalPte.u.Soft.Prototype == 0)); 01014 } 01015 01016 /* More locked pages! */ 01017 InterlockedExchangeAddSizeT(&MmSystemLockPagesCount, 1); 01018 01019 /* Loop trying to update the reference count */ 01020 do 01021 { 01022 /* Get the current reference count, make sure it's valid */ 01023 OldRefCount = Pfn1->u3.e2.ReferenceCount; 01024 ASSERT(OldRefCount != 0); 01025 ASSERT(OldRefCount < 2500); 01026 01027 /* Bump it up by one */ 01028 RefCount = InterlockedCompareExchange16((PSHORT)&Pfn1->u3.e2.ReferenceCount, 01029 OldRefCount + 1, 01030 OldRefCount); 01031 ASSERT(RefCount != 0); 01032 } while (OldRefCount != RefCount); 01033 01034 /* Was this the first lock attempt? */ 01035 if (OldRefCount != 1) 01036 { 01037 /* Someone else came through */ 01038 InterlockedExchangeAddSizeT(&MmSystemLockPagesCount, -1); 01039 } 01040 } 01041 else 01042 { 01043 // 01044 // For I/O addresses, just remember this 01045 // 01046 Mdl->MdlFlags |= MDL_IO_SPACE; 01047 } 01048 01049 // 01050 // Write the page and move on 01051 // 01052 *MdlPages++ = PageFrameIndex; 01053 PointerPte++; 01054 01055 /* Check if we're on a PDE boundary */ 01056 if (MiIsPteOnPdeBoundary(PointerPte)) PointerPde++; 01057 #if (_MI_PAGING_LEVELS >= 3) 01058 if (MiIsPteOnPpeBoundary(PointerPte)) PointerPpe++; 01059 #endif 01060 #if (_MI_PAGING_LEVELS == 4) 01061 if (MiIsPteOnPxeBoundary(PointerPte)) PointerPxe++; 01062 #endif 01063 01064 } while (PointerPte <= LastPte); 01065 01066 // 01067 // What kind of lock were we using? 01068 // 01069 if (UsePfnLock) 01070 { 01071 // 01072 // Release PFN lock 01073 // 01074 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 01075 } 01076 else 01077 { 01078 /* Release process working set */ 01079 MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread()); 01080 } 01081 01082 // 01083 // Sanity check 01084 // 01085 ASSERT((Mdl->MdlFlags & MDL_DESCRIBES_AWE) == 0); 01086 return; 01087 01088 CleanupWithLock: 01089 // 01090 // This is the failure path 01091 // 01092 ASSERT(!NT_SUCCESS(Status)); 01093 01094 // 01095 // What kind of lock were we using? 01096 // 01097 if (UsePfnLock) 01098 { 01099 // 01100 // Release PFN lock 01101 // 01102 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 01103 } 01104 else 01105 { 01106 /* Release process working set */ 01107 MiUnlockProcessWorkingSet(CurrentProcess, PsGetCurrentThread()); 01108 } 01109 Cleanup: 01110 // 01111 // Pages must be locked so MmUnlock can work 01112 // 01113 ASSERT(Mdl->MdlFlags & MDL_PAGES_LOCKED); 01114 MmUnlockPages(Mdl); 01115 01116 // 01117 // Raise the error 01118 // 01119 ExRaiseStatus(Status); 01120 } 01121 01122 /* 01123 * @implemented 01124 */ 01125 VOID 01126 NTAPI 01127 MmUnlockPages(IN PMDL Mdl) 01128 { 01129 PPFN_NUMBER MdlPages, LastPage; 01130 PEPROCESS Process; 01131 PVOID Base; 01132 ULONG Flags, PageCount; 01133 KIRQL OldIrql; 01134 USHORT RefCount, OldRefCount; 01135 PMMPFN Pfn1; 01136 DPRINT("Unlocking MDL: %p\n", Mdl); 01137 01138 // 01139 // Sanity checks 01140 // 01141 ASSERT((Mdl->MdlFlags & MDL_PAGES_LOCKED) != 0); 01142 ASSERT((Mdl->MdlFlags & MDL_SOURCE_IS_NONPAGED_POOL) == 0); 01143 ASSERT((Mdl->MdlFlags & MDL_PARTIAL) == 0); 01144 ASSERT(Mdl->ByteCount != 0); 01145 01146 // 01147 // Get the process associated and capture the flags which are volatile 01148 // 01149 Process = Mdl->Process; 01150 Flags = Mdl->MdlFlags; 01151 01152 // 01153 // Automagically undo any calls to MmGetSystemAddressForMdl's for this MDL 01154 // 01155 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) 01156 { 01157 // 01158 // Unmap the pages from system space 01159 // 01160 MmUnmapLockedPages(Mdl->MappedSystemVa, Mdl); 01161 } 01162 01163 // 01164 // Get the page count 01165 // 01166 MdlPages = (PPFN_NUMBER)(Mdl + 1); 01167 Base = (PVOID)((ULONG_PTR)Mdl->StartVa + Mdl->ByteOffset); 01168 PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(Base, Mdl->ByteCount); 01169 ASSERT(PageCount != 0); 01170 01171 // 01172 // We don't support AWE 01173 // 01174 if (Flags & MDL_DESCRIBES_AWE) ASSERT(FALSE); 01175 01176 // 01177 // Check if the buffer is mapped I/O space 01178 // 01179 if (Flags & MDL_IO_SPACE) 01180 { 01181 // 01182 // Acquire PFN lock 01183 // 01184 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 01185 01186 // 01187 // Loop every page 01188 // 01189 LastPage = MdlPages + PageCount; 01190 do 01191 { 01192 // 01193 // Last page, break out 01194 // 01195 if (*MdlPages == LIST_HEAD) break; 01196 01197 // 01198 // Check if this page is in the PFN database 01199 // 01200 Pfn1 = MiGetPfnEntry(*MdlPages); 01201 if (Pfn1) 01202 { 01203 /* Get the current entry and reference count */ 01204 OldRefCount = Pfn1->u3.e2.ReferenceCount; 01205 ASSERT(OldRefCount != 0); 01206 01207 /* Is this already the last dereference */ 01208 if (OldRefCount == 1) 01209 { 01210 /* It should be on a free list waiting for us */ 01211 ASSERT(Pfn1->u3.e2.ReferenceCount == 1); 01212 ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid); 01213 ASSERT(Pfn1->u2.ShareCount == 0); 01214 01215 /* Not supported yet */ 01216 ASSERT((Pfn1->u3.e1.PrototypePte == 0) && 01217 (Pfn1->OriginalPte.u.Soft.Prototype == 0)); 01218 01219 /* One less page */ 01220 InterlockedExchangeAddSizeT(&MmSystemLockPagesCount, -1); 01221 01222 /* Do the last dereference, we're done here */ 01223 MiDecrementReferenceCount(Pfn1, *MdlPages); 01224 } 01225 else 01226 { 01227 /* Loop decrementing one reference */ 01228 do 01229 { 01230 /* Make sure it's still valid */ 01231 OldRefCount = Pfn1->u3.e2.ReferenceCount; 01232 ASSERT(OldRefCount != 0); 01233 01234 /* Take off one reference */ 01235 RefCount = InterlockedCompareExchange16((PSHORT)&Pfn1->u3.e2.ReferenceCount, 01236 OldRefCount - 1, 01237 OldRefCount); 01238 ASSERT(RefCount != 0); 01239 } while (OldRefCount != RefCount); 01240 ASSERT(RefCount > 1); 01241 01242 /* Are there only lock references left? */ 01243 if (RefCount == 2) 01244 { 01245 /* And does the page still have users? */ 01246 if (Pfn1->u2.ShareCount >= 1) 01247 { 01248 /* Then it should still be valid */ 01249 ASSERT(Pfn1->u3.e1.PageLocation == ActiveAndValid); 01250 01251 /* Not supported yet */ 01252 ASSERT((Pfn1->u3.e1.PrototypePte == 0) && 01253 (Pfn1->OriginalPte.u.Soft.Prototype == 0)); 01254 01255 /* But there is one less "locked" page though */ 01256 InterlockedExchangeAddSizeT(&MmSystemLockPagesCount, -1); 01257 } 01258 } 01259 } 01260 } 01261 } while (++MdlPages < LastPage); 01262 01263 // 01264 // Release the lock 01265 // 01266 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 01267 01268 // 01269 // Check if we have a process 01270 // 01271 if (Process) 01272 { 01273 // 01274 // Handle the accounting of locked pages 01275 // 01276 ASSERT(Process->NumberOfLockedPages > 0); 01277 InterlockedExchangeAddSizeT(&Process->NumberOfLockedPages, 01278 -(LONG_PTR)PageCount); 01279 } 01280 01281 // 01282 // We're done 01283 // 01284 Mdl->MdlFlags &= ~MDL_IO_SPACE; 01285 Mdl->MdlFlags &= ~MDL_PAGES_LOCKED; 01286 return; 01287 } 01288 01289 // 01290 // Check if we have a process 01291 // 01292 if (Process) 01293 { 01294 // 01295 // Handle the accounting of locked pages 01296 // 01297 ASSERT(Process->NumberOfLockedPages > 0); 01298 InterlockedExchangeAddSizeT(&Process->NumberOfLockedPages, 01299 -(LONG_PTR)PageCount); 01300 } 01301 01302 // 01303 // Loop every page 01304 // 01305 LastPage = MdlPages + PageCount; 01306 do 01307 { 01308 // 01309 // Last page reached 01310 // 01311 if (*MdlPages == LIST_HEAD) 01312 { 01313 // 01314 // Were there no pages at all? 01315 // 01316 if (MdlPages == (PPFN_NUMBER)(Mdl + 1)) 01317 { 01318 // 01319 // We're already done 01320 // 01321 Mdl->MdlFlags &= ~MDL_PAGES_LOCKED; 01322 return; 01323 } 01324 01325 // 01326 // Otherwise, stop here 01327 // 01328 LastPage = MdlPages; 01329 break; 01330 } 01331 01332 /* Save the PFN entry instead for the secondary loop */ 01333 *MdlPages = (PFN_NUMBER)MiGetPfnEntry(*MdlPages); 01334 ASSERT(*MdlPages != 0); 01335 } while (++MdlPages < LastPage); 01336 01337 // 01338 // Reset pointer 01339 // 01340 MdlPages = (PPFN_NUMBER)(Mdl + 1); 01341 01342 // 01343 // Now grab the PFN lock for the actual unlock and dereference 01344 // 01345 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 01346 do 01347 { 01348 /* Get the current entry and reference count */ 01349 Pfn1 = (PMMPFN)*MdlPages; 01350 OldRefCount = Pfn1->u3.e2.ReferenceCount; 01351 ASSERT(OldRefCount != 0); 01352 01353 /* Is this already the last dereference */ 01354 if (OldRefCount == 1) 01355 { 01356 /* It should be on a free list waiting for us */ 01357 ASSERT(Pfn1->u3.e2.ReferenceCount == 1); 01358 ASSERT(Pfn1->u3.e1.PageLocation != ActiveAndValid); 01359 ASSERT(Pfn1->u2.ShareCount == 0); 01360 01361 /* Not supported yet */ 01362 ASSERT(((Pfn1->u3.e1.PrototypePte == 0) && 01363 (Pfn1->OriginalPte.u.Soft.Prototype == 0))); 01364 01365 /* One less page */ 01366 InterlockedExchangeAddSizeT(&MmSystemLockPagesCount, -1); 01367 01368 /* Do the last dereference, we're done here */ 01369 MiDecrementReferenceCount(Pfn1, MiGetPfnEntryIndex(Pfn1)); 01370 } 01371 else 01372 { 01373 /* Loop decrementing one reference */ 01374 do 01375 { 01376 /* Make sure it's still valid */ 01377 OldRefCount = Pfn1->u3.e2.ReferenceCount; 01378 ASSERT(OldRefCount != 0); 01379 01380 /* Take off one reference */ 01381 RefCount = InterlockedCompareExchange16((PSHORT)&Pfn1->u3.e2.ReferenceCount, 01382 OldRefCount - 1, 01383 OldRefCount); 01384 ASSERT(RefCount != 0); 01385 } while (OldRefCount != RefCount); 01386 ASSERT(RefCount > 1); 01387 01388 /* Are there only lock references left? */ 01389 if (RefCount == 2) 01390 { 01391 /* And does the page still have users? */ 01392 if (Pfn1->u2.ShareCount >= 1) 01393 { 01394 /* Then it should still be valid */ 01395 ASSERT(Pfn1->u3.e1.PageLocation == ActiveAndValid); 01396 01397 /* Not supported yet */ 01398 ASSERT(((Pfn1->u3.e1.PrototypePte == 0) && 01399 (Pfn1->OriginalPte.u.Soft.Prototype == 0))); 01400 01401 /* But there is one less "locked" page though */ 01402 InterlockedExchangeAddSizeT(&MmSystemLockPagesCount, -1); 01403 } 01404 } 01405 } 01406 } while (++MdlPages < LastPage); 01407 01408 // 01409 // Release the lock 01410 // 01411 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 01412 01413 // 01414 // We're done 01415 // 01416 Mdl->MdlFlags &= ~MDL_PAGES_LOCKED; 01417 } 01418 01419 /* 01420 * @unimplemented 01421 */ 01422 NTSTATUS 01423 NTAPI 01424 MmAdvanceMdl(IN PMDL Mdl, 01425 IN ULONG NumberOfBytes) 01426 { 01427 UNIMPLEMENTED; 01428 return STATUS_NOT_IMPLEMENTED; 01429 } 01430 01431 /* 01432 * @unimplemented 01433 */ 01434 PVOID 01435 NTAPI 01436 MmMapLockedPagesWithReservedMapping(IN PVOID MappingAddress, 01437 IN ULONG PoolTag, 01438 IN PMDL MemoryDescriptorList, 01439 IN MEMORY_CACHING_TYPE CacheType) 01440 { 01441 UNIMPLEMENTED; 01442 return 0; 01443 } 01444 01445 /* 01446 * @unimplemented 01447 */ 01448 VOID 01449 NTAPI 01450 MmUnmapReservedMapping(IN PVOID BaseAddress, 01451 IN ULONG PoolTag, 01452 IN PMDL MemoryDescriptorList) 01453 { 01454 UNIMPLEMENTED; 01455 } 01456 01457 /* 01458 * @unimplemented 01459 */ 01460 NTSTATUS 01461 NTAPI 01462 MmPrefetchPages(IN ULONG NumberOfLists, 01463 IN PREAD_LIST *ReadLists) 01464 { 01465 UNIMPLEMENTED; 01466 return STATUS_NOT_IMPLEMENTED; 01467 } 01468 01469 /* 01470 * @unimplemented 01471 */ 01472 NTSTATUS 01473 NTAPI 01474 MmProtectMdlSystemAddress(IN PMDL MemoryDescriptorList, 01475 IN ULONG NewProtect) 01476 { 01477 UNIMPLEMENTED; 01478 return STATUS_NOT_IMPLEMENTED; 01479 } 01480 01481 /* 01482 * @unimplemented 01483 */ 01484 VOID 01485 NTAPI 01486 MmProbeAndLockProcessPages(IN OUT PMDL MemoryDescriptorList, 01487 IN PEPROCESS Process, 01488 IN KPROCESSOR_MODE AccessMode, 01489 IN LOCK_OPERATION Operation) 01490 { 01491 UNIMPLEMENTED; 01492 } 01493 01494 01495 /* 01496 * @unimplemented 01497 */ 01498 VOID 01499 NTAPI 01500 MmProbeAndLockSelectedPages(IN OUT PMDL MemoryDescriptorList, 01501 IN LARGE_INTEGER PageList[], 01502 IN KPROCESSOR_MODE AccessMode, 01503 IN LOCK_OPERATION Operation) 01504 { 01505 UNIMPLEMENTED; 01506 } 01507 01508 /* 01509 * @unimplemented 01510 */ 01511 VOID 01512 NTAPI 01513 MmMapMemoryDumpMdl(IN PMDL Mdl) 01514 { 01515 UNIMPLEMENTED; 01516 } 01517 01518 /* EOF */ Generated on Sun May 27 2012 04:37:04 for ReactOS by
1.7.6.1
|