/* * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * * PROJECT: ReactOS kernel * FILE: ntoskrnl/mm/section.c * PURPOSE: Section object page tables * * PROGRAMMERS: arty */ /* INCLUDES *****************************************************************/ #include #include "newmm.h" #define NDEBUG #include #define DPRINTC DPRINT /* TYPES *********************************************************************/ extern KSPIN_LOCK MiSectionPageTableLock; static PVOID NTAPI MiSectionPageTableAllocate(PRTL_GENERIC_TABLE Table, CLONG Bytes) { PVOID Result; Result = ExAllocatePoolWithTag(NonPagedPool, Bytes, 'MmPt'); DPRINT("MiSectionPageTableAllocate(%d) => %p\n", Bytes, Result); return Result; } static VOID NTAPI MiSectionPageTableFree(PRTL_GENERIC_TABLE Table, PVOID Data) { DPRINT("MiSectionPageTableFree(%p)\n", Data); ExFreePoolWithTag(Data, 'MmPt'); } static RTL_GENERIC_COMPARE_RESULTS NTAPI MiSectionPageTableCompare(PRTL_GENERIC_TABLE Table, PVOID PtrA, PVOID PtrB) { PLARGE_INTEGER A = PtrA, B = PtrB; BOOLEAN Result = (A->QuadPart < B->QuadPart) ? GenericLessThan : (A->QuadPart == B->QuadPart) ? GenericEqual : GenericGreaterThan; DPRINT ("Compare: %08x%08x vs %08x%08x => %s\n", A->u.HighPart, A->u.LowPart, B->u.HighPart, B->u.LowPart, Result == GenericLessThan ? "GenericLessThan" : Result == GenericGreaterThan ? "GenericGreaterThan" : "GenericEqual"); return Result; } static PCACHE_SECTION_PAGE_TABLE NTAPI MiSectionPageTableGet (PRTL_GENERIC_TABLE Table, PLARGE_INTEGER FileOffset) { LARGE_INTEGER SearchFileOffset; PCACHE_SECTION_PAGE_TABLE PageTable; SearchFileOffset.QuadPart = ROUND_DOWN(FileOffset->QuadPart, ENTRIES_PER_ELEMENT * PAGE_SIZE); PageTable = RtlLookupElementGenericTable(Table, &SearchFileOffset); DPRINT ("MiSectionPageTableGet(%08x,%08x%08x)\n", Table, FileOffset->HighPart, FileOffset->LowPart); return PageTable; } static PCACHE_SECTION_PAGE_TABLE NTAPI MiSectionPageTableGetOrAllocate (PRTL_GENERIC_TABLE Table, PLARGE_INTEGER FileOffset) { LARGE_INTEGER SearchFileOffset; PCACHE_SECTION_PAGE_TABLE PageTableSlice = MiSectionPageTableGet(Table, FileOffset); if (!PageTableSlice) { CACHE_SECTION_PAGE_TABLE SectionZeroPageTable = { }; SearchFileOffset.QuadPart = ROUND_DOWN(FileOffset->QuadPart, ENTRIES_PER_ELEMENT * PAGE_SIZE); SectionZeroPageTable.FileOffset = SearchFileOffset; SectionZeroPageTable.Refcount = 1; PageTableSlice = RtlInsertElementGenericTable (Table, &SectionZeroPageTable, sizeof(SectionZeroPageTable), NULL); DPRINT ("Allocate page table %x (%08x%08x)\n", PageTableSlice, PageTableSlice->FileOffset.u.HighPart, PageTableSlice->FileOffset.u.LowPart); if (!PageTableSlice) return NULL; } return PageTableSlice; } VOID NTAPI MiInitializeSectionPageTable(PMM_CACHE_SECTION_SEGMENT Segment) { RtlInitializeGenericTable (&Segment->PageTable, MiSectionPageTableCompare, MiSectionPageTableAllocate, MiSectionPageTableFree, NULL); DPRINT("MiInitializeSectionPageTable(%p)\n", &Segment->PageTable); } NTSTATUS NTAPI _MiSetPageEntryCacheSectionSegment (PMM_CACHE_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset, ULONG Entry, const char *file, int line) { ULONG PageIndex, OldEntry; PCACHE_SECTION_PAGE_TABLE PageTable; PageTable = MiSectionPageTableGetOrAllocate(&Segment->PageTable, Offset); if (!PageTable) return STATUS_NO_MEMORY; ASSERT(MiSectionPageTableGet(&Segment->PageTable, Offset)); PageTable->Segment = Segment; PageIndex = (Offset->QuadPart - PageTable->FileOffset.QuadPart) / PAGE_SIZE; OldEntry = PageTable->PageEntries[PageIndex]; if (OldEntry && !IS_SWAP_FROM_SSE(OldEntry)) { MmDeleteSectionAssociation(PFN_FROM_SSE(OldEntry)); } if (Entry && !IS_SWAP_FROM_SSE(Entry)) { MmSetSectionAssociation(PFN_FROM_SSE(Entry), Segment, Offset); } PageTable->PageEntries[PageIndex] = Entry; DPRINT ("MiSetPageEntrySectionSegment(%p,%08x%08x,%x) %s:%d\n", Segment, Offset->u.HighPart, Offset->u.LowPart, Entry, file, line); return STATUS_SUCCESS; } ULONG NTAPI _MiGetPageEntryCacheSectionSegment (PMM_CACHE_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset, const char *file, int line) { LARGE_INTEGER FileOffset; ULONG PageIndex, Result; PCACHE_SECTION_PAGE_TABLE PageTable; FileOffset.QuadPart = ROUND_DOWN(Offset->QuadPart, ENTRIES_PER_ELEMENT * PAGE_SIZE); PageTable = MiSectionPageTableGet(&Segment->PageTable, &FileOffset); if (!PageTable) return 0; PageIndex = (Offset->QuadPart - PageTable->FileOffset.QuadPart) / PAGE_SIZE; Result = PageTable->PageEntries[PageIndex]; #if 0 DPRINTC ("MiGetPageEntrySectionSegment(%p,%08x%08x) => %x %s:%d\n", Segment, FileOffset.u.HighPart, FileOffset.u.LowPart + PageIndex * PAGE_SIZE, Result, file, line); #endif return Result; } VOID NTAPI MiFreePageTablesSectionSegment (PMM_CACHE_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 %x -> %08x%08x\n", Segment, Element->FileOffset.u.HighPart, Element->FileOffset.u.LowPart); if (FreePage) { int i; for (i = 0; i < ENTRIES_PER_ELEMENT; i++) { ULONG Entry; LARGE_INTEGER Offset; Offset.QuadPart = Element->FileOffset.QuadPart + i * PAGE_SIZE; Entry = Element->PageEntries[i]; if (Entry && !IS_SWAP_FROM_SSE(Entry)) { DPRINTC("Freeing page %x:%x @ %x\n", Segment, Entry, Offset.LowPart); FreePage(Segment, &Offset); } } } DPRINT("Remove memory\n"); RtlDeleteElementGenericTable(&Segment->PageTable, Element); } DPRINT("Done\n"); } PMM_CACHE_SECTION_SEGMENT NTAPI MmGetSectionAssociation(PFN_NUMBER Page, PLARGE_INTEGER Offset) { ULONG RawOffset; PMM_CACHE_SECTION_SEGMENT Segment = NULL; PCACHE_SECTION_PAGE_TABLE PageTable; PageTable = (PCACHE_SECTION_PAGE_TABLE)MmGetSegmentRmap(Page, &RawOffset); if (PageTable) { Segment = PageTable->Segment; Offset->QuadPart = PageTable->FileOffset.QuadPart + (RawOffset << PAGE_SHIFT); } return(Segment); } NTSTATUS NTAPI MmSetSectionAssociation(PFN_NUMBER Page, PMM_CACHE_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset) { PCACHE_SECTION_PAGE_TABLE PageTable; ULONG ActualOffset; PageTable = MiSectionPageTableGet(&Segment->PageTable, Offset); ASSERT(PageTable); ActualOffset = (ULONG)(Offset->QuadPart - PageTable->FileOffset.QuadPart); MmInsertRmap(Page, (PEPROCESS)PageTable, (PVOID)(RMAP_SEGMENT_MASK | (ActualOffset >> PAGE_SHIFT))); return STATUS_SUCCESS; }