Пример #1
0
NTSTATUS
NTAPI
_MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
                              PLARGE_INTEGER Offset,
                              ULONG_PTR Entry,
                              const char *file,
                              int line)
{
    ULONG_PTR PageIndex, OldEntry;
    PCACHE_SECTION_PAGE_TABLE PageTable;

    ASSERT(Segment->Locked);
    ASSERT(!IS_SWAP_FROM_SSE(Entry) || !IS_DIRTY_SSE(Entry));

    if (Entry && !IS_SWAP_FROM_SSE(Entry))
        MmGetRmapListHeadPage(PFN_FROM_SSE(Entry));

    PageTable = MiSectionPageTableGetOrAllocate(&Segment->PageTable, Offset);

    if (!PageTable) return STATUS_NO_MEMORY;

    ASSERT(MiSectionPageTableGet(&Segment->PageTable, Offset));

    PageTable->Segment = Segment;
    PageIndex = (ULONG_PTR)((Offset->QuadPart - PageTable->FileOffset.QuadPart) / PAGE_SIZE);
    OldEntry = PageTable->PageEntries[PageIndex];

    DPRINT("MiSetPageEntrySectionSegment(%p,%08x%08x,%x=>%x)\n",
            Segment,
            Offset->u.HighPart,
            Offset->u.LowPart,
            OldEntry,
            Entry);

    if (PFN_FROM_SSE(Entry) == PFN_FROM_SSE(OldEntry)) {
        /* Nothing */
    } else if (Entry && !IS_SWAP_FROM_SSE(Entry)) {
        ASSERT(!OldEntry || IS_SWAP_FROM_SSE(OldEntry));
        MmSetSectionAssociation(PFN_FROM_SSE(Entry), Segment, Offset);
    } else if (OldEntry && !IS_SWAP_FROM_SSE(OldEntry)) {
        ASSERT(!Entry || IS_SWAP_FROM_SSE(Entry));
        MmDeleteSectionAssociation(PFN_FROM_SSE(OldEntry));
    } else if (IS_SWAP_FROM_SSE(Entry)) {
        ASSERT(!IS_SWAP_FROM_SSE(OldEntry) ||
               SWAPENTRY_FROM_SSE(OldEntry) == MM_WAIT_ENTRY);
        if (OldEntry && SWAPENTRY_FROM_SSE(OldEntry) != MM_WAIT_ENTRY)
            MmDeleteSectionAssociation(PFN_FROM_SSE(OldEntry));
    } else if (IS_SWAP_FROM_SSE(OldEntry)) {
        ASSERT(!IS_SWAP_FROM_SSE(Entry));
        if (Entry)
            MmSetSectionAssociation(PFN_FROM_SSE(OldEntry), Segment, Offset);
    } else {
        /* We should not be replacing a page like this */
        ASSERT(FALSE);
    }
    PageTable->PageEntries[PageIndex] = Entry;
    return STATUS_SUCCESS;
}
Пример #2
0
ULONG
NTAPI
MiCacheEvictPages(PMM_SECTION_SEGMENT Segment,
                  ULONG Target)
{
    ULONG_PTR Entry;
    ULONG Result = 0, i, j;
    NTSTATUS Status;
    PFN_NUMBER Page;
    LARGE_INTEGER Offset;

    MmLockSectionSegment(Segment);

    for (i = 0; i < RtlNumberGenericTableElements(&Segment->PageTable); i++) {

        PCACHE_SECTION_PAGE_TABLE Element = RtlGetElementGenericTable(&Segment->PageTable,
                                                                      i);

        ASSERT(Element);

        Offset = Element->FileOffset;
        for (j = 0; j < ENTRIES_PER_ELEMENT; j++, Offset.QuadPart += PAGE_SIZE) {
            Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
            if (Entry && !IS_SWAP_FROM_SSE(Entry)) {
                Page = PFN_FROM_SSE(Entry);
                MmUnlockSectionSegment(Segment);
                Status = MmpPageOutPhysicalAddress(Page);
                if (NT_SUCCESS(Status))
                    Result++;
                MmLockSectionSegment(Segment);
            }
        }
    }

    MmUnlockSectionSegment(Segment);

    return Result;
}
Пример #3
0
VOID
NTAPI
MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment,
                               FREE_SECTION_PAGE_FUN FreePage)
{
    PCACHE_SECTION_PAGE_TABLE Element;
    DPRINT("MiFreePageTablesSectionSegment(%p)\n", &Segment->PageTable);
    while ((Element = RtlGetElementGenericTable(&Segment->PageTable, 0))) {
        DPRINT("Delete table for <%wZ> %p -> %I64x\n",
               Segment->FileObject ? &Segment->FileObject->FileName : NULL,
               Segment,
               Element->FileOffset.QuadPart);
        if (FreePage)
        {
            ULONG i;
            for (i = 0; i < ENTRIES_PER_ELEMENT; i++)
            {
                ULONG_PTR Entry;
                LARGE_INTEGER Offset;
                Offset.QuadPart = Element->FileOffset.QuadPart + i * PAGE_SIZE;
                Entry = Element->PageEntries[i];
                if (Entry && !IS_SWAP_FROM_SSE(Entry))
                {
                    DPRINT("Freeing page %p:%Ix @ %I64x\n",
                           Segment,
                           Entry,
                           Offset.QuadPart);

                    FreePage(Segment, &Offset);
                }
            }
        }
        DPRINT("Remove memory\n");
        RtlDeleteElementGenericTable(&Segment->PageTable, Element);
    }
    DPRINT("Done\n");
}
Пример #4
0
NTSTATUS
NTAPI
MiCowCacheSectionPage (
    _In_ PMMSUPPORT AddressSpace,
    _In_ PMEMORY_AREA MemoryArea,
    _In_ PVOID Address,
    _In_ BOOLEAN Locked,
    _Inout_ PMM_REQUIRED_RESOURCES Required)
{
    PMM_SECTION_SEGMENT Segment;
    PFN_NUMBER NewPage, OldPage;
    NTSTATUS Status;
    PVOID PAddress;
    LARGE_INTEGER Offset;
    PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);

    DPRINT("MmAccessFaultSectionView(%p, %p, %p, %u)\n",
           AddressSpace,
           MemoryArea,
           Address,
           Locked);

    Segment = MemoryArea->Data.SectionData.Segment;

   /* Lock the segment */
    MmLockSectionSegment(Segment);

   /* Find the offset of the page */
    PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
    Offset.QuadPart = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress +
                      MemoryArea->Data.SectionData.ViewOffset.QuadPart;

    if (!Segment->WriteCopy /*&&
        !MemoryArea->Data.SectionData.WriteCopyView*/ ||
        Segment->Image.Characteristics & IMAGE_SCN_MEM_SHARED)
    {
#if 0
        if (Region->Protect == PAGE_READWRITE ||
            Region->Protect == PAGE_EXECUTE_READWRITE)
#endif
        {
            ULONG_PTR Entry;
            DPRINTC("setting non-cow page %p %p:%p offset %I64x (%Ix) to writable\n",
                    Segment,
                    Process,
                    PAddress,
                    Offset.QuadPart,
                    MmGetPfnForProcess(Process, Address));
            if (Segment->FileObject)
            {
                DPRINTC("file %wZ\n", &Segment->FileObject->FileName);
            }
            Entry = MmGetPageEntrySectionSegment(Segment, &Offset);
            DPRINT("Entry %x\n", Entry);
            if (Entry &&
                !IS_SWAP_FROM_SSE(Entry) &&
                PFN_FROM_SSE(Entry) == MmGetPfnForProcess(Process, Address)) {

                MmSetPageEntrySectionSegment(Segment,
                                             &Offset,
                                             DIRTY_SSE(Entry));
            }
            MmSetPageProtect(Process, PAddress, PAGE_READWRITE);
            MmSetDirtyPage(Process, PAddress);
            MmUnlockSectionSegment(Segment);
            DPRINT("Done\n");
            return STATUS_SUCCESS;
        }
#if 0
        else
        {
            DPRINT("Not supposed to be writable\n");
            MmUnlockSectionSegment(Segment);
            return STATUS_ACCESS_VIOLATION;
        }
#endif
    }

    if (!Required->Page[0])
    {
        SWAPENTRY SwapEntry;
        if (MmIsPageSwapEntry(Process, Address))
        {
            MmGetPageFileMapping(Process, Address, &SwapEntry);
            MmUnlockSectionSegment(Segment);
            if (SwapEntry == MM_WAIT_ENTRY)
                return STATUS_SUCCESS + 1; // Wait ... somebody else is getting it right now
            else
                return STATUS_SUCCESS; // Nonwait swap entry ... handle elsewhere
        }
        /* Call out to acquire a page to copy to.  We'll be re-called when
         * the page has been allocated. */
        Required->Page[1] = MmGetPfnForProcess(Process, Address);
        Required->Consumer = MC_CACHE;
        Required->Amount = 1;
        Required->File = __FILE__;
        Required->Line = __LINE__;
        Required->DoAcquisition = MiGetOnePage;
        MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY);
        MmUnlockSectionSegment(Segment);
        return STATUS_MORE_PROCESSING_REQUIRED;
    }

    NewPage = Required->Page[0];
    OldPage = Required->Page[1];

    DPRINT("Allocated page %x\n", NewPage);

    /* Unshare the old page */
    MmDeleteRmap(OldPage, Process, PAddress);

   /* Copy the old page */
    DPRINT("Copying\n");
    MiCopyPageToPage(NewPage, OldPage);

   /* Set the PTE to point to the new page */
    Status = MmCreateVirtualMapping(Process,
                                    Address,
                                    PAGE_READWRITE,
                                    &NewPage,
                                    1);

    if (!NT_SUCCESS(Status))
    {
        DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
        ASSERT(FALSE);
        MmUnlockSectionSegment(Segment);
        return Status;
    }

    MmInsertRmap(NewPage, Process, PAddress);
    MmReleasePageMemoryConsumer(MC_CACHE, OldPage);
    MmUnlockSectionSegment(Segment);

    DPRINT("Address 0x%p\n", Address);
    return STATUS_SUCCESS;
}
Пример #5
0
/*

MmWithdrawSectionPage removes a page entry from the section segment, replacing
it with a wait entry.  The caller must replace the wait entry with a 0, when
any required writing is done.  The wait entry must remain until the page is
written to protect against cases where a fault brings a stale copy of the page
back before writing is complete.

*/
PFN_NUMBER
NTAPI
MmWithdrawSectionPage(PMM_SECTION_SEGMENT Segment,
                      PLARGE_INTEGER FileOffset,
                      BOOLEAN *Dirty)
{
    ULONG_PTR Entry;

    DPRINT("MmWithdrawSectionPage(%p,%08x%08x,%p)\n",
           Segment,
           FileOffset->HighPart,
           FileOffset->LowPart,
           Dirty);

    MmLockSectionSegment(Segment);
    Entry = MmGetPageEntrySectionSegment(Segment, FileOffset);

    *Dirty = !!IS_DIRTY_SSE(Entry);

    DPRINT("Withdraw %x (%x) of %wZ\n",
           FileOffset->LowPart,
           Entry,
           Segment->FileObject ? &Segment->FileObject->FileName : NULL);

    if (!Entry)
    {
        DPRINT("Stoeled!\n");
        MmUnlockSectionSegment(Segment);
        return 0;
    }
    else if (MM_IS_WAIT_PTE(Entry))
    {
        DPRINT("WAIT\n");
        MmUnlockSectionSegment(Segment);
        return MM_WAIT_ENTRY;
    }
    else if (Entry && !IS_SWAP_FROM_SSE(Entry))
    {
        DPRINT("Page %x\n", PFN_FROM_SSE(Entry));

        *Dirty |= (Entry & 2);

        MmSetPageEntrySectionSegment(Segment,
                                     FileOffset,
                                     MAKE_SWAP_SSE(MM_WAIT_ENTRY));

        MmUnlockSectionSegment(Segment);
        return PFN_FROM_SSE(Entry);
    }
    else
    {
        DPRINT1("SWAP ENTRY?! (%p:%08x%08x)\n",
                Segment,
                FileOffset->HighPart,
                FileOffset->LowPart);

        ASSERT(FALSE);
        MmUnlockSectionSegment(Segment);
        return 0;
    }
}