ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

sptab.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00017  *
00018  *
00019  * PROJECT:         ReactOS kernel
00020  * FILE:            ntoskrnl/mm/section.c
00021  * PURPOSE:         Section object page tables
00022  *
00023  * PROGRAMMERS:     arty
00024  */
00025 
00026 /*
00027 
00028 This file implements the section page table.  It relies on rtl generic table
00029 functionality to provide access to 256-page chunks.  Calls to
00030 MiSetPageEntrySectionSegment and MiGetPageEntrySectionSegment must be
00031 synchronized by holding the segment lock.
00032 
00033 Each page table entry is a ULONG as in x86.
00034 
00035 Bit 1 is used as a swap entry indication as in the main page table.
00036 Bit 2 is used as a dirty indication.  A dirty page will eventually be written
00037 back to the file.
00038 Bits 3-11 are used as a map count in the legacy mm code, Note that zero is
00039 illegal, as the legacy code does not take advantage of segment rmaps.
00040 Therefore, every segment page is mapped in at least one address space, and
00041 MmUnsharePageEntry is quite complicated.  In addition, the page may also be
00042 owned by the legacy cache manager, giving an implied additional reference.
00043 Upper bits are a PFN_NUMBER.
00044 
00045 These functions, in addition to maintaining the segment page table also
00046 automatically maintain the segment rmap by calling MmSetSectionAssociation
00047 and MmDeleteSectionAssociation.  Segment rmaps are discussed in rmap.c.  The
00048 upshot is that it is impossible to have a page properly registered in a segment
00049 page table and not also found in a segment rmap that can be found from the
00050 paging machinery.
00051 
00052 */
00053 
00054 /* INCLUDES *****************************************************************/
00055 
00056 #include <ntoskrnl.h>
00057 #include "newmm.h"
00058 #define NDEBUG
00059 #include <debug.h>
00060 
00061 #define DPRINTC DPRINT
00062 
00063 /* TYPES *********************************************************************/
00064 
00065 extern KSPIN_LOCK MiSectionPageTableLock;
00066 
00067 static
00068 PVOID
00069 NTAPI
00070 MiSectionPageTableAllocate(PRTL_GENERIC_TABLE Table, CLONG Bytes)
00071 {
00072     PVOID Result;
00073     Result = ExAllocatePoolWithTag(NonPagedPool, Bytes, 'MmPt');
00074     //DPRINT("MiSectionPageTableAllocate(%d) => %p\n", Bytes, Result);
00075     return Result;
00076 }
00077 
00078 static
00079 VOID
00080 NTAPI
00081 MiSectionPageTableFree(PRTL_GENERIC_TABLE Table, PVOID Data)
00082 {
00083     //DPRINT("MiSectionPageTableFree(%p)\n", Data);
00084     ExFreePoolWithTag(Data, 'MmPt');
00085 }
00086 
00087 static
00088 RTL_GENERIC_COMPARE_RESULTS
00089 NTAPI
00090 MiSectionPageTableCompare(PRTL_GENERIC_TABLE Table,
00091                           PVOID PtrA,
00092                           PVOID PtrB)
00093 {
00094     PLARGE_INTEGER A = PtrA, B = PtrB;
00095     BOOLEAN Result = (A->QuadPart < B->QuadPart) ? GenericLessThan :
00096         (A->QuadPart == B->QuadPart) ? GenericEqual : GenericGreaterThan;
00097 
00098 #if 0
00099     DPRINT
00100         ("Compare: %08x%08x vs %08x%08x => %s\n",
00101          A->u.HighPart, A->u.LowPart,
00102          B->u.HighPart, B->u.LowPart,
00103          Result == GenericLessThan ? "GenericLessThan" :
00104          Result == GenericGreaterThan ? "GenericGreaterThan" :
00105             "GenericEqual");
00106 #endif
00107 
00108     return Result;
00109 }
00110 
00111 static
00112 PCACHE_SECTION_PAGE_TABLE
00113 NTAPI
00114 MiSectionPageTableGet(PRTL_GENERIC_TABLE Table,
00115                       PLARGE_INTEGER FileOffset)
00116 {
00117     LARGE_INTEGER SearchFileOffset;
00118     PCACHE_SECTION_PAGE_TABLE PageTable;
00119     SearchFileOffset.QuadPart = ROUND_DOWN(FileOffset->QuadPart,
00120                                            ENTRIES_PER_ELEMENT * PAGE_SIZE);
00121     PageTable = RtlLookupElementGenericTable(Table, &SearchFileOffset);
00122 
00123     DPRINT("MiSectionPageTableGet(%08x,%08x%08x)\n",
00124            Table,
00125            FileOffset->HighPart,
00126            FileOffset->LowPart);
00127 
00128     return PageTable;
00129 }
00130 
00131 static
00132 PCACHE_SECTION_PAGE_TABLE
00133 NTAPI
00134 MiSectionPageTableGetOrAllocate(PRTL_GENERIC_TABLE Table,
00135                                 PLARGE_INTEGER FileOffset)
00136 {
00137     LARGE_INTEGER SearchFileOffset;
00138     CACHE_SECTION_PAGE_TABLE SectionZeroPageTable;
00139     PCACHE_SECTION_PAGE_TABLE PageTableSlice = MiSectionPageTableGet(Table,
00140                                                                      FileOffset);
00141     /* Please zero memory when taking away zero initialization. */
00142     RtlZeroMemory(&SectionZeroPageTable, sizeof(CACHE_SECTION_PAGE_TABLE));
00143     if (!PageTableSlice)
00144     {
00145         SearchFileOffset.QuadPart = ROUND_DOWN(FileOffset->QuadPart,
00146                                                ENTRIES_PER_ELEMENT * PAGE_SIZE);
00147         SectionZeroPageTable.FileOffset = SearchFileOffset;
00148         SectionZeroPageTable.Refcount = 1;
00149         PageTableSlice = RtlInsertElementGenericTable(Table,
00150                                                       &SectionZeroPageTable,
00151                                                       sizeof(SectionZeroPageTable),
00152                                                       NULL);
00153         if (!PageTableSlice) return NULL;
00154         DPRINT("Allocate page table %x (%08x%08x)\n",
00155                PageTableSlice,
00156                PageTableSlice->FileOffset.u.HighPart,
00157                PageTableSlice->FileOffset.u.LowPart);
00158     }
00159     return PageTableSlice;
00160 }
00161 
00162 VOID
00163 NTAPI
00164 MiInitializeSectionPageTable(PMM_SECTION_SEGMENT Segment)
00165 {
00166     RtlInitializeGenericTable(&Segment->PageTable,
00167                               MiSectionPageTableCompare,
00168                               MiSectionPageTableAllocate,
00169                               MiSectionPageTableFree,
00170                               NULL);
00171 
00172     DPRINT("MiInitializeSectionPageTable(%p)\n", &Segment->PageTable);
00173 }
00174 
00175 NTSTATUS
00176 NTAPI
00177 _MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
00178                               PLARGE_INTEGER Offset,
00179                               ULONG_PTR Entry,
00180                               const char *file,
00181                               int line)
00182 {
00183     ULONG_PTR PageIndex, OldEntry;
00184     PCACHE_SECTION_PAGE_TABLE PageTable;
00185 
00186     ASSERT(Segment->Locked);
00187     ASSERT(!IS_SWAP_FROM_SSE(Entry) || !IS_DIRTY_SSE(Entry));
00188 
00189     if (Entry && !IS_SWAP_FROM_SSE(Entry))
00190         MmGetRmapListHeadPage(PFN_FROM_SSE(Entry));
00191 
00192     PageTable = MiSectionPageTableGetOrAllocate(&Segment->PageTable, Offset);
00193 
00194     if (!PageTable) return STATUS_NO_MEMORY;
00195 
00196     ASSERT(MiSectionPageTableGet(&Segment->PageTable, Offset));
00197 
00198     PageTable->Segment = Segment;
00199     PageIndex = (Offset->QuadPart - PageTable->FileOffset.QuadPart) / PAGE_SIZE;
00200     OldEntry = PageTable->PageEntries[PageIndex];
00201 
00202     DPRINT("MiSetPageEntrySectionSegment(%p,%08x%08x,%x=>%x)\n",
00203             Segment,
00204             Offset->u.HighPart,
00205             Offset->u.LowPart,
00206             OldEntry,
00207             Entry);
00208 
00209     if (PFN_FROM_SSE(Entry) == PFN_FROM_SSE(OldEntry)) {
00210         /* Nothing */
00211     } else if (Entry && !IS_SWAP_FROM_SSE(Entry)) {
00212         ASSERT(!OldEntry || IS_SWAP_FROM_SSE(OldEntry));
00213         MmSetSectionAssociation(PFN_FROM_SSE(Entry), Segment, Offset);
00214     } else if (OldEntry && !IS_SWAP_FROM_SSE(OldEntry)) {
00215         ASSERT(!Entry || IS_SWAP_FROM_SSE(Entry));
00216         MmDeleteSectionAssociation(PFN_FROM_SSE(OldEntry));
00217     } else if (IS_SWAP_FROM_SSE(Entry)) {
00218         ASSERT(!IS_SWAP_FROM_SSE(OldEntry) || 
00219                SWAPENTRY_FROM_SSE(OldEntry) == MM_WAIT_ENTRY);
00220         if (OldEntry && SWAPENTRY_FROM_SSE(OldEntry) != MM_WAIT_ENTRY)
00221             MmDeleteSectionAssociation(PFN_FROM_SSE(OldEntry));
00222     } else if (IS_SWAP_FROM_SSE(OldEntry)) {
00223         ASSERT(!IS_SWAP_FROM_SSE(Entry));
00224         if (Entry)
00225             MmSetSectionAssociation(PFN_FROM_SSE(OldEntry), Segment, Offset);
00226     } else {
00227         /* We should not be replacing a page like this */
00228         ASSERT(FALSE);
00229     }
00230     PageTable->PageEntries[PageIndex] = Entry;
00231     return STATUS_SUCCESS;
00232 }
00233 
00234 ULONG_PTR
00235 NTAPI
00236 _MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment,
00237                               PLARGE_INTEGER Offset,
00238                               const char *file,
00239                               int line)
00240 {
00241     LARGE_INTEGER FileOffset;
00242     ULONG_PTR PageIndex, Result;
00243     PCACHE_SECTION_PAGE_TABLE PageTable;
00244 
00245     ASSERT(Segment->Locked);
00246     FileOffset.QuadPart = ROUND_DOWN(Offset->QuadPart,
00247                                      ENTRIES_PER_ELEMENT * PAGE_SIZE);
00248     PageTable = MiSectionPageTableGet(&Segment->PageTable, &FileOffset);
00249     if (!PageTable) return 0;
00250     PageIndex = (Offset->QuadPart - PageTable->FileOffset.QuadPart) / PAGE_SIZE;
00251     Result = PageTable->PageEntries[PageIndex];
00252 #if 0
00253     DPRINTC
00254         ("MiGetPageEntrySectionSegment(%p,%08x%08x) => %x %s:%d\n",
00255          Segment,
00256          FileOffset.u.HighPart,
00257          FileOffset.u.LowPart + PageIndex * PAGE_SIZE,
00258          Result,
00259          file, line);
00260 #endif
00261     return Result;
00262 }
00263 
00264 /*
00265 
00266 Destroy the rtl generic table that serves as the section's page table.  Call
00267 the FreePage function for each non-zero entry in the section page table as
00268 we go.  Note that the page table is still techinally valid until after all
00269 pages are destroyed, as we don't finally destroy the table until we've free
00270 each slice.  There is no order guarantee for deletion of individual elements
00271 although it's in-order as written now.
00272 
00273 */
00274 
00275 VOID
00276 NTAPI
00277 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment,
00278                                FREE_SECTION_PAGE_FUN FreePage)
00279 {
00280     PCACHE_SECTION_PAGE_TABLE Element;
00281     DPRINT("MiFreePageTablesSectionSegment(%p)\n", &Segment->PageTable);
00282     while ((Element = RtlGetElementGenericTable(&Segment->PageTable, 0))) {
00283         DPRINT("Delete table for <%wZ> %x -> %08x%08x\n",
00284                Segment->FileObject ? &Segment->FileObject->FileName : NULL,
00285                Segment,
00286                Element->FileOffset.u.HighPart,
00287                Element->FileOffset.u.LowPart);
00288         if (FreePage)
00289         {
00290             ULONG i;
00291             for (i = 0; i < ENTRIES_PER_ELEMENT; i++)
00292             {
00293                 ULONG_PTR Entry;
00294                 LARGE_INTEGER Offset;
00295                 Offset.QuadPart = Element->FileOffset.QuadPart + i * PAGE_SIZE;
00296                 Entry = Element->PageEntries[i];
00297                 if (Entry && !IS_SWAP_FROM_SSE(Entry))
00298                 {
00299                     DPRINT("Freeing page %x:%x @ %x\n",
00300                            Segment,
00301                            Entry,
00302                            Offset.LowPart);
00303 
00304                     FreePage(Segment, &Offset);
00305                 }
00306             }
00307         }
00308         DPRINT("Remove memory\n");
00309         RtlDeleteElementGenericTable(&Segment->PageTable, Element);
00310     }
00311     DPRINT("Done\n");
00312 }
00313 
00314 /*
00315 
00316 Retrieves the MM_SECTION_SEGMENT and fills in the LARGE_INTEGER Offset given
00317 by the caller that corresponds to the page specified.  This uses
00318 MmGetSegmentRmap to find the rmap belonging to the segment itself, and uses
00319 the result as a pointer to a 256-entry page table structure.  The rmap also
00320 includes 8 bits of offset information indication one of 256 page entries that
00321 the rmap corresponds to.  This information together gives us an exact offset
00322 into the file, as well as the MM_SECTION_SEGMENT pointer stored in the page
00323 table slice.
00324 
00325 NULL is returned is there is no segment rmap for the page.
00326 
00327 */
00328 
00329 PMM_SECTION_SEGMENT
00330 NTAPI
00331 MmGetSectionAssociation(PFN_NUMBER Page,
00332                         PLARGE_INTEGER Offset)
00333 {
00334     ULONG RawOffset;
00335     PMM_SECTION_SEGMENT Segment = NULL;
00336     PCACHE_SECTION_PAGE_TABLE PageTable;
00337 
00338     PageTable = (PCACHE_SECTION_PAGE_TABLE)MmGetSegmentRmap(Page,
00339                                                             &RawOffset);
00340     if (PageTable)
00341     {
00342         Segment = PageTable->Segment;
00343         Offset->QuadPart = PageTable->FileOffset.QuadPart +
00344                            (RawOffset << PAGE_SHIFT);
00345     }
00346 
00347     return Segment;
00348 }
00349 
00350 NTSTATUS
00351 NTAPI
00352 MmSetSectionAssociation(PFN_NUMBER Page,
00353                         PMM_SECTION_SEGMENT Segment,
00354                         PLARGE_INTEGER Offset)
00355 {
00356     PCACHE_SECTION_PAGE_TABLE PageTable;
00357     ULONG ActualOffset;
00358 
00359     PageTable = MiSectionPageTableGet(&Segment->PageTable, Offset);
00360     ASSERT(PageTable);
00361 
00362     ActualOffset = (ULONG)(Offset->QuadPart - PageTable->FileOffset.QuadPart);
00363     MmInsertRmap(Page,
00364                  (PEPROCESS)PageTable,
00365                  (PVOID)(RMAP_SEGMENT_MASK | (ActualOffset >> PAGE_SHIFT)));
00366 
00367     return STATUS_SUCCESS;
00368 }

Generated on Sun May 27 2012 04:37:05 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.