ReactOS  0.4.15-dev-1367-g07cc0b5
rmap.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top directory
3  * PROJECT: ReactOS kernel
4  * FILE: ntoskrnl/mm/rmap.c
5  * PURPOSE: Kernel memory managment functions
6  *
7  * PROGRAMMERS: David Welch (welch@cwcom.net)
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include <ntoskrnl.h>
13 #include <cache/section/newmm.h>
14 #define NDEBUG
15 #include <debug.h>
16 
17 /* TYPES ********************************************************************/
18 
19 /* GLOBALS ******************************************************************/
20 
23 
24 /* FUNCTIONS ****************************************************************/
25 
27 static
28 VOID
29 NTAPI
30 RmapListFree(
32 {
34 }
35 
36 CODE_SEG("INIT")
37 VOID
38 NTAPI
40 {
43  NULL,
44  RmapListFree,
45  0,
46  sizeof(MM_RMAP_ENTRY),
47  TAG_RMAP,
48  50);
49 }
50 
52 NTAPI
54 {
58  ULONG Type;
59  PVOID Address;
63 
66 
67 #ifdef NEWCC
68  // Special case for NEWCC: we can have a page that's only in a segment
69  // page table
70  if (entry && RMAP_IS_SEGMENT(entry->Address) && entry->Next == NULL)
71  {
72  /* NEWCC does locking itself */
74  return MmpPageOutPhysicalAddress(Page);
75  }
76 #endif
77 
78  while (entry && RMAP_IS_SEGMENT(entry->Address))
79  entry = entry->Next;
80 
81  if (entry == NULL)
82  {
84  return(STATUS_UNSUCCESSFUL);
85  }
86 
87  Process = entry->Process;
88 
89  Address = entry->Address;
90 
91  if ((((ULONG_PTR)Address) & 0xFFF) != 0)
92  {
93  KeBugCheck(MEMORY_MANAGEMENT);
94  }
95 
97  {
98  if (!ExAcquireRundownProtection(&Process->RundownProtect))
99  {
102  }
103 
106  if (!NT_SUCCESS(Status))
107  {
108  ExReleaseRundownProtection(&Process->RundownProtect);
109  return Status;
110  }
111  AddressSpace = &Process->Vm;
112  }
113  else
114  {
117  }
118 
122  {
125  {
126  ExReleaseRundownProtection(&Process->RundownProtect);
128  }
129  return(STATUS_UNSUCCESSFUL);
130  }
131  Type = MemoryArea->Type;
133  {
135  Offset = MemoryArea->Data.SectionData.ViewOffset.QuadPart +
137 
139 
140  /*
141  * Get or create a pageop
142  */
145  if (Entry && MM_IS_WAIT_PTE(Entry))
146  {
150  {
151  ExReleaseRundownProtection(&Process->RundownProtect);
153  }
154  return(STATUS_UNSUCCESSFUL);
155  }
156 
158 
159  /*
160  * Release locks now we have a page op.
161  */
164 
165  /*
166  * Do the actual page out work.
167  */
169  }
170  else if (Type == MEMORY_AREA_CACHE)
171  {
172  /* NEWCC does locking itself */
175  }
176  else
177  {
178  KeBugCheck(MEMORY_MANAGEMENT);
179  }
180 
182  {
183  ExReleaseRundownProtection(&Process->RundownProtect);
185  }
186  return(Status);
187 }
188 
189 VOID
190 NTAPI
192 {
193  PMM_RMAP_ENTRY current_entry;
194 
196  current_entry = MmGetRmapListHeadPage(Page);
197  if (current_entry == NULL)
198  {
199  DPRINT1("MmIsDirtyRmap: No rmaps.\n");
200  KeBugCheck(MEMORY_MANAGEMENT);
201  }
202  while (current_entry != NULL)
203  {
204  if (!RMAP_IS_SEGMENT(current_entry->Address))
205  MmSetCleanPage(current_entry->Process, current_entry->Address);
206  current_entry = current_entry->Next;
207  }
209 }
210 
211 VOID
212 NTAPI
214 {
215  PMM_RMAP_ENTRY current_entry;
216 
218  current_entry = MmGetRmapListHeadPage(Page);
219  if (current_entry == NULL)
220  {
221  DPRINT1("MmIsDirtyRmap: No rmaps.\n");
222  KeBugCheck(MEMORY_MANAGEMENT);
223  }
224  while (current_entry != NULL)
225  {
226  if (!RMAP_IS_SEGMENT(current_entry->Address))
227  MmSetDirtyPage(current_entry->Process, current_entry->Address);
228  current_entry = current_entry->Next;
229  }
231 }
232 
233 BOOLEAN
234 NTAPI
236 {
237  PMM_RMAP_ENTRY current_entry;
238 
240  current_entry = MmGetRmapListHeadPage(Page);
241  if (current_entry == NULL)
242  {
244  return(FALSE);
245  }
246  while (current_entry != NULL)
247  {
248  if (
249  !RMAP_IS_SEGMENT(current_entry->Address) &&
250  MmIsDirtyPage(current_entry->Process, current_entry->Address))
251  {
253  return(TRUE);
254  }
255  current_entry = current_entry->Next;
256  }
258  return(FALSE);
259 }
260 
261 VOID
262 NTAPI
264  PVOID Address)
265 {
266  PMM_RMAP_ENTRY current_entry;
267  PMM_RMAP_ENTRY new_entry;
268  ULONG PrevSize;
269  if (!RMAP_IS_SEGMENT(Address))
271 
272  new_entry = ExAllocateFromNPagedLookasideList(&RmapLookasideList);
273  if (new_entry == NULL)
274  {
275  KeBugCheck(MEMORY_MANAGEMENT);
276  }
277  new_entry->Address = Address;
278  new_entry->Process = (PEPROCESS)Process;
279 #if DBG
280 #ifdef __GNUC__
281  new_entry->Caller = __builtin_return_address(0);
282 #else
283  new_entry->Caller = _ReturnAddress();
284 #endif
285 #endif
286 
287  if (
290  {
291  DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
292  "address 0x%.8X\n", Process ? Process->UniqueProcessId : 0,
293  Address,
295  Page << PAGE_SHIFT);
296  KeBugCheck(MEMORY_MANAGEMENT);
297  }
298 
300  current_entry = MmGetRmapListHeadPage(Page);
301  new_entry->Next = current_entry;
302 #if DBG
303  while (current_entry)
304  {
305  if (current_entry->Address == new_entry->Address && current_entry->Process == new_entry->Process)
306  {
307  DbgPrint("MmInsertRmap tries to add a second rmap entry for address %p\n current caller ",
308  current_entry->Address);
309  DbgPrint("%p", new_entry->Caller);
310  DbgPrint("\n previous caller ");
311  DbgPrint("%p", current_entry->Caller);
312  DbgPrint("\n");
313  KeBugCheck(MEMORY_MANAGEMENT);
314  }
315  current_entry = current_entry->Next;
316  }
317 #endif
318  MmSetRmapListHeadPage(Page, new_entry);
320  if (!RMAP_IS_SEGMENT(Address))
321  {
322  if (Process == NULL)
323  {
325  }
326  if (Process)
327  {
328  PrevSize = InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, PAGE_SIZE);
329  if (PrevSize >= Process->Vm.PeakWorkingSetSize)
330  {
331  Process->Vm.PeakWorkingSetSize = PrevSize + PAGE_SIZE;
332  }
333  }
334  }
335 }
336 
337 VOID
338 NTAPI
340  VOID (*DeleteMapping)(PVOID Context, PEPROCESS Process,
341  PVOID Address))
342 {
343  PMM_RMAP_ENTRY current_entry;
344  PMM_RMAP_ENTRY previous_entry;
346 
348  current_entry = MmGetRmapListHeadPage(Page);
349  if (current_entry == NULL)
350  {
351  DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
352  KeBugCheck(MEMORY_MANAGEMENT);
353  }
356 
357  while (current_entry != NULL)
358  {
359  previous_entry = current_entry;
360  current_entry = current_entry->Next;
361  if (!RMAP_IS_SEGMENT(previous_entry->Address))
362  {
363  if (DeleteMapping)
364  {
365  DeleteMapping(Context, previous_entry->Process,
366  previous_entry->Address);
367  }
368  Process = previous_entry->Process;
369  ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
370  if (Process == NULL)
371  {
373  }
374  if (Process)
375  {
376  (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
377  }
378  }
379  else
380  {
381  ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
382  }
383  }
384 }
385 
386 VOID
387 NTAPI
389  PVOID Address)
390 {
391  PMM_RMAP_ENTRY current_entry, previous_entry;
392 
394  previous_entry = NULL;
395  current_entry = MmGetRmapListHeadPage(Page);
396 
397  while (current_entry != NULL)
398  {
399  if (current_entry->Process == (PEPROCESS)Process &&
400  current_entry->Address == Address)
401  {
402  if (previous_entry == NULL)
403  {
404  MmSetRmapListHeadPage(Page, current_entry->Next);
405  }
406  else
407  {
408  previous_entry->Next = current_entry->Next;
409  }
411  ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
412  if (!RMAP_IS_SEGMENT(Address))
413  {
414  if (Process == NULL)
415  {
417  }
418  if (Process)
419  {
420  (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
421  }
422  }
423  return;
424  }
425  previous_entry = current_entry;
426  current_entry = current_entry->Next;
427  }
428  KeBugCheck(MEMORY_MANAGEMENT);
429 }
430 
431 /*
432 
433 Return the process pointer given when a previous call to MmInsertRmap was
434 called with a process and address pointer that conform to the segment rmap
435 schema. In short, this requires the address part to be 0xffffff00 + n
436 where n is between 0 and 255. When such an rmap exists, it specifies a
437 segment rmap in which the process part is a pointer to a slice of a section
438 page table, and the low 8 bits of the address represent a page index in the
439 page table slice. Together, this information is used by
440 MmGetSectionAssociation to determine which page entry points to this page in
441 the segment page table.
442 
443 */
444 
445 PVOID
446 NTAPI
448 {
450  PMM_RMAP_ENTRY current_entry;//, previous_entry;
451 
453  //previous_entry = NULL;
454  current_entry = MmGetRmapListHeadPage(Page);
455  while (current_entry != NULL)
456  {
457  if (RMAP_IS_SEGMENT(current_entry->Address))
458  {
459  Result = (PCACHE_SECTION_PAGE_TABLE)current_entry->Process;
460  *RawOffset = (ULONG_PTR)current_entry->Address & ~RMAP_SEGMENT_MASK;
461  InterlockedIncrementUL(&Result->Segment->ReferenceCount);
463  return Result;
464  }
465  //previous_entry = current_entry;
466  current_entry = current_entry->Next;
467  }
469  return NULL;
470 }
471 
472 /*
473 
474 Remove the section rmap associated with the indicated page, if it exists.
475 
476 */
477 
478 VOID
479 NTAPI
481 {
482  PMM_RMAP_ENTRY current_entry, previous_entry;
483 
485  previous_entry = NULL;
486  current_entry = MmGetRmapListHeadPage(Page);
487  while (current_entry != NULL)
488  {
489  if (RMAP_IS_SEGMENT(current_entry->Address))
490  {
491  if (previous_entry == NULL)
492  {
493  MmSetRmapListHeadPage(Page, current_entry->Next);
494  }
495  else
496  {
497  previous_entry->Next = current_entry->Next;
498  }
500  ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
501  return;
502  }
503  previous_entry = current_entry;
504  current_entry = current_entry->Next;
505  }
507 }
#define MmSetPageEntrySectionSegment(S, O, E)
Definition: newmm.h:141
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
VOID NTAPI MmDeleteRmap(PFN_NUMBER Page, PEPROCESS Process, PVOID Address)
Definition: rmap.c:388
VOID NTAPI MmSetDirtyAllRmaps(PFN_NUMBER Page)
Definition: rmap.c:213
PEPROCESS Process
Definition: mm.h:245
struct LOOKASIDE_ALIGN _NPAGED_LOOKASIDE_LIST NPAGED_LOOKASIDE_LIST
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
ULONG Type
Definition: mm.h:220
#define PROCESS_ALL_ACCESS
Definition: nt_native.h:1324
struct _Entry Entry
Definition: kefuncs.h:627
#define DbgPrint
Definition: loader.c:25
NTKERNELAPI VOID FASTCALL ExReleaseRundownProtection(_Inout_ PEX_RUNDOWN_REF RunRef)
#define TRUE
Definition: types.h:120
struct _MM_RMAP_ENTRY *NTAPI MmGetRmapListHeadPage(PFN_NUMBER Page)
Definition: freelist.c:427
_In_ ULONG _In_ PHYSICAL_ADDRESS _Inout_ PULONG AddressSpace
Definition: iofuncs.h:2268
union _MEMORY_AREA::@1781 Data
FORCEINLINE VOID MmUnlockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1423
LONG NTSTATUS
Definition: precomp.h:26
struct _EPROCESS * PEPROCESS
Definition: nt_native.h:30
#define ExAcquireRundownProtection
Definition: ex.h:128
#define PAGE_ROUND_DOWN(x)
Definition: mmtypes.h:36
#define RMAP_SEGMENT_MASK
Definition: newmm.h:24
struct _CACHE_SECTION_PAGE_TABLE * PCACHE_SECTION_PAGE_TABLE
VOID NTAPI MmDeleteSectionAssociation(PFN_NUMBER Page)
Definition: rmap.c:480
BOOLEAN NTAPI MmIsDirtyPageRmap(PFN_NUMBER Page)
Definition: rmap.c:235
PMEMORY_AREA NTAPI MmLocateMemoryAreaByAddress(PMMSUPPORT AddressSpace, PVOID Address)
Definition: marea.c:60
VOID FASTCALL ExReleaseFastMutex(IN PFAST_MUTEX FastMutex)
Definition: fmutex.c:31
#define MEMORY_AREA_CACHE
Definition: mm.h:72
uint32_t ULONG_PTR
Definition: typedefs.h:65
PVOID NTAPI MmGetSegmentRmap(PFN_NUMBER Page, PULONG RawOffset)
Definition: rmap.c:447
ULONG PFN_NUMBER
Definition: ke.h:8
VOID NTAPI MmSetDirtyPage(struct _EPROCESS *Process, PVOID Address)
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
PEPROCESS PsInitialSystemProcess
Definition: psmgr.c:50
_IRQL_requires_max_(DISPATCH_LEVEL)
Definition: rmap.c:26
DECLSPEC_NORETURN VOID NTAPI KeBugCheck(ULONG BugCheckCode)
Definition: bug.c:1427
NTSTATUS NTAPI MmpPageOutPhysicalAddress(PFN_NUMBER Page)
Definition: swapout.c:345
VOID NTAPI MmInitializeRmapList(VOID)
Definition: rmap.c:39
VOID NTAPI MmSetCleanPage(struct _EPROCESS *Process, PVOID Address)
unsigned char BOOLEAN
static WCHAR Address[46]
Definition: ping.c:68
NTSTATUS NTAPI MmPageOutSectionView(PMMSUPPORT AddressSpace, PMEMORY_AREA MemoryArea, PVOID Address, ULONG_PTR Entry)
_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
NTSTATUS NTAPI ObReferenceObjectByPointer(IN PVOID Object, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode)
Definition: obref.c:383
void * PVOID
Definition: retypes.h:9
#define MEMORY_AREA_SECTION_VIEW
Definition: mm.h:71
VOID NTAPI MmSetRmapListHeadPage(PFN_NUMBER Page, struct _MM_RMAP_ENTRY *ListHead)
Status
Definition: gdiplustypes.h:24
FAST_MUTEX
Definition: extypes.h:17
VOID NTAPI ExInitializeNPagedLookasideList(IN PNPAGED_LOOKASIDE_LIST Lookaside, IN PALLOCATE_FUNCTION Allocate OPTIONAL, IN PFREE_FUNCTION Free OPTIONAL, IN ULONG Flags, IN SIZE_T Size, IN ULONG Tag, IN USHORT Depth)
Definition: lookas.c:218
FAST_MUTEX RmapListLock
Definition: rmap.c:22
#define TAG_RMAP
Definition: tag.h:133
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
struct _MEMORY_AREA::@1781::@1782 SectionData
uint64_t ULONGLONG
Definition: typedefs.h:67
#define InterlockedExchangeAddUL(Addend, Value)
Definition: ex.h:1505
FORCEINLINE VOID ExInitializeFastMutex(_Out_ PFAST_MUTEX FastMutex)
Definition: exfuncs.h:274
#define STATUS_PROCESS_IS_TERMINATING
Definition: ntstatus.h:502
#define ObDereferenceObject
Definition: obfuncs.h:203
BOOLEAN DeleteInProgress
Definition: mm.h:223
Type
Definition: Type.h:6
CODE_SEG("INIT")
Definition: fsrtlpc.c:19
VOID NTAPI MmSetCleanAllRmaps(PFN_NUMBER Page)
Definition: rmap.c:191
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
uint32_t entry
Definition: isohybrid.c:63
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define P(row, col)
#define MA_GetStartingAddress(_MemoryArea)
Definition: mm.h:213
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
#define _In_
Definition: no_sal2.h:158
FORCEINLINE PMMSUPPORT MmGetKernelAddressSpace(VOID)
Definition: mm.h:1445
VOID FASTCALL ExAcquireFastMutex(IN PFAST_MUTEX FastMutex)
Definition: fmutex.c:23
PFN_NUMBER NTAPI MmGetPfnForProcess(struct _EPROCESS *Process, PVOID Address)
#define InterlockedIncrementUL(Addend)
Definition: ex.h:1499
unsigned int * PULONG
Definition: retypes.h:1
VOID NTAPI MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process, PVOID Address)
Definition: rmap.c:263
#define NULL
Definition: types.h:112
#define __drv_freesMem(kind)
Definition: driverspecs.h:254
struct _MM_RMAP_ENTRY * Next
Definition: mm.h:244
#define DPRINT1
Definition: precomp.h:8
#define MmLockSectionSegment(x)
Definition: newmm.h:276
#define MM_IS_WAIT_PTE(E)
Definition: newmm.h:9
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:219
void * _ReturnAddress(void)
unsigned int ULONG
Definition: retypes.h:1
Definition: mm.h:242
#define ULONG_PTR
Definition: config.h:101
static NPAGED_LOOKASIDE_LIST RmapLookasideList
Definition: rmap.c:21
PVOID Address
Definition: mm.h:246
#define STATUS_SUCCESS
Definition: shellext.h:65
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
NTSTATUS NTAPI MmPageOutPhysicalAddress(PFN_NUMBER Page)
Definition: rmap.c:53
#define MmUnlockSectionSegment(x)
Definition: newmm.h:284
#define RMAP_IS_SEGMENT(x)
Definition: newmm.h:25
VOID NTAPI MmDeleteAllRmaps(PFN_NUMBER Page, PVOID Context, VOID(*DeleteMapping)(PVOID Context, PEPROCESS Process, PVOID Address))
Definition: rmap.c:339
#define MAKE_SWAP_SSE(S)
Definition: newmm.h:13
struct _MEMORY_AREA * MemoryArea
Definition: newmm.h:65
FORCEINLINE VOID MmLockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1416
BOOLEAN NTAPI MmIsDirtyPage(struct _EPROCESS *Process, PVOID Address)
#define MmSystemRangeStart
Definition: mm.h:32
base of all file and directory entries
Definition: entries.h:82
#define MmGetPageEntrySectionSegment(S, O)
Definition: newmm.h:143