[NTOSKRNL]

- Allow placement of a wait entry in virgin address space prior to mapping a page.
- Add a wait entry in the address space when paging in section view.
- Correct a problem that previously prevented us from evicting or querying pages that
  had been protected into PAGE_NOACCESS protection by adding a query for disabled
  mappings and handling disabled mappings in a few places (this may be controversial).

svn path=/trunk/; revision=56682
This commit is contained in:
Art Yerkes 2012-06-01 09:01:41 +00:00
parent 15425106b9
commit 2bbb9b2930
4 changed files with 44 additions and 6 deletions

View file

@ -4,7 +4,6 @@
/* TYPES *********************************************************************/ /* TYPES *********************************************************************/
#define MM_WAIT_ENTRY 0x7ffffc00
#define PFN_FROM_SSE(E) ((PFN_NUMBER)((E) >> PAGE_SHIFT)) #define PFN_FROM_SSE(E) ((PFN_NUMBER)((E) >> PAGE_SHIFT))
#define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001) #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
#define MM_IS_WAIT_PTE(E) \ #define MM_IS_WAIT_PTE(E) \

View file

@ -179,6 +179,10 @@ typedef ULONG_PTR SWAPENTRY;
(PAGE_WRITECOPY | \ (PAGE_WRITECOPY | \
PAGE_EXECUTE_WRITECOPY) PAGE_EXECUTE_WRITECOPY)
//
// Wait entry for marking pages that are being serviced
//
#define MM_WAIT_ENTRY 0x7ffffc00
#define InterlockedCompareExchangePte(PointerPte, Exchange, Comperand) \ #define InterlockedCompareExchangePte(PointerPte, Exchange, Comperand) \
InterlockedCompareExchange((PLONG)(PointerPte), Exchange, Comperand) InterlockedCompareExchange((PLONG)(PointerPte), Exchange, Comperand)
@ -1263,6 +1267,13 @@ MmIsPagePresent(
PVOID Address PVOID Address
); );
BOOLEAN
NTAPI
MmIsDisabledPage(
struct _EPROCESS* Process,
PVOID Address
);
VOID VOID
NTAPI NTAPI
MmInitGlobalKernelPageDirectory(VOID); MmInitGlobalKernelPageDirectory(VOID);

View file

@ -467,7 +467,9 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN FreePage,
*/ */
Pte = InterlockedExchangePte(Pt, 0); Pte = InterlockedExchangePte(Pt, 0);
WasValid = (Pte & PA_PRESENT); /* We count a mapping as valid if it's a present page, or it's a nonzero pfn with
* the swap bit unset, indicating a valid page protected to PAGE_NOACCESS. */
WasValid = (Pte & PA_PRESENT) || ((Pte >> PAGE_SHIFT) && !(Pte & 0x800));
if (WasValid) if (WasValid)
{ {
/* Flush the TLB since we transitioned this PTE /* Flush the TLB since we transitioned this PTE
@ -700,6 +702,14 @@ MmIsPagePresent(PEPROCESS Process, PVOID Address)
return MmGetPageEntryForProcess(Process, Address) & PA_PRESENT; return MmGetPageEntryForProcess(Process, Address) & PA_PRESENT;
} }
BOOLEAN
NTAPI
MmIsDisabledPage(PEPROCESS Process, PVOID Address)
{
ULONG_PTR Entry = MmGetPageEntryForProcess(Process, Address);
return !(Entry & PA_PRESENT) && !(Entry & 0x800) && (Entry >> PAGE_SHIFT);
}
BOOLEAN BOOLEAN
NTAPI NTAPI
MmIsPageSwapEntry(PEPROCESS Process, PVOID Address) MmIsPageSwapEntry(PEPROCESS Process, PVOID Address)
@ -738,12 +748,17 @@ MmCreatePageFileMapping(PEPROCESS Process,
if (Pt == NULL) if (Pt == NULL)
{ {
/* Nobody should page out an address that hasn't even been mapped */ /* Nobody should page out an address that hasn't even been mapped */
KeBugCheck(MEMORY_MANAGEMENT); /* But we might place a wait entry first, requiring the page table */
if (SwapEntry != MM_WAIT_ENTRY)
{
KeBugCheck(MEMORY_MANAGEMENT);
}
Pt = MmGetPageTableForProcess(Process, Address, TRUE);
} }
Pte = InterlockedExchangePte(Pt, SwapEntry << 1); Pte = InterlockedExchangePte(Pt, SwapEntry << 1);
if (Pte != 0) if (Pte != 0)
{ {
KeBugCheck(MEMORY_MANAGEMENT); KeBugCheckEx(MEMORY_MANAGEMENT, SwapEntry, (ULONG_PTR)Process, (ULONG_PTR)Address, 0);
} }
if (Address < MmSystemRangeStart) if (Address < MmSystemRangeStart)
@ -975,7 +990,8 @@ MmSetPageProtect(PEPROCESS Process, PVOID Address, ULONG flProtect)
} }
Pte = InterlockedExchangePte(Pt, PAGE_MASK(*Pt) | Attributes | (*Pt & (PA_ACCESSED|PA_DIRTY))); Pte = InterlockedExchangePte(Pt, PAGE_MASK(*Pt) | Attributes | (*Pt & (PA_ACCESSED|PA_DIRTY)));
if (!(Pte & PA_PRESENT)) // We should be able to bring a page back from PAGE_NOACCESS
if ((Pte & 0x800) || !(Pte >> PAGE_SHIFT))
{ {
DPRINT1("Invalid Pte %lx\n", Pte); DPRINT1("Invalid Pte %lx\n", Pte);
KeBugCheck(MEMORY_MANAGEMENT); KeBugCheck(MEMORY_MANAGEMENT);

View file

@ -1223,6 +1223,11 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
if (MmIsDisabledPage(Process, Address))
{
return(STATUS_ACCESS_VIOLATION);
}
/* /*
* Check for the virtual memory area being deleted. * Check for the virtual memory area being deleted.
*/ */
@ -1438,6 +1443,8 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
if (Entry == 0) if (Entry == 0)
{ {
SWAPENTRY FakeSwapEntry;
/* /*
* If the entry is zero (and it can't change because we have * If the entry is zero (and it can't change because we have
* locked the segment) then we need to load the page. * locked the segment) then we need to load the page.
@ -1448,6 +1455,7 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
*/ */
MmSetPageEntrySectionSegment(Segment, &Offset, MAKE_SWAP_SSE(MM_WAIT_ENTRY)); MmSetPageEntrySectionSegment(Segment, &Offset, MAKE_SWAP_SSE(MM_WAIT_ENTRY));
MmUnlockSectionSegment(Segment); MmUnlockSectionSegment(Segment);
MmCreatePageFileMapping(Process, PAddress, MM_WAIT_ENTRY);
MmUnlockAddressSpace(AddressSpace); MmUnlockAddressSpace(AddressSpace);
if ((Segment->Flags & MM_PAGEFILE_SEGMENT) || if ((Segment->Flags & MM_PAGEFILE_SEGMENT) ||
@ -1496,6 +1504,9 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
MmSetPageEntrySectionSegment(Segment, &Offset, Entry); MmSetPageEntrySectionSegment(Segment, &Offset, Entry);
MmUnlockSectionSegment(Segment); MmUnlockSectionSegment(Segment);
MmDeletePageFileMapping(Process, PAddress, &FakeSwapEntry);
DPRINT("CreateVirtualMapping Page %x Process %p PAddress %p Attributes %x\n",
Page, Process, PAddress, Attributes);
Status = MmCreateVirtualMapping(Process, Status = MmCreateVirtualMapping(Process,
PAddress, PAddress,
Attributes, Attributes,
@ -1506,6 +1517,7 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
DPRINT1("Unable to create virtual mapping\n"); DPRINT1("Unable to create virtual mapping\n");
KeBugCheck(MEMORY_MANAGEMENT); KeBugCheck(MEMORY_MANAGEMENT);
} }
ASSERT(MmIsPagePresent(Process, PAddress));
MmInsertRmap(Page, Process, Address); MmInsertRmap(Page, Process, Address);
MiSetPageEvent(Process, Address); MiSetPageEvent(Process, Address);
@ -2441,7 +2453,7 @@ MmAlterViewAttributes(PMMSUPPORT AddressSpace,
} }
} }
if (MmIsPagePresent(Process, Address)) if (MmIsPagePresent(Process, Address) || MmIsDisabledPage(Process, Address))
{ {
MmSetPageProtect(Process, Address, MmSetPageProtect(Process, Address,
Protect); Protect);