ReactOS  0.4.13-dev-259-g5ca9c9c
sptab.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  *
19  * PROJECT: ReactOS kernel
20  * FILE: ntoskrnl/cache/section/sptab.c
21  * PURPOSE: Section object page tables
22  *
23  * PROGRAMMERS: arty
24  */
25 
26 /*
27 
28 This file implements the section page table. It relies on rtl generic table
29 functionality to provide access to 256-page chunks. Calls to
30 MiSetPageEntrySectionSegment and MiGetPageEntrySectionSegment must be
31 synchronized by holding the segment lock.
32 
33 Each page table entry is a ULONG as in x86.
34 
35 Bit 1 is used as a swap entry indication as in the main page table.
36 Bit 2 is used as a dirty indication. A dirty page will eventually be written
37 back to the file.
38 Bits 3-11 are used as a map count in the legacy mm code, Note that zero is
39 illegal, as the legacy code does not take advantage of segment rmaps.
40 Therefore, every segment page is mapped in at least one address space, and
41 MmUnsharePageEntry is quite complicated. In addition, the page may also be
42 owned by the legacy cache manager, giving an implied additional reference.
43 Upper bits are a PFN_NUMBER.
44 
45 These functions, in addition to maintaining the segment page table also
46 automatically maintain the segment rmap by calling MmSetSectionAssociation
47 and MmDeleteSectionAssociation. Segment rmaps are discussed in rmap.c. The
48 upshot is that it is impossible to have a page properly registered in a segment
49 page table and not also found in a segment rmap that can be found from the
50 paging machinery.
51 
52 */
53 
54 /* INCLUDES *****************************************************************/
55 
56 #include <ntoskrnl.h>
57 #include "newmm.h"
58 #define NDEBUG
59 #include <debug.h>
60 
61 #define DPRINTC DPRINT
62 
63 /* TYPES *********************************************************************/
64 
66 
67 _Function_class_(RTL_GENERIC_ALLOCATE_ROUTINE)
68 static
69 PVOID
70 NTAPI
71 MiSectionPageTableAllocate(PRTL_GENERIC_TABLE Table, CLONG Bytes)
72 {
73  PVOID Result;
75  //DPRINT("MiSectionPageTableAllocate(%d) => %p\n", Bytes, Result);
76  return Result;
77 }
78 
79 _Function_class_(RTL_GENERIC_FREE_ROUTINE)
80 static
81 VOID
82 NTAPI
83 MiSectionPageTableFree(PRTL_GENERIC_TABLE Table, PVOID Data)
84 {
85  //DPRINT("MiSectionPageTableFree(%p)\n", Data);
86  ExFreePoolWithTag(Data, 'tPmM');
87 }
88 
89 _Function_class_(RTL_GENERIC_COMPARE_ROUTINE)
90 static
92 NTAPI
93 MiSectionPageTableCompare(PRTL_GENERIC_TABLE Table,
94  PVOID PtrA,
95  PVOID PtrB)
96 {
97  PLARGE_INTEGER A = PtrA, B = PtrB;
98  BOOLEAN Result = (A->QuadPart < B->QuadPart) ? GenericLessThan :
99  (A->QuadPart == B->QuadPart) ? GenericEqual : GenericGreaterThan;
100 
101 #if 0
102  DPRINT
103  ("Compare: %08x%08x vs %08x%08x => %s\n",
104  A->u.HighPart, A->u.LowPart,
105  B->u.HighPart, B->u.LowPart,
106  Result == GenericLessThan ? "GenericLessThan" :
107  Result == GenericGreaterThan ? "GenericGreaterThan" :
108  "GenericEqual");
109 #endif
110 
111  return Result;
112 }
113 
114 static
116 NTAPI
119 {
120  LARGE_INTEGER SearchFileOffset;
122  SearchFileOffset.QuadPart = ROUND_DOWN(FileOffset->QuadPart,
124  PageTable = RtlLookupElementGenericTable(Table, &SearchFileOffset);
125 
126  DPRINT("MiSectionPageTableGet(%p,%I64x)\n",
127  Table,
128  FileOffset->QuadPart);
129 
130  return PageTable;
131 }
132 
133 static
135 NTAPI
138 {
139  LARGE_INTEGER SearchFileOffset;
140  CACHE_SECTION_PAGE_TABLE SectionZeroPageTable;
142  FileOffset);
143  /* Please zero memory when taking away zero initialization. */
144  RtlZeroMemory(&SectionZeroPageTable, sizeof(CACHE_SECTION_PAGE_TABLE));
145  if (!PageTableSlice)
146  {
147  SearchFileOffset.QuadPart = ROUND_DOWN(FileOffset->QuadPart,
149  SectionZeroPageTable.FileOffset = SearchFileOffset;
150  SectionZeroPageTable.Refcount = 1;
151  PageTableSlice = RtlInsertElementGenericTable(Table,
152  &SectionZeroPageTable,
153  sizeof(SectionZeroPageTable),
154  NULL);
155  if (!PageTableSlice) return NULL;
156  DPRINT("Allocate page table %p (%I64x)\n",
157  PageTableSlice,
158  PageTableSlice->FileOffset.QuadPart);
159  }
160  return PageTableSlice;
161 }
162 
163 VOID
164 NTAPI
166 {
168  MiSectionPageTableCompare,
169  MiSectionPageTableAllocate,
170  MiSectionPageTableFree,
171  NULL);
172 
173  DPRINT("MiInitializeSectionPageTable(%p)\n", &Segment->PageTable);
174 }
175 
176 NTSTATUS
177 NTAPI
181  const char *file,
182  int line)
183 {
184  ULONG_PTR PageIndex, OldEntry;
186 
187  ASSERT(Segment->Locked);
189 
190  if (Entry && !IS_SWAP_FROM_SSE(Entry))
192 
194 
195  if (!PageTable) return STATUS_NO_MEMORY;
196 
198 
199  PageTable->Segment = Segment;
200  PageIndex = (ULONG_PTR)((Offset->QuadPart - PageTable->FileOffset.QuadPart) / PAGE_SIZE);
201  OldEntry = PageTable->PageEntries[PageIndex];
202 
203  DPRINT("MiSetPageEntrySectionSegment(%p,%08x%08x,%x=>%x)\n",
204  Segment,
205  Offset->u.HighPart,
206  Offset->u.LowPart,
207  OldEntry,
208  Entry);
209 
210  if (PFN_FROM_SSE(Entry) == PFN_FROM_SSE(OldEntry)) {
211  /* Nothing */
212  } else if (Entry && !IS_SWAP_FROM_SSE(Entry)) {
213  ASSERT(!OldEntry || IS_SWAP_FROM_SSE(OldEntry));
215  } else if (OldEntry && !IS_SWAP_FROM_SSE(OldEntry)) {
218  } else if (IS_SWAP_FROM_SSE(Entry)) {
219  ASSERT(!IS_SWAP_FROM_SSE(OldEntry) ||
220  SWAPENTRY_FROM_SSE(OldEntry) == MM_WAIT_ENTRY);
221  if (OldEntry && SWAPENTRY_FROM_SSE(OldEntry) != MM_WAIT_ENTRY)
223  } else if (IS_SWAP_FROM_SSE(OldEntry)) {
225  if (Entry)
227  } else {
228  /* We should not be replacing a page like this */
229  ASSERT(FALSE);
230  }
231  PageTable->PageEntries[PageIndex] = Entry;
232  return STATUS_SUCCESS;
233 }
234 
235 ULONG_PTR
236 NTAPI
239  const char *file,
240  int line)
241 {
243  ULONG_PTR PageIndex, Result;
245 
246  ASSERT(Segment->Locked);
247  FileOffset.QuadPart = ROUND_DOWN(Offset->QuadPart,
250  if (!PageTable) return 0;
251  PageIndex = (ULONG_PTR)((Offset->QuadPart - PageTable->FileOffset.QuadPart) / PAGE_SIZE);
252  Result = PageTable->PageEntries[PageIndex];
253 #if 0
254  DPRINTC
255  ("MiGetPageEntrySectionSegment(%p,%08x%08x) => %x %s:%d\n",
256  Segment,
257  FileOffset.u.HighPart,
258  FileOffset.u.LowPart + PageIndex * PAGE_SIZE,
259  Result,
260  file, line);
261 #endif
262  return Result;
263 }
264 
265 /*
266 
267 Destroy the rtl generic table that serves as the section's page table. Call
268 the FreePage function for each non-zero entry in the section page table as
269 we go. Note that the page table is still techinally valid until after all
270 pages are destroyed, as we don't finally destroy the table until we've free
271 each slice. There is no order guarantee for deletion of individual elements
272 although it's in-order as written now.
273 
274 */
275 
276 VOID
277 NTAPI
280 {
282  DPRINT("MiFreePageTablesSectionSegment(%p)\n", &Segment->PageTable);
283  while ((Element = RtlGetElementGenericTable(&Segment->PageTable, 0))) {
284  DPRINT("Delete table for <%wZ> %p -> %I64x\n",
285  Segment->FileObject ? &Segment->FileObject->FileName : NULL,
286  Segment,
287  Element->FileOffset.QuadPart);
288  if (FreePage)
289  {
290  ULONG i;
291  for (i = 0; i < ENTRIES_PER_ELEMENT; i++)
292  {
295  Offset.QuadPart = Element->FileOffset.QuadPart + i * PAGE_SIZE;
296  Entry = Element->PageEntries[i];
297  if (Entry && !IS_SWAP_FROM_SSE(Entry))
298  {
299  DPRINT("Freeing page %p:%Ix @ %I64x\n",
300  Segment,
301  Entry,
302  Offset.QuadPart);
303 
305  }
306  }
307  }
308  DPRINT("Remove memory\n");
309  RtlDeleteElementGenericTable(&Segment->PageTable, Element);
310  }
311  DPRINT("Done\n");
312 }
313 
314 /*
315 
316 Retrieves the MM_SECTION_SEGMENT and fills in the LARGE_INTEGER Offset given
317 by the caller that corresponds to the page specified. This uses
318 MmGetSegmentRmap to find the rmap belonging to the segment itself, and uses
319 the result as a pointer to a 256-entry page table structure. The rmap also
320 includes 8 bits of offset information indication one of 256 page entries that
321 the rmap corresponds to. This information together gives us an exact offset
322 into the file, as well as the MM_SECTION_SEGMENT pointer stored in the page
323 table slice.
324 
325 NULL is returned is there is no segment rmap for the page.
326 
327 */
328 
330 NTAPI
333 {
334  ULONG RawOffset;
337 
339  &RawOffset);
340  if (PageTable)
341  {
342  Segment = PageTable->Segment;
343  Offset->QuadPart = PageTable->FileOffset.QuadPart +
344  ((ULONG64)RawOffset << PAGE_SHIFT);
345  }
346 
347  return Segment;
348 }
349 
350 NTSTATUS
351 NTAPI
355 {
357  ULONG ActualOffset;
358 
360  ASSERT(PageTable);
361 
362  ActualOffset = (ULONG)(Offset->QuadPart - PageTable->FileOffset.QuadPart);
363  MmInsertRmap(Page,
365  (PVOID)(RMAP_SEGMENT_MASK | (ActualOffset >> PAGE_SHIFT)));
366 
367  return STATUS_SUCCESS;
368 }
VOID(NTAPI * FREE_SECTION_PAGE_FUN)(PMM_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset)
Definition: newmm.h:145
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
ASMGENDATA Table[]
Definition: genincdata.c:61
VOID NTAPI MmInsertRmap(PFN_NUMBER Page, struct _EPROCESS *Process, PVOID Address)
PVOID NTAPI MmGetSegmentRmap(PFN_NUMBER Page, PULONG RawOffset)
Definition: rmap.c:451
#define IS_DIRTY_SSE(E)
Definition: newmm.h:16
struct _Entry Entry
Definition: kefuncs.h:640
#define PFN_FROM_SSE(E)
Definition: newmm.h:7
static PMEM_HOOK PageTable[TOTAL_PAGES]
Definition: memory.c:40
ULONG_PTR NTAPI _MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset, const char *file, int line)
Definition: sptab.c:237
struct _MM_RMAP_ENTRY *NTAPI MmGetRmapListHeadPage(PFN_NUMBER Page)
Definition: freelist.c:427
LONG NTSTATUS
Definition: precomp.h:26
static PCACHE_SECTION_PAGE_TABLE NTAPI MiSectionPageTableGet(PRTL_GENERIC_TABLE Table, PLARGE_INTEGER FileOffset)
Definition: sptab.c:117
_In_ UINT Bytes
Definition: mmcopy.h:9
VOID NTAPI MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment, FREE_SECTION_PAGE_FUN FreePage)
Definition: sptab.c:278
#define RMAP_SEGMENT_MASK
Definition: newmm.h:24
#define MM_WAIT_ENTRY
Definition: mm.h:152
struct _CACHE_SECTION_PAGE_TABLE * PCACHE_SECTION_PAGE_TABLE
static PCACHE_SECTION_PAGE_TABLE NTAPI MiSectionPageTableGetOrAllocate(PRTL_GENERIC_TABLE Table, PLARGE_INTEGER FileOffset)
Definition: sptab.c:136
VOID NTAPI RtlInitializeGenericTable(IN PRTL_GENERIC_TABLE Table, IN PRTL_GENERIC_COMPARE_ROUTINE CompareRoutine, IN PRTL_GENERIC_ALLOCATE_ROUTINE AllocateRoutine, IN PRTL_GENERIC_FREE_ROUTINE FreeRoutine, IN PVOID TableContext)
Definition: generictable.c:100
uint32_t ULONG_PTR
Definition: typedefs.h:63
ULONG CLONG
Definition: umtypes.h:126
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
ULONG PFN_NUMBER
Definition: ke.h:8
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
ULONG_PTR PageEntries[ENTRIES_PER_ELEMENT]
Definition: newmm.h:58
_Function_class_(RTL_GENERIC_ALLOCATE_ROUTINE)
Definition: sptab.c:67
KSPIN_LOCK MiSectionPageTableLock
VOID NTAPI MmDeleteSectionAssociation(PFN_NUMBER Page)
Definition: rmap.c:484
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:426
Definition: parser.c:48
void DPRINT(...)
Definition: polytest.cpp:61
_Inout_ PVOID Segment
Definition: exfuncs.h:893
_Must_inspect_result_ NTSYSAPI PVOID NTAPI RtlLookupElementGenericTable(_In_ PRTL_GENERIC_TABLE Table, _In_ PVOID Buffer)
PMM_SECTION_SEGMENT NTAPI MmGetSectionAssociation(PFN_NUMBER Page, PLARGE_INTEGER Offset)
Definition: sptab.c:331
NTSTATUS NTAPI _MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset, ULONG_PTR Entry, const char *file, int line)
Definition: sptab.c:178
#define SWAPENTRY_FROM_SSE(E)
Definition: newmm.h:12
_Must_inspect_result_ NTSYSAPI PVOID NTAPI RtlGetElementGenericTable(_In_ PRTL_GENERIC_TABLE Table, _In_ ULONG I)
LARGE_INTEGER FileOffset
Definition: newmm.h:55
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
NTSTATUS NTAPI MmSetSectionAssociation(PFN_NUMBER Page, PMM_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset)
Definition: sptab.c:352
unsigned __int64 ULONG64
Definition: imports.h:198
Definition: ttei1.cpp:12
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define IS_SWAP_FROM_SSE(E)
Definition: newmm.h:8
#define ROUND_DOWN(n, align)
Definition: eventvwr.h:30
NTSYSAPI BOOLEAN NTAPI RtlDeleteElementGenericTable(_In_ PRTL_GENERIC_TABLE Table, _In_ PVOID Buffer)
VOID NTAPI MiInitializeSectionPageTable(PMM_SECTION_SEGMENT Segment)
Definition: sptab.c:165
_In_ PFCB _In_ LONGLONG FileOffset
Definition: cdprocs.h:151
#define STATUS_NO_MEMORY
Definition: ntstatus.h:246
ULONG KSPIN_LOCK
Definition: env_spec_w32.h:72
#define B(row, col)
enum _RTL_GENERIC_COMPARE_RESULTS RTL_GENERIC_COMPARE_RESULTS
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define ULONG_PTR
Definition: config.h:101
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
#define DPRINTC
Definition: sptab.c:61
return STATUS_SUCCESS
Definition: btrfs.c:2745
NTSYSAPI PVOID NTAPI RtlInsertElementGenericTable(_In_ PRTL_GENERIC_TABLE Table, _In_reads_bytes_(BufferSize) PVOID Buffer, _In_ CLONG BufferSize, _Out_opt_ PBOOLEAN NewElement)
base of all file and directory entries
Definition: entries.h:82
LONGLONG QuadPart
Definition: typedefs.h:112
#define ENTRIES_PER_ELEMENT
Definition: newmm.h:49
Definition: fci.c:126