ReactOS 0.4.15-dev-5666-gc548b97
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
22
23/* FUNCTIONS ****************************************************************/
24
26static
27VOID
29RmapListFree(
31{
33}
34
35CODE_SEG("INIT")
36VOID
39{
41 NULL,
42 RmapListFree,
43 0,
44 sizeof(MM_RMAP_ENTRY),
46 50);
47}
48
52{
60 LARGE_INTEGER SegmentOffset;
62
63GetEntry:
64 OldIrql = MiAcquirePfnLock();
65
67
68 while (entry && RMAP_IS_SEGMENT(entry->Address))
69 entry = entry->Next;
70
71 if (entry == NULL)
72 {
73 MiReleasePfnLock(OldIrql);
74 goto WriteSegment;
75 }
76
77 Process = entry->Process;
78 Address = entry->Address;
79
80 if ((((ULONG_PTR)Address) & 0xFFF) != 0)
81 {
82 KeBugCheck(MEMORY_MANAGEMENT);
83 }
84
85 /* This is for user-mode address only */
87
88 if (!ExAcquireRundownProtection(&Process->RundownProtect))
89 {
90 MiReleasePfnLock(OldIrql);
92 }
93
95 MiReleasePfnLock(OldIrql);
96 if (!NT_SUCCESS(Status))
97 {
98 ExReleaseRundownProtection(&Process->RundownProtect);
99 return Status;
100 }
101 AddressSpace = &Process->Vm;
102
104
107 {
109 ExReleaseRundownProtection(&Process->RundownProtect);
111 goto GetEntry;
112 }
113
114
115 /* Attach to it, if needed */
119
121 {
122 /* This changed in the short window where we didn't have any locks */
126 ExReleaseRundownProtection(&Process->RundownProtect);
128 goto GetEntry;
129 }
130
132 {
134 BOOLEAN Dirty;
135 PFN_NUMBER MapPage;
137 BOOLEAN Released;
138 BOOLEAN Unmapped;
139
140 Offset.QuadPart = MemoryArea->SectionData.ViewOffset +
142
143 Segment = MemoryArea->SectionData.Segment;
144
146
148 if (Entry && MM_IS_WAIT_PTE(Entry))
149 {
150 /* The segment is being read or something. Give up */
155 ExReleaseRundownProtection(&Process->RundownProtect);
157 return(STATUS_UNSUCCESSFUL);
158 }
159
160 /* Delete this virtual mapping in the process */
162 Unmapped = MmDeleteVirtualMapping(Process, Address, &Dirty, &MapPage);
163 if (!Unmapped || (MapPage != Page))
164 {
165 /*
166 * Something's corrupted, we got there because this process is
167 * supposed to be mapping this page there.
168 */
169 KeBugCheckEx(MEMORY_MANAGEMENT,
172 (ULONG_PTR)__FILE__,
173 __LINE__);
174 }
175
176 if (Page != PFN_FROM_SSE(Entry))
177 {
178 SWAPENTRY SwapEntry;
179
180 /* This page is private to the process */
182
183 /* Check if we should write it back to the page file */
184 SwapEntry = MmGetSavedSwapEntryPage(Page);
185
186 if ((SwapEntry == 0) && Dirty)
187 {
188 /* We don't have a Swap entry, yet the page is dirty. Get one */
189 SwapEntry = MmAllocSwapPage();
190 if (!SwapEntry)
191 {
193 &MemoryArea->SectionData.RegionListHead,
194 Address, NULL);
195
196 /* We can't, so let this page in the Process VM */
200
204 ExReleaseRundownProtection(&Process->RundownProtect);
206
207 return STATUS_UNSUCCESSFUL;
208 }
209 }
210
211 if (Dirty)
212 {
213 SWAPENTRY Dummy;
214
215 /* Put a wait entry into the process and unlock */
216 MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY);
218
219 Status = MmWriteToSwapPage(SwapEntry, Page);
220
223 ASSERT(Dummy == MM_WAIT_ENTRY);
224
225 if (!NT_SUCCESS(Status))
226 {
227 /* We failed at saving the content of this page. Keep it in */
229 &MemoryArea->SectionData.RegionListHead,
230 Address, NULL);
231
232 /* This Swap Entry is useless to us */
234 MmFreeSwapPage(SwapEntry);
235
236 /* We can't, so let this page in the Process VM */
240
244 ExReleaseRundownProtection(&Process->RundownProtect);
246
247 return STATUS_UNSUCCESSFUL;
248 }
249 }
250
251 if (SwapEntry)
252 {
253 /* Keep this in the process VM */
256 }
257
258 /* We can finally let this page go */
262#if DBG
263 OldIrql = MiAcquirePfnLock();
265 MiReleasePfnLock(OldIrql);
266#endif
268
269 ExReleaseRundownProtection(&Process->RundownProtect);
271
272 return STATUS_SUCCESS;
273 }
274
275 /* One less mapping referencing this segment */
277
282
283 ExReleaseRundownProtection(&Process->RundownProtect);
285
286 if (Released) return STATUS_SUCCESS;
287 }
288#ifdef NEWCC
289 else if (Type == MEMORY_AREA_CACHE)
290 {
291 /* NEWCC does locking itself */
294 }
295#endif
296 else
297 {
298 KeBugCheck(MEMORY_MANAGEMENT);
299 }
300
301WriteSegment:
302 /* Now write this page to file, if needed */
303 Segment = MmGetSectionAssociation(Page, &SegmentOffset);
304 if (Segment)
305 {
306 BOOLEAN Released;
307
309
310 Released = MmCheckDirtySegment(Segment, &SegmentOffset, FALSE, TRUE);
311
313 MmDereferenceSegment(Segment);
314
315 if (Released)
316 {
317 return STATUS_SUCCESS;
318 }
319 }
320
321 /* If we are here, then we didn't release the page */
322 return STATUS_UNSUCCESSFUL;
323}
324
325VOID
326NTAPI
329{
330 PMM_RMAP_ENTRY current_entry;
331 PMM_RMAP_ENTRY new_entry;
332 ULONG PrevSize;
334
337
338 new_entry = ExAllocateFromNPagedLookasideList(&RmapLookasideList);
339 if (new_entry == NULL)
340 {
341 KeBugCheck(MEMORY_MANAGEMENT);
342 }
343 new_entry->Address = Address;
344 new_entry->Process = (PEPROCESS)Process;
345#if DBG
346 new_entry->Caller = _ReturnAddress();
347#endif
348
349 if (
352 {
353 DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
354 "address 0x%.8X\n", Process ? Process->UniqueProcessId : 0,
355 Address,
357 Page << PAGE_SHIFT);
358 KeBugCheck(MEMORY_MANAGEMENT);
359 }
360
361 OldIrql = MiAcquirePfnLock();
362 current_entry = MmGetRmapListHeadPage(Page);
363
364 PMM_RMAP_ENTRY previous_entry = NULL;
365 /* Keep the list sorted */
366 while (current_entry && (current_entry->Address < Address))
367 {
368 previous_entry = current_entry;
369 current_entry = current_entry->Next;
370 }
371
372 /* In case of clash in the address, sort by process */
373 if (current_entry && (current_entry->Address == Address))
374 {
375 while (current_entry && (current_entry->Process < Process))
376 {
377 previous_entry = current_entry;
378 current_entry = current_entry->Next;
379 }
380 }
381
382 if (current_entry && (current_entry->Address == Address) && (current_entry->Process == Process))
383 {
384#if DBG
385 DbgPrint("MmInsertRmap tries to add a second rmap entry for address %p\n", current_entry->Address);
386 DbgPrint(" current caller %p\n", new_entry->Caller);
387 DbgPrint(" previous caller %p\n", current_entry->Caller);
388#endif
389 KeBugCheck(MEMORY_MANAGEMENT);
390 }
391
392 new_entry->Next = current_entry;
393 if (previous_entry)
394 previous_entry->Next = new_entry;
395 else
396 MmSetRmapListHeadPage(Page, new_entry);
397
398 MiReleasePfnLock(OldIrql);
399
401 {
402 ASSERT(Process != NULL);
403 PrevSize = InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, PAGE_SIZE);
404 if (PrevSize >= Process->Vm.PeakWorkingSetSize)
405 {
406 Process->Vm.PeakWorkingSetSize = PrevSize + PAGE_SIZE;
407 }
408 }
409}
410
411VOID
412NTAPI
415{
416 PMM_RMAP_ENTRY current_entry, previous_entry;
418
419 OldIrql = MiAcquirePfnLock();
420 previous_entry = NULL;
421 current_entry = MmGetRmapListHeadPage(Page);
422
423 while (current_entry != NULL)
424 {
425 if (current_entry->Process == (PEPROCESS)Process &&
426 current_entry->Address == Address)
427 {
428 if (previous_entry == NULL)
429 {
430 MmSetRmapListHeadPage(Page, current_entry->Next);
431 }
432 else
433 {
434 previous_entry->Next = current_entry->Next;
435 }
436 MiReleasePfnLock(OldIrql);
437
438 ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
440 {
441 ASSERT(Process != NULL);
442 (void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
443 }
444 return;
445 }
446 previous_entry = current_entry;
447 current_entry = current_entry->Next;
448 }
449 KeBugCheck(MEMORY_MANAGEMENT);
450}
451
452/*
453
454Return the process pointer given when a previous call to MmInsertRmap was
455called with a process and address pointer that conform to the segment rmap
456schema. In short, this requires the address part to be 0xffffff00 + n
457where n is between 0 and 255. When such an rmap exists, it specifies a
458segment rmap in which the process part is a pointer to a slice of a section
459page table, and the low 8 bits of the address represent a page index in the
460page table slice. Together, this information is used by
461MmGetSectionAssociation to determine which page entry points to this page in
462the segment page table.
463
464*/
465
466PVOID
467NTAPI
469{
471 PMM_RMAP_ENTRY current_entry;//, previous_entry;
472 KIRQL OldIrql = MiAcquirePfnLock();
473
474 //previous_entry = NULL;
475 current_entry = MmGetRmapListHeadPage(Page);
476 while (current_entry != NULL)
477 {
478 if (RMAP_IS_SEGMENT(current_entry->Address))
479 {
480 Result = (PCACHE_SECTION_PAGE_TABLE)current_entry->Process;
481 *RawOffset = (ULONG_PTR)current_entry->Address & ~RMAP_SEGMENT_MASK;
482 if (*Result->Segment->Flags & MM_SEGMENT_INDELETE)
483 {
484 MiReleasePfnLock(OldIrql);
485 return NULL;
486 }
487 MiReleasePfnLock(OldIrql);
488 return Result;
489 }
490 //previous_entry = current_entry;
491 current_entry = current_entry->Next;
492 }
493 MiReleasePfnLock(OldIrql);
494 return NULL;
495}
496
497/*
498
499Remove the section rmap associated with the indicated page, if it exists.
500
501*/
502
503VOID
504NTAPI
506{
507 PMM_RMAP_ENTRY current_entry, previous_entry;
508 KIRQL OldIrql = MiAcquirePfnLock();
509
510 previous_entry = NULL;
511 current_entry = MmGetRmapListHeadPage(Page);
512 while (current_entry != NULL)
513 {
514 if (RMAP_IS_SEGMENT(current_entry->Address))
515 {
516 if (previous_entry == NULL)
517 {
518 MmSetRmapListHeadPage(Page, current_entry->Next);
519 }
520 else
521 {
522 previous_entry->Next = current_entry->Next;
523 }
524 MiReleasePfnLock(OldIrql);
525 ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
526 return;
527 }
528 previous_entry = current_entry;
529 current_entry = current_entry->Next;
530 }
531 MiReleasePfnLock(OldIrql);
532}
unsigned char BOOLEAN
Type
Definition: Type.h:7
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
DECLSPEC_NORETURN VOID NTAPI KeBugCheck(ULONG BugCheckCode)
Definition: bug.c:1427
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define P(row, col)
#define ULONG_PTR
Definition: config.h:101
#define __drv_freesMem(kind)
Definition: driverspecs.h:271
#define _IRQL_requires_max_(irql)
Definition: driverspecs.h:230
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define PAGE_SHIFT
Definition: env_spec_w32.h:45
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
#define ExReleaseRundownProtection
Definition: ex.h:135
#define InterlockedExchangeAddUL(Addend, Value)
Definition: ex.h:1532
#define ExAcquireRundownProtection
Definition: ex.h:134
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:223
Status
Definition: gdiplustypes.h:25
#define DbgPrint
Definition: hal.h:12
#define _ReturnAddress()
Definition: intrin_arm.h:35
static CODE_SEG("PAGE")
Definition: isapnp.c:1482
uint32_t entry
Definition: isohybrid.c:63
unsigned int * PULONG
Definition: retypes.h:1
void * PVOID
Definition: retypes.h:9
unsigned int ULONG
Definition: retypes.h:1
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
#define ASSERT(a)
Definition: mode.c:44
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
#define _In_
Definition: ms_sal.h:308
#define KernelMode
Definition: asm.h:34
#define PAGE_ROUND_DOWN(x)
Definition: mmtypes.h:36
_In_ PMEMORY_AREA MemoryArea
Definition: newmm.h:207
NTSTATUS NTAPI MmpPageOutPhysicalAddress(PFN_NUMBER Page)
Definition: swapout.c:345
struct _CACHE_SECTION_PAGE_TABLE * PCACHE_SECTION_PAGE_TABLE
#define PROCESS_ALL_ACCESS
Definition: nt_native.h:1324
struct _EPROCESS * PEPROCESS
Definition: nt_native.h:30
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
#define MmSystemRangeStart
Definition: mm.h:32
#define MmSetDirtyPage(__P, __A)
Definition: mm.h:1244
#define MmGetPageEntrySectionSegment(S, O)
Definition: mm.h:1586
FORCEINLINE VOID MmLockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1659
struct _MM_RMAP_ENTRY *NTAPI MmGetRmapListHeadPage(PFN_NUMBER Page)
Definition: freelist.c:458
#define MmLockSectionSegment(x)
Definition: mm.h:1380
#define MC_USER
Definition: mm.h:114
#define MmUnlockSectionSegment(x)
Definition: mm.h:1388
#define RMAP_IS_SEGMENT(x)
Definition: mm.h:940
BOOLEAN NTAPI MmUnsharePageEntrySectionSegment(PMEMORY_AREA MemoryArea, PMM_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset, BOOLEAN Dirty, BOOLEAN PageOut, ULONG_PTR *InEntry)
Definition: section.c:1090
_In_ PVOID _Out_opt_ BOOLEAN _Out_opt_ PPFN_NUMBER Page
Definition: mm.h:1298
SWAPENTRY NTAPI MmAllocSwapPage(VOID)
Definition: pagefile.c:322
PMEMORY_AREA NTAPI MmLocateMemoryAreaByAddress(PMMSUPPORT AddressSpace, PVOID Address)
Definition: marea.c:60
BOOLEAN NTAPI MmCheckDirtySegment(PMM_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset, BOOLEAN ForceDirty, BOOLEAN PageOut)
NTSTATUS NTAPI MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
Definition: pagefile.c:147
PMM_REGION NTAPI MmFindRegion(PVOID BaseAddress, PLIST_ENTRY RegionListHead, PVOID Address, PVOID *RegionBaseAddress)
Definition: region.c:257
ULONG_PTR SWAPENTRY
Definition: mm.h:57
PFN_NUMBER NTAPI MmGetPfnForProcess(struct _EPROCESS *Process, PVOID Address)
#define MA_GetStartingAddress(_MemoryArea)
Definition: mm.h:244
FORCEINLINE VOID MmUnlockAddressSpace(PMMSUPPORT AddressSpace)
Definition: mm.h:1666
VOID NTAPI MmDeletePageFileMapping(struct _EPROCESS *Process, PVOID Address, SWAPENTRY *SwapEntry)
#define MM_SEGMENT_INDELETE
Definition: mm.h:239
VOID NTAPI MmFreeSwapPage(SWAPENTRY Entry)
Definition: pagefile.c:291
VOID NTAPI MmSetSavedSwapEntryPage(PFN_NUMBER Page, SWAPENTRY SavedSwapEntry)
Definition: freelist.c:483
#define PFN_FROM_SSE(E)
Definition: mm.h:1351
#define MEMORY_AREA_SECTION_VIEW
Definition: mm.h:93
SWAPENTRY NTAPI MmGetSavedSwapEntryPage(PFN_NUMBER Page)
Definition: freelist.c:499
NTSTATUS NTAPI MmCreateVirtualMapping(struct _EPROCESS *Process, PVOID Address, ULONG flProtect, PFN_NUMBER Page)
NTSTATUS NTAPI MmCreatePageFileMapping(struct _EPROCESS *Process, PVOID Address, SWAPENTRY SwapEntry)
#define MM_IS_WAIT_PTE(E)
Definition: mm.h:1353
NTSTATUS NTAPI MmReleasePageMemoryConsumer(ULONG Consumer, PFN_NUMBER Page)
Definition: balance.c:73
VOID NTAPI MmSetRmapListHeadPage(PFN_NUMBER Page, struct _MM_RMAP_ENTRY *ListHead)
VOID NTAPI MmDeleteVirtualMapping(IN PEPROCESS Process, IN PVOID Address, OUT PBOOLEAN WasDirty, OUT PPFN_NUMBER Page)
Definition: page.c:177
#define STATUS_PROCESS_IS_TERMINATING
Definition: ntstatus.h:502
NTSTATUS NTAPI ObReferenceObjectByPointer(IN PVOID Object, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode)
Definition: obref.c:381
static WCHAR Address[46]
Definition: ping.c:68
VOID NTAPI KeDetachProcess(VOID)
Definition: procobj.c:621
VOID NTAPI KeAttachProcess(IN PKPROCESS Process)
Definition: procobj.c:582
PEPROCESS PsInitialSystemProcess
Definition: psmgr.c:50
static NPAGED_LOOKASIDE_LIST RmapLookasideList
Definition: rmap.c:21
VOID NTAPI MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process, PVOID Address)
Definition: rmap.c:327
VOID NTAPI MmDeleteRmap(PFN_NUMBER Page, PEPROCESS Process, PVOID Address)
Definition: rmap.c:413
PVOID NTAPI MmGetSegmentRmap(PFN_NUMBER Page, PULONG RawOffset)
Definition: rmap.c:468
VOID NTAPI MmDeleteSectionAssociation(PFN_NUMBER Page)
Definition: rmap.c:505
VOID NTAPI MmInitializeRmapList(VOID)
Definition: rmap.c:38
NTSTATUS NTAPI MmPageOutPhysicalAddress(PFN_NUMBER Page)
Definition: rmap.c:51
VOID NTAPI KeBugCheckEx(_In_ ULONG BugCheckCode, _In_ ULONG_PTR BugCheckParameter1, _In_ ULONG_PTR BugCheckParameter2, _In_ ULONG_PTR BugCheckParameter3, _In_ ULONG_PTR BugCheckParameter4)
Definition: rtlcompat.c:108
ULONG PFN_NUMBER
Definition: ke.h:9
#define STATUS_SUCCESS
Definition: shellext.h:65
PMM_SECTION_SEGMENT NTAPI MmGetSectionAssociation(PFN_NUMBER Page, PLARGE_INTEGER Offset)
Definition: sptab.c:360
base of all file and directory entries
Definition: entries.h:83
struct _MEMORY_AREA::@1776 SectionData
BOOLEAN DeleteInProgress
Definition: mm.h:253
ULONG Type
Definition: mm.h:251
Definition: mm.h:463
Definition: mm.h:266
PVOID Address
Definition: mm.h:269
PEPROCESS Process
Definition: mm.h:268
struct _MM_RMAP_ENTRY * Next
Definition: mm.h:267
#define TAG_RMAP
Definition: tag.h:112
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
_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
_Inout_ PVOID Segment
Definition: exfuncs.h:1101
struct LOOKASIDE_ALIGN _NPAGED_LOOKASIDE_LIST NPAGED_LOOKASIDE_LIST
_In_ ULONG _In_ PHYSICAL_ADDRESS _Inout_ PULONG AddressSpace
Definition: iofuncs.h:2274
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:792
#define ObDereferenceObject
Definition: obfuncs.h:203
#define PsGetCurrentProcess
Definition: psfuncs.h:17