Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygensptab.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
1.7.6.1
|