Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

mapcache.c File Reference

#include "mi.h"

Go to the source code of this file.

Defines

#define X256K   0x40000

Functions

VOID MiFreeInPageSupportBlock (IN PMMINPAGE_SUPPORT Support)
VOID MiRemoveMappedPtes (IN PVOID BaseAddress, IN ULONG NumberOfPtes, IN PCONTROL_AREA ControlArea, IN PMMSUPPORT WorkingSetInfo)
LONG MiMapCacheExceptionFilter (IN PNTSTATUS Status, IN PEXCEPTION_POINTERS ExceptionPointer)
NTSTATUS MmMapViewInSystemCache (IN PVOID SectionToMap, OUT PVOID *CapturedBase, IN OUT PLARGE_INTEGER SectionOffset, IN OUT PULONG CapturedViewSize)
VOID MiAddMappedPtes (IN PMMPTE FirstPte, IN ULONG NumberOfPtes, IN PCONTROL_AREA ControlArea)
VOID MmUnmapViewInSystemCache (IN PVOID BaseAddress, IN PVOID SectionToUnmap, IN ULONG AddToFront)
VOID MiInitializeSystemCache (IN ULONG MinimumWorkingSet, IN ULONG MaximumWorkingSet)
BOOLEAN MmCheckCachedPageState (IN PVOID Address, IN BOOLEAN SetToZero)
NTSTATUS MmCopyToCachedPage (IN PVOID Address, IN PVOID UserBuffer, IN ULONG Offset, IN SIZE_T CountInBytes, IN BOOLEAN DontZero)
VOID MmUnlockCachedPage (IN PVOID AddressInCache)

Variables

ULONG MmFrontOfList
PMMPTE MmFirstFreeSystemCache
PMMPTE MmLastFreeSystemCache
PMMPTE MmFlushSystemCache
PMMPTE MmSystemCachePteBase


Define Documentation

#define X256K   0x40000
 

Definition at line 45 of file mapcache.c.

Referenced by MiInitializeSystemCache(), and MmUnmapViewInSystemCache().


Function Documentation

VOID MiAddMappedPtes IN PMMPTE  FirstPte,
IN ULONG  NumberOfPtes,
IN PCONTROL_AREA  ControlArea
 

Definition at line 287 of file mapcache.c.

References ASSERT, MiProtoAddressForKernelPte, MM_COLOR_MASK, _SUBSECTION::NextSubsection, PTE_SHIFT, _SUBSECTION::PtesInSubsection, _SUBSECTION::SubsectionBase, _MMPTE::u, and ZeroKernelPte.

Referenced by MiMapViewInSystemSpace(), and MiShareSessionImage().

00295 : 00296 00297 This function maps a view in the current address space to the 00298 specified control area. The page protection is identical to that 00299 of the prototype PTE. 00300 00301 This routine assumes the caller has called MiCheckPurgeAndUpMapCount, 00302 hence the PFN lock is not needed here. 00303 00304 Arguments: 00305 00306 FirstPte - Supplies a pointer to the first PTE of the current address 00307 space to initialize. 00308 00309 NumberOfPtes - Supplies the number of PTEs to initialize. 00310 00311 ControlArea - Supplies the control area to point the PTEs at. 00312 00313 Return Value: 00314 00315 None. 00316 00317 Environment: 00318 00319 Kernel mode. 00320 00321 --*/ 00322 00323 { 00324 PMMPTE PointerPte; 00325 PMMPTE ProtoPte; 00326 PMMPTE LastProto; 00327 PMMPTE LastPte; 00328 PSUBSECTION Subsection; 00329 00330 if (ControlArea->u.Flags.GlobalOnlyPerSession == 0) { 00331 Subsection = (PSUBSECTION)(ControlArea + 1); 00332 } 00333 else { 00334 Subsection = (PSUBSECTION)((PLARGE_CONTROL_AREA)ControlArea + 1); 00335 } 00336 00337 PointerPte = FirstPte; 00338 ASSERT (NumberOfPtes != 0); 00339 LastPte = FirstPte + NumberOfPtes; 00340 00341 ASSERT (ControlArea->NumberOfMappedViews >= 1); 00342 ASSERT (ControlArea->NumberOfUserReferences >= 1); 00343 ASSERT (ControlArea->u.Flags.HadUserReference == 1); 00344 ASSERT (ControlArea->NumberOfSectionReferences != 0); 00345 00346 ASSERT (ControlArea->u.Flags.BeingCreated == 0); 00347 ASSERT (ControlArea->u.Flags.BeingDeleted == 0); 00348 ASSERT (ControlArea->u.Flags.BeingPurged == 0); 00349 00350 ProtoPte = Subsection->SubsectionBase; 00351 00352 LastProto = &Subsection->SubsectionBase[Subsection->PtesInSubsection]; 00353 00354 while (PointerPte < LastPte) { 00355 00356 if (ProtoPte >= LastProto) { 00357 00358 // 00359 // Handle extended subsections. 00360 // 00361 00362 Subsection = Subsection->NextSubsection; 00363 ProtoPte = Subsection->SubsectionBase; 00364 LastProto = &Subsection->SubsectionBase[ 00365 Subsection->PtesInSubsection]; 00366 } 00367 ASSERT (PointerPte->u.Long == ZeroKernelPte.u.Long); 00368 PointerPte->u.Long = MiProtoAddressForKernelPte (ProtoPte); 00369 00370 ASSERT (((ULONG_PTR)PointerPte & (MM_COLOR_MASK << PTE_SHIFT)) == 00371 (((ULONG_PTR)ProtoPte & (MM_COLOR_MASK << PTE_SHIFT)))); 00372 00373 PointerPte += 1; 00374 ProtoPte += 1; 00375 } 00376 00377 return; 00378 }

VOID MiFreeInPageSupportBlock IN PMMINPAGE_SUPPORT  Support  ) 
 

Definition at line 4252 of file pagfault.c.

04258 : 04259 04260 This routine returns the in page support block to a list 04261 of freed blocks. 04262 04263 Arguments: 04264 04265 Support - Supplies the in page support block to put on the free list. 04266 04267 Return Value: 04268 04269 None. 04270 04271 Environment: 04272 04273 Kernel mode, PFN lock held. 04274 04275 --*/ 04276 04277 { 04278 04279 MM_PFN_LOCK_ASSERT(); 04280 04281 ASSERT (Support->u.Thread != NULL); 04282 ASSERT (Support->WaitCount != 0); 04283 #if defined (_PREFETCH_) 04284 ASSERT ((Support->ListEntry.Flink == NULL) || 04285 (Support->PrefetchMdl != NULL)); 04286 #else 04287 ASSERT (Support->ListEntry.Flink == NULL); 04288 #endif 04289 Support->WaitCount -= 1; 04290 if (Support->WaitCount == 0) { 04291 Support->u.Thread = NULL; 04292 InsertTailList (&MmInPageSupportList.ListHead, 04293 &Support->ListEntry); 04294 MmInPageSupportList.Count += 1; 04295 } 04296 return; 04297 }

VOID MiInitializeSystemCache IN ULONG  MinimumWorkingSet,
IN ULONG  MaximumWorkingSet
 

Definition at line 814 of file mapcache.c.

References _MMSUPPORT::AllowWorkingSetAdjustment, COMPUTE_PAGES_SPANNED, _MMWSL::FirstDynamic, _MMWSL::FirstFree, _MMWSL::HashTable, _MMWSL::HashTableSize, _MMWSL::HashTableStart, _MMWSL::HighestPermittedHashAddress, L, _MMWSL::LastEntry, _MMWSL::LastInitializedWsle, _MMWORKING_SET_EXPANSION_HEAD::ListHead, LOCK_PFN, LOCK_SYSTEM_WS, _MMSUPPORT::MaximumWorkingSetSize, MI_GET_PAGE_COLOR_FROM_PTE, MI_PTE_BASE_FOR_LOWEST_KERNEL_ADDRESS, MI_WRITE_VALID_PTE, MiGetPteAddress, MiGrowWsleHash(), MiInitializePfn(), _MMSUPPORT::MinimumWorkingSetSize, MiRemoveZeroPage(), MiSystemCacheEndExtra, MiSystemCacheStartExtra, MM_EMPTY_PTE_LIST, MM_FREE_WSLE_SHIFT, MM_MAXIMUM_WORKING_SET, MM_SYSTEM_CACHE_START, MmFirstFreeSystemCache, MmLastFreeSystemCache, MmSystemCacheEnd, MmSystemCachePteBase, MmSystemCacheStart, MmSystemCacheWorkingSetList, MmSystemCacheWs, MmSystemCacheWsle, MmSystemCacheWsMaximum, MmSystemCacheWsMinimum, MmWorkingSetExpansionHead, MMWSLE, _MMWSL::NextSlot, NULL, PAGE_ALIGN, PAGE_SHIFT, PAGE_SIZE, _MMWSL::Quota, TRUE, _MMPTE::u, _MMWSLE::u1, UNLOCK_PFN, UNLOCK_SYSTEM_WS, _MMWSL::UsedPageTableEntries, ValidKernelPte, _MMSUPPORT::VmWorkingSetList, _MMSUPPORT::WorkingSetExpansionLinks, _MMSUPPORT::WorkingSetSize, _MMWSL::Wsle, WSLE_NULL_INDEX, and X256K.

Referenced by MmInitSystem().

00821 : 00822 00823 This routine initializes the system cache working set and 00824 data management structures. 00825 00826 Arguments: 00827 00828 MinimumWorkingSet - Supplies the minimum working set for the system 00829 cache. 00830 00831 MaximumWorkingSet - Supplies the maximum working set size for the 00832 system cache. 00833 00834 Return Value: 00835 00836 None. 00837 00838 Environment: 00839 00840 Kernel mode, called only at phase 0 initialization. 00841 00842 --*/ 00843 00844 { 00845 ULONG SizeOfSystemCacheInPages; 00846 ULONG HunksOf256KInCache; 00847 PMMWSLE WslEntry; 00848 ULONG NumberOfEntriesMapped; 00849 PFN_NUMBER i; 00850 MMPTE PteContents; 00851 PMMPTE PointerPte; 00852 KIRQL OldIrql; 00853 00854 PointerPte = MiGetPteAddress (MmSystemCacheWorkingSetList); 00855 00856 PteContents = ValidKernelPte; 00857 00858 LOCK_PFN (OldIrql); 00859 00860 i = MiRemoveZeroPage(MI_GET_PAGE_COLOR_FROM_PTE (PointerPte)); 00861 00862 PteContents.u.Hard.PageFrameNumber = i; 00863 00864 MI_WRITE_VALID_PTE (PointerPte, PteContents); 00865 00866 MiInitializePfn (i, PointerPte, 1L); 00867 00868 UNLOCK_PFN (OldIrql); 00869 00870 #if defined (_WIN64) 00871 MmSystemCacheWsle = (PMMWSLE)(MmSystemCacheWorkingSetList + 1); 00872 #else 00873 MmSystemCacheWsle = 00874 (PMMWSLE)(&MmSystemCacheWorkingSetList->UsedPageTableEntries[0]); 00875 #endif 00876 00877 MmSystemCacheWs.VmWorkingSetList = MmSystemCacheWorkingSetList; 00878 MmSystemCacheWs.WorkingSetSize = 0; 00879 MmSystemCacheWs.MinimumWorkingSetSize = MinimumWorkingSet; 00880 MmSystemCacheWs.MaximumWorkingSetSize = MaximumWorkingSet; 00881 InsertTailList (&MmWorkingSetExpansionHead.ListHead, 00882 &MmSystemCacheWs.WorkingSetExpansionLinks); 00883 00884 MmSystemCacheWs.AllowWorkingSetAdjustment = TRUE; 00885 00886 // 00887 // Don't use entry 0 as an index of zero in the PFN database 00888 // means that the page can be assigned to a slot. This is not 00889 // a problem for process working sets as page 0 is private. 00890 // 00891 00892 MmSystemCacheWorkingSetList->FirstFree = 1; 00893 MmSystemCacheWorkingSetList->FirstDynamic = 1; 00894 MmSystemCacheWorkingSetList->NextSlot = 1; 00895 MmSystemCacheWorkingSetList->LastEntry = (ULONG)MmSystemCacheWsMinimum; 00896 MmSystemCacheWorkingSetList->Quota = MmSystemCacheWorkingSetList->LastEntry; 00897 MmSystemCacheWorkingSetList->HashTable = NULL; 00898 MmSystemCacheWorkingSetList->HashTableSize = 0; 00899 MmSystemCacheWorkingSetList->Wsle = MmSystemCacheWsle; 00900 00901 MmSystemCacheWorkingSetList->HashTableStart = 00902 (PVOID)((PCHAR)PAGE_ALIGN (&MmSystemCacheWorkingSetList->Wsle[MM_MAXIMUM_WORKING_SET]) + PAGE_SIZE); 00903 00904 MmSystemCacheWorkingSetList->HighestPermittedHashAddress = (PVOID)(MM_SYSTEM_CACHE_START); 00905 00906 NumberOfEntriesMapped = (ULONG)(((PMMWSLE)((PCHAR)MmSystemCacheWorkingSetList + 00907 PAGE_SIZE)) - MmSystemCacheWsle); 00908 00909 LOCK_PFN (OldIrql); 00910 00911 while (NumberOfEntriesMapped < MmSystemCacheWsMaximum) { 00912 00913 PointerPte += 1; 00914 i = MiRemoveZeroPage(MI_GET_PAGE_COLOR_FROM_PTE (PointerPte)); 00915 PteContents.u.Hard.PageFrameNumber = i; 00916 MI_WRITE_VALID_PTE (PointerPte, PteContents); 00917 MiInitializePfn (i, PointerPte, 1L); 00918 NumberOfEntriesMapped += PAGE_SIZE / sizeof(MMWSLE); 00919 } 00920 00921 UNLOCK_PFN (OldIrql); 00922 00923 // 00924 // Initialize the following slots as free. 00925 // 00926 00927 WslEntry = MmSystemCacheWsle + 1; 00928 00929 for (i = 1; i < NumberOfEntriesMapped; i++) { 00930 00931 // 00932 // Build the free list, note that the first working 00933 // set entries (CurrentEntry) are not on the free list. 00934 // These entries are reserved for the pages which 00935 // map the working set and the page which contains the PDE. 00936 // 00937 00938 WslEntry->u1.Long = (i + 1) << MM_FREE_WSLE_SHIFT; 00939 WslEntry += 1; 00940 } 00941 00942 WslEntry -= 1; 00943 WslEntry->u1.Long = WSLE_NULL_INDEX << MM_FREE_WSLE_SHIFT; // End of list. 00944 00945 MmSystemCacheWorkingSetList->LastInitializedWsle = NumberOfEntriesMapped - 1; 00946 00947 // 00948 // Build a free list structure in the PTEs for the system cache. 00949 // 00950 00951 MmSystemCachePteBase = MI_PTE_BASE_FOR_LOWEST_KERNEL_ADDRESS; 00952 00953 SizeOfSystemCacheInPages = COMPUTE_PAGES_SPANNED (MmSystemCacheStart, 00954 (PCHAR)MmSystemCacheEnd - (PCHAR)MmSystemCacheStart + 1); 00955 00956 HunksOf256KInCache = SizeOfSystemCacheInPages / (X256K / PAGE_SIZE); 00957 00958 PointerPte = MiGetPteAddress (MmSystemCacheStart); 00959 00960 MmFirstFreeSystemCache = PointerPte; 00961 00962 for (i = 0; i < HunksOf256KInCache; i += 1) { 00963 PointerPte->u.List.NextEntry = (PointerPte + (X256K / PAGE_SIZE)) - MmSystemCachePteBase; 00964 PointerPte += X256K / PAGE_SIZE; 00965 } 00966 00967 PointerPte -= X256K / PAGE_SIZE; 00968 00969 #if defined(_X86_) 00970 00971 // 00972 // Add any extended ranges. 00973 // 00974 00975 if (MiSystemCacheEndExtra != MmSystemCacheEnd) { 00976 00977 SizeOfSystemCacheInPages = COMPUTE_PAGES_SPANNED (MiSystemCacheStartExtra, 00978 (PCHAR)MiSystemCacheEndExtra - (PCHAR)MiSystemCacheStartExtra + 1); 00979 00980 HunksOf256KInCache = SizeOfSystemCacheInPages / (X256K / PAGE_SIZE); 00981 00982 if (HunksOf256KInCache) { 00983 00984 PMMPTE PointerPteExtended; 00985 00986 PointerPteExtended = MiGetPteAddress (MiSystemCacheStartExtra); 00987 PointerPte->u.List.NextEntry = PointerPteExtended - MmSystemCachePteBase; 00988 PointerPte = PointerPteExtended; 00989 00990 for (i = 0; i < HunksOf256KInCache; i += 1) { 00991 PointerPte->u.List.NextEntry = (PointerPte + (X256K / PAGE_SIZE)) - MmSystemCachePteBase; 00992 PointerPte += X256K / PAGE_SIZE; 00993 } 00994 00995 PointerPte -= X256K / PAGE_SIZE; 00996 } 00997 } 00998 #endif 00999 01000 PointerPte->u.List.NextEntry = MM_EMPTY_PTE_LIST; 01001 MmLastFreeSystemCache = PointerPte; 01002 01003 if (MaximumWorkingSet > ((1536*1024) >> PAGE_SHIFT)) { 01004 01005 // 01006 // The working set list consists of more than a single page. 01007 // 01008 01009 LOCK_SYSTEM_WS (OldIrql); 01010 MiGrowWsleHash (&MmSystemCacheWs); 01011 UNLOCK_SYSTEM_WS (OldIrql); 01012 } 01013 }

LONG MiMapCacheExceptionFilter IN PNTSTATUS  Status,
IN PEXCEPTION_POINTERS  ExceptionPointer
 

Definition at line 1779 of file mapcache.c.

References EXCEPTION_EXECUTE_HANDLER, NTSTATUS(), and Status.

Referenced by MiLoadImageSection(), and MmCopyToCachedPage().

01786 : 01787 01788 This routine is a filter for exceptions during copying data 01789 from the user buffer to the system cache. It stores the 01790 status code from the exception record into the status argument. 01791 In the case of an in page i/o error it returns the actual 01792 error code and in the case of an access violation it returns 01793 STATUS_INVALID_USER_BUFFER. 01794 01795 Arguments: 01796 01797 Status - Returns the status from the exception record. 01798 01799 ExceptionCode - Supplies the exception code to being checked. 01800 01801 Return Value: 01802 01803 ULONG - returns EXCEPTION_EXECUTE_HANDLER 01804 01805 --*/ 01806 01807 { 01808 NTSTATUS local; 01809 01810 local = ExceptionPointer->ExceptionRecord->ExceptionCode; 01811 01812 // 01813 // If the exception is STATUS_IN_PAGE_ERROR, get the I/O error code 01814 // from the exception record. 01815 // 01816 01817 if (local == STATUS_IN_PAGE_ERROR) { 01818 if (ExceptionPointer->ExceptionRecord->NumberParameters >= 3) { 01819 local = (NTSTATUS)ExceptionPointer->ExceptionRecord->ExceptionInformation[2]; 01820 } 01821 } 01822 01823 if (local == STATUS_ACCESS_VIOLATION) { 01824 local = STATUS_INVALID_USER_BUFFER; 01825 } 01826 01827 *Status = local; 01828 return EXCEPTION_EXECUTE_HANDLER; 01829 }

VOID MiRemoveMappedPtes IN PVOID  BaseAddress,
IN ULONG  NumberOfPtes,
IN PCONTROL_AREA  ControlArea,
IN PMMSUPPORT  WorkingSetInfo
 

Definition at line 579 of file mapcache.c.

References ASSERT, _MMPTE_FLUSH_LIST::Count, FALSE, _MMPTE_FLUSH_LIST::FlushPte, _MMPTE_FLUSH_LIST::FlushVa, LOCK_PFN, LOCK_SYSTEM_WS, MI_CAPTURE_DIRTY_BIT_TO_PFN, MI_FLUSH_ENTIRE_SESSION_TB, MI_GET_PAGE_FRAME_FROM_PTE, MI_PFN_ELEMENT, MI_SET_PTE_IN_WORKING_SET, MI_WRITE_INVALID_PTE, MI_WRITE_VALID_PTE, MiCheckControlArea(), MiDecrementShareAndValidCount, MiDecrementShareCount(), MiFlushPteList(), MiGetPteAddress, MiHydra, MiLocateWsle(), MiReleaseWsle(), MiRemoveWsle(), MM_MAXIMUM_FLUSH_COUNT, MmSystemCacheWs, MmSystemPagePtes, NULL, PAGE_SIZE, PDE_PER_PAGE, TRUE, _MMPTE::u, _MMPFN::u1, UNLOCK_PFN, UNLOCK_SYSTEM_WS, WSLE_NULL_INDEX, and ZeroKernelPte.

00588 : 00589 00590 This function unmaps a view from the system cache or a session space. 00591 00592 NOTE: When this function is called, no pages may be locked in 00593 the cache (or session space) for the specified view. 00594 00595 Arguments: 00596 00597 BaseAddress - Supplies the base address of the section in the 00598 system cache or session space. 00599 00600 NumberOfPtes - Supplies the number of PTEs to unmap. 00601 00602 ControlArea - Supplies the control area mapping the view. 00603 00604 WorkingSetInfo - Supplies the charged working set structures. 00605 00606 Return Value: 00607 00608 None. 00609 00610 Environment: 00611 00612 Kernel mode. 00613 00614 --*/ 00615 00616 { 00617 PMMPTE PointerPte; 00618 PMMPTE PointerPde; 00619 PMMPFN Pfn1; 00620 PMMPTE FirstPte; 00621 MMPTE PteContents; 00622 KIRQL OldIrql; 00623 KIRQL OldIrqlWs; 00624 ULONG WorkingSetIndex; 00625 ULONG DereferenceSegment; 00626 MMPTE_FLUSH_LIST PteFlushList; 00627 ULONG WsHeld; 00628 00629 DereferenceSegment = FALSE; 00630 WsHeld = FALSE; 00631 00632 PteFlushList.Count = 0; 00633 PointerPte = MiGetPteAddress (BaseAddress); 00634 FirstPte = PointerPte; 00635 00636 // 00637 // Get the control area for the segment which is mapped here. 00638 // 00639 00640 while (NumberOfPtes) { 00641 00642 // 00643 // The cache is organized in chunks of 256k bytes, clear 00644 // the first chunk, then check to see if this is the last 00645 // chunk. 00646 // 00647 00648 // 00649 // The page table page is always resident for the system cache (and 00650 // for a session space map). 00651 // 00652 // Check each PTE, it is in one of two states, either valid or 00653 // prototype PTE format. 00654 // 00655 00656 PteContents = *PointerPte; 00657 if (PteContents.u.Hard.Valid == 1) { 00658 00659 // 00660 // The system cache is locked by us, all others are locked by 00661 // the caller. 00662 // 00663 00664 if (WorkingSetInfo == &MmSystemCacheWs) { 00665 if (!WsHeld) { 00666 WsHeld = TRUE; 00667 LOCK_SYSTEM_WS (OldIrqlWs); 00668 continue; 00669 } 00670 } 00671 00672 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 00673 00674 WorkingSetIndex = MiLocateWsle (BaseAddress, 00675 WorkingSetInfo->VmWorkingSetList, 00676 Pfn1->u1.WsIndex ); 00677 ASSERT (WorkingSetIndex != WSLE_NULL_INDEX); 00678 00679 MiRemoveWsle (WorkingSetIndex, 00680 WorkingSetInfo->VmWorkingSetList ); 00681 MiReleaseWsle (WorkingSetIndex, WorkingSetInfo); 00682 00683 MI_SET_PTE_IN_WORKING_SET (PointerPte, 0); 00684 00685 LOCK_PFN (OldIrql); 00686 00687 // 00688 // The PTE is valid. 00689 // 00690 00691 // 00692 // Capture the state of the modified bit for this PTE. 00693 // 00694 00695 MI_CAPTURE_DIRTY_BIT_TO_PFN (PointerPte, Pfn1); 00696 00697 // 00698 // Flush the TB for this page. 00699 // 00700 00701 if (PteFlushList.Count != MM_MAXIMUM_FLUSH_COUNT) { 00702 PteFlushList.FlushPte[PteFlushList.Count] = PointerPte; 00703 PteFlushList.FlushVa[PteFlushList.Count] = BaseAddress; 00704 PteFlushList.Count += 1; 00705 } 00706 00707 PointerPde = MiGetPteAddress (PointerPte); 00708 00709 #if !defined (_WIN64) 00710 00711 // 00712 // The PDE must be carefully checked against the master table 00713 // because the PDEs are all zeroed in process creation. If this 00714 // process has never faulted on any address in this range (all 00715 // references prior and above were filled directly by the TB as 00716 // the PTEs are global on non-Hydra), then the PDE reference 00717 // below to determine the page table frame will be zero. 00718 // 00719 // Note this cannot happen on NT64 as no master table is used. 00720 // 00721 00722 if (PointerPde->u.Long == 0) { 00723 00724 PMMPTE MasterPde; 00725 00726 ASSERT (MiHydra == FALSE); 00727 00728 #if !defined (_X86PAE_) 00729 MasterPde = &MmSystemPagePtes [((ULONG_PTR)PointerPde & 00730 ((sizeof(MMPTE) * PDE_PER_PAGE) - 1)) / sizeof(MMPTE)]; 00731 #else 00732 MasterPde = &MmSystemPagePtes [((ULONG_PTR)PointerPde & 00733 (PD_PER_SYSTEM * (sizeof(MMPTE) * PDE_PER_PAGE) - 1)) / sizeof(MMPTE)]; 00734 #endif 00735 ASSERT (MasterPde->u.Hard.Valid == 1); 00736 MI_WRITE_VALID_PTE (PointerPde, *MasterPde); 00737 } 00738 #endif 00739 00740 // 00741 // Decrement the share and valid counts of the page table 00742 // page which maps this PTE. 00743 // 00744 00745 MiDecrementShareAndValidCount (MI_GET_PAGE_FRAME_FROM_PTE (PointerPde)); 00746 00747 // 00748 // Decrement the share count for the physical page. 00749 // 00750 00751 MiDecrementShareCount (MI_GET_PAGE_FRAME_FROM_PTE (&PteContents)); 00752 UNLOCK_PFN (OldIrql); 00753 00754 } else { 00755 if (WorkingSetInfo == &MmSystemCacheWs) { 00756 if (WsHeld) { 00757 UNLOCK_SYSTEM_WS (OldIrqlWs); 00758 WsHeld = FALSE; 00759 } 00760 } 00761 00762 ASSERT ((PteContents.u.Long == ZeroKernelPte.u.Long) || 00763 (PteContents.u.Soft.Prototype == 1)); 00764 NOTHING; 00765 } 00766 MI_WRITE_INVALID_PTE (PointerPte, ZeroKernelPte); 00767 00768 PointerPte += 1; 00769 BaseAddress = (PVOID)((PCHAR)BaseAddress + PAGE_SIZE); 00770 NumberOfPtes -= 1; 00771 } 00772 00773 if (WorkingSetInfo == &MmSystemCacheWs) { 00774 if (WsHeld) { 00775 UNLOCK_SYSTEM_WS (OldIrqlWs); 00776 } 00777 } 00778 LOCK_PFN (OldIrql); 00779 00780 MiFlushPteList (&PteFlushList, TRUE, ZeroKernelPte); 00781 00782 if (WorkingSetInfo != &MmSystemCacheWs) { 00783 00784 // 00785 // Session space has no ASN - flush the entire TB. 00786 // 00787 00788 MI_FLUSH_ENTIRE_SESSION_TB (TRUE, TRUE); 00789 } 00790 00791 // 00792 // Decrement the number of user references as the caller upped them 00793 // via MiCheckPurgeAndUpMapCount when this was originally mapped. 00794 // 00795 00796 ControlArea->NumberOfUserReferences -= 1; 00797 00798 // 00799 // Decrement the number of mapped views for the segment 00800 // and check to see if the segment should be deleted. 00801 // 00802 00803 ControlArea->NumberOfMappedViews -= 1; 00804 00805 // 00806 // Check to see if the control area (segment) should be deleted. 00807 // This routine releases the PFN lock. 00808 // 00809 00810 MiCheckControlArea (ControlArea, NULL, OldIrql); 00811 }

BOOLEAN MmCheckCachedPageState IN PVOID  Address,
IN BOOLEAN  SetToZero
 

Definition at line 1016 of file mapcache.c.

References ActiveAndValid, ASSERT, FALSE, KernelMode, LOCK_PFN, LOCK_SYSTEM_WS, MI_BARRIER_SYNCHRONIZE, MI_DETERMINE_OWNER, MI_GET_PAGE_COLOR_FROM_PTE, MI_GET_PAGE_FRAME_FROM_PTE, MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE, MI_MAKE_VALID_PTE, MI_PFN_ELEMENT, MI_SET_GLOBAL_STATE, MI_SET_PTE_IN_WORKING_SET, MI_WRITE_VALID_PTE, MiGetPteAddress, MiGetSubsectionAddress, MiGetVirtualAddressMappedByPte, MiInitializePfn(), MiLocateAndReserveWsle(), MiMakeSystemAddressValidPfn(), MiPteToProto, MiRemoveZeroPage(), MiUnlinkPageFromList(), MiUpdateWsle(), MM_PTE_OWNER_MASK, MmAccessFault(), MmAvailablePages, MmSystemCacheWorkingSetList, MmSystemCacheWs, MmSystemCacheWsle, NULL, _MMPFN::OriginalPte, PsGetCurrentThread, _MMPFN::PteFrame, TRUE, _MMPTE::u, _MMWSLE::u1, _MMPFN::u1, _MMPFN::u2, _MMPFN::u3, UNLOCK_PFN, UNLOCK_SYSTEM_WS, and WSLE_NUMBER.

Referenced by CcCopyRead(), CcFastCopyRead(), CcMapAndRead(), and CcPerformReadAhead().

01023 : 01024 01025 This routine checks the state of the specified page that is mapped in 01026 the system cache. If the specified virtual address can be made valid 01027 (i.e., the page is already in memory), it is made valid and the value 01028 TRUE is returned. 01029 01030 If the page is not in memory, and SetToZero is FALSE, the 01031 value FALSE is returned. However, if SetToZero is TRUE, a page of 01032 zeroes is materialized for the specified virtual address and the address 01033 is made valid and the value TRUE is returned. 01034 01035 This routine is for usage by the cache manager. 01036 01037 Arguments: 01038 01039 Address - Supplies the address of a page mapped in the system cache. 01040 01041 SetToZero - Supplies TRUE if a page of zeroes should be created in the 01042 case where no page is already mapped. 01043 01044 Return Value: 01045 01046 FALSE if there if touching this page would cause a page fault resulting 01047 in a page read. 01048 01049 TRUE if there is a physical page in memory for this address. 01050 01051 Environment: 01052 01053 Kernel mode. 01054 01055 --*/ 01056 01057 { 01058 PMMPTE PointerPte; 01059 PMMPTE PointerPde; 01060 PMMPTE ProtoPte; 01061 PFN_NUMBER PageFrameIndex; 01062 WSLE_NUMBER WorkingSetIndex; 01063 MMPTE TempPte; 01064 MMPTE ProtoPteContents; 01065 PMMPFN Pfn1; 01066 PMMPFN Pfn2; 01067 KIRQL OldIrql; 01068 LOGICAL BarrierNeeded; 01069 ULONG BarrierStamp; 01070 01071 BarrierNeeded = FALSE; 01072 01073 PointerPte = MiGetPteAddress (Address); 01074 01075 // 01076 // Make the PTE valid if possible. 01077 // 01078 01079 if (PointerPte->u.Hard.Valid == 1) { 01080 return TRUE; 01081 } 01082 01083 LOCK_PFN (OldIrql); 01084 01085 if (PointerPte->u.Hard.Valid == 1) { 01086 goto UnlockAndReturnTrue; 01087 } 01088 01089 ASSERT (PointerPte->u.Soft.Prototype == 1); 01090 01091 ProtoPte = MiPteToProto (PointerPte); 01092 01093 // 01094 // Pte is not valid, check the state of the prototype PTE. 01095 // 01096 01097 if (MiMakeSystemAddressValidPfn (ProtoPte)) { 01098 01099 // 01100 // If page fault occurred, recheck state of original PTE. 01101 // 01102 01103 if (PointerPte->u.Hard.Valid == 1) { 01104 goto UnlockAndReturnTrue; 01105 } 01106 } 01107 01108 ProtoPteContents = *ProtoPte; 01109 01110 if (ProtoPteContents.u.Hard.Valid == 1) { 01111 01112 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (&ProtoPteContents); 01113 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 01114 01115 // 01116 // The prototype PTE is valid, make the cache PTE 01117 // valid and add it to the working set. 01118 // 01119 01120 TempPte = ProtoPteContents; 01121 01122 } else if ((ProtoPteContents.u.Soft.Transition == 1) && 01123 (ProtoPteContents.u.Soft.Prototype == 0)) { 01124 01125 // 01126 // Prototype PTE is in the transition state. Remove the page 01127 // from the page list and make it valid. 01128 // 01129 01130 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE (&ProtoPteContents); 01131 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 01132 if ((Pfn1->u3.e1.ReadInProgress) || 01133 (Pfn1->u3.e1.InPageError)) { 01134 01135 // 01136 // Collided page fault, return. 01137 // 01138 01139 goto UnlockAndReturnTrue; 01140 } 01141 01142 MiUnlinkPageFromList (Pfn1); 01143 01144 Pfn1->u3.e2.ReferenceCount += 1; 01145 Pfn1->u3.e1.PageLocation = ActiveAndValid; 01146 01147 MI_MAKE_VALID_PTE (TempPte, 01148 PageFrameIndex, 01149 Pfn1->OriginalPte.u.Soft.Protection, 01150 NULL ); 01151 01152 MI_WRITE_VALID_PTE (ProtoPte, TempPte); 01153 01154 // 01155 // Increment the valid PTE count for the page containing 01156 // the prototype PTE. 01157 // 01158 01159 Pfn2 = MI_PFN_ELEMENT (Pfn1->PteFrame); 01160 01161 } else { 01162 01163 // 01164 // Page is not in memory, if a page of zeroes is requested, 01165 // get a page of zeroes and make it valid. 01166 // 01167 01168 if ((SetToZero == FALSE) || (MmAvailablePages < 8)) { 01169 UNLOCK_PFN (OldIrql); 01170 01171 // 01172 // Fault the page into memory. 01173 // 01174 01175 MmAccessFault (FALSE, Address, KernelMode, (PVOID)0); 01176 return FALSE; 01177 } 01178 01179 // 01180 // Increment the count of Pfn references for the control area 01181 // corresponding to this file. 01182 // 01183 01184 MiGetSubsectionAddress ( 01185 ProtoPte)->ControlArea->NumberOfPfnReferences += 1; 01186 01187 PageFrameIndex = MiRemoveZeroPage(MI_GET_PAGE_COLOR_FROM_PTE (ProtoPte)); 01188 01189 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 01190 01191 // 01192 // This barrier check is needed after zeroing the page and 01193 // before setting the PTE (not the prototype PTE) valid. 01194 // Capture it now, check it at the last possible moment. 01195 // 01196 01197 BarrierNeeded = TRUE; 01198 BarrierStamp = (ULONG)Pfn1->PteFrame; 01199 01200 MiInitializePfn (PageFrameIndex, ProtoPte, 1); 01201 Pfn1->u2.ShareCount = 0; 01202 Pfn1->u3.e1.PrototypePte = 1; 01203 01204 MI_MAKE_VALID_PTE (TempPte, 01205 PageFrameIndex, 01206 Pfn1->OriginalPte.u.Soft.Protection, 01207 NULL ); 01208 01209 MI_WRITE_VALID_PTE (ProtoPte, TempPte); 01210 } 01211 01212 // 01213 // Increment the share count since the page is being put into a working 01214 // set. 01215 // 01216 01217 Pfn1->u2.ShareCount += 1; 01218 01219 if (Pfn1->u1.Event == NULL) { 01220 Pfn1->u1.Event = (PVOID)PsGetCurrentThread(); 01221 } 01222 01223 // 01224 // Increment the reference count of the page table 01225 // page for this PTE. 01226 // 01227 01228 PointerPde = MiGetPteAddress (PointerPte); 01229 Pfn2 = MI_PFN_ELEMENT (PointerPde->u.Hard.PageFrameNumber); 01230 01231 Pfn2->u2.ShareCount += 1; 01232 01233 MI_SET_GLOBAL_STATE (TempPte, 1); 01234 01235 #if defined (_WIN64) 01236 if (MI_DETERMINE_OWNER (PointerPte) == 0) { 01237 TempPte.u.Long &= ~MM_PTE_OWNER_MASK; 01238 } 01239 #else 01240 TempPte.u.Hard.Owner = MI_DETERMINE_OWNER (PointerPte); 01241 #endif 01242 01243 if (BarrierNeeded) { 01244 MI_BARRIER_SYNCHRONIZE (BarrierStamp); 01245 } 01246 01247 MI_WRITE_VALID_PTE (PointerPte, TempPte); 01248 01249 UNLOCK_PFN (OldIrql); 01250 01251 LOCK_SYSTEM_WS (OldIrql); 01252 01253 WorkingSetIndex = MiLocateAndReserveWsle (&MmSystemCacheWs); 01254 01255 MiUpdateWsle (&WorkingSetIndex, 01256 MiGetVirtualAddressMappedByPte (PointerPte), 01257 MmSystemCacheWorkingSetList, 01258 Pfn1); 01259 01260 MmSystemCacheWsle[WorkingSetIndex].u1.e1.SameProtectAsProto = 1; 01261 01262 MI_SET_PTE_IN_WORKING_SET (PointerPte, WorkingSetIndex); 01263 01264 UNLOCK_SYSTEM_WS (OldIrql); 01265 01266 return TRUE; 01267 01268 UnlockAndReturnTrue: 01269 UNLOCK_PFN (OldIrql); 01270 return TRUE; 01271 }

NTSTATUS MmCopyToCachedPage IN PVOID  Address,
IN PVOID  UserBuffer,
IN ULONG  Offset,
IN SIZE_T  CountInBytes,
IN BOOLEAN  DontZero
 

Definition at line 1274 of file mapcache.c.

References ActiveAndValid, APC_LEVEL, _ETHREAD::ApcNeeded, ASSERT, Buffer, CHAR, Copy, DISPATCH_LEVEL, Event(), EXCEPTION_EXECUTE_HANDLER, FALSE, IoRetryIrpCompletions(), KeDelayExecutionThread(), KeEnterCriticalRegion, KeLeaveCriticalRegion, KeLowerIrql(), KeRaiseIrql(), KernelMode, KeSetEvent(), LOCK_PFN, LOCK_SYSTEM_WS, MI_ADD_LOCKED_PAGE_CHARGE, MI_ADD_LOCKED_PAGE_CHARGE_FOR_MODIFIED_PAGE, MI_DETERMINE_OWNER, MI_GET_PAGE_COLOR_FROM_PTE, MI_GET_PAGE_FRAME_FROM_PTE, MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE, MI_MAGIC_AWE_PTEFRAME, MI_MAKE_VALID_PTE, MI_PFN_ELEMENT, MI_REMOVE_LOCKED_PAGE_CHARGE, MI_SET_GLOBAL_STATE, MI_SET_PTE_DIRTY, MI_SET_PTE_IN_WORKING_SET, MI_WRITE_VALID_PTE, MiEnsureAvailablePageOrWait(), MiFreeInPageSupportBlock(), MiGetInPageSupportBlock(), MiGetPteAddress, MiGetSubsectionAddress, MiGetVirtualAddressMappedByPte, MiInitializeTransitionPfn(), MiLocateAndReserveWsle(), MiMakeSystemAddressValidPfn(), MiMapCacheExceptionFilter(), MiPteToProto, MiRemoveAnyPage(), MiUnlinkPageFromList(), MiUpdateWsle(), MM_PTE_OWNER_MASK, MmResetPageFaultReadAhead, MmSavePageFaultReadAhead, MmSetPageFaultReadAhead, MmShortTime, MmSystemCacheWorkingSetList, MmSystemCacheWs, MmSystemCacheWsle, _ETHREAD::NestedFaultCount, NTSTATUS(), NULL, _CONTROL_AREA::NumberOfPfnReferences, _CONTROL_AREA::NumberOfUserReferences, Offset, _MMPFN::OriginalPte, PAGE_SIZE, PsGetCurrentThread, _MMPFN::PteAddress, _MMPFN::PteFrame, TRUE, _MMPTE::u, _MMWSLE::u1, _MMPFN::u1, _MMPFN::u2, _MMPFN::u3, UNLOCK_PFN, UNLOCK_SYSTEM_WS, and WSLE_NUMBER.

Referenced by CcMapAndCopy().

01284 : 01285 01286 This routine checks the state of the specified page that is mapped in 01287 the system cache. If the specified virtual address can be made valid 01288 (i.e., the page is already in memory), it is made valid and the value 01289 TRUE is returned. 01290 01291 If the page is not in memory, and SetToZero is FALSE, the 01292 value FALSE is returned. However, if SetToZero is TRUE, a page of 01293 zeroes is materialized for the specified virtual address and the address 01294 is made valid and the value TRUE is returned. 01295 01296 This routine is for usage by the cache manager. 01297 01298 Arguments: 01299 01300 Address - Supplies the address of a page mapped in the system cache. 01301 This MUST be a page aligned address! 01302 01303 UserBuffer - Supplies the address of a user buffer to copy into the 01304 system cache at the specified address + offset. 01305 01306 Offset - Supplies the offset into the UserBuffer to copy the data. 01307 01308 CountInBytes - Supplies the byte count to copy from the user buffer. 01309 01310 DontZero - Supplies TRUE if the buffer should not be zeroed (the 01311 caller will track zeroing). FALSE if it should be zeroed. 01312 01313 Return Value: 01314 01315 Returns the status of the copy. 01316 01317 Environment: 01318 01319 Kernel mode, <= APC_LEVEL. 01320 01321 --*/ 01322 01323 { 01324 PMMPTE PointerPte; 01325 PMMPTE PointerPde; 01326 PMMPTE ProtoPte; 01327 PFN_NUMBER PageFrameIndex; 01328 WSLE_NUMBER WorkingSetIndex; 01329 MMPTE TempPte; 01330 MMPTE ProtoPteContents; 01331 PMMPFN Pfn1; 01332 PMMPFN Pfn2; 01333 KIRQL OldIrql; 01334 ULONG TransitionState; 01335 ULONG AddToWorkingSet; 01336 LOGICAL ShareCountUpped; 01337 SIZE_T EndFill; 01338 PVOID Buffer; 01339 NTSTATUS status; 01340 PMMINPAGE_SUPPORT Event; 01341 PCONTROL_AREA ControlArea; 01342 PETHREAD Thread; 01343 ULONG SavedState; 01344 LOGICAL ApcsExplicitlyBlocked; 01345 LOGICAL ApcNeeded; 01346 01347 TransitionState = FALSE; 01348 AddToWorkingSet = FALSE; 01349 ApcsExplicitlyBlocked = FALSE; 01350 ApcNeeded = FALSE; 01351 01352 ASSERT (((ULONG_PTR)Address & (PAGE_SIZE - 1)) == 0); 01353 ASSERT ((CountInBytes + Offset) <= PAGE_SIZE); 01354 ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL); 01355 01356 PointerPte = MiGetPteAddress (Address); 01357 01358 if (PointerPte->u.Hard.Valid == 1) { 01359 goto Copy; 01360 } 01361 01362 // 01363 // Touch the user's buffer to make it resident. This is required in 01364 // order to safely detect the case where both the system and user 01365 // address are pointing at the same physical page. This case causes 01366 // a deadlock during the RtlCopyBytes if the inpage support block needed 01367 // to be allocated and the PTE for the user page is not valid. This 01368 // potential deadlock is resolved because if the user page causes a 01369 // collided fault, the initiator thread is checked for. If they are 01370 // the same, then an exception is thrown by the pager. 01371 // 01372 01373 try { 01374 01375 *(volatile CHAR *)UserBuffer; 01376 01377 } except (EXCEPTION_EXECUTE_HANDLER) { 01378 return GetExceptionCode(); 01379 } 01380 01381 // 01382 // Make the PTE valid if possible. 01383 // 01384 01385 LOCK_PFN (OldIrql); 01386 01387 Recheck: 01388 01389 if (PointerPte->u.Hard.Valid == 1) { 01390 goto UnlockAndCopy; 01391 } 01392 01393 ASSERT (PointerPte->u.Soft.Prototype == 1); 01394 01395 ProtoPte = MiPteToProto (PointerPte); 01396 01397 // 01398 // Pte is not valid, check the state of the prototype PTE. 01399 // 01400 01401 if (MiMakeSystemAddressValidPfn (ProtoPte)) { 01402 01403 // 01404 // If page fault occurred, recheck state of original PTE. 01405 // 01406 01407 if (PointerPte->u.Hard.Valid == 1) { 01408 goto UnlockAndCopy; 01409 } 01410 } 01411 01412 ShareCountUpped = FALSE; 01413 ProtoPteContents = *ProtoPte; 01414 01415 if (ProtoPteContents.u.Hard.Valid == 1) { 01416 01417 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (&ProtoPteContents); 01418 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 01419 01420 // 01421 // Increment the share count so the prototype PTE will remain 01422 // valid until this can be added into the system's working set. 01423 // 01424 01425 Pfn1->u2.ShareCount += 1; 01426 ShareCountUpped = TRUE; 01427 01428 // 01429 // The prototype PTE is valid, make the cache PTE 01430 // valid and add it to the working set. 01431 // 01432 01433 TempPte = ProtoPteContents; 01434 01435 } else if ((ProtoPteContents.u.Soft.Transition == 1) && 01436 (ProtoPteContents.u.Soft.Prototype == 0)) { 01437 01438 // 01439 // Prototype PTE is in the transition state. Remove the page 01440 // from the page list and make it valid. 01441 // 01442 01443 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_TRANSITION_PTE (&ProtoPteContents); 01444 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 01445 if ((Pfn1->u3.e1.ReadInProgress) || 01446 (Pfn1->u3.e1.InPageError)) { 01447 01448 // 01449 // Collided page fault or in page error, try the copy 01450 // operation incurring a page fault. 01451 // 01452 01453 goto UnlockAndCopy; 01454 } 01455 01456 MiUnlinkPageFromList (Pfn1); 01457 01458 Pfn1->u3.e2.ReferenceCount += 1; 01459 Pfn1->u3.e1.PageLocation = ActiveAndValid; 01460 Pfn1->u3.e1.Modified = 1; 01461 ASSERT (Pfn1->u2.ShareCount == 0); 01462 Pfn1->u2.ShareCount += 1; 01463 ShareCountUpped = TRUE; 01464 01465 MI_MAKE_VALID_PTE (TempPte, 01466 PageFrameIndex, 01467 Pfn1->OriginalPte.u.Soft.Protection, 01468 NULL ); 01469 MI_SET_PTE_DIRTY (TempPte); 01470 01471 MI_WRITE_VALID_PTE (ProtoPte, TempPte); 01472 01473 // 01474 // Increment the valid pte count for the page containing 01475 // the prototype PTE. 01476 // 01477 01478 } else { 01479 01480 // 01481 // Page is not in memory, if a page of zeroes is requested, 01482 // get a page of zeroes and make it valid. 01483 // 01484 01485 if (MiEnsureAvailablePageOrWait (NULL, NULL)) { 01486 01487 // 01488 // A wait operation occurred which could have changed the 01489 // state of the PTE. Recheck the PTE state. 01490 // 01491 01492 goto Recheck; 01493 } 01494 01495 Event = MiGetInPageSupportBlock (); 01496 if (Event == NULL) { 01497 UNLOCK_PFN (OldIrql); 01498 KeDelayExecutionThread (KernelMode, FALSE, (PLARGE_INTEGER)&MmShortTime); 01499 LOCK_PFN (OldIrql); 01500 goto Recheck; 01501 } 01502 01503 // 01504 // Increment the count of Pfn references for the control area 01505 // corresponding to this file. 01506 // 01507 01508 ControlArea = MiGetSubsectionAddress (ProtoPte)->ControlArea; 01509 ControlArea->NumberOfPfnReferences += 1; 01510 if (ControlArea->NumberOfUserReferences > 0) { 01511 01512 // 01513 // There is a user reference to this file, always zero ahead. 01514 // 01515 01516 DontZero = FALSE; 01517 } 01518 01519 // 01520 // Remove any page from the list and turn it into a transition 01521 // page in the cache with read in progress set. This causes 01522 // any other references to this page to block on the specified 01523 // event while the copy operation to the cache is on-going. 01524 // 01525 01526 PageFrameIndex = MiRemoveAnyPage(MI_GET_PAGE_COLOR_FROM_PTE (ProtoPte)); 01527 01528 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 01529 01530 // 01531 // Increment the valid PTE count for the page containing 01532 // the prototype PTE. 01533 // 01534 01535 MiInitializeTransitionPfn (PageFrameIndex, ProtoPte, 0xFFFFFFFF); 01536 01537 Pfn1->u2.ShareCount = 0; 01538 01539 Pfn1->u3.e2.ReferenceCount = 0; // for the add_locked_page macro 01540 MI_ADD_LOCKED_PAGE_CHARGE_FOR_MODIFIED_PAGE (Pfn1, 24); 01541 01542 Pfn1->u3.e2.ReferenceCount = 1; 01543 Pfn1->u3.e1.PrototypePte = 1; 01544 Pfn1->u3.e1.Modified = 1; 01545 Pfn1->u3.e1.ReadInProgress = 1; 01546 Pfn1->u1.Event = &Event->Event; 01547 Event->Pfn = Pfn1; 01548 01549 // 01550 // This is needed in case a special kernel APC fires that ends up 01551 // referencing the same page (this may even be through a different 01552 // virtual address from the user/system one here). 01553 // 01554 01555 Thread = PsGetCurrentThread (); 01556 ASSERT (Thread->NestedFaultCount <= 1); 01557 Thread->NestedFaultCount += 1; 01558 01559 TransitionState = TRUE; 01560 01561 MI_MAKE_VALID_PTE (TempPte, 01562 PageFrameIndex, 01563 Pfn1->OriginalPte.u.Soft.Protection, 01564 NULL); 01565 MI_SET_PTE_DIRTY (TempPte); 01566 01567 // 01568 // APCs must be explicitly disabled to prevent suspend APCs from 01569 // interrupting this thread before the RtlCopyBytes completes. 01570 // Otherwise this page can remain in transition indefinitely (until 01571 // the suspend APC is released) which blocks any other threads that 01572 // may reference it. 01573 // 01574 01575 KeEnterCriticalRegion(); 01576 ApcsExplicitlyBlocked = TRUE; 01577 } 01578 01579 // 01580 // Increment the share count of the page table page for this PTE. 01581 // 01582 01583 PointerPde = MiGetPteAddress (PointerPte); 01584 Pfn2 = MI_PFN_ELEMENT (PointerPde->u.Hard.PageFrameNumber); 01585 01586 Pfn2->u2.ShareCount += 1; 01587 01588 MI_SET_GLOBAL_STATE (TempPte, 1); 01589 #if defined (_WIN64) 01590 if (MI_DETERMINE_OWNER (PointerPte) == 0) { 01591 TempPte.u.Long &= ~MM_PTE_OWNER_MASK; 01592 } 01593 #else 01594 TempPte.u.Hard.Owner = MI_DETERMINE_OWNER (PointerPte); 01595 #endif 01596 MI_WRITE_VALID_PTE (PointerPte, TempPte); 01597 01598 AddToWorkingSet = TRUE; 01599 01600 UnlockAndCopy: 01601 01602 // 01603 // Unlock the PFN database and perform the copy. 01604 // 01605 01606 UNLOCK_PFN (OldIrql); 01607 01608 Copy: 01609 01610 Thread = PsGetCurrentThread (); 01611 MmSavePageFaultReadAhead( Thread, &SavedState ); 01612 MmSetPageFaultReadAhead( Thread, 0 ); 01613 status = STATUS_SUCCESS; 01614 01615 // 01616 // Copy the user buffer into the cache under an exception handler. 01617 // 01618 01619 try { 01620 01621 Buffer = (PVOID)((PCHAR)Address + Offset); 01622 RtlCopyBytes (Buffer, UserBuffer, CountInBytes); 01623 01624 if (TransitionState) { 01625 01626 // 01627 // Only zero the memory outside the range if a page was taken 01628 // from the free list. 01629 // 01630 01631 if (Offset != 0) { 01632 RtlZeroMemory (Address, Offset); 01633 } 01634 01635 if (DontZero == FALSE) { 01636 EndFill = PAGE_SIZE - (Offset + CountInBytes); 01637 01638 if (EndFill != 0) { 01639 Buffer = (PVOID)((PCHAR)Buffer + CountInBytes); 01640 RtlZeroMemory (Buffer, EndFill); 01641 } 01642 } 01643 } 01644 } except (MiMapCacheExceptionFilter (&status, GetExceptionInformation())) { 01645 01646 if (status == STATUS_MULTIPLE_FAULT_VIOLATION) { 01647 ASSERT (TransitionState == TRUE); 01648 } 01649 01650 // 01651 // Zero out the page if it came from the free list. 01652 // 01653 01654 if (TransitionState) { 01655 RtlZeroMemory (Address, PAGE_SIZE); 01656 } 01657 } 01658 01659 MmResetPageFaultReadAhead(Thread, SavedState); 01660 01661 if (AddToWorkingSet) { 01662 01663 LOCK_PFN (OldIrql); 01664 01665 if (ApcsExplicitlyBlocked == TRUE) { 01666 KeLeaveCriticalRegion(); 01667 } 01668 01669 ASSERT (Pfn1->u3.e2.ReferenceCount != 0); 01670 ASSERT (Pfn1->PteAddress == ProtoPte); 01671 01672 if (TransitionState) { 01673 01674 // 01675 // This is a newly allocated page. 01676 // 01677 01678 ASSERT (ShareCountUpped == FALSE); 01679 ASSERT (Pfn1->u2.ShareCount <= 1); 01680 ASSERT (Pfn1->u1.Event == &Event->Event); 01681 01682 MiMakeSystemAddressValidPfn (ProtoPte); 01683 MI_SET_GLOBAL_STATE (TempPte, 0); 01684 MI_WRITE_VALID_PTE (ProtoPte, TempPte); 01685 Pfn1->u1.Event = (PVOID)PsGetCurrentThread(); 01686 ASSERT (Pfn1->u3.e2.ReferenceCount != 0); 01687 ASSERT (Pfn1->PteFrame != MI_MAGIC_AWE_PTEFRAME); 01688 01689 ASSERT (Event->Completed == FALSE); 01690 Event->Completed = TRUE; 01691 01692 ASSERT (Pfn1->u2.ShareCount == 0); 01693 MI_REMOVE_LOCKED_PAGE_CHARGE(Pfn1, 41); 01694 Pfn1->u3.e1.PageLocation = ActiveAndValid; 01695 01696 ASSERT (Pfn1->u3.e1.ReadInProgress == 1); 01697 Pfn1->u3.e1.ReadInProgress = 0; 01698 01699 // 01700 // Increment the share count since the page is 01701 // being put into a working set. 01702 // 01703 01704 Pfn1->u2.ShareCount += 1; 01705 01706 if (Event->WaitCount != 1) { 01707 Event->IoStatus.Status = STATUS_SUCCESS; 01708 Event->IoStatus.Information = 0; 01709 KeSetEvent (&Event->Event, 0, FALSE); 01710 } 01711 01712 MiFreeInPageSupportBlock (Event); 01713 if (DontZero != FALSE) { 01714 MI_ADD_LOCKED_PAGE_CHARGE(Pfn1, 40); 01715 Pfn1->u3.e2.ReferenceCount += 1; 01716 status = STATUS_CACHE_PAGE_LOCKED; 01717 } 01718 01719 ASSERT (Thread->NestedFaultCount <= 3); 01720 ASSERT (Thread->NestedFaultCount != 0); 01721 01722 Thread->NestedFaultCount -= 1; 01723 01724 if ((Thread->ApcNeeded == 1) && (Thread->NestedFaultCount == 0)) { 01725 ApcNeeded = TRUE; 01726 Thread->ApcNeeded = 0; 01727 } 01728 01729 } else { 01730 01731 // 01732 // This is either a frame that was originally on the transition list 01733 // or was already valid when this routine began execution. Either 01734 // way, the share count (and therefore the systemwide locked pages 01735 // count) has been dealt with. 01736 // 01737 01738 ASSERT (ShareCountUpped == TRUE); 01739 01740 if (Pfn1->u1.Event == NULL) { 01741 Pfn1->u1.Event = (PVOID)PsGetCurrentThread(); 01742 } 01743 } 01744 01745 UNLOCK_PFN (OldIrql); 01746 01747 LOCK_SYSTEM_WS (OldIrql); 01748 01749 WorkingSetIndex = MiLocateAndReserveWsle (&MmSystemCacheWs); 01750 01751 MiUpdateWsle (&WorkingSetIndex, 01752 MiGetVirtualAddressMappedByPte (PointerPte), 01753 MmSystemCacheWorkingSetList, 01754 Pfn1); 01755 01756 MmSystemCacheWsle[WorkingSetIndex].u1.e1.SameProtectAsProto = 1; 01757 01758 MI_SET_PTE_IN_WORKING_SET (PointerPte, WorkingSetIndex); 01759 01760 UNLOCK_SYSTEM_WS (OldIrql); 01761 01762 if (ApcNeeded == TRUE) { 01763 ASSERT (OldIrql < APC_LEVEL); 01764 ASSERT (Thread->NestedFaultCount == 0); 01765 ASSERT (Thread->ApcNeeded == 0); 01766 KeRaiseIrql (APC_LEVEL, &OldIrql); 01767 IoRetryIrpCompletions (); 01768 KeLowerIrql (OldIrql); 01769 } 01770 } 01771 else { 01772 ASSERT (ApcsExplicitlyBlocked == FALSE); 01773 } 01774 01775 return status; 01776 }

NTSTATUS MmMapViewInSystemCache IN PVOID  SectionToMap,
OUT PVOID *  CapturedBase,
IN OUT PLARGE_INTEGER  SectionOffset,
IN OUT PULONG  CapturedViewSize
 

Definition at line 63 of file mapcache.c.

References ASSERT, _SEGMENT::ControlArea, KeBugCheckEx(), KeFlushEntireTb(), L, LOCK_PFN, MiGetPteAddress, MiGetVirtualAddressMappedByPte, MiProtoAddressForKernelPte, MM_COLOR_MASK, MM_EMPTY_LIST, MM_EMPTY_PTE_LIST, MmFirstFreeSystemCache, MmFlushSystemCache, MmSystemCacheEnd, MmSystemCachePteBase, _SUBSECTION::NextSubsection, NULL, _CONTROL_AREA::NumberOfMappedViews, _CONTROL_AREA::NumberOfSectionReferences, _CONTROL_AREA::NumberOfSystemCacheViews, PAGE_SHIFT, PAGE_SIZE, PSECTION, PTE_SHIFT, _SUBSECTION::PtesInSubsection, _CONTROL_AREA::Segment, _SUBSECTION::SubsectionBase, TRUE, _MMPTE::u, _CONTROL_AREA::u, UNLOCK_PFN, and ZeroKernelPte.

Referenced by CcGetVacbMiss().

00072 : 00073 00074 This function maps a view in the specified subject process to 00075 the section object. The page protection is identical to that 00076 of the prototype PTE. 00077 00078 This function is a kernel mode interface to allow LPC to map 00079 a section given the section pointer to map. 00080 00081 This routine assumes all arguments have been probed and captured. 00082 00083 Arguments: 00084 00085 SectionToMap - Supplies a pointer to the section object. 00086 00087 BaseAddress - Supplies a pointer to a variable that will receive 00088 the base address of the view. If the initial value 00089 of this argument is not null, then the view will 00090 be allocated starting at the specified virtual 00091 address rounded down to the next 64kb address 00092 boundary. If the initial value of this argument is 00093 null, then the operating system will determine 00094 where to allocate the view using the information 00095 specified by the ZeroBits argument value and the 00096 section allocation attributes (i.e. based and 00097 tiled). 00098 00099 SectionOffset - Supplies the offset from the beginning of the 00100 section to the view in bytes. This value must be a multiple 00101 of 256k. 00102 00103 ViewSize - Supplies a pointer to a variable that will receive 00104 the actual size in bytes of the view. 00105 The initial values of this argument specifies the 00106 size of the view in bytes and is rounded up to the 00107 next host page size boundary and must be less than or equal 00108 to 256k. 00109 00110 Return Value: 00111 00112 Returns the status 00113 00114 TBS 00115 00116 Environment: 00117 00118 Kernel mode. 00119 00120 --*/ 00121 00122 { 00123 PSECTION Section; 00124 ULONG PteOffset; 00125 KIRQL OldIrql; 00126 PMMPTE PointerPte; 00127 PMMPTE LastPte; 00128 PMMPTE ProtoPte; 00129 PMMPTE LastProto; 00130 PSUBSECTION Subsection; 00131 PVOID EndingVa; 00132 PCONTROL_AREA ControlArea; 00133 00134 Section = SectionToMap; 00135 00136 // 00137 // Assert the view size is less 256kb and the section offset 00138 // is aligned on a 256k boundary. 00139 // 00140 00141 ASSERT (*CapturedViewSize <= 256L*1024L); 00142 ASSERT ((SectionOffset->LowPart & (256L*1024L - 1)) == 0); 00143 00144 // 00145 // Make sure the section is not an image section or a page file 00146 // backed section. 00147 // 00148 00149 if (Section->u.Flags.Image) { 00150 return STATUS_NOT_MAPPED_DATA; 00151 } 00152 00153 ControlArea = Section->Segment->ControlArea; 00154 00155 ASSERT (*CapturedViewSize != 0); 00156 00157 ASSERT (ControlArea->u.Flags.GlobalOnlyPerSession == 0); 00158 00159 Subsection = (PSUBSECTION)(ControlArea + 1); 00160 00161 LOCK_PFN (OldIrql); 00162 00163 ASSERT (ControlArea->u.Flags.BeingCreated == 0); 00164 ASSERT (ControlArea->u.Flags.BeingDeleted == 0); 00165 ASSERT (ControlArea->u.Flags.BeingPurged == 0); 00166 00167 // 00168 // Find a free 256k base in the cache. 00169 // 00170 00171 if (MmFirstFreeSystemCache == (PMMPTE)MM_EMPTY_LIST) { 00172 UNLOCK_PFN (OldIrql); 00173 return STATUS_NO_MEMORY; 00174 } 00175 00176 if (MmFirstFreeSystemCache == MmFlushSystemCache) { 00177 00178 // 00179 // All system cache PTEs have been used, flush the entire 00180 // TB to remove any stale TB entries. 00181 // 00182 00183 KeFlushEntireTb (TRUE, TRUE); 00184 MmFlushSystemCache = NULL; 00185 } 00186 00187 PointerPte = MmFirstFreeSystemCache; 00188 00189 // 00190 // Update next free entry. 00191 // 00192 00193 ASSERT (PointerPte->u.Hard.Valid == 0); 00194 00195 if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) { 00196 KeBugCheckEx (MEMORY_MANAGEMENT, 00197 0x778, 00198 (ULONG_PTR)PointerPte, 00199 0, 00200 0); 00201 MmFirstFreeSystemCache = (PMMPTE)MM_EMPTY_LIST; 00202 } 00203 else { 00204 MmFirstFreeSystemCache = MmSystemCachePteBase + PointerPte->u.List.NextEntry; 00205 ASSERT (MmFirstFreeSystemCache <= MiGetPteAddress (MmSystemCacheEnd)); 00206 } 00207 00208 // 00209 // Increment the count of the number of views for the 00210 // section object. This requires the PFN lock to be held. 00211 // 00212 00213 ControlArea->NumberOfMappedViews += 1; 00214 ControlArea->NumberOfSystemCacheViews += 1; 00215 ASSERT (ControlArea->NumberOfSectionReferences != 0); 00216 00217 UNLOCK_PFN (OldIrql); 00218 00219 *CapturedBase = MiGetVirtualAddressMappedByPte (PointerPte); 00220 00221 EndingVa = (PVOID)(((ULONG_PTR)*CapturedBase + 00222 *CapturedViewSize - 1L) | (PAGE_SIZE - 1L)); 00223 00224 // 00225 // An unoccupied address range has been found, put the PTEs in 00226 // the range into prototype PTEs. 00227 // 00228 00229 #if DBG 00230 00231 // 00232 // Zero out the next pointer field. 00233 // 00234 00235 PointerPte->u.List.NextEntry = 0; 00236 #endif //DBG 00237 00238 LastPte = MiGetPteAddress (EndingVa); 00239 00240 // 00241 // Calculate the first prototype PTE address. 00242 // 00243 00244 PteOffset = (ULONG)(SectionOffset->QuadPart >> PAGE_SHIFT); 00245 00246 // 00247 // Make sure the PTEs are not in the extended part of the 00248 // segment. 00249 // 00250 00251 while (PteOffset >= Subsection->PtesInSubsection) { 00252 PteOffset -= Subsection->PtesInSubsection; 00253 Subsection = Subsection->NextSubsection; 00254 } 00255 00256 ProtoPte = &Subsection->SubsectionBase[PteOffset]; 00257 00258 LastProto = &Subsection->SubsectionBase[Subsection->PtesInSubsection]; 00259 00260 while (PointerPte <= LastPte) { 00261 00262 if (ProtoPte >= LastProto) { 00263 00264 // 00265 // Handle extended subsections. 00266 // 00267 00268 Subsection = Subsection->NextSubsection; 00269 ProtoPte = Subsection->SubsectionBase; 00270 LastProto = &Subsection->SubsectionBase[ 00271 Subsection->PtesInSubsection]; 00272 } 00273 ASSERT (PointerPte->u.Long == ZeroKernelPte.u.Long); 00274 PointerPte->u.Long = MiProtoAddressForKernelPte (ProtoPte); 00275 00276 ASSERT (((ULONG_PTR)PointerPte & (MM_COLOR_MASK << PTE_SHIFT)) == 00277 (((ULONG_PTR)ProtoPte & (MM_COLOR_MASK << PTE_SHIFT)))); 00278 00279 PointerPte += 1; 00280 ProtoPte += 1; 00281 } 00282 00283 return STATUS_SUCCESS; 00284 }

VOID MmUnlockCachedPage IN PVOID  AddressInCache  ) 
 

Definition at line 1833 of file mapcache.c.

References ASSERT, KeBugCheckEx(), LOCK_PFN, MI_PFN_ELEMENT, MI_REMOVE_LOCKED_PAGE_CHARGE, MiGetPteAddress, _MMPTE::u, _MMPFN::u3, and UNLOCK_PFN.

Referenced by CcFreeActiveVacb().

01839 : 01840 01841 This routine unlocks a previous locked cached page. 01842 01843 Arguments: 01844 01845 AddressInCache - Supplies the address where the page was locked 01846 in the system cache. This must be the same 01847 address that MmCopyToCachedPage was called with. 01848 01849 Return Value: 01850 01851 None. 01852 01853 --*/ 01854 01855 { 01856 PMMPTE PointerPte; 01857 PMMPFN Pfn1; 01858 KIRQL OldIrql; 01859 01860 PointerPte = MiGetPteAddress (AddressInCache); 01861 01862 ASSERT (PointerPte->u.Hard.Valid == 1); 01863 Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); 01864 01865 LOCK_PFN (OldIrql); 01866 01867 if (Pfn1->u3.e2.ReferenceCount <= 1) { 01868 KeBugCheckEx (MEMORY_MANAGEMENT, 01869 0x777, 01870 (ULONG_PTR)PointerPte->u.Hard.PageFrameNumber, 01871 Pfn1->u3.e2.ReferenceCount, 01872 (ULONG_PTR)AddressInCache); 01873 return; 01874 } 01875 01876 MI_REMOVE_LOCKED_PAGE_CHARGE(Pfn1, 25); 01877 Pfn1->u3.e2.ReferenceCount -= 1; 01878 01879 UNLOCK_PFN (OldIrql); 01880 return; 01881 } }

VOID MmUnmapViewInSystemCache IN PVOID  BaseAddress,
IN PVOID  SectionToUnmap,
IN ULONG  AddToFront
 

Definition at line 381 of file mapcache.c.

References APC_LEVEL, ASSERT, _SEGMENT::ControlArea, FALSE, LOCK_PFN, LOCK_SYSTEM_WS, MI_CAPTURE_DIRTY_BIT_TO_PFN, MI_GET_PAGE_FRAME_FROM_PTE, MI_PFN_ELEMENT, MI_SET_PTE_IN_WORKING_SET, MI_WRITE_INVALID_PTE, MiCheckControlArea(), MiDecrementShareAndValidCount, MiDecrementShareCount(), MiGetPteAddress, MiLocateWsle(), MiReleaseWsle(), MiRemoveWsle(), MM_EMPTY_PTE_LIST, MmFlushSystemCache, MmFrontOfList, MmLastFreeSystemCache, MmSystemCachePteBase, MmSystemCacheWorkingSetList, MmSystemCacheWs, NULL, _CONTROL_AREA::NumberOfMappedViews, _CONTROL_AREA::NumberOfSystemCacheViews, PAGE_SIZE, PSECTION, _CONTROL_AREA::Segment, TRUE, _MMPTE::u, _MMPFN::u1, _MMPFN::u2, UNLOCK_PFN, UNLOCK_SYSTEM_WS, WSLE_NUMBER, X256K, and ZeroKernelPte.

Referenced by CcUnmapVacb().

00389 : 00390 00391 This function unmaps a view from the system cache. 00392 00393 NOTE: When this function is called, no pages may be locked in 00394 the cache for the specified view. 00395 00396 Arguments: 00397 00398 BaseAddress - Supplies the base address of the section in the 00399 system cache. 00400 00401 SectionToUnmap - Supplies a pointer to the section which the 00402 base address maps. 00403 00404 AddToFront - Supplies TRUE if the unmapped pages should be 00405 added to the front of the standby list (i.e., their 00406 value in the cache is low). FALSE otherwise 00407 00408 Return Value: 00409 00410 none. 00411 00412 Environment: 00413 00414 Kernel mode. 00415 00416 --*/ 00417 00418 { 00419 PMMPTE PointerPte; 00420 PMMPFN Pfn1; 00421 PMMPTE FirstPte; 00422 MMPTE PteContents; 00423 KIRQL OldIrql; 00424 KIRQL OldIrqlWs; 00425 PFN_NUMBER i; 00426 WSLE_NUMBER WorkingSetIndex; 00427 PCONTROL_AREA ControlArea; 00428 ULONG WsHeld; 00429 PFN_NUMBER PdeFrameNumber; 00430 00431 WsHeld = FALSE; 00432 00433 ASSERT (KeGetCurrentIrql() <= APC_LEVEL); 00434 00435 PointerPte = MiGetPteAddress (BaseAddress); 00436 FirstPte = PointerPte; 00437 ControlArea = ((PSECTION)SectionToUnmap)->Segment->ControlArea; 00438 PdeFrameNumber = MI_GET_PAGE_FRAME_FROM_PTE (MiGetPteAddress (PointerPte)); 00439 00440 // 00441 // Get the control area for the segment which is mapped here. 00442 // 00443 00444 i = 0; 00445 00446 do { 00447 00448 // 00449 // The cache is organized in chunks of 256k bytes, clear 00450 // the first chunk then check to see if this is the last 00451 // chunk. 00452 // 00453 00454 // 00455 // The page table page is always resident for the system cache. 00456 // Check each PTE, it is in one of two states, either valid or 00457 // prototype PTE format. 00458 // 00459 00460 PteContents = *(volatile MMPTE *)PointerPte; 00461 if (PteContents.u.Hard.Valid == 1) { 00462 00463 if (!WsHeld) { 00464 WsHeld = TRUE; 00465 LOCK_SYSTEM_WS (OldIrqlWs); 00466 continue; 00467 } 00468 00469 Pfn1 = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 00470 00471 WorkingSetIndex = MiLocateWsle (BaseAddress, 00472 MmSystemCacheWorkingSetList, 00473 Pfn1->u1.WsIndex ); 00474 MiRemoveWsle (WorkingSetIndex, 00475 MmSystemCacheWorkingSetList ); 00476 MiReleaseWsle (WorkingSetIndex, &MmSystemCacheWs); 00477 00478 MI_SET_PTE_IN_WORKING_SET (PointerPte, 0); 00479 00480 // 00481 // The PTE is valid. 00482 // 00483 00484 LOCK_PFN (OldIrql); 00485 00486 // 00487 // Capture the state of the modified bit for this PTE. 00488 // 00489 00490 MI_CAPTURE_DIRTY_BIT_TO_PFN (PointerPte, Pfn1); 00491 00492 // 00493 // Decrement the share and valid counts of the page table 00494 // page which maps this PTE. 00495 // 00496 00497 MiDecrementShareAndValidCount (PdeFrameNumber); 00498 00499 // 00500 // Decrement the share count for the physical page. 00501 // 00502 00503 #if DBG 00504 if (ControlArea->NumberOfMappedViews == 1) { 00505 PMMPFN Pfn; 00506 Pfn = MI_PFN_ELEMENT (PteContents.u.Hard.PageFrameNumber); 00507 ASSERT (Pfn->u2.ShareCount == 1); 00508 } 00509 #endif //DBG 00510 00511 00512 MmFrontOfList = AddToFront; 00513 MiDecrementShareCount (MI_GET_PAGE_FRAME_FROM_PTE (&PteContents)); 00514 MmFrontOfList = FALSE; 00515 UNLOCK_PFN (OldIrql); 00516 } else { 00517 if (WsHeld) { 00518 UNLOCK_SYSTEM_WS (OldIrqlWs); 00519 WsHeld = FALSE; 00520 } 00521 00522 ASSERT ((PteContents.u.Long == ZeroKernelPte.u.Long) || 00523 (PteContents.u.Soft.Prototype == 1)); 00524 NOTHING; 00525 } 00526 MI_WRITE_INVALID_PTE (PointerPte, ZeroKernelPte); 00527 00528 PointerPte += 1; 00529 BaseAddress = (PVOID)((PCHAR)BaseAddress + PAGE_SIZE); 00530 i += 1; 00531 } while (i < (X256K / PAGE_SIZE)); 00532 00533 if (WsHeld) { 00534 UNLOCK_SYSTEM_WS (OldIrqlWs); 00535 } 00536 00537 FirstPte->u.List.NextEntry = MM_EMPTY_PTE_LIST; 00538 00539 LOCK_PFN (OldIrql); 00540 00541 // 00542 // Free this entry to the end of the list. 00543 // 00544 00545 if (MmFlushSystemCache == NULL) { 00546 00547 // 00548 // If there is no entry marked to initiate a TB flush when 00549 // reused, mark this entry as the one. This way the TB 00550 // only needs to be flushed when the list wraps. 00551 // 00552 00553 MmFlushSystemCache = FirstPte; 00554 } 00555 00556 MmLastFreeSystemCache->u.List.NextEntry = FirstPte - MmSystemCachePteBase; 00557 MmLastFreeSystemCache = FirstPte; 00558 00559 // 00560 // Decrement the number of mapped views for the segment 00561 // and check to see if the segment should be deleted. 00562 // 00563 00564 ControlArea->NumberOfMappedViews -= 1; 00565 ControlArea->NumberOfSystemCacheViews -= 1; 00566 00567 // 00568 // Check to see if the control area (segment) should be deleted. 00569 // This routine releases the PFN lock. 00570 // 00571 00572 MiCheckControlArea (ControlArea, NULL, OldIrql); 00573 00574 return; 00575 }


Variable Documentation

PMMPTE MmFirstFreeSystemCache
 

Definition at line 47 of file mapcache.c.

Referenced by MiInitializeSystemCache(), and MmMapViewInSystemCache().

PMMPTE MmFlushSystemCache
 

Definition at line 51 of file mapcache.c.

Referenced by MmMapViewInSystemCache(), and MmUnmapViewInSystemCache().

ULONG MmFrontOfList
 

Definition at line 30 of file mapcache.c.

Referenced by MiDecrementReferenceCount(), and MmUnmapViewInSystemCache().

PMMPTE MmLastFreeSystemCache
 

Definition at line 49 of file mapcache.c.

Referenced by MiInitializeSystemCache(), and MmUnmapViewInSystemCache().

PMMPTE MmSystemCachePteBase
 

Definition at line 53 of file mapcache.c.

Referenced by MiInitializeSystemCache(), MmMapViewInSystemCache(), and MmUnmapViewInSystemCache().


Generated on Sat May 15 19:44:36 2004 for test by doxygen 1.3.7