3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: section.c,v 1.166 2004/10/22 20:38:23 ekohl Exp $
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/section.c
23 * PURPOSE: Implements section objects
24 * PROGRAMMER: David Welch (welch@mcmail.com)
29 /* INCLUDES *****************************************************************/
33 #include <internal/debug.h>
35 /* TYPES *********************************************************************/
39 PSECTION_OBJECT Section
;
40 PMM_SECTION_SEGMENT Segment
;
45 MM_SECTION_PAGEOUT_CONTEXT
;
47 /* GLOBALS *******************************************************************/
49 POBJECT_TYPE EXPORTED MmSectionObjectType
= NULL
;
51 static GENERIC_MAPPING MmpSectionMapping
= {
52 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
53 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
54 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
57 #define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S')
58 #define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T')
60 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
61 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
62 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
63 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
64 #define MAX_SHARE_COUNT 0x7FF
65 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
66 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
67 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
69 /* FUNCTIONS *****************************************************************/
71 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
74 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
75 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
76 * RETURNS: Status of the wait.
79 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
81 LARGE_INTEGER Timeout
;
82 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
84 Timeout
.QuadPart
= -100000000LL; // 10 sec
87 Timeout
.QuadPart
= -100000000; // 10 sec
90 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
95 * FUNCTION: Sets the page op completion event and releases the page op.
96 * ARGUMENTS: PMM_PAGEOP.
97 * RETURNS: In shorter time than it takes you to even read this
98 * description, so don't even think about geting a mug of coffee.
101 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
103 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
104 MmReleasePageOp(PageOp
);
109 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
110 * ARGUMENTS: PFILE_OBJECT to wait for.
111 * RETURNS: Status of the wait.
114 MmspWaitForFileLock(PFILE_OBJECT File
)
116 return KeWaitForSingleObject(&File
->Lock
, 0, KernelMode
, FALSE
, NULL
);
121 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
124 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
126 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
128 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
130 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
137 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
139 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
141 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
142 PMM_SECTION_SEGMENT SectionSegments
;
146 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
147 NrSegments
= ImageSectionObject
->NrSegments
;
148 SectionSegments
= ImageSectionObject
->Segments
;
149 for (i
= 0; i
< NrSegments
; i
++)
151 if (SectionSegments
[i
].ReferenceCount
!= 0)
153 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
154 SectionSegments
[i
].ReferenceCount
);
157 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
159 ExFreePool(ImageSectionObject
);
160 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
162 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
164 PMM_SECTION_SEGMENT Segment
;
166 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
169 if (Segment
->ReferenceCount
!= 0)
171 DPRINT1("Data segment still referenced\n");
174 MmFreePageTablesSectionSegment(Segment
);
176 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
181 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
183 ExAcquireFastMutex(&Segment
->Lock
);
187 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
189 ExReleaseFastMutex(&Segment
->Lock
);
193 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
197 PSECTION_PAGE_TABLE Table
;
198 ULONG DirectoryOffset
;
201 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
203 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
207 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
208 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
212 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
213 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
214 TAG_SECTION_PAGE_TABLE
);
219 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
220 DPRINT("Table %x\n", Table
);
223 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
224 Table
->Entry
[TableOffset
] = Entry
;
229 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
232 PSECTION_PAGE_TABLE Table
;
234 ULONG DirectoryOffset
;
237 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
239 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
241 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
245 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
246 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
247 DPRINT("Table %x\n", Table
);
253 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
254 Entry
= Table
->Entry
[TableOffset
];
259 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
264 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
267 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
270 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
272 DPRINT1("Maximum share count reached\n");
275 if (IS_SWAP_FROM_SSE(Entry
))
279 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
280 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
284 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section
,
285 PMM_SECTION_SEGMENT Segment
,
291 BOOLEAN IsDirectMapped
= FALSE
;
293 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
296 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
299 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
301 DPRINT1("Zero share count for unshare\n");
304 if (IS_SWAP_FROM_SSE(Entry
))
308 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
310 * If we reducing the share count of this entry to zero then set the entry
311 * to zero and tell the cache the page is no longer mapped.
313 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
315 PFILE_OBJECT FileObject
;
317 SWAPENTRY SavedSwapEntry
;
319 BOOLEAN IsImageSection
;
322 FileOffset
= Offset
+ Segment
->FileOffset
;
324 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
326 Page
= PFN_FROM_SSE(Entry
);
327 FileObject
= Section
->FileObject
;
328 if (FileObject
!= NULL
&&
329 !(Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
332 if ((FileOffset
% PAGE_SIZE
) == 0 &&
333 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
336 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
337 IsDirectMapped
= TRUE
;
338 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
339 if (!NT_SUCCESS(Status
))
341 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
347 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
348 if (SavedSwapEntry
== 0)
351 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
352 (Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
)))
356 * Try to page out this page and set the swap entry
357 * within the section segment. There exist no rmap entry
358 * for this page. The pager thread can't page out a
359 * page without a rmap entry.
361 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
365 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
368 MmReleasePageMemoryConsumer(MC_USER
, Page
);
374 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
375 (Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
383 * We hold all locks. Nobody can do something with the current
384 * process and the current segment (also not within an other process).
387 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
388 if (!NT_SUCCESS(Status
))
390 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
394 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
395 MmSetSavedSwapEntryPage(Page
, 0);
397 MmReleasePageMemoryConsumer(MC_USER
, Page
);
401 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
408 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
410 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
413 BOOL
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
416 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
419 PCACHE_SEGMENT CacheSeg
;
420 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
421 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
424 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
432 MiReadPage(PMEMORY_AREA MemoryArea
,
436 * FUNCTION: Read a page for a section backed memory area.
438 * MemoryArea - Memory area to read the page for.
439 * Offset - Offset of the page to read.
440 * Page - Variable that receives a page contains the read data.
447 PCACHE_SEGMENT CacheSeg
;
448 PFILE_OBJECT FileObject
;
452 BOOLEAN IsImageSection
;
455 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
456 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
457 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
458 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
459 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
463 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
466 * If the file system is letting us go directly to the cache and the
467 * memory area was mapped at an offset in the file which is page aligned
468 * then get the related cache segment.
470 if ((FileOffset
% PAGE_SIZE
) == 0 &&
471 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
472 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
476 * Get the related cache segment; we use a lower level interface than
477 * filesystems do because it is safe for us to use an offset with a
478 * alignment less than the file system block size.
480 Status
= CcRosGetCacheSegment(Bcb
,
486 if (!NT_SUCCESS(Status
))
493 * If the cache segment isn't up to date then call the file
494 * system to read in the data.
496 Status
= ReadCacheSegment(CacheSeg
);
497 if (!NT_SUCCESS(Status
))
499 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
504 * Retrieve the page from the cache segment that we actually want.
506 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
507 FileOffset
- BaseOffset
).QuadPart
>> PAGE_SHIFT
;
509 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
514 ULONG CacheSegOffset
;
516 * Allocate a page, this is rather complicated by the possibility
517 * we might have to move other things out of memory
519 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
520 if (!NT_SUCCESS(Status
))
524 Status
= CcRosGetCacheSegment(Bcb
,
530 if (!NT_SUCCESS(Status
))
537 * If the cache segment isn't up to date then call the file
538 * system to read in the data.
540 Status
= ReadCacheSegment(CacheSeg
);
541 if (!NT_SUCCESS(Status
))
543 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
547 PageAddr
= ExAllocatePageWithPhysPage(*Page
);
548 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
549 Length
= RawLength
- SegOffset
;
550 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
552 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
554 else if (CacheSegOffset
>= PAGE_SIZE
)
556 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
560 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
561 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
562 Status
= CcRosGetCacheSegment(Bcb
,
563 FileOffset
+ CacheSegOffset
,
568 if (!NT_SUCCESS(Status
))
570 ExUnmapPage(PageAddr
);
576 * If the cache segment isn't up to date then call the file
577 * system to read in the data.
579 Status
= ReadCacheSegment(CacheSeg
);
580 if (!NT_SUCCESS(Status
))
582 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
583 ExUnmapPage(PageAddr
);
587 if (Length
< PAGE_SIZE
)
589 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
593 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
596 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
597 ExUnmapPage(PageAddr
);
599 return(STATUS_SUCCESS
);
603 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
604 MEMORY_AREA
* MemoryArea
,
612 PSECTION_OBJECT Section
;
613 PMM_SECTION_SEGMENT Segment
;
622 * There is a window between taking the page fault and locking the
623 * address space when another thread could load the page so we check
626 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
630 MmLockPage(MmGetPfnForProcess(AddressSpace
->Process
, Address
));
632 return(STATUS_SUCCESS
);
635 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
636 Offset
= PAddress
- (ULONG
)MemoryArea
->BaseAddress
;
638 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
639 Section
= MemoryArea
->Data
.SectionData
.Section
;
640 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
641 &MemoryArea
->Data
.SectionData
.RegionListHead
,
646 MmLockSectionSegment(Segment
);
649 * Check if this page needs to be mapped COW
651 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
652 (Region
->Protect
== PAGE_READWRITE
||
653 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
655 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
659 Attributes
= Region
->Protect
;
663 * Get or create a page operation descriptor
665 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
668 DPRINT1("MmGetPageOp failed\n");
673 * Check if someone else is already handling this fault, if so wait
676 if (PageOp
->Thread
!= PsGetCurrentThread())
678 MmUnlockSectionSegment(Segment
);
679 MmUnlockAddressSpace(AddressSpace
);
680 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
682 * Check for various strange conditions
684 if (Status
!= STATUS_SUCCESS
)
686 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
689 if (PageOp
->Status
== STATUS_PENDING
)
691 DPRINT1("Woke for page op before completion\n");
694 MmLockAddressSpace(AddressSpace
);
696 * If this wasn't a pagein then restart the operation
698 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
700 MmspCompleteAndReleasePageOp(PageOp
);
701 DPRINT("Address 0x%.8X\n", Address
);
702 return(STATUS_MM_RESTART_OPERATION
);
706 * If the thread handling this fault has failed then we don't retry
708 if (!NT_SUCCESS(PageOp
->Status
))
710 Status
= PageOp
->Status
;
711 MmspCompleteAndReleasePageOp(PageOp
);
712 DPRINT("Address 0x%.8X\n", Address
);
715 MmLockSectionSegment(Segment
);
717 * If the completed fault was for another address space then set the
720 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
722 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
723 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
725 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
728 * The page was a private page in another or in our address space
730 MmUnlockSectionSegment(Segment
);
731 MmspCompleteAndReleasePageOp(PageOp
);
732 return(STATUS_MM_RESTART_OPERATION
);
735 Page
= PFN_FROM_SSE(Entry
);
737 MmSharePageEntrySectionSegment(Segment
, Offset
);
739 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
744 if (!NT_SUCCESS(Status
))
746 DbgPrint("Unable to create virtual mapping\n");
749 MmInsertRmap(Page
, MemoryArea
->Process
, (PVOID
)PAddress
);
755 MmUnlockSectionSegment(Segment
);
756 PageOp
->Status
= STATUS_SUCCESS
;
757 MmspCompleteAndReleasePageOp(PageOp
);
758 DPRINT("Address 0x%.8X\n", Address
);
759 return(STATUS_SUCCESS
);
762 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
766 * Must be private page we have swapped out.
773 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
775 DPRINT1("Found a swaped out private page in a pagefile section.\n");
779 MmUnlockSectionSegment(Segment
);
780 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
782 MmUnlockAddressSpace(AddressSpace
);
783 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
784 if (!NT_SUCCESS(Status
))
789 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
790 if (!NT_SUCCESS(Status
))
792 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
795 MmLockAddressSpace(AddressSpace
);
796 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
801 if (!NT_SUCCESS(Status
))
803 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
809 * Store the swap entry for later use.
811 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
814 * Add the page to the process's working set
816 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
819 * Finish the operation
825 PageOp
->Status
= STATUS_SUCCESS
;
826 MmspCompleteAndReleasePageOp(PageOp
);
827 DPRINT("Address 0x%.8X\n", Address
);
828 return(STATUS_SUCCESS
);
832 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
834 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
836 MmUnlockSectionSegment(Segment
);
838 * Just map the desired physical page
840 Page
= (Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
) >> PAGE_SHIFT
;
841 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
846 if (!NT_SUCCESS(Status
))
848 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
853 * Don't add an rmap entry since the page mapped could be for
862 * Cleanup and release locks
864 PageOp
->Status
= STATUS_SUCCESS
;
865 MmspCompleteAndReleasePageOp(PageOp
);
866 DPRINT("Address 0x%.8X\n", Address
);
867 return(STATUS_SUCCESS
);
871 * Map anonymous memory for BSS sections
873 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
)
875 MmUnlockSectionSegment(Segment
);
876 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
877 if (!NT_SUCCESS(Status
))
879 MmUnlockAddressSpace(AddressSpace
);
880 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
881 MmLockAddressSpace(AddressSpace
);
883 if (!NT_SUCCESS(Status
))
887 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
892 if (!NT_SUCCESS(Status
))
894 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
898 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
905 * Cleanup and release locks
907 PageOp
->Status
= STATUS_SUCCESS
;
908 MmspCompleteAndReleasePageOp(PageOp
);
909 DPRINT("Address 0x%.8X\n", Address
);
910 return(STATUS_SUCCESS
);
914 * Get the entry corresponding to the offset within the section
916 Offset
+= MemoryArea
->Data
.SectionData
.ViewOffset
;
917 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
922 * If the entry is zero (and it can't change because we have
923 * locked the segment) then we need to load the page.
927 * Release all our locks and read in the page from disk
929 MmUnlockSectionSegment(Segment
);
930 MmUnlockAddressSpace(AddressSpace
);
932 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
933 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
935 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
936 if (!NT_SUCCESS(Status
))
938 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
943 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
944 if (!NT_SUCCESS(Status
))
946 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
949 if (!NT_SUCCESS(Status
))
952 * FIXME: What do we know in this case?
955 * Cleanup and release locks
957 MmLockAddressSpace(AddressSpace
);
958 PageOp
->Status
= Status
;
959 MmspCompleteAndReleasePageOp(PageOp
);
960 DPRINT("Address 0x%.8X\n", Address
);
964 * Relock the address space and segment
966 MmLockAddressSpace(AddressSpace
);
967 MmLockSectionSegment(Segment
);
970 * Check the entry. No one should change the status of a page
971 * that has a pending page-in.
973 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
976 DbgPrint("Someone changed ppte entry while we slept\n");
981 * Mark the offset within the section as having valid, in-memory
984 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
985 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
986 MmUnlockSectionSegment(Segment
);
988 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
993 if (!NT_SUCCESS(Status
))
995 DbgPrint("Unable to create virtual mapping\n");
998 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1004 PageOp
->Status
= STATUS_SUCCESS
;
1005 MmspCompleteAndReleasePageOp(PageOp
);
1006 DPRINT("Address 0x%.8X\n", Address
);
1007 return(STATUS_SUCCESS
);
1009 else if (IS_SWAP_FROM_SSE(Entry
))
1011 SWAPENTRY SwapEntry
;
1013 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1016 * Release all our locks and read in the page from disk
1018 MmUnlockSectionSegment(Segment
);
1020 MmUnlockAddressSpace(AddressSpace
);
1022 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1023 if (!NT_SUCCESS(Status
))
1028 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1029 if (!NT_SUCCESS(Status
))
1035 * Relock the address space and segment
1037 MmLockAddressSpace(AddressSpace
);
1038 MmLockSectionSegment(Segment
);
1041 * Check the entry. No one should change the status of a page
1042 * that has a pending page-in.
1044 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1045 if (Entry
!= Entry1
)
1047 DbgPrint("Someone changed ppte entry while we slept\n");
1052 * Mark the offset within the section as having valid, in-memory
1055 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1056 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1057 MmUnlockSectionSegment(Segment
);
1060 * Save the swap entry.
1062 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1063 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1068 if (!NT_SUCCESS(Status
))
1070 DbgPrint("Unable to create virtual mapping\n");
1073 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1078 PageOp
->Status
= STATUS_SUCCESS
;
1079 MmspCompleteAndReleasePageOp(PageOp
);
1080 DPRINT("Address 0x%.8X\n", Address
);
1081 return(STATUS_SUCCESS
);
1086 * If the section offset is already in-memory and valid then just
1087 * take another reference to the page
1090 Page
= PFN_FROM_SSE(Entry
);
1092 MmSharePageEntrySectionSegment(Segment
, Offset
);
1093 MmUnlockSectionSegment(Segment
);
1095 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1100 if (!NT_SUCCESS(Status
))
1102 DbgPrint("Unable to create virtual mapping\n");
1105 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1110 PageOp
->Status
= STATUS_SUCCESS
;
1111 MmspCompleteAndReleasePageOp(PageOp
);
1112 DPRINT("Address 0x%.8X\n", Address
);
1113 return(STATUS_SUCCESS
);
1118 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1119 MEMORY_AREA
* MemoryArea
,
1123 PMM_SECTION_SEGMENT Segment
;
1124 PSECTION_OBJECT Section
;
1136 * Check if the page has been paged out or has already been set readwrite
1138 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1139 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1141 DPRINT("Address 0x%.8X\n", Address
);
1142 return(STATUS_SUCCESS
);
1146 * Find the offset of the page
1148 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
1149 Offset
= PAddress
- (ULONG
)MemoryArea
->BaseAddress
;
1151 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1152 Section
= MemoryArea
->Data
.SectionData
.Section
;
1153 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1154 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1159 MmLockSectionSegment(Segment
);
1161 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1162 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1164 MmUnlockSectionSegment(Segment
);
1167 * Check if we are doing COW
1169 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1170 (Region
->Protect
== PAGE_READWRITE
||
1171 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1173 DPRINT("Address 0x%.8X\n", Address
);
1174 return(STATUS_UNSUCCESSFUL
);
1177 if (IS_SWAP_FROM_SSE(Entry
) ||
1178 PFN_FROM_SSE(Entry
) != OldPage
)
1180 /* This is a private page. We must only change the page protection. */
1181 MmSetPageProtect(AddressSpace
->Process
, (PVOID
)PAddress
, Region
->Protect
);
1182 return(STATUS_SUCCESS
);
1186 * Get or create a pageop
1188 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
,
1189 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1192 DPRINT1("MmGetPageOp failed\n");
1197 * Wait for any other operations to complete
1199 if (PageOp
->Thread
!= PsGetCurrentThread())
1201 MmUnlockAddressSpace(AddressSpace
);
1202 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1204 * Check for various strange conditions
1206 if (Status
== STATUS_TIMEOUT
)
1208 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1211 if (PageOp
->Status
== STATUS_PENDING
)
1213 DPRINT1("Woke for page op before completion\n");
1217 * Restart the operation
1219 MmLockAddressSpace(AddressSpace
);
1220 MmspCompleteAndReleasePageOp(PageOp
);
1221 DPRINT("Address 0x%.8X\n", Address
);
1222 return(STATUS_MM_RESTART_OPERATION
);
1226 * Release locks now we have the pageop
1228 MmUnlockAddressSpace(AddressSpace
);
1233 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1234 if (!NT_SUCCESS(Status
))
1243 NewAddress
= ExAllocatePageWithPhysPage(NewPage
);
1244 memcpy(NewAddress
, (PVOID
)PAddress
, PAGE_SIZE
);
1245 ExUnmapPage(NewAddress
);
1248 * Delete the old entry.
1250 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1253 * Set the PTE to point to the new page
1255 MmLockAddressSpace(AddressSpace
);
1256 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1261 if (!NT_SUCCESS(Status
))
1263 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1267 MmInsertRmap(NewPage
, AddressSpace
->Process
, (PVOID
)PAddress
);
1268 if (!NT_SUCCESS(Status
))
1270 DbgPrint("Unable to create virtual mapping\n");
1275 MmLockPage(NewPage
);
1276 MmUnlockPage(OldPage
);
1280 * Unshare the old page.
1282 MmDeleteRmap(OldPage
, AddressSpace
->Process
, (PVOID
)PAddress
);
1283 MmLockSectionSegment(Segment
);
1284 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1285 MmUnlockSectionSegment(Segment
);
1287 PageOp
->Status
= STATUS_SUCCESS
;
1288 MmspCompleteAndReleasePageOp(PageOp
);
1289 DPRINT("Address 0x%.8X\n", Address
);
1290 return(STATUS_SUCCESS
);
1294 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1296 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1300 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1301 MmDeleteVirtualMapping(Process
,
1308 PageOutContext
->WasDirty
= TRUE
;
1310 if (!PageOutContext
->Private
)
1312 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1313 PageOutContext
->Segment
,
1314 PageOutContext
->Offset
,
1315 PageOutContext
->WasDirty
,
1320 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1323 DPRINT("PhysicalAddress %I64x, Address %x\n", Page
, Address
);
1327 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1328 MEMORY_AREA
* MemoryArea
,
1333 MM_SECTION_PAGEOUT_CONTEXT Context
;
1334 SWAPENTRY SwapEntry
;
1338 PFILE_OBJECT FileObject
;
1340 BOOLEAN DirectMapped
;
1341 BOOLEAN IsImageSection
;
1343 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1346 * Get the segment and section.
1348 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1349 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1351 Context
.Offset
= (ULONG
)((char*)Address
- (ULONG
)MemoryArea
->BaseAddress
);
1352 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1354 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1356 FileObject
= Context
.Section
->FileObject
;
1357 DirectMapped
= FALSE
;
1358 if (FileObject
!= NULL
&&
1359 !(Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
1361 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1364 * If the file system is letting us go directly to the cache and the
1365 * memory area was mapped at an offset in the file which is page aligned
1366 * then note this is a direct mapped page.
1368 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1369 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1371 DirectMapped
= TRUE
;
1377 * This should never happen since mappings of physical memory are never
1378 * placed in the rmap lists.
1380 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1382 DPRINT1("Trying to page out from physical memory section address 0x%X "
1383 "process %d\n", Address
,
1384 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1389 * Get the section segment entry and the physical address.
1391 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1392 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1394 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1395 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1398 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1399 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1402 * Prepare the context structure for the rmap delete call.
1404 Context
.WasDirty
= FALSE
;
1405 if (Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1406 IS_SWAP_FROM_SSE(Entry
) ||
1407 PFN_FROM_SSE(Entry
) != Page
)
1409 Context
.Private
= TRUE
;
1413 Context
.Private
= FALSE
;
1417 * Take an additional reference to the page or the cache segment.
1419 if (DirectMapped
&& !Context
.Private
)
1421 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1423 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1429 MmReferencePage(Page
);
1432 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1435 * If this wasn't a private page then we should have reduced the entry to
1436 * zero by deleting all the rmaps.
1438 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1440 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1441 !(Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
1448 * If the page wasn't dirty then we can just free it as for a readonly page.
1449 * Since we unmapped all the mappings above we know it will not suddenly
1451 * If the page is from a pagefile section and has no swap entry,
1452 * we can't free the page at this point.
1454 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1455 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1457 if (Context
.Private
)
1459 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1460 Context
.WasDirty
? "dirty" : "clean", Address
);
1463 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1465 MmSetSavedSwapEntryPage(Page
, 0);
1466 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1467 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1468 PageOp
->Status
= STATUS_SUCCESS
;
1469 MmspCompleteAndReleasePageOp(PageOp
);
1470 return(STATUS_SUCCESS
);
1473 else if (Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
)
1475 if (Context
.Private
)
1477 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1478 Context
.WasDirty
? "dirty" : "clean", Address
);
1481 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1483 MmSetSavedSwapEntryPage(Page
, 0);
1486 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1488 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1489 PageOp
->Status
= STATUS_SUCCESS
;
1490 MmspCompleteAndReleasePageOp(PageOp
);
1491 return(STATUS_SUCCESS
);
1494 else if (!Context
.Private
&& DirectMapped
)
1498 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1502 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1503 if (!NT_SUCCESS(Status
))
1505 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1508 PageOp
->Status
= STATUS_SUCCESS
;
1509 MmspCompleteAndReleasePageOp(PageOp
);
1510 return(STATUS_SUCCESS
);
1512 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1516 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1520 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1521 PageOp
->Status
= STATUS_SUCCESS
;
1522 MmspCompleteAndReleasePageOp(PageOp
);
1523 return(STATUS_SUCCESS
);
1525 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1527 MmSetSavedSwapEntryPage(Page
, 0);
1528 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1531 if (!NT_SUCCESS(Status
))
1535 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1536 PageOp
->Status
= STATUS_SUCCESS
;
1537 MmspCompleteAndReleasePageOp(PageOp
);
1538 return(STATUS_SUCCESS
);
1542 * If necessary, allocate an entry in the paging file for this page
1546 SwapEntry
= MmAllocSwapPage();
1549 MmShowOutOfSpaceMessagePagingFile();
1552 * For private pages restore the old mappings.
1554 if (Context
.Private
)
1556 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1558 MemoryArea
->Attributes
,
1561 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1563 MemoryArea
->Process
,
1569 * For non-private pages if the page wasn't direct mapped then
1570 * set it back into the section segment entry so we don't loose
1571 * our copy. Otherwise it will be handled by the cache manager.
1573 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1575 MemoryArea
->Attributes
,
1578 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1580 MemoryArea
->Process
,
1582 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1583 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1585 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1586 MmspCompleteAndReleasePageOp(PageOp
);
1587 return(STATUS_PAGEFILE_QUOTA
);
1592 * Write the page to the pagefile
1594 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1595 if (!NT_SUCCESS(Status
))
1597 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1600 * As above: undo our actions.
1601 * FIXME: Also free the swap page.
1603 if (Context
.Private
)
1605 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1607 MemoryArea
->Attributes
,
1610 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1612 MemoryArea
->Process
,
1617 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1619 MemoryArea
->Attributes
,
1622 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1624 MemoryArea
->Process
,
1626 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1627 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1629 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1630 MmspCompleteAndReleasePageOp(PageOp
);
1631 return(STATUS_UNSUCCESSFUL
);
1635 * Otherwise we have succeeded.
1637 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1638 MmSetSavedSwapEntryPage(Page
, 0);
1639 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1640 Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
)
1642 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1646 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1649 if (Context
.Private
)
1651 Status
= MmCreatePageFileMapping(MemoryArea
->Process
,
1654 if (!NT_SUCCESS(Status
))
1661 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1662 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1665 PageOp
->Status
= STATUS_SUCCESS
;
1666 MmspCompleteAndReleasePageOp(PageOp
);
1667 return(STATUS_SUCCESS
);
1671 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1672 PMEMORY_AREA MemoryArea
,
1677 PSECTION_OBJECT Section
;
1678 PMM_SECTION_SEGMENT Segment
;
1680 SWAPENTRY SwapEntry
;
1684 PFILE_OBJECT FileObject
;
1686 BOOLEAN DirectMapped
;
1687 BOOLEAN IsImageSection
;
1689 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1691 Offset
= (ULONG
)((char*)Address
- (ULONG
)MemoryArea
->BaseAddress
);
1694 * Get the segment and section.
1696 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1697 Section
= MemoryArea
->Data
.SectionData
.Section
;
1698 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1700 FileObject
= Section
->FileObject
;
1701 DirectMapped
= FALSE
;
1702 if (FileObject
!= NULL
&&
1703 !(Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
1705 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1708 * If the file system is letting us go directly to the cache and the
1709 * memory area was mapped at an offset in the file which is page aligned
1710 * then note this is a direct mapped page.
1712 if ((Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
% PAGE_SIZE
) == 0 &&
1713 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1715 DirectMapped
= TRUE
;
1720 * This should never happen since mappings of physical memory are never
1721 * placed in the rmap lists.
1723 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1725 DPRINT1("Trying to write back page from physical memory mapped at %X "
1726 "process %d\n", Address
,
1727 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1732 * Get the section segment entry and the physical address.
1734 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1735 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1737 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1738 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1741 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1742 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1745 * Check for a private (COWed) page.
1747 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1748 IS_SWAP_FROM_SSE(Entry
) ||
1749 PFN_FROM_SSE(Entry
) != Page
)
1759 * Speculatively set all mappings of the page to clean.
1761 MmSetCleanAllRmaps(Page
);
1764 * If this page was direct mapped from the cache then the cache manager
1765 * will take care of writing it back to disk.
1767 if (DirectMapped
&& !Private
)
1769 ASSERT(SwapEntry
== 0);
1770 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
1771 PageOp
->Status
= STATUS_SUCCESS
;
1772 MmspCompleteAndReleasePageOp(PageOp
);
1773 return(STATUS_SUCCESS
);
1777 * If necessary, allocate an entry in the paging file for this page
1781 SwapEntry
= MmAllocSwapPage();
1784 MmSetDirtyAllRmaps(Page
);
1785 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1786 MmspCompleteAndReleasePageOp(PageOp
);
1787 return(STATUS_PAGEFILE_QUOTA
);
1789 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1793 * Write the page to the pagefile
1795 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1796 if (!NT_SUCCESS(Status
))
1798 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1800 MmSetDirtyAllRmaps(Page
);
1801 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1802 MmspCompleteAndReleasePageOp(PageOp
);
1803 return(STATUS_UNSUCCESSFUL
);
1807 * Otherwise we have succeeded.
1809 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1810 PageOp
->Status
= STATUS_SUCCESS
;
1811 MmspCompleteAndReleasePageOp(PageOp
);
1812 return(STATUS_SUCCESS
);
1816 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1824 PMEMORY_AREA MemoryArea
;
1825 PMM_SECTION_SEGMENT Segment
;
1829 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1830 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1832 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1833 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1838 if (OldProtect
!= NewProtect
)
1840 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1842 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1843 ULONG Protect
= NewProtect
;
1846 * If we doing COW for this segment then check if the page is
1849 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1855 Offset
= (ULONG
)Address
- (ULONG
)MemoryArea
->BaseAddress
;
1856 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1857 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1859 Protect
= PAGE_READONLY
;
1860 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1861 IS_SWAP_FROM_SSE(Entry
) ||
1862 PFN_FROM_SSE(Entry
) != Page
)
1864 Protect
= NewProtect
;
1868 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1870 MmSetPageProtect(AddressSpace
->Process
, Address
,
1878 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1879 PMEMORY_AREA MemoryArea
,
1889 min(Length
, (ULONG
) ((char*)MemoryArea
->BaseAddress
+ MemoryArea
->Length
- (char*)BaseAddress
));
1890 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1891 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1893 *OldProtect
= Region
->Protect
;
1894 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->BaseAddress
,
1895 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1896 BaseAddress
, Length
, Region
->Type
, Protect
,
1897 MmAlterViewAttributes
);
1903 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
1905 PMEMORY_BASIC_INFORMATION Info
,
1906 PULONG ResultLength
)
1909 PVOID RegionBaseAddress
;
1910 PSECTION_OBJECT Section
;
1911 PLIST_ENTRY CurrentEntry
;
1912 PMEMORY_AREA CurrentMArea
;
1915 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1916 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1917 Address
, &RegionBaseAddress
);
1920 return STATUS_UNSUCCESSFUL
;
1922 Section
= MemoryArea
->Data
.SectionData
.Section
;
1923 if (Section
->AllocationAttributes
& SEC_IMAGE
)
1925 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
1926 CurrentEntry
= Section
->ViewListHead
.Flink
;
1927 Info
->AllocationBase
= NULL
;
1928 while (CurrentEntry
!= &Section
->ViewListHead
)
1930 CurrentMArea
= CONTAINING_RECORD(CurrentEntry
, MEMORY_AREA
, Data
.SectionData
.ViewListEntry
);
1931 CurrentEntry
= CurrentEntry
->Flink
;
1932 if (Info
->AllocationBase
== NULL
)
1934 Info
->AllocationBase
= CurrentMArea
->BaseAddress
;
1936 else if (CurrentMArea
->BaseAddress
< Info
->AllocationBase
)
1938 Info
->AllocationBase
= CurrentMArea
->BaseAddress
;
1941 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
1942 Info
->BaseAddress
= RegionBaseAddress
;
1943 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1944 Info
->Type
= MEM_IMAGE
;
1948 Info
->BaseAddress
= RegionBaseAddress
;
1949 Info
->AllocationBase
= MemoryArea
->BaseAddress
;
1950 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1951 Info
->Type
= MEM_MAPPED
;
1953 Info
->RegionSize
= PAGE_ROUND_UP(MemoryArea
->Length
);
1954 Info
->State
= MEM_COMMIT
;
1955 Info
->Protect
= Region
->Protect
;
1957 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
1958 return(STATUS_SUCCESS
);
1962 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
1967 ULONG SavedSwapEntry
;
1972 Length
= PAGE_ROUND_UP(Segment
->Length
);
1973 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
1975 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1978 if (IS_SWAP_FROM_SSE(Entry
))
1980 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
1984 Page
= PFN_FROM_SSE(Entry
);
1985 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
1986 if (SavedSwapEntry
!= 0)
1988 MmSetSavedSwapEntryPage(Page
, 0);
1989 MmFreeSwapPage(SavedSwapEntry
);
1991 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1993 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
1999 MmpDeleteSection(PVOID ObjectBody
)
2001 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
2003 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2004 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2009 PMM_SECTION_SEGMENT SectionSegments
;
2012 * NOTE: Section->ImageSection can be NULL for short time
2013 * during the section creating. If we fail for some reason
2014 * until the image section is properly initialized we shouldn't
2015 * process further here.
2017 if (Section
->ImageSection
== NULL
)
2020 SectionSegments
= Section
->ImageSection
->Segments
;
2021 NrSegments
= Section
->ImageSection
->NrSegments
;
2023 for (i
= 0; i
< NrSegments
; i
++)
2025 if (SectionSegments
[i
].Characteristics
& IMAGE_SECTION_CHAR_SHARED
)
2027 MmLockSectionSegment(&SectionSegments
[i
]);
2029 RefCount
= InterlockedDecrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2030 if (SectionSegments
[i
].Characteristics
& IMAGE_SECTION_CHAR_SHARED
)
2034 MmpFreePageFileSegment(&SectionSegments
[i
]);
2036 MmUnlockSectionSegment(&SectionSegments
[i
]);
2043 * NOTE: Section->Segment can be NULL for short time
2044 * during the section creating.
2046 if (Section
->Segment
== NULL
)
2049 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2051 MmpFreePageFileSegment(Section
->Segment
);
2052 MmFreePageTablesSectionSegment(Section
->Segment
);
2053 ExFreePool(Section
->Segment
);
2054 Section
->Segment
= NULL
;
2058 InterlockedDecrement((LONG
*)&Section
->Segment
->ReferenceCount
);
2061 if (Section
->FileObject
!= NULL
)
2063 CcRosDereferenceCache(Section
->FileObject
);
2064 ObDereferenceObject(Section
->FileObject
);
2065 Section
->FileObject
= NULL
;
2070 MmpCloseSection(PVOID ObjectBody
,
2073 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2074 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2078 MmpCreateSection(PVOID ObjectBody
,
2080 PWSTR RemainingPath
,
2081 POBJECT_ATTRIBUTES ObjectAttributes
)
2083 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2084 ObjectBody
, Parent
, RemainingPath
);
2086 if (RemainingPath
== NULL
)
2088 return(STATUS_SUCCESS
);
2091 if (wcschr(RemainingPath
+1, L
'\\') != NULL
)
2093 return(STATUS_UNSUCCESSFUL
);
2095 return(STATUS_SUCCESS
);
2098 NTSTATUS INIT_FUNCTION
2099 MmCreatePhysicalMemorySection(VOID
)
2101 PSECTION_OBJECT PhysSection
;
2103 OBJECT_ATTRIBUTES Obj
;
2104 UNICODE_STRING Name
= ROS_STRING_INITIALIZER(L
"\\Device\\PhysicalMemory");
2105 LARGE_INTEGER SectionSize
;
2108 * Create the section mapping physical memory
2110 SectionSize
.QuadPart
= 0xFFFFFFFF;
2111 InitializeObjectAttributes(&Obj
,
2116 Status
= MmCreateSection(&PhysSection
,
2120 PAGE_EXECUTE_READWRITE
,
2124 if (!NT_SUCCESS(Status
))
2126 DbgPrint("Failed to create PhysicalMemory section\n");
2129 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2131 return(STATUS_SUCCESS
);
2134 NTSTATUS INIT_FUNCTION
2135 MmInitSectionImplementation(VOID
)
2137 MmSectionObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
2139 RtlRosInitUnicodeStringFromLiteral(&MmSectionObjectType
->TypeName
, L
"Section");
2141 MmSectionObjectType
->Tag
= TAG('S', 'E', 'C', 'T');
2142 MmSectionObjectType
->TotalObjects
= 0;
2143 MmSectionObjectType
->TotalHandles
= 0;
2144 MmSectionObjectType
->MaxObjects
= ULONG_MAX
;
2145 MmSectionObjectType
->MaxHandles
= ULONG_MAX
;
2146 MmSectionObjectType
->PagedPoolCharge
= 0;
2147 MmSectionObjectType
->NonpagedPoolCharge
= sizeof(SECTION_OBJECT
);
2148 MmSectionObjectType
->Mapping
= &MmpSectionMapping
;
2149 MmSectionObjectType
->Dump
= NULL
;
2150 MmSectionObjectType
->Open
= NULL
;
2151 MmSectionObjectType
->Close
= MmpCloseSection
;
2152 MmSectionObjectType
->Delete
= MmpDeleteSection
;
2153 MmSectionObjectType
->Parse
= NULL
;
2154 MmSectionObjectType
->Security
= NULL
;
2155 MmSectionObjectType
->QueryName
= NULL
;
2156 MmSectionObjectType
->OkayToClose
= NULL
;
2157 MmSectionObjectType
->Create
= MmpCreateSection
;
2158 MmSectionObjectType
->DuplicationNotify
= NULL
;
2161 * NOTE: Do not register the section object type here because
2162 * the object manager it not initialized yet!
2163 * The section object type will be created in ObInit().
2165 ObpCreateTypeObject(MmSectionObjectType
);
2167 return(STATUS_SUCCESS
);
2171 MmCreatePageFileSection(PSECTION_OBJECT
*SectionObject
,
2172 ACCESS_MASK DesiredAccess
,
2173 POBJECT_ATTRIBUTES ObjectAttributes
,
2174 PLARGE_INTEGER UMaximumSize
,
2175 ULONG SectionPageProtection
,
2176 ULONG AllocationAttributes
)
2178 * Create a section which is backed by the pagefile
2181 LARGE_INTEGER MaximumSize
;
2182 PSECTION_OBJECT Section
;
2183 PMM_SECTION_SEGMENT Segment
;
2186 if (UMaximumSize
== NULL
)
2188 return(STATUS_UNSUCCESSFUL
);
2190 MaximumSize
= *UMaximumSize
;
2193 * Create the section
2195 Status
= ObCreateObject(ExGetPreviousMode(),
2196 MmSectionObjectType
,
2198 ExGetPreviousMode(),
2200 sizeof(SECTION_OBJECT
),
2203 (PVOID
*)(PVOID
)&Section
);
2204 if (!NT_SUCCESS(Status
))
2212 Section
->SectionPageProtection
= SectionPageProtection
;
2213 Section
->AllocationAttributes
= AllocationAttributes
;
2214 Section
->Segment
= NULL
;
2215 InitializeListHead(&Section
->ViewListHead
);
2216 KeInitializeSpinLock(&Section
->ViewListLock
);
2217 Section
->FileObject
= NULL
;
2218 Section
->MaximumSize
= MaximumSize
;
2219 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2220 TAG_MM_SECTION_SEGMENT
);
2221 if (Segment
== NULL
)
2223 ObDereferenceObject(Section
);
2224 return(STATUS_NO_MEMORY
);
2226 Section
->Segment
= Segment
;
2227 Segment
->ReferenceCount
= 1;
2228 ExInitializeFastMutex(&Segment
->Lock
);
2229 Segment
->FileOffset
= 0;
2230 Segment
->Protection
= SectionPageProtection
;
2231 Segment
->Attributes
= AllocationAttributes
;
2232 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2233 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2234 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2235 Segment
->WriteCopy
= FALSE
;
2236 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2237 Segment
->VirtualAddress
= 0;
2238 Segment
->Characteristics
= 0;
2239 *SectionObject
= Section
;
2240 return(STATUS_SUCCESS
);
2245 MmCreateDataFileSection(PSECTION_OBJECT
*SectionObject
,
2246 ACCESS_MASK DesiredAccess
,
2247 POBJECT_ATTRIBUTES ObjectAttributes
,
2248 PLARGE_INTEGER UMaximumSize
,
2249 ULONG SectionPageProtection
,
2250 ULONG AllocationAttributes
,
2253 * Create a section backed by a data file
2256 PSECTION_OBJECT Section
;
2258 LARGE_INTEGER MaximumSize
;
2259 PFILE_OBJECT FileObject
;
2260 PMM_SECTION_SEGMENT Segment
;
2262 IO_STATUS_BLOCK Iosb
;
2263 LARGE_INTEGER Offset
;
2265 FILE_STANDARD_INFORMATION FileInfo
;
2268 * Create the section
2270 Status
= ObCreateObject(ExGetPreviousMode(),
2271 MmSectionObjectType
,
2273 ExGetPreviousMode(),
2275 sizeof(SECTION_OBJECT
),
2278 (PVOID
*)(PVOID
)&Section
);
2279 if (!NT_SUCCESS(Status
))
2287 Section
->SectionPageProtection
= SectionPageProtection
;
2288 Section
->AllocationAttributes
= AllocationAttributes
;
2289 Section
->Segment
= NULL
;
2290 InitializeListHead(&Section
->ViewListHead
);
2291 KeInitializeSpinLock(&Section
->ViewListLock
);
2294 * Check file access required
2296 if (SectionPageProtection
& PAGE_READWRITE
||
2297 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2299 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2303 FileAccess
= FILE_READ_DATA
;
2307 * Reference the file handle
2309 Status
= ObReferenceObjectByHandle(FileHandle
,
2313 (PVOID
*)(PVOID
)&FileObject
,
2315 if (!NT_SUCCESS(Status
))
2317 ObDereferenceObject(Section
);
2322 * FIXME: This is propably not entirely correct. We can't look into
2323 * the standard FCB header because it might not be initialized yet
2324 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2325 * standard file information is filled on first request).
2327 Status
= NtQueryInformationFile(FileHandle
,
2330 sizeof(FILE_STANDARD_INFORMATION
),
2331 FileStandardInformation
);
2332 if (!NT_SUCCESS(Status
))
2334 ObDereferenceObject(Section
);
2335 ObDereferenceObject(FileObject
);
2340 * FIXME: Revise this once a locking order for file size changes is
2343 if (UMaximumSize
!= NULL
)
2345 MaximumSize
= *UMaximumSize
;
2349 MaximumSize
= FileInfo
.EndOfFile
;
2350 /* Mapping zero-sized files isn't allowed. */
2351 if (MaximumSize
.QuadPart
== 0)
2353 ObDereferenceObject(Section
);
2354 ObDereferenceObject(FileObject
);
2355 return STATUS_FILE_INVALID
;
2359 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2361 Status
= NtSetInformationFile(FileHandle
,
2364 sizeof(LARGE_INTEGER
),
2365 FileAllocationInformation
);
2366 if (!NT_SUCCESS(Status
))
2368 ObDereferenceObject(Section
);
2369 ObDereferenceObject(FileObject
);
2370 return(STATUS_SECTION_NOT_EXTENDED
);
2374 if (FileObject
->SectionObjectPointer
== NULL
||
2375 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2378 * Read a bit so caching is initiated for the file object.
2379 * This is only needed because MiReadPage currently cannot
2380 * handle non-cached streams.
2382 Offset
.QuadPart
= 0;
2383 Status
= ZwReadFile(FileHandle
,
2392 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2394 ObDereferenceObject(Section
);
2395 ObDereferenceObject(FileObject
);
2398 if (FileObject
->SectionObjectPointer
== NULL
||
2399 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2401 /* FIXME: handle this situation */
2402 ObDereferenceObject(Section
);
2403 ObDereferenceObject(FileObject
);
2404 return STATUS_INVALID_PARAMETER
;
2411 Status
= MmspWaitForFileLock(FileObject
);
2412 if (Status
!= STATUS_SUCCESS
)
2414 ObDereferenceObject(Section
);
2415 ObDereferenceObject(FileObject
);
2420 * If this file hasn't been mapped as a data file before then allocate a
2421 * section segment to describe the data file mapping
2423 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2425 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2426 TAG_MM_SECTION_SEGMENT
);
2427 if (Segment
== NULL
)
2429 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2430 ObDereferenceObject(Section
);
2431 ObDereferenceObject(FileObject
);
2432 return(STATUS_NO_MEMORY
);
2434 Section
->Segment
= Segment
;
2435 Segment
->ReferenceCount
= 1;
2436 ExInitializeFastMutex(&Segment
->Lock
);
2438 * Set the lock before assigning the segment to the file object
2440 ExAcquireFastMutex(&Segment
->Lock
);
2441 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2443 Segment
->FileOffset
= 0;
2444 Segment
->Protection
= SectionPageProtection
;
2445 Segment
->Attributes
= 0;
2446 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2447 Segment
->Characteristics
= 0;
2448 Segment
->WriteCopy
= FALSE
;
2449 if (AllocationAttributes
& SEC_RESERVE
)
2451 Segment
->Length
= Segment
->RawLength
= 0;
2455 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2456 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2458 Segment
->VirtualAddress
= NULL
;
2459 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2464 * If the file is already mapped as a data file then we may need
2468 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2470 Section
->Segment
= Segment
;
2471 InterlockedIncrement((PLONG
)&Segment
->ReferenceCount
);
2472 MmLockSectionSegment(Segment
);
2474 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2475 !(AllocationAttributes
& SEC_RESERVE
))
2477 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2478 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2481 MmUnlockSectionSegment(Segment
);
2482 Section
->FileObject
= FileObject
;
2483 Section
->MaximumSize
= MaximumSize
;
2484 CcRosReferenceCache(FileObject
);
2485 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2486 *SectionObject
= Section
;
2487 return(STATUS_SUCCESS
);
2490 static ULONG SectionCharacteristicsToProtect
[16] =
2492 PAGE_NOACCESS
, // 0 = NONE
2493 PAGE_NOACCESS
, // 1 = SHARED
2494 PAGE_EXECUTE
, // 2 = EXECUTABLE
2495 PAGE_EXECUTE
, // 3 = EXECUTABLE, SHARED
2496 PAGE_READONLY
, // 4 = READABLE
2497 PAGE_READONLY
, // 5 = READABLE, SHARED
2498 PAGE_EXECUTE_READ
, // 6 = READABLE, EXECUTABLE
2499 PAGE_EXECUTE_READ
, // 7 = READABLE, EXECUTABLE, SHARED
2500 PAGE_READWRITE
, // 8 = WRITABLE
2501 PAGE_READWRITE
, // 9 = WRITABLE, SHARED
2502 PAGE_EXECUTE_READWRITE
, // 10 = WRITABLE, EXECUTABLE
2503 PAGE_EXECUTE_READWRITE
, // 11 = WRITABLE, EXECUTABLE, SHARED
2504 PAGE_READWRITE
, // 12 = WRITABLE, READABLE
2505 PAGE_READWRITE
, // 13 = WRITABLE, READABLE, SHARED
2506 PAGE_EXECUTE_READWRITE
, // 14 = WRITABLE, READABLE, EXECUTABLE,
2507 PAGE_EXECUTE_READWRITE
, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
2511 MmCreateImageSection(PSECTION_OBJECT
*SectionObject
,
2512 ACCESS_MASK DesiredAccess
,
2513 POBJECT_ATTRIBUTES ObjectAttributes
,
2514 PLARGE_INTEGER UMaximumSize
,
2515 ULONG SectionPageProtection
,
2516 ULONG AllocationAttributes
,
2519 PSECTION_OBJECT Section
;
2521 PFILE_OBJECT FileObject
;
2522 IMAGE_DOS_HEADER DosHeader
;
2523 IO_STATUS_BLOCK Iosb
;
2524 LARGE_INTEGER Offset
;
2525 IMAGE_NT_HEADERS PEHeader
;
2526 PMM_SECTION_SEGMENT SectionSegments
;
2528 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
2531 ULONG Characteristics
;
2532 ULONG FileAccess
= 0;
2535 * Specifying a maximum size is meaningless for an image section
2537 if (UMaximumSize
!= NULL
)
2539 return(STATUS_INVALID_PARAMETER_4
);
2543 * Reference the file handle
2545 Status
= ObReferenceObjectByHandle(FileHandle
,
2549 (PVOID
*)(PVOID
)&FileObject
,
2551 if (!NT_SUCCESS(Status
))
2557 * Initialized caching for this file object if previously caching
2558 * was initialized for the same on disk file
2560 Status
= CcTryToInitializeFileCache(FileObject
);
2562 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
2564 PIMAGE_SECTION_HEADER ImageSections
;
2566 * Read the dos header and check the DOS signature
2568 Offset
.QuadPart
= 0;
2569 Status
= ZwReadFile(FileHandle
,
2578 if (!NT_SUCCESS(Status
))
2580 ObDereferenceObject(FileObject
);
2585 * Check the DOS signature
2587 if (Iosb
.Information
!= sizeof(DosHeader
) ||
2588 DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
)
2590 ObDereferenceObject(FileObject
);
2591 return(STATUS_INVALID_IMAGE_FORMAT
);
2595 * Read the PE header
2597 Offset
.QuadPart
= DosHeader
.e_lfanew
;
2598 Status
= ZwReadFile(FileHandle
,
2607 if (!NT_SUCCESS(Status
))
2609 ObDereferenceObject(FileObject
);
2614 * Check the signature
2616 if (Iosb
.Information
!= sizeof(PEHeader
) ||
2617 PEHeader
.Signature
!= IMAGE_NT_SIGNATURE
)
2619 ObDereferenceObject(FileObject
);
2620 return(STATUS_INVALID_IMAGE_FORMAT
);
2624 * Read in the section headers
2626 Offset
.QuadPart
= DosHeader
.e_lfanew
+ sizeof(PEHeader
);
2627 ImageSections
= ExAllocatePool(NonPagedPool
,
2628 PEHeader
.FileHeader
.NumberOfSections
*
2629 sizeof(IMAGE_SECTION_HEADER
));
2630 if (ImageSections
== NULL
)
2632 ObDereferenceObject(FileObject
);
2633 return(STATUS_NO_MEMORY
);
2636 Status
= ZwReadFile(FileHandle
,
2642 PEHeader
.FileHeader
.NumberOfSections
*
2643 sizeof(IMAGE_SECTION_HEADER
),
2646 if (!NT_SUCCESS(Status
))
2648 ObDereferenceObject(FileObject
);
2649 ExFreePool(ImageSections
);
2652 if (Iosb
.Information
!= (PEHeader
.FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
)))
2654 ObDereferenceObject(FileObject
);
2655 ExFreePool(ImageSections
);
2656 return(STATUS_INVALID_IMAGE_FORMAT
);
2660 * Create the section
2662 Status
= ObCreateObject (ExGetPreviousMode(),
2663 MmSectionObjectType
,
2665 ExGetPreviousMode(),
2667 sizeof(SECTION_OBJECT
),
2670 (PVOID
*)(PVOID
)&Section
);
2671 if (!NT_SUCCESS(Status
))
2673 ObDereferenceObject(FileObject
);
2674 ExFreePool(ImageSections
);
2681 Section
->SectionPageProtection
= SectionPageProtection
;
2682 Section
->AllocationAttributes
= AllocationAttributes
;
2683 Section
->ImageSection
= NULL
;
2684 InitializeListHead(&Section
->ViewListHead
);
2685 KeInitializeSpinLock(&Section
->ViewListLock
);
2688 * Check file access required
2690 if (SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
2692 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2696 FileAccess
= FILE_READ_DATA
;
2702 Status
= MmspWaitForFileLock(FileObject
);
2703 if (Status
!= STATUS_SUCCESS
)
2705 ObDereferenceObject(Section
);
2706 ObDereferenceObject(FileObject
);
2707 ExFreePool(ImageSections
);
2712 * allocate the section segments to describe the mapping
2714 NrSegments
= PEHeader
.FileHeader
.NumberOfSections
+ 1;
2715 Size
= sizeof(MM_IMAGE_SECTION_OBJECT
) + sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2716 ImageSectionObject
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_MM_SECTION_SEGMENT
);
2717 if (ImageSectionObject
== NULL
)
2719 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2720 ObDereferenceObject(Section
);
2721 ObDereferenceObject(FileObject
);
2722 ExFreePool(ImageSections
);
2723 return(STATUS_NO_MEMORY
);
2725 Section
->ImageSection
= ImageSectionObject
;
2726 ImageSectionObject
->NrSegments
= NrSegments
;
2727 ImageSectionObject
->ImageBase
= (PVOID
)PEHeader
.OptionalHeader
.ImageBase
;
2728 ImageSectionObject
->EntryPoint
= (PVOID
)PEHeader
.OptionalHeader
.AddressOfEntryPoint
;
2729 ImageSectionObject
->StackReserve
= PEHeader
.OptionalHeader
.SizeOfStackReserve
;
2730 ImageSectionObject
->StackCommit
= PEHeader
.OptionalHeader
.SizeOfStackCommit
;
2731 ImageSectionObject
->Subsystem
= PEHeader
.OptionalHeader
.Subsystem
;
2732 ImageSectionObject
->MinorSubsystemVersion
= PEHeader
.OptionalHeader
.MinorSubsystemVersion
;
2733 ImageSectionObject
->MajorSubsystemVersion
= PEHeader
.OptionalHeader
.MajorSubsystemVersion
;
2734 ImageSectionObject
->ImageCharacteristics
= PEHeader
.FileHeader
.Characteristics
;
2735 ImageSectionObject
->Machine
= PEHeader
.FileHeader
.Machine
;
2736 ImageSectionObject
->Executable
= (PEHeader
.OptionalHeader
.SizeOfCode
!= 0);
2738 SectionSegments
= ImageSectionObject
->Segments
;
2739 SectionSegments
[0].FileOffset
= 0;
2740 SectionSegments
[0].Characteristics
= IMAGE_SECTION_CHAR_DATA
;
2741 SectionSegments
[0].Protection
= PAGE_READONLY
;
2742 SectionSegments
[0].RawLength
= PAGE_SIZE
;
2743 SectionSegments
[0].Length
= PAGE_SIZE
;
2744 SectionSegments
[0].Flags
= 0;
2745 SectionSegments
[0].ReferenceCount
= 1;
2746 SectionSegments
[0].VirtualAddress
= 0;
2747 SectionSegments
[0].WriteCopy
= TRUE
;
2748 SectionSegments
[0].Attributes
= 0;
2749 ExInitializeFastMutex(&SectionSegments
[0].Lock
);
2750 RtlZeroMemory(&SectionSegments
[0].PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2751 for (i
= 1; i
< NrSegments
; i
++)
2753 SectionSegments
[i
].FileOffset
= ImageSections
[i
-1].PointerToRawData
;
2754 SectionSegments
[i
].Characteristics
= ImageSections
[i
-1].Characteristics
;
2757 * Set up the protection and write copy variables.
2759 Characteristics
= ImageSections
[i
- 1].Characteristics
;
2760 if (Characteristics
& (IMAGE_SECTION_CHAR_READABLE
|IMAGE_SECTION_CHAR_WRITABLE
|IMAGE_SECTION_CHAR_EXECUTABLE
))
2762 SectionSegments
[i
].Protection
= SectionCharacteristicsToProtect
[Characteristics
>> 28];
2763 SectionSegments
[i
].WriteCopy
= !(Characteristics
& IMAGE_SECTION_CHAR_SHARED
);
2765 else if (Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2767 SectionSegments
[i
].Protection
= PAGE_EXECUTE_READ
;
2768 SectionSegments
[i
].WriteCopy
= TRUE
;
2770 else if (Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2772 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2773 SectionSegments
[i
].WriteCopy
= TRUE
;
2775 else if (Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2777 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2778 SectionSegments
[i
].WriteCopy
= TRUE
;
2782 SectionSegments
[i
].Protection
= PAGE_NOACCESS
;
2783 SectionSegments
[i
].WriteCopy
= TRUE
;
2787 * Set up the attributes.
2789 if (Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2791 SectionSegments
[i
].Attributes
= 0;
2793 else if (Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2795 SectionSegments
[i
].Attributes
= 0;
2797 else if (Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2799 SectionSegments
[i
].Attributes
= MM_SECTION_SEGMENT_BSS
;
2803 SectionSegments
[i
].Attributes
= 0;
2806 SectionSegments
[i
].RawLength
= ImageSections
[i
-1].SizeOfRawData
;
2807 if (ImageSections
[i
-1].Misc
.VirtualSize
!= 0)
2809 SectionSegments
[i
].Length
= ImageSections
[i
-1].Misc
.VirtualSize
;
2813 SectionSegments
[i
].Length
= ImageSections
[i
-1].SizeOfRawData
;
2815 SectionSegments
[i
].Flags
= 0;
2816 SectionSegments
[i
].ReferenceCount
= 1;
2817 SectionSegments
[i
].VirtualAddress
= (PVOID
)ImageSections
[i
-1].VirtualAddress
;
2818 ExInitializeFastMutex(&SectionSegments
[i
].Lock
);
2819 RtlZeroMemory(&SectionSegments
[i
].PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2821 if (0 != InterlockedCompareExchange((PLONG
)&FileObject
->SectionObjectPointer
->ImageSectionObject
,
2822 (LONG
)ImageSectionObject
, 0))
2825 * An other thread has initialized the some image in the background
2827 ExFreePool(ImageSectionObject
);
2828 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
2829 Section
->ImageSection
= ImageSectionObject
;
2830 SectionSegments
= ImageSectionObject
->Segments
;
2832 for (i
= 0; i
< NrSegments
; i
++)
2834 InterlockedIncrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2837 ExFreePool(ImageSections
);
2842 * Create the section
2844 Status
= ObCreateObject (ExGetPreviousMode(),
2845 MmSectionObjectType
,
2847 ExGetPreviousMode(),
2849 sizeof(SECTION_OBJECT
),
2852 (PVOID
*)(PVOID
)&Section
);
2853 if (!NT_SUCCESS(Status
))
2855 ObDereferenceObject(FileObject
);
2862 Section
->SectionPageProtection
= SectionPageProtection
;
2863 Section
->AllocationAttributes
= AllocationAttributes
;
2864 InitializeListHead(&Section
->ViewListHead
);
2865 KeInitializeSpinLock(&Section
->ViewListLock
);
2868 * Check file access required
2870 if (SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
2872 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2876 FileAccess
= FILE_READ_DATA
;
2882 Status
= MmspWaitForFileLock(FileObject
);
2883 if (Status
!= STATUS_SUCCESS
)
2885 ObDereferenceObject(Section
);
2886 ObDereferenceObject(FileObject
);
2890 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
2891 Section
->ImageSection
= ImageSectionObject
;
2892 SectionSegments
= ImageSectionObject
->Segments
;
2893 NrSegments
= ImageSectionObject
->NrSegments
;
2896 * Otherwise just reference all the section segments
2898 for (i
= 0; i
< NrSegments
; i
++)
2900 InterlockedIncrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2904 Section
->FileObject
= FileObject
;
2905 CcRosReferenceCache(FileObject
);
2906 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2907 *SectionObject
= Section
;
2908 return(STATUS_SUCCESS
);
2915 NtCreateSection (OUT PHANDLE SectionHandle
,
2916 IN ACCESS_MASK DesiredAccess
,
2917 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
2918 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
2919 IN ULONG SectionPageProtection OPTIONAL
,
2920 IN ULONG AllocationAttributes
,
2921 IN HANDLE FileHandle OPTIONAL
)
2923 PSECTION_OBJECT SectionObject
;
2927 * Check the protection
2929 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2930 SectionPageProtection
)
2932 return(STATUS_INVALID_PAGE_PROTECTION
);
2935 Status
= MmCreateSection(&SectionObject
,
2939 SectionPageProtection
,
2940 AllocationAttributes
,
2944 if (NT_SUCCESS(Status
))
2946 Status
= ObInsertObject ((PVOID
)SectionObject
,
2952 ObDereferenceObject(SectionObject
);
2959 /**********************************************************************
2977 NtOpenSection(PHANDLE SectionHandle
,
2978 ACCESS_MASK DesiredAccess
,
2979 POBJECT_ATTRIBUTES ObjectAttributes
)
2985 Status
= ObOpenObjectByName(ObjectAttributes
,
2986 MmSectionObjectType
,
2997 MmMapViewOfSegment(PEPROCESS Process
,
2998 PMADDRESS_SPACE AddressSpace
,
2999 PSECTION_OBJECT Section
,
3000 PMM_SECTION_SEGMENT Segment
,
3010 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3012 BoundaryAddressMultiple
.QuadPart
= 0;
3014 Status
= MmCreateMemoryArea(Process
,
3016 MEMORY_AREA_SECTION_VIEW
,
3023 BoundaryAddressMultiple
);
3024 if (!NT_SUCCESS(Status
))
3026 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
3027 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
);
3031 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3032 InsertTailList(&Section
->ViewListHead
,
3033 &MArea
->Data
.SectionData
.ViewListEntry
);
3034 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3036 ObReferenceObjectByPointer((PVOID
)Section
,
3039 ExGetPreviousMode());
3040 MArea
->Data
.SectionData
.Segment
= Segment
;
3041 MArea
->Data
.SectionData
.Section
= Section
;
3042 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3043 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3044 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3045 ViewSize
, 0, Protect
);
3047 return(STATUS_SUCCESS
);
3051 /**********************************************************************
3053 * NtMapViewOfSection
3056 * Maps a view of a section into the virtual address space of a
3061 * Handle of the section.
3064 * Handle of the process.
3067 * Desired base address (or NULL) on entry;
3068 * Actual base address of the view on exit.
3071 * Number of high order address bits that must be zero.
3074 * Size in bytes of the initially committed section of
3078 * Offset in bytes from the beginning of the section
3079 * to the beginning of the view.
3082 * Desired length of map (or zero to map all) on entry
3083 * Actual length mapped on exit.
3085 * InheritDisposition
3086 * Specified how the view is to be shared with
3090 * Type of allocation for the pages.
3093 * Protection for the committed region of the view.
3101 NtMapViewOfSection(HANDLE SectionHandle
,
3102 HANDLE ProcessHandle
,
3106 PLARGE_INTEGER SectionOffset
,
3108 SECTION_INHERIT InheritDisposition
,
3109 ULONG AllocationType
,
3112 PSECTION_OBJECT Section
;
3115 PMADDRESS_SPACE AddressSpace
;
3117 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3118 PROCESS_VM_OPERATION
,
3121 (PVOID
*)(PVOID
)&Process
,
3123 if (!NT_SUCCESS(Status
))
3128 AddressSpace
= &Process
->AddressSpace
;
3130 Status
= ObReferenceObjectByHandle(SectionHandle
,
3132 MmSectionObjectType
,
3134 (PVOID
*)(PVOID
)&Section
,
3136 if (!(NT_SUCCESS(Status
)))
3138 DPRINT("ObReference failed rc=%x\n",Status
);
3139 ObDereferenceObject(Process
);
3143 Status
= MmMapViewOfSection(Section
,
3154 ObDereferenceObject(Section
);
3155 ObDereferenceObject(Process
);
3161 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3162 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3166 PFILE_OBJECT FileObject
;
3169 SWAPENTRY SavedSwapEntry
;
3172 PSECTION_OBJECT Section
;
3173 PMM_SECTION_SEGMENT Segment
;
3175 MArea
= (PMEMORY_AREA
)Context
;
3177 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3179 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MArea
->BaseAddress
) +
3180 MemoryArea
->Data
.SectionData
.ViewOffset
;
3182 Section
= MArea
->Data
.SectionData
.Section
;
3183 Segment
= MArea
->Data
.SectionData
.Segment
;
3185 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3189 MmUnlockSectionSegment(Segment
);
3190 MmUnlockAddressSpace(&MArea
->Process
->AddressSpace
);
3192 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3193 if (Status
!= STATUS_SUCCESS
)
3195 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3199 MmLockAddressSpace(&MArea
->Process
->AddressSpace
);
3200 MmLockSectionSegment(Segment
);
3201 MmspCompleteAndReleasePageOp(PageOp
);
3202 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3205 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3208 * For a dirty, datafile, non-private page mark it as dirty in the
3211 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3213 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3215 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3216 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3217 CcRosMarkDirtyCacheSegment(Bcb
, Offset
);
3218 ASSERT(SwapEntry
== 0);
3227 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3229 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3232 MmFreeSwapPage(SwapEntry
);
3236 if (IS_SWAP_FROM_SSE(Entry
) ||
3237 Page
!= PFN_FROM_SSE(Entry
))
3242 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3244 DPRINT1("Found a private page in a pagefile section.\n");
3248 * Just dereference private pages
3250 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3251 if (SavedSwapEntry
!= 0)
3253 MmFreeSwapPage(SavedSwapEntry
);
3254 MmSetSavedSwapEntryPage(Page
, 0);
3256 MmDeleteRmap(Page
, MArea
->Process
, Address
);
3257 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3261 MmDeleteRmap(Page
, MArea
->Process
, Address
);
3262 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3268 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3272 PMEMORY_AREA MemoryArea
;
3273 PSECTION_OBJECT Section
;
3274 PMM_SECTION_SEGMENT Segment
;
3276 PLIST_ENTRY CurrentEntry
;
3277 PMM_REGION CurrentRegion
;
3278 PLIST_ENTRY RegionListHead
;
3280 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
3282 if (MemoryArea
== NULL
)
3284 return(STATUS_UNSUCCESSFUL
);
3287 MemoryArea
->DeleteInProgress
= TRUE
;
3288 Section
= MemoryArea
->Data
.SectionData
.Section
;
3289 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3291 MmLockSectionSegment(Segment
);
3292 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3293 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
3294 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3296 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3297 while (!IsListEmpty(RegionListHead
))
3299 CurrentEntry
= RemoveHeadList(RegionListHead
);
3300 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3301 ExFreePool(CurrentRegion
);
3304 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3306 Status
= MmFreeMemoryArea(AddressSpace
,
3314 Status
= MmFreeMemoryArea(AddressSpace
,
3320 MmUnlockSectionSegment(Segment
);
3321 ObDereferenceObject(Section
);
3322 return(STATUS_SUCCESS
);
3329 MmUnmapViewOfSection(PEPROCESS Process
,
3333 PMEMORY_AREA MemoryArea
;
3334 PMADDRESS_SPACE AddressSpace
;
3335 PSECTION_OBJECT Section
;
3337 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3338 Process
, BaseAddress
);
3342 AddressSpace
= &Process
->AddressSpace
;
3343 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
3345 if (MemoryArea
== NULL
||
3346 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
3347 MemoryArea
->DeleteInProgress
)
3349 return STATUS_NOT_MAPPED_VIEW
;
3352 Section
= MemoryArea
->Data
.SectionData
.Section
;
3354 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3358 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3359 PMM_SECTION_SEGMENT SectionSegments
;