ReactOS  0.4.14-dev-552-g2fad488
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 #if defined (ALLOC_PRAGMA)
18 #pragma alloc_text(INIT, MmInitializeRmapList)
19 #endif
20 
21 /* TYPES ********************************************************************/
22 
23 /* GLOBALS ******************************************************************/
24 
27 
28 /* FUNCTIONS ****************************************************************/
29 
31 static
32 VOID
33 NTAPI
34 RmapListFree(
36 {
38 }
39 
40 VOID
41 INIT_FUNCTION
42 NTAPI
44 {
47  NULL,
48  RmapListFree,
49  0,
50  sizeof(MM_RMAP_ENTRY),
51  TAG_RMAP,
52  50);
53 }
54 
56 NTAPI
58 {
62  ULONG Type;
63  PVOID Address;
67 
70 
71 #ifdef NEWCC
72  // Special case for NEWCC: we can have a page that's only in a segment
73  // page table
74  if (entry && RMAP_IS_SEGMENT(entry->Address) && entry->Next == NULL)
75  {
76  /* NEWCC does locking itself */
78  return MmpPageOutPhysicalAddress(Page);
79  }
80 #endif
81 
82  while (entry && RMAP_IS_SEGMENT(entry->Address))
83  entry = entry->Next;
84 
85  if (entry == NULL)
86  {
88  return(STATUS_UNSUCCESSFUL);
89  }
90 
91  Process = entry->Process;
92 
93  Address = entry->Address;
94 
95  if ((((ULONG_PTR)Address) & 0xFFF) != 0)
96  {
97  KeBugCheck(MEMORY_MANAGEMENT);
98  }
99 
101  {
102  if (!ExAcquireRundownProtection(&Process->RundownProtect))
103  {
106  }
107 
110  if (!NT_SUCCESS(Status))
111  {
112  ExReleaseRundownProtection(&Process->RundownProtect);
113  return Status;
114  }
115  AddressSpace = &Process->Vm;
116  }
117  else
118  {
121  }
122 
126  {
129  {
130  ExReleaseRundownProtection(&Process->RundownProtect);
132  }
133  return(STATUS_UNSUCCESSFUL);
134  }
135  Type = MemoryArea->Type;
137  {
139  Offset = MemoryArea->Data.SectionData.ViewOffset.QuadPart +
141 
143 
144  /*
145  * Get or create a pageop
146  */
149  if (Entry && MM_IS_WAIT_PTE(Entry))
150  {
154  {
155  ExReleaseRundownProtection(&Process->RundownProtect);
157  }
158  return(STATUS_UNSUCCESSFUL);
159  }
160 
162 
163  /*
164  * Release locks now we have a page op.
165  */
168 
169  /*
170  * Do the actual page out work.
171  */
173  }
174  else if (Type == MEMORY_AREA_CACHE)
175  {
176  /* NEWCC does locking itself */
179  }
180  else
181  {
182  KeBugCheck(MEMORY_MANAGEMENT);
183  }
184 
186  {
187  ExReleaseRundownProtection(&Process->RundownProtect);
189  }
190  return(Status);
191 }
192 
193 VOID
194 NTAPI
196 {
197  PMM_RMAP_ENTRY current_entry;
198 
200  current_entry = MmGetRmapListHeadPage(Page);
201  if (current_entry == NULL)
202  {
203  DPRINT1("MmIsDirtyRmap: No rmaps.\n");
204  KeBugCheck(MEMORY_MANAGEMENT);
205  }
206  while (current_entry != NULL)
207  {
208  if (!RMAP_IS_SEGMENT(current_entry->Address))
209  MmSetCleanPage(current_entry->Process, current_entry->Address);
210  current_entry = current_entry->Next;
211  }
213 }
214 
215 VOID
216 NTAPI
218 {
219  PMM_RMAP_ENTRY current_entry;
220 
222  current_entry = MmGetRmapListHeadPage(Page);
223  if (current_entry == NULL)
224  {
225  DPRINT1("MmIsDirtyRmap: No rmaps.\n");
226  KeBugCheck(MEMORY_MANAGEMENT);
227  }
228  while (current_entry != NULL)
229  {
230  if (!RMAP_IS_SEGMENT(current_entry->Address))
231  MmSetDirtyPage(current_entry->Process, current_entry->Address);
232  current_entry = current_entry->Next;
233  }
235 }
236 
237 BOOLEAN
238 NTAPI
240 {
241  PMM_RMAP_ENTRY current_entry;
242 
244  current_entry = MmGetRmapListHeadPage(Page);
245  if (current_entry == NULL)
246  {
248  return(FALSE);
249  }
250  while (current_entry != NULL)
251  {
252  if (
253  !RMAP_IS_SEGMENT(current_entry->Address) &&
254  MmIsDirtyPage(current_entry->Process, current_entry->Address))
255  {
257  return(TRUE);
258  }
259  current_entry = current_entry->Next;
260  }
262  return(FALSE);
263 }
264 
265 VOID
266 NTAPI
268  PVOID Address)
269 {
270  PMM_RMAP_ENTRY current_entry;
271  PMM_RMAP_ENTRY new_entry;
272  ULONG PrevSize;
273  if (!RMAP_IS_SEGMENT(Address))
275 
276  new_entry = ExAllocateFromNPagedLookasideList(&RmapLookasideList);
277  if (new_entry == NULL)
278  {
279  KeBugCheck(MEMORY_MANAGEMENT);
280  }
281  new_entry->Address = Address;
282  new_entry->Process = (PEPROCESS)Process;
283 #if DBG
284 #ifdef __GNUC__
285  new_entry->Caller = __builtin_return_address(0);
286 #else
287  new_entry->Caller = _ReturnAddress();
288 #endif
289 #endif
290 
291  if (
294  {
295  DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
296  "address 0x%.8X\n", Process ? Process->UniqueProcessId : 0,
297  Address,
299  Page << PAGE_SHIFT);
300  KeBugCheck(MEMORY_MANAGEMENT);
301  }
302 
304  current_entry = MmGetRmapListHeadPage(Page);
305  new_entry->Next = current_entry;
306 #if DBG
307  while (current_entry)
308  {
309  if (current_entry->Address == new_entry->Address && current_entry->Process == new_entry->Process)
310  {
311  DbgPrint("MmInsertRmap tries to add a second rmap entry for address %p\n current caller ",
312  current_entry->Address);
313  DbgPrint("%p", new_entry->Caller);
314  DbgPrint("\n previous caller ");
315  DbgPrint("%p", current_entry->Caller);
316  DbgPrint("\n");
317  KeBugCheck(MEMORY_MANAGEMENT);
318  }
319  current_entry = current_entry->Next;
320  }
321 #endif
322  MmSetRmapListHeadPage(Page, new_entry);
324  if (!RMAP_IS_SEGMENT(Address))
325  {
326  if (Process == NULL)
327  {
329  }
330  if (Process)
331  {
332  PrevSize = InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, PAGE_SIZE);
333  if (PrevSize >= Process->Vm.PeakWorkingSetSize)
334  {
335  Process->Vm.PeakWorkingSetSize = PrevSize + PAGE_SIZE;
336  }
337  }
338  }
339 }
340 
341 VOID
342 NTAPI
344  VOID (*DeleteMapping)(PVOID Context, PEPROCESS Process,
345  PVOID Address))
346 {
347  PMM_RMAP_ENTRY current_entry;
348  PMM_RMAP_ENTRY previous_entry;
350 
352  current_entry = MmGetRmapListHeadPage(Page);
353  if (current_entry == NULL)
354  {
355  DPRINT1("MmDeleteAllRmaps: No rmaps.\n");
356  KeBugCheck(MEMORY_MANAGEMENT);
357  }
360 
361  while (current_entry != NULL)
362  {
363  previous_entry = current_entry;
364  current_entry = current_entry->Next;
365  if (!RMAP_IS_SEGMENT(previous_entry->Address))
366  {
367  if (DeleteMapping)
368  {
369  DeleteMapping(Context, previous_entry->Process,
370  previous_entry->Address);
371  }
372  Process = previous_entry->Process;
373  ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
374  if (Process == NULL)
375  {
377  }
378  if (Process)
379  {
380  (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
381  }
382  }
383  else
384  {
385  ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
386  }
387  }
388 }
389 
390 VOID
391 NTAPI
393  PVOID Address)
394 {
395  PMM_RMAP_ENTRY current_entry, previous_entry;
396 
398  previous_entry = NULL;
399  current_entry = MmGetRmapListHeadPage(Page);
400 
401  while (current_entry != NULL)
402  {
403  if (current_entry->Process == (PEPROCESS)Process &&
404  current_entry->Address == Address)
405  {
406  if (previous_entry == NULL)
407  {
408  MmSetRmapListHeadPage(Page, current_entry->Next);
409  }
410  else
411  {
412  previous_entry->Next = current_entry->Next;
413  }
415  ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
416  if (!RMAP_IS_SEGMENT(Address))
417  {
418  if (Process == NULL)
419  {
421  }
422  if (Process)
423  {
424  (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
425  }
426  }
427  return;
428  }
429  previous_entry = current_entry;
430  current_entry = current_entry->Next;
431  }
432  KeBugCheck(MEMORY_MANAGEMENT);
433 }
434 
435 /*
436 
437 Return the process pointer given when a previous call to MmInsertRmap was
438 called with a process and address pointer that conform to the segment rmap
439 schema. In short, this requires the address part to be 0xffffff00 + n
440 where n is between 0 and 255. When such an rmap exists, it specifies a
441 segment rmap in which the process part is a pointer to a slice of a section
442 page table, and the low 8 bits of the address represent a page index in the
443 page table slice. Together, this information is used by
444 MmGetSectionAssociation to determine which page entry points to this page in
445 the segment page table.
446 
447 */
448 
449 PVOID
450 NTAPI
452 {
454  PMM_RMAP_ENTRY current_entry;//, previous_entry;
455 
457  //previous_entry = NULL;
458  current_entry = MmGetRmapListHeadPage(Page);
459  while (current_entry != NULL)
460  {
461  if (RMAP_IS_SEGMENT(current_entry->Address))
462  {
463  Result = (PCACHE_SECTION_PAGE_TABLE)current_entry->Process;
464  *RawOffset = (ULONG_PTR)current_entry->Address & ~RMAP_SEGMENT_MASK;
465  InterlockedIncrementUL(&Result->Segment->ReferenceCount);
467  return Result;
468  }
469  //previous_entry = current_entry;
470  current_entry = current_entry->Next;
471  }
473  return NULL;
474 }
475 
476 /*
477 
478 Remove the section rmap associated with the indicated page, if it exists.
479 
480 */
481 
482 VOID
483 NTAPI
485 {
486  PMM_RMAP_ENTRY current_entry, previous_entry;
487 
489  previous_entry = NULL;
490  current_entry = MmGetRmapListHeadPage(Page);
491  while (current_entry != NULL)
492  {
493  if (RMAP_IS_SEGMENT(current_entry->Address))
494  {
495  if (previous_entry == NULL)
496  {
497  MmSetRmapListHeadPage(Page, current_entry->Next);
498  }
499  else
500  {
501  previous_entry->Next = current_entry->Next;
502  }
504  ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
505  return;
506  }
507  previous_entry = current_entry;
508  current_entry = current_entry->Next;
509  }
511 }
#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:392
VOID NTAPI MmSetDirtyAllRmaps(PFN_NUMBER Page)
Definition: rmap.c:217
#define TRUE
Definition: types.h:120
PEPROCESS Process
Definition: mm.h:239
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:214
#define PROCESS_ALL_ACCESS
Definition: nt_native.h:1324
Type
Definition: Type.h:6
struct _Entry Entry
Definition: kefuncs.h:640
#define DbgPrint
Definition: loader.c:25
NTKERNELAPI VOID FASTCALL ExReleaseRundownProtection(_Inout_ PEX_RUNDOWN_REF RunRef)
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
FORCEINLINE VOID MmUnlockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1431
LONG NTSTATUS
Definition: precomp.h:26
struct _EPROCESS * PEPROCESS
Definition: nt_native.h:30
#define ExAcquireRundownProtection
Definition: ex.h:130
#define PAGE_ROUND_DOWN(x)
Definition: mmtypes.h:36
#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
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
VOID NTAPI MmDeleteSectionAssociation(PFN_NUMBER Page)
Definition: rmap.c:484
BOOLEAN NTAPI MmIsDirtyPageRmap(PFN_NUMBER Page)
Definition: rmap.c:239
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:63
PVOID NTAPI MmGetSegmentRmap(PFN_NUMBER Page, PULONG RawOffset)
Definition: rmap.c:451
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
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
PEPROCESS PsInitialSystemProcess
Definition: psmgr.c:50
_IRQL_requires_max_(DISPATCH_LEVEL)
Definition: rmap.c:30
union _MEMORY_AREA::@1743 Data
NTSTATUS NTAPI MmpPageOutPhysicalAddress(PFN_NUMBER Page)
Definition: swapout.c:345
VOID NTAPI MmSetCleanPage(struct _EPROCESS *Process, PVOID Address)
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
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
VOID NTAPI KeBugCheck(ULONG BugCheckCode)
Definition: bug.c:1507
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)
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:222
FAST_MUTEX RmapListLock
Definition: rmap.c:26
#define TAG_RMAP
Definition: tag.h:133
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
uint64_t ULONGLONG
Definition: typedefs.h:65
#define InterlockedExchangeAddUL(Addend, Value)
Definition: ex.h:1519
FORCEINLINE VOID ExInitializeFastMutex(_Out_ PFAST_MUTEX FastMutex)
Definition: exfuncs.h:274
#define STATUS_PROCESS_IS_TERMINATING
Definition: ntstatus.h:488
struct _MEMORY_AREA::@1743::@1744 SectionData
BOOLEAN DeleteInProgress
Definition: mm.h:217
VOID NTAPI MmSetCleanAllRmaps(PFN_NUMBER Page)
Definition: rmap.c:195
VOID INIT_FUNCTION NTAPI MmInitializeRmapList(VOID)
Definition: rmap.c:43
#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:207
Status
Definition: gdiplustypes.h:24
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define _In_
Definition: no_sal2.h:204
FORCEINLINE PMMSUPPORT MmGetKernelAddressSpace(VOID)
Definition: mm.h:1453
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:1513
unsigned int * PULONG
Definition: retypes.h:1
VOID NTAPI MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process, PVOID Address)
Definition: rmap.c:267
#define __drv_freesMem(kind)
Definition: driverspecs.h:254
struct _MM_RMAP_ENTRY * Next
Definition: mm.h:238
#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:236
#define ULONG_PTR
Definition: config.h:101
static NPAGED_LOOKASIDE_LIST RmapLookasideList
Definition: rmap.c:25
PVOID Address
Definition: mm.h:240
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
NTSTATUS NTAPI MmPageOutPhysicalAddress(PFN_NUMBER Page)
Definition: rmap.c:57
#define MmUnlockSectionSegment(x)
Definition: newmm.h:284
#define RMAP_IS_SEGMENT(x)
Definition: newmm.h:25
return STATUS_SUCCESS
Definition: btrfs.c:2938
VOID NTAPI MmDeleteAllRmaps(PFN_NUMBER Page, PVOID Context, VOID(*DeleteMapping)(PVOID Context, PEPROCESS Process, PVOID Address))
Definition: rmap.c:343
#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:1424
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