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.158 2004/08/15 16:39:08 chorns 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 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
921 * If the entry is zero (and it can't change because we have
922 * locked the segment) then we need to load the page.
926 * Release all our locks and read in the page from disk
928 MmUnlockSectionSegment(Segment
);
929 MmUnlockAddressSpace(AddressSpace
);
931 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
932 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
934 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
935 if (!NT_SUCCESS(Status
))
937 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
942 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
943 if (!NT_SUCCESS(Status
))
945 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
948 if (!NT_SUCCESS(Status
))
951 * FIXME: What do we know in this case?
954 * Cleanup and release locks
956 MmLockAddressSpace(AddressSpace
);
957 PageOp
->Status
= Status
;
958 MmspCompleteAndReleasePageOp(PageOp
);
959 DPRINT("Address 0x%.8X\n", Address
);
963 * Relock the address space and segment
965 MmLockAddressSpace(AddressSpace
);
966 MmLockSectionSegment(Segment
);
969 * Check the entry. No one should change the status of a page
970 * that has a pending page-in.
972 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
975 DbgPrint("Someone changed ppte entry while we slept\n");
980 * Mark the offset within the section as having valid, in-memory
983 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
984 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
985 MmUnlockSectionSegment(Segment
);
987 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
992 if (!NT_SUCCESS(Status
))
994 DbgPrint("Unable to create virtual mapping\n");
997 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1003 PageOp
->Status
= STATUS_SUCCESS
;
1004 MmspCompleteAndReleasePageOp(PageOp
);
1005 DPRINT("Address 0x%.8X\n", Address
);
1006 return(STATUS_SUCCESS
);
1008 else if (IS_SWAP_FROM_SSE(Entry
))
1010 SWAPENTRY SwapEntry
;
1012 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1015 * Release all our locks and read in the page from disk
1017 MmUnlockSectionSegment(Segment
);
1019 MmUnlockAddressSpace(AddressSpace
);
1021 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1022 if (!NT_SUCCESS(Status
))
1027 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1028 if (!NT_SUCCESS(Status
))
1034 * Relock the address space and segment
1036 MmLockAddressSpace(AddressSpace
);
1037 MmLockSectionSegment(Segment
);
1040 * Check the entry. No one should change the status of a page
1041 * that has a pending page-in.
1043 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1044 if (Entry
!= Entry1
)
1046 DbgPrint("Someone changed ppte entry while we slept\n");
1051 * Mark the offset within the section as having valid, in-memory
1054 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1055 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1056 MmUnlockSectionSegment(Segment
);
1059 * Save the swap entry.
1061 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1062 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1067 if (!NT_SUCCESS(Status
))
1069 DbgPrint("Unable to create virtual mapping\n");
1072 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1077 PageOp
->Status
= STATUS_SUCCESS
;
1078 MmspCompleteAndReleasePageOp(PageOp
);
1079 DPRINT("Address 0x%.8X\n", Address
);
1080 return(STATUS_SUCCESS
);
1085 * If the section offset is already in-memory and valid then just
1086 * take another reference to the page
1089 Page
= PFN_FROM_SSE(Entry
);
1091 MmSharePageEntrySectionSegment(Segment
, Offset
);
1092 MmUnlockSectionSegment(Segment
);
1094 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1099 if (!NT_SUCCESS(Status
))
1101 DbgPrint("Unable to create virtual mapping\n");
1104 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1109 PageOp
->Status
= STATUS_SUCCESS
;
1110 MmspCompleteAndReleasePageOp(PageOp
);
1111 DPRINT("Address 0x%.8X\n", Address
);
1112 return(STATUS_SUCCESS
);
1117 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1118 MEMORY_AREA
* MemoryArea
,
1122 PMM_SECTION_SEGMENT Segment
;
1123 PSECTION_OBJECT Section
;
1135 * Check if the page has been paged out or has already been set readwrite
1137 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1138 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1140 DPRINT("Address 0x%.8X\n", Address
);
1141 return(STATUS_SUCCESS
);
1145 * Find the offset of the page
1147 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
1148 Offset
= PAddress
- (ULONG
)MemoryArea
->BaseAddress
;
1150 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1151 Section
= MemoryArea
->Data
.SectionData
.Section
;
1152 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1153 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1158 MmLockSectionSegment(Segment
);
1160 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1161 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1163 MmUnlockSectionSegment(Segment
);
1166 * Check if we are doing COW
1168 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1169 (Region
->Protect
== PAGE_READWRITE
||
1170 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1172 DPRINT("Address 0x%.8X\n", Address
);
1173 return(STATUS_UNSUCCESSFUL
);
1176 if (IS_SWAP_FROM_SSE(Entry
) ||
1177 PFN_FROM_SSE(Entry
) != OldPage
)
1179 /* This is a private page. We must only change the page protection. */
1180 MmSetPageProtect(AddressSpace
->Process
, (PVOID
)PAddress
, Region
->Protect
);
1181 return(STATUS_SUCCESS
);
1185 * Get or create a pageop
1187 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
,
1188 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1191 DPRINT1("MmGetPageOp failed\n");
1196 * Wait for any other operations to complete
1198 if (PageOp
->Thread
!= PsGetCurrentThread())
1200 MmUnlockAddressSpace(AddressSpace
);
1201 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1203 * Check for various strange conditions
1205 if (Status
== STATUS_TIMEOUT
)
1207 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1210 if (PageOp
->Status
== STATUS_PENDING
)
1212 DPRINT1("Woke for page op before completion\n");
1216 * Restart the operation
1218 MmLockAddressSpace(AddressSpace
);
1219 MmspCompleteAndReleasePageOp(PageOp
);
1220 DPRINT("Address 0x%.8X\n", Address
);
1221 return(STATUS_MM_RESTART_OPERATION
);
1225 * Release locks now we have the pageop
1227 MmUnlockAddressSpace(AddressSpace
);
1232 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1233 if (!NT_SUCCESS(Status
))
1242 NewAddress
= ExAllocatePageWithPhysPage(NewPage
);
1243 memcpy(NewAddress
, (PVOID
)PAddress
, PAGE_SIZE
);
1244 ExUnmapPage(NewAddress
);
1247 * Delete the old entry.
1249 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1252 * Set the PTE to point to the new page
1254 MmLockAddressSpace(AddressSpace
);
1255 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1260 if (!NT_SUCCESS(Status
))
1262 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1266 MmInsertRmap(NewPage
, AddressSpace
->Process
, (PVOID
)PAddress
);
1267 if (!NT_SUCCESS(Status
))
1269 DbgPrint("Unable to create virtual mapping\n");
1274 MmLockPage(NewPage
);
1275 MmUnlockPage(OldPage
);
1279 * Unshare the old page.
1281 MmDeleteRmap(OldPage
, AddressSpace
->Process
, (PVOID
)PAddress
);
1282 MmLockSectionSegment(Segment
);
1283 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1284 MmUnlockSectionSegment(Segment
);
1286 PageOp
->Status
= STATUS_SUCCESS
;
1287 MmspCompleteAndReleasePageOp(PageOp
);
1288 DPRINT("Address 0x%.8X\n", Address
);
1289 return(STATUS_SUCCESS
);
1293 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1295 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1299 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1300 MmDeleteVirtualMapping(Process
,
1307 PageOutContext
->WasDirty
= TRUE
;
1309 if (!PageOutContext
->Private
)
1311 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1312 PageOutContext
->Segment
,
1313 PageOutContext
->Offset
,
1314 PageOutContext
->WasDirty
,
1319 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1322 DPRINT("PhysicalAddress %I64x, Address %x\n", Page
, Address
);
1326 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1327 MEMORY_AREA
* MemoryArea
,
1332 MM_SECTION_PAGEOUT_CONTEXT Context
;
1333 SWAPENTRY SwapEntry
;
1337 PFILE_OBJECT FileObject
;
1339 BOOLEAN DirectMapped
;
1340 BOOLEAN IsImageSection
;
1342 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1345 * Get the segment and section.
1347 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1348 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1350 Context
.Offset
= (ULONG
)((char*)Address
- (ULONG
)MemoryArea
->BaseAddress
);
1351 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1353 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1355 FileObject
= Context
.Section
->FileObject
;
1356 DirectMapped
= FALSE
;
1357 if (FileObject
!= NULL
&&
1358 !(Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
1360 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1363 * If the file system is letting us go directly to the cache and the
1364 * memory area was mapped at an offset in the file which is page aligned
1365 * then note this is a direct mapped page.
1367 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1368 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1370 DirectMapped
= TRUE
;
1376 * This should never happen since mappings of physical memory are never
1377 * placed in the rmap lists.
1379 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1381 DPRINT1("Trying to page out from physical memory section address 0x%X "
1382 "process %d\n", Address
,
1383 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1388 * Get the section segment entry and the physical address.
1390 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1391 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1393 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1394 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1397 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1398 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1401 * Prepare the context structure for the rmap delete call.
1403 Context
.WasDirty
= FALSE
;
1404 if (Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1405 IS_SWAP_FROM_SSE(Entry
) ||
1406 PFN_FROM_SSE(Entry
) != Page
)
1408 Context
.Private
= TRUE
;
1412 Context
.Private
= FALSE
;
1416 * Take an additional reference to the page or the cache segment.
1418 if (DirectMapped
&& !Context
.Private
)
1420 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1422 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1428 MmReferencePage(Page
);
1431 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1434 * If this wasn't a private page then we should have reduced the entry to
1435 * zero by deleting all the rmaps.
1437 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1439 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1440 !(Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
1447 * If the page wasn't dirty then we can just free it as for a readonly page.
1448 * Since we unmapped all the mappings above we know it will not suddenly
1450 * If the page is from a pagefile section and has no swap entry,
1451 * we can't free the page at this point.
1453 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1454 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1456 if (Context
.Private
)
1458 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1459 Context
.WasDirty
? "dirty" : "clean", Address
);
1462 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1464 MmSetSavedSwapEntryPage(Page
, 0);
1465 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1466 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1467 PageOp
->Status
= STATUS_SUCCESS
;
1468 MmspCompleteAndReleasePageOp(PageOp
);
1469 return(STATUS_SUCCESS
);
1472 else if (Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
)
1474 if (Context
.Private
)
1476 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1477 Context
.WasDirty
? "dirty" : "clean", Address
);
1480 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1482 MmSetSavedSwapEntryPage(Page
, 0);
1485 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1487 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1488 PageOp
->Status
= STATUS_SUCCESS
;
1489 MmspCompleteAndReleasePageOp(PageOp
);
1490 return(STATUS_SUCCESS
);
1493 else if (!Context
.Private
&& DirectMapped
)
1497 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1501 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1502 if (!NT_SUCCESS(Status
))
1504 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1507 PageOp
->Status
= STATUS_SUCCESS
;
1508 MmspCompleteAndReleasePageOp(PageOp
);
1509 return(STATUS_SUCCESS
);
1511 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1515 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1519 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1520 PageOp
->Status
= STATUS_SUCCESS
;
1521 MmspCompleteAndReleasePageOp(PageOp
);
1522 return(STATUS_SUCCESS
);
1524 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1526 MmSetSavedSwapEntryPage(Page
, 0);
1527 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1530 if (!NT_SUCCESS(Status
))
1534 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1535 PageOp
->Status
= STATUS_SUCCESS
;
1536 MmspCompleteAndReleasePageOp(PageOp
);
1537 return(STATUS_SUCCESS
);
1541 * If necessary, allocate an entry in the paging file for this page
1545 SwapEntry
= MmAllocSwapPage();
1548 MmShowOutOfSpaceMessagePagingFile();
1551 * For private pages restore the old mappings.
1553 if (Context
.Private
)
1555 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1557 MemoryArea
->Attributes
,
1560 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1562 MemoryArea
->Process
,
1568 * For non-private pages if the page wasn't direct mapped then
1569 * set it back into the section segment entry so we don't loose
1570 * our copy. Otherwise it will be handled by the cache manager.
1572 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1574 MemoryArea
->Attributes
,
1577 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1579 MemoryArea
->Process
,
1581 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1582 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1584 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1585 MmspCompleteAndReleasePageOp(PageOp
);
1586 return(STATUS_PAGEFILE_QUOTA
);
1591 * Write the page to the pagefile
1593 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1594 if (!NT_SUCCESS(Status
))
1596 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1599 * As above: undo our actions.
1600 * FIXME: Also free the swap page.
1602 if (Context
.Private
)
1604 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1606 MemoryArea
->Attributes
,
1609 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1611 MemoryArea
->Process
,
1616 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1618 MemoryArea
->Attributes
,
1621 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1623 MemoryArea
->Process
,
1625 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1626 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1628 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1629 MmspCompleteAndReleasePageOp(PageOp
);
1630 return(STATUS_UNSUCCESSFUL
);
1634 * Otherwise we have succeeded.
1636 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1637 MmSetSavedSwapEntryPage(Page
, 0);
1638 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1639 Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
)
1641 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1645 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1648 if (Context
.Private
)
1650 Status
= MmCreatePageFileMapping(MemoryArea
->Process
,
1653 if (!NT_SUCCESS(Status
))
1660 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1661 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1664 PageOp
->Status
= STATUS_SUCCESS
;
1665 MmspCompleteAndReleasePageOp(PageOp
);
1666 return(STATUS_SUCCESS
);
1670 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1671 PMEMORY_AREA MemoryArea
,
1676 PSECTION_OBJECT Section
;
1677 PMM_SECTION_SEGMENT Segment
;
1679 SWAPENTRY SwapEntry
;
1683 PFILE_OBJECT FileObject
;
1685 BOOLEAN DirectMapped
;
1686 BOOLEAN IsImageSection
;
1688 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1690 Offset
= (ULONG
)((char*)Address
- (ULONG
)MemoryArea
->BaseAddress
);
1693 * Get the segment and section.
1695 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1696 Section
= MemoryArea
->Data
.SectionData
.Section
;
1697 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1699 FileObject
= Section
->FileObject
;
1700 DirectMapped
= FALSE
;
1701 if (FileObject
!= NULL
&&
1702 !(Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
1704 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1707 * If the file system is letting us go directly to the cache and the
1708 * memory area was mapped at an offset in the file which is page aligned
1709 * then note this is a direct mapped page.
1711 if ((Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
% PAGE_SIZE
) == 0 &&
1712 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1714 DirectMapped
= TRUE
;
1719 * This should never happen since mappings of physical memory are never
1720 * placed in the rmap lists.
1722 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1724 DPRINT1("Trying to write back page from physical memory mapped at %X "
1725 "process %d\n", Address
,
1726 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1731 * Get the section segment entry and the physical address.
1733 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1734 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1736 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1737 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1740 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1741 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1744 * Check for a private (COWed) page.
1746 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1747 IS_SWAP_FROM_SSE(Entry
) ||
1748 PFN_FROM_SSE(Entry
) != Page
)
1758 * Speculatively set all mappings of the page to clean.
1760 MmSetCleanAllRmaps(Page
);
1763 * If this page was direct mapped from the cache then the cache manager
1764 * will take care of writing it back to disk.
1766 if (DirectMapped
&& !Private
)
1768 assert(SwapEntry
== 0);
1769 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
1770 PageOp
->Status
= STATUS_SUCCESS
;
1771 MmspCompleteAndReleasePageOp(PageOp
);
1772 return(STATUS_SUCCESS
);
1776 * If necessary, allocate an entry in the paging file for this page
1780 SwapEntry
= MmAllocSwapPage();
1783 MmSetDirtyAllRmaps(Page
);
1784 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1785 MmspCompleteAndReleasePageOp(PageOp
);
1786 return(STATUS_PAGEFILE_QUOTA
);
1788 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1792 * Write the page to the pagefile
1794 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1795 if (!NT_SUCCESS(Status
))
1797 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1799 MmSetDirtyAllRmaps(Page
);
1800 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1801 MmspCompleteAndReleasePageOp(PageOp
);
1802 return(STATUS_UNSUCCESSFUL
);
1806 * Otherwise we have succeeded.
1808 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1809 PageOp
->Status
= STATUS_SUCCESS
;
1810 MmspCompleteAndReleasePageOp(PageOp
);
1811 return(STATUS_SUCCESS
);
1815 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1823 PMEMORY_AREA MemoryArea
;
1824 PMM_SECTION_SEGMENT Segment
;
1828 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1829 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1831 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1832 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1837 if (OldProtect
!= NewProtect
)
1839 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1841 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1842 ULONG Protect
= NewProtect
;
1845 * If we doing COW for this segment then check if the page is
1848 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1854 Offset
= (ULONG
)Address
- (ULONG
)MemoryArea
->BaseAddress
;
1855 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1856 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1858 Protect
= PAGE_READONLY
;
1859 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1860 IS_SWAP_FROM_SSE(Entry
) ||
1861 PFN_FROM_SSE(Entry
) != Page
)
1863 Protect
= NewProtect
;
1867 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1869 MmSetPageProtect(AddressSpace
->Process
, Address
,
1877 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1878 PMEMORY_AREA MemoryArea
,
1888 min(Length
, (ULONG
) ((char*)MemoryArea
->BaseAddress
+ MemoryArea
->Length
- (char*)BaseAddress
));
1889 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1890 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1892 *OldProtect
= Region
->Protect
;
1893 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->BaseAddress
,
1894 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1895 BaseAddress
, Length
, Region
->Type
, Protect
,
1896 MmAlterViewAttributes
);
1902 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
1904 PMEMORY_BASIC_INFORMATION Info
,
1905 PULONG ResultLength
)
1908 PVOID RegionBaseAddress
;
1909 PSECTION_OBJECT Section
;
1910 PLIST_ENTRY CurrentEntry
;
1911 PMEMORY_AREA CurrentMArea
;
1914 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1915 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1916 Address
, &RegionBaseAddress
);
1919 return STATUS_UNSUCCESSFUL
;
1921 Section
= MemoryArea
->Data
.SectionData
.Section
;
1922 if (Section
->AllocationAttributes
& SEC_IMAGE
)
1924 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
1925 CurrentEntry
= Section
->ViewListHead
.Flink
;
1926 Info
->AllocationBase
= NULL
;
1927 while (CurrentEntry
!= &Section
->ViewListHead
)
1929 CurrentMArea
= CONTAINING_RECORD(CurrentEntry
, MEMORY_AREA
, Data
.SectionData
.ViewListEntry
);
1930 CurrentEntry
= CurrentEntry
->Flink
;
1931 if (Info
->AllocationBase
== NULL
)
1933 Info
->AllocationBase
= CurrentMArea
->BaseAddress
;
1935 else if (CurrentMArea
->BaseAddress
< Info
->AllocationBase
)
1937 Info
->AllocationBase
= CurrentMArea
->BaseAddress
;
1940 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
1941 Info
->BaseAddress
= RegionBaseAddress
;
1942 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1943 Info
->Type
= MEM_IMAGE
;
1947 Info
->BaseAddress
= RegionBaseAddress
;
1948 Info
->AllocationBase
= MemoryArea
->BaseAddress
;
1949 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1950 Info
->Type
= MEM_MAPPED
;
1952 Info
->RegionSize
= PAGE_ROUND_UP(MemoryArea
->Length
);
1953 Info
->State
= MEM_COMMIT
;
1954 Info
->Protect
= Region
->Protect
;
1956 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
1957 return(STATUS_SUCCESS
);
1961 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
1966 ULONG SavedSwapEntry
;
1971 Length
= PAGE_ROUND_UP(Segment
->Length
);
1972 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
1974 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1977 if (IS_SWAP_FROM_SSE(Entry
))
1979 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
1983 Page
= PFN_FROM_SSE(Entry
);
1984 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
1985 if (SavedSwapEntry
!= 0)
1987 MmSetSavedSwapEntryPage(Page
, 0);
1988 MmFreeSwapPage(SavedSwapEntry
);
1990 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1992 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
1998 MmpDeleteSection(PVOID ObjectBody
)
2000 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
2002 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2003 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2008 PMM_SECTION_SEGMENT SectionSegments
;
2010 SectionSegments
= Section
->ImageSection
->Segments
;
2011 NrSegments
= Section
->ImageSection
->NrSegments
;
2013 for (i
= 0; i
< NrSegments
; i
++)
2015 if (SectionSegments
[i
].Characteristics
& IMAGE_SECTION_CHAR_SHARED
)
2017 MmLockSectionSegment(&SectionSegments
[i
]);
2019 RefCount
= InterlockedDecrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2020 if (SectionSegments
[i
].Characteristics
& IMAGE_SECTION_CHAR_SHARED
)
2024 MmpFreePageFileSegment(&SectionSegments
[i
]);
2026 MmUnlockSectionSegment(&SectionSegments
[i
]);
2032 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2034 MmpFreePageFileSegment(Section
->Segment
);
2035 MmFreePageTablesSectionSegment(Section
->Segment
);
2036 ExFreePool(Section
->Segment
);
2037 Section
->Segment
= NULL
;
2041 InterlockedDecrement((LONG
*)&Section
->Segment
->ReferenceCount
);
2044 if (Section
->FileObject
!= NULL
)
2046 CcRosDereferenceCache(Section
->FileObject
);
2047 ObDereferenceObject(Section
->FileObject
);
2048 Section
->FileObject
= NULL
;
2053 MmpCloseSection(PVOID ObjectBody
,
2056 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2057 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2061 MmpCreateSection(PVOID ObjectBody
,
2063 PWSTR RemainingPath
,
2064 POBJECT_ATTRIBUTES ObjectAttributes
)
2066 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2067 ObjectBody
, Parent
, RemainingPath
);
2069 if (RemainingPath
== NULL
)
2071 return(STATUS_SUCCESS
);
2074 if (wcschr(RemainingPath
+1, L
'\\') != NULL
)
2076 return(STATUS_UNSUCCESSFUL
);
2078 return(STATUS_SUCCESS
);
2081 NTSTATUS INIT_FUNCTION
2082 MmCreatePhysicalMemorySection(VOID
)
2084 PSECTION_OBJECT PhysSection
;
2086 OBJECT_ATTRIBUTES Obj
;
2087 UNICODE_STRING Name
= ROS_STRING_INITIALIZER(L
"\\Device\\PhysicalMemory");
2088 LARGE_INTEGER SectionSize
;
2091 * Create the section mapping physical memory
2093 SectionSize
.QuadPart
= 0xFFFFFFFF;
2094 InitializeObjectAttributes(&Obj
,
2099 Status
= MmCreateSection(&PhysSection
,
2103 PAGE_EXECUTE_READWRITE
,
2107 if (!NT_SUCCESS(Status
))
2109 DbgPrint("Failed to create PhysicalMemory section\n");
2112 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2114 return(STATUS_SUCCESS
);
2117 NTSTATUS INIT_FUNCTION
2118 MmInitSectionImplementation(VOID
)
2120 MmSectionObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
2122 RtlRosInitUnicodeStringFromLiteral(&MmSectionObjectType
->TypeName
, L
"Section");
2124 MmSectionObjectType
->Tag
= TAG('S', 'E', 'C', 'T');
2125 MmSectionObjectType
->TotalObjects
= 0;
2126 MmSectionObjectType
->TotalHandles
= 0;
2127 MmSectionObjectType
->MaxObjects
= ULONG_MAX
;
2128 MmSectionObjectType
->MaxHandles
= ULONG_MAX
;
2129 MmSectionObjectType
->PagedPoolCharge
= 0;
2130 MmSectionObjectType
->NonpagedPoolCharge
= sizeof(SECTION_OBJECT
);
2131 MmSectionObjectType
->Mapping
= &MmpSectionMapping
;
2132 MmSectionObjectType
->Dump
= NULL
;
2133 MmSectionObjectType
->Open
= NULL
;
2134 MmSectionObjectType
->Close
= MmpCloseSection
;
2135 MmSectionObjectType
->Delete
= MmpDeleteSection
;
2136 MmSectionObjectType
->Parse
= NULL
;
2137 MmSectionObjectType
->Security
= NULL
;
2138 MmSectionObjectType
->QueryName
= NULL
;
2139 MmSectionObjectType
->OkayToClose
= NULL
;
2140 MmSectionObjectType
->Create
= MmpCreateSection
;
2141 MmSectionObjectType
->DuplicationNotify
= NULL
;
2144 * NOTE: Do not register the section object type here because
2145 * the object manager it not initialized yet!
2146 * The section object type will be created in ObInit().
2148 ObpCreateTypeObject(MmSectionObjectType
);
2150 return(STATUS_SUCCESS
);
2154 MmCreatePageFileSection(PSECTION_OBJECT
*SectionObject
,
2155 ACCESS_MASK DesiredAccess
,
2156 POBJECT_ATTRIBUTES ObjectAttributes
,
2157 PLARGE_INTEGER UMaximumSize
,
2158 ULONG SectionPageProtection
,
2159 ULONG AllocationAttributes
)
2161 * Create a section which is backed by the pagefile
2164 LARGE_INTEGER MaximumSize
;
2165 PSECTION_OBJECT Section
;
2166 PMM_SECTION_SEGMENT Segment
;
2169 if (UMaximumSize
== NULL
)
2171 return(STATUS_UNSUCCESSFUL
);
2173 MaximumSize
= *UMaximumSize
;
2176 * Check the protection
2178 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2179 SectionPageProtection
)
2181 return(STATUS_INVALID_PAGE_PROTECTION
);
2185 * Create the section
2187 Status
= ObCreateObject(ExGetPreviousMode(),
2188 MmSectionObjectType
,
2190 ExGetPreviousMode(),
2192 sizeof(SECTION_OBJECT
),
2196 if (!NT_SUCCESS(Status
))
2204 Section
->SectionPageProtection
= SectionPageProtection
;
2205 Section
->AllocationAttributes
= AllocationAttributes
;
2206 InitializeListHead(&Section
->ViewListHead
);
2207 KeInitializeSpinLock(&Section
->ViewListLock
);
2208 Section
->FileObject
= NULL
;
2209 Section
->MaximumSize
= MaximumSize
;
2210 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2211 TAG_MM_SECTION_SEGMENT
);
2212 if (Segment
== NULL
)
2214 ObDereferenceObject(Section
);
2215 return(STATUS_NO_MEMORY
);
2217 Section
->Segment
= Segment
;
2218 Segment
->ReferenceCount
= 1;
2219 ExInitializeFastMutex(&Segment
->Lock
);
2220 Segment
->FileOffset
= 0;
2221 Segment
->Protection
= SectionPageProtection
;
2222 Segment
->Attributes
= AllocationAttributes
;
2223 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2224 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2225 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2226 Segment
->WriteCopy
= FALSE
;
2227 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2228 Segment
->VirtualAddress
= 0;
2229 Segment
->Characteristics
= 0;
2230 *SectionObject
= Section
;
2231 return(STATUS_SUCCESS
);
2236 MmCreateDataFileSection(PSECTION_OBJECT
*SectionObject
,
2237 ACCESS_MASK DesiredAccess
,
2238 POBJECT_ATTRIBUTES ObjectAttributes
,
2239 PLARGE_INTEGER UMaximumSize
,
2240 ULONG SectionPageProtection
,
2241 ULONG AllocationAttributes
,
2244 * Create a section backed by a data file
2247 PSECTION_OBJECT Section
;
2249 LARGE_INTEGER MaximumSize
;
2250 PFILE_OBJECT FileObject
;
2251 PMM_SECTION_SEGMENT Segment
;
2253 IO_STATUS_BLOCK Iosb
;
2254 LARGE_INTEGER Offset
;
2258 * Check the protection
2260 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2261 SectionPageProtection
)
2263 return(STATUS_INVALID_PAGE_PROTECTION
);
2266 * Create the section
2268 Status
= ObCreateObject(ExGetPreviousMode(),
2269 MmSectionObjectType
,
2271 ExGetPreviousMode(),
2273 sizeof(SECTION_OBJECT
),
2277 if (!NT_SUCCESS(Status
))
2285 Section
->SectionPageProtection
= SectionPageProtection
;
2286 Section
->AllocationAttributes
= AllocationAttributes
;
2287 InitializeListHead(&Section
->ViewListHead
);
2288 KeInitializeSpinLock(&Section
->ViewListLock
);
2291 * Check file access required
2293 if (SectionPageProtection
& PAGE_READWRITE
||
2294 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2296 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2300 FileAccess
= FILE_READ_DATA
;
2304 * Reference the file handle
2306 Status
= ObReferenceObjectByHandle(FileHandle
,
2310 (PVOID
*)&FileObject
,
2312 if (!NT_SUCCESS(Status
))
2314 ObDereferenceObject(Section
);
2319 * We can't do memory mappings if the file system doesn't support the
2322 if (!(FileObject
->Flags
& FO_FCB_IS_VALID
))
2324 ObDereferenceObject(Section
);
2325 ObDereferenceObject(FileObject
);
2326 return(STATUS_INVALID_FILE_FOR_SECTION
);
2330 * FIXME: Revise this once a locking order for file size changes is
2333 if (UMaximumSize
!= NULL
)
2335 MaximumSize
= *UMaximumSize
;
2340 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
;
2343 if (MaximumSize
.QuadPart
>
2344 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
.QuadPart
)
2346 Status
= NtSetInformationFile(FileHandle
,
2349 sizeof(LARGE_INTEGER
),
2350 FileAllocationInformation
);
2351 if (!NT_SUCCESS(Status
))
2353 ObDereferenceObject(Section
);
2354 ObDereferenceObject(FileObject
);
2355 return(STATUS_SECTION_NOT_EXTENDED
);
2359 if (FileObject
->SectionObjectPointer
== NULL
||
2360 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2363 * Read a bit so caching is initiated for the file object.
2364 * This is only needed because MiReadPage currently cannot
2365 * handle non-cached streams.
2367 Offset
.QuadPart
= 0;
2368 Status
= ZwReadFile(FileHandle
,
2377 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2379 ObDereferenceObject(Section
);
2380 ObDereferenceObject(FileObject
);
2383 if (FileObject
->SectionObjectPointer
== NULL
||
2384 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2386 /* FIXME: handle this situation */
2387 ObDereferenceObject(Section
);
2388 ObDereferenceObject(FileObject
);
2389 return STATUS_INVALID_PARAMETER
;
2396 Status
= MmspWaitForFileLock(FileObject
);
2397 if (Status
!= STATUS_SUCCESS
)
2399 ObDereferenceObject(Section
);
2400 ObDereferenceObject(FileObject
);
2405 * If this file hasn't been mapped as a data file before then allocate a
2406 * section segment to describe the data file mapping
2408 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2410 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2411 TAG_MM_SECTION_SEGMENT
);
2412 if (Segment
== NULL
)
2414 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2415 ObDereferenceObject(Section
);
2416 ObDereferenceObject(FileObject
);
2417 return(STATUS_NO_MEMORY
);
2419 Section
->Segment
= Segment
;
2420 Segment
->ReferenceCount
= 1;
2421 ExInitializeFastMutex(&Segment
->Lock
);
2423 * Set the lock before assigning the segment to the file object
2425 ExAcquireFastMutex(&Segment
->Lock
);
2426 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2428 Segment
->FileOffset
= 0;
2429 Segment
->Protection
= SectionPageProtection
;
2430 Segment
->Attributes
= 0;
2431 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2432 Segment
->Characteristics
= 0;
2433 Segment
->WriteCopy
= FALSE
;
2434 if (AllocationAttributes
& SEC_RESERVE
)
2436 Segment
->Length
= Segment
->RawLength
= 0;
2440 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2441 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2443 Segment
->VirtualAddress
= NULL
;
2444 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2449 * If the file is already mapped as a data file then we may need
2453 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2455 Section
->Segment
= Segment
;
2456 InterlockedIncrement((PLONG
)&Segment
->ReferenceCount
);
2457 MmLockSectionSegment(Segment
);
2459 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2460 !(AllocationAttributes
& SEC_RESERVE
))
2462 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2463 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2466 MmUnlockSectionSegment(Segment
);
2467 Section
->FileObject
= FileObject
;
2468 Section
->MaximumSize
= MaximumSize
;
2469 CcRosReferenceCache(FileObject
);
2470 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2471 *SectionObject
= Section
;
2472 return(STATUS_SUCCESS
);
2475 static ULONG SectionCharacteristicsToProtect
[16] =
2477 PAGE_NOACCESS
, // 0 = NONE
2478 PAGE_NOACCESS
, // 1 = SHARED
2479 PAGE_EXECUTE
, // 2 = EXECUTABLE
2480 PAGE_EXECUTE
, // 3 = EXECUTABLE, SHARED
2481 PAGE_READONLY
, // 4 = READABLE
2482 PAGE_READONLY
, // 5 = READABLE, SHARED
2483 PAGE_EXECUTE_READ
, // 6 = READABLE, EXECUTABLE
2484 PAGE_EXECUTE_READ
, // 7 = READABLE, EXECUTABLE, SHARED
2485 PAGE_READWRITE
, // 8 = WRITABLE
2486 PAGE_READWRITE
, // 9 = WRITABLE, SHARED
2487 PAGE_EXECUTE_READWRITE
, // 10 = WRITABLE, EXECUTABLE
2488 PAGE_EXECUTE_READWRITE
, // 11 = WRITABLE, EXECUTABLE, SHARED
2489 PAGE_READWRITE
, // 12 = WRITABLE, READABLE
2490 PAGE_READWRITE
, // 13 = WRITABLE, READABLE, SHARED
2491 PAGE_EXECUTE_READWRITE
, // 14 = WRITABLE, READABLE, EXECUTABLE,
2492 PAGE_EXECUTE_READWRITE
, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
2496 MmCreateImageSection(PSECTION_OBJECT
*SectionObject
,
2497 ACCESS_MASK DesiredAccess
,
2498 POBJECT_ATTRIBUTES ObjectAttributes
,
2499 PLARGE_INTEGER UMaximumSize
,
2500 ULONG SectionPageProtection
,
2501 ULONG AllocationAttributes
,
2504 PSECTION_OBJECT Section
;
2506 PFILE_OBJECT FileObject
;
2507 IMAGE_DOS_HEADER DosHeader
;
2508 IO_STATUS_BLOCK Iosb
;
2509 LARGE_INTEGER Offset
;
2510 IMAGE_NT_HEADERS PEHeader
;
2511 PMM_SECTION_SEGMENT SectionSegments
;
2513 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
2516 ULONG Characteristics
;
2517 ULONG FileAccess
= 0;
2519 * Check the protection
2521 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2522 SectionPageProtection
)
2524 return(STATUS_INVALID_PAGE_PROTECTION
);
2528 * Specifying a maximum size is meaningless for an image section
2530 if (UMaximumSize
!= NULL
)
2532 return(STATUS_INVALID_PARAMETER_4
);
2536 * Reference the file handle
2538 Status
= ObReferenceObjectByHandle(FileHandle
,
2542 (PVOID
*)&FileObject
,
2544 if (!NT_SUCCESS(Status
))
2550 * Initialized caching for this file object if previously caching
2551 * was initialized for the same on disk file
2553 Status
= CcTryToInitializeFileCache(FileObject
);
2555 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
2557 PIMAGE_SECTION_HEADER ImageSections
;
2559 * Read the dos header and check the DOS signature
2561 Offset
.QuadPart
= 0;
2562 Status
= ZwReadFile(FileHandle
,
2571 if (!NT_SUCCESS(Status
))
2573 ObDereferenceObject(FileObject
);
2578 * Check the DOS signature
2580 if (Iosb
.Information
!= sizeof(DosHeader
) ||
2581 DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
)
2583 ObDereferenceObject(FileObject
);
2584 return(STATUS_INVALID_IMAGE_FORMAT
);
2588 * Read the PE header
2590 Offset
.QuadPart
= DosHeader
.e_lfanew
;
2591 Status
= ZwReadFile(FileHandle
,
2600 if (!NT_SUCCESS(Status
))
2602 ObDereferenceObject(FileObject
);
2607 * Check the signature
2609 if (Iosb
.Information
!= sizeof(PEHeader
) ||
2610 PEHeader
.Signature
!= IMAGE_NT_SIGNATURE
)
2612 ObDereferenceObject(FileObject
);
2613 return(STATUS_INVALID_IMAGE_FORMAT
);
2617 * Read in the section headers
2619 Offset
.QuadPart
= DosHeader
.e_lfanew
+ sizeof(PEHeader
);
2620 ImageSections
= ExAllocatePool(NonPagedPool
,
2621 PEHeader
.FileHeader
.NumberOfSections
*
2622 sizeof(IMAGE_SECTION_HEADER
));
2623 if (ImageSections
== NULL
)
2625 ObDereferenceObject(FileObject
);
2626 return(STATUS_NO_MEMORY
);
2629 Status
= ZwReadFile(FileHandle
,
2635 PEHeader
.FileHeader
.NumberOfSections
*
2636 sizeof(IMAGE_SECTION_HEADER
),
2639 if (!NT_SUCCESS(Status
))
2641 ObDereferenceObject(FileObject
);
2642 ExFreePool(ImageSections
);
2645 if (Iosb
.Information
!= (PEHeader
.FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
)))
2647 ObDereferenceObject(FileObject
);
2648 ExFreePool(ImageSections
);
2649 return(STATUS_INVALID_IMAGE_FORMAT
);
2653 * Create the section
2655 Status
= ObCreateObject (ExGetPreviousMode(),
2656 MmSectionObjectType
,
2658 ExGetPreviousMode(),
2660 sizeof(SECTION_OBJECT
),
2664 if (!NT_SUCCESS(Status
))
2666 ObDereferenceObject(FileObject
);
2667 ExFreePool(ImageSections
);
2674 Section
->SectionPageProtection
= SectionPageProtection
;
2675 Section
->AllocationAttributes
= AllocationAttributes
;
2676 InitializeListHead(&Section
->ViewListHead
);
2677 KeInitializeSpinLock(&Section
->ViewListLock
);
2680 * Check file access required
2682 if (SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
2684 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2688 FileAccess
= FILE_READ_DATA
;
2692 * We can't do memory mappings if the file system doesn't support the
2695 if (!(FileObject
->Flags
& FO_FCB_IS_VALID
))
2697 ObDereferenceObject(Section
);
2698 ObDereferenceObject(FileObject
);
2699 ExFreePool(ImageSections
);
2700 return(STATUS_INVALID_FILE_FOR_SECTION
);
2706 Status
= MmspWaitForFileLock(FileObject
);
2707 if (Status
!= STATUS_SUCCESS
)
2709 ObDereferenceObject(Section
);
2710 ObDereferenceObject(FileObject
);
2711 ExFreePool(ImageSections
);
2716 * allocate the section segments to describe the mapping
2718 NrSegments
= PEHeader
.FileHeader
.NumberOfSections
+ 1;
2719 Size
= sizeof(MM_IMAGE_SECTION_OBJECT
) + sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2720 ImageSectionObject
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_MM_SECTION_SEGMENT
);
2721 if (ImageSectionObject
== NULL
)
2723 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2724 ObDereferenceObject(Section
);
2725 ObDereferenceObject(FileObject
);
2726 ExFreePool(ImageSections
);
2727 return(STATUS_NO_MEMORY
);
2729 Section
->ImageSection
= ImageSectionObject
;
2730 ImageSectionObject
->NrSegments
= NrSegments
;
2731 ImageSectionObject
->ImageBase
= (PVOID
)PEHeader
.OptionalHeader
.ImageBase
;
2732 ImageSectionObject
->EntryPoint
= (PVOID
)PEHeader
.OptionalHeader
.AddressOfEntryPoint
;
2733 ImageSectionObject
->StackReserve
= PEHeader
.OptionalHeader
.SizeOfStackReserve
;
2734 ImageSectionObject
->StackCommit
= PEHeader
.OptionalHeader
.SizeOfStackCommit
;
2735 ImageSectionObject
->Subsystem
= PEHeader
.OptionalHeader
.Subsystem
;
2736 ImageSectionObject
->MinorSubsystemVersion
= PEHeader
.OptionalHeader
.MinorSubsystemVersion
;
2737 ImageSectionObject
->MajorSubsystemVersion
= PEHeader
.OptionalHeader
.MajorSubsystemVersion
;
2738 ImageSectionObject
->ImageCharacteristics
= PEHeader
.FileHeader
.Characteristics
;
2739 ImageSectionObject
->Machine
= PEHeader
.FileHeader
.Machine
;
2740 ImageSectionObject
->Executable
= (PEHeader
.OptionalHeader
.SizeOfCode
!= 0);
2742 SectionSegments
= ImageSectionObject
->Segments
;
2743 SectionSegments
[0].FileOffset
= 0;
2744 SectionSegments
[0].Characteristics
= IMAGE_SECTION_CHAR_DATA
;
2745 SectionSegments
[0].Protection
= PAGE_READONLY
;
2746 SectionSegments
[0].RawLength
= PAGE_SIZE
;
2747 SectionSegments
[0].Length
= PAGE_SIZE
;
2748 SectionSegments
[0].Flags
= 0;
2749 SectionSegments
[0].ReferenceCount
= 1;
2750 SectionSegments
[0].VirtualAddress
= 0;
2751 SectionSegments
[0].WriteCopy
= TRUE
;
2752 SectionSegments
[0].Attributes
= 0;
2753 ExInitializeFastMutex(&SectionSegments
[0].Lock
);
2754 RtlZeroMemory(&SectionSegments
[0].PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2755 for (i
= 1; i
< NrSegments
; i
++)
2757 SectionSegments
[i
].FileOffset
= ImageSections
[i
-1].PointerToRawData
;
2758 SectionSegments
[i
].Characteristics
= ImageSections
[i
-1].Characteristics
;
2761 * Set up the protection and write copy variables.
2763 Characteristics
= ImageSections
[i
- 1].Characteristics
;
2764 if (Characteristics
& (IMAGE_SECTION_CHAR_READABLE
|IMAGE_SECTION_CHAR_WRITABLE
|IMAGE_SECTION_CHAR_EXECUTABLE
))
2766 SectionSegments
[i
].Protection
= SectionCharacteristicsToProtect
[Characteristics
>> 28];
2767 SectionSegments
[i
].WriteCopy
= !(Characteristics
& IMAGE_SECTION_CHAR_SHARED
);
2769 else if (Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2771 SectionSegments
[i
].Protection
= PAGE_EXECUTE_READ
;
2772 SectionSegments
[i
].WriteCopy
= TRUE
;
2774 else if (Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2776 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2777 SectionSegments
[i
].WriteCopy
= TRUE
;
2779 else if (Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2781 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2782 SectionSegments
[i
].WriteCopy
= TRUE
;
2786 SectionSegments
[i
].Protection
= PAGE_NOACCESS
;
2787 SectionSegments
[i
].WriteCopy
= TRUE
;
2791 * Set up the attributes.
2793 if (Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2795 SectionSegments
[i
].Attributes
= 0;
2797 else if (Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2799 SectionSegments
[i
].Attributes
= 0;
2801 else if (Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2803 SectionSegments
[i
].Attributes
= MM_SECTION_SEGMENT_BSS
;
2807 SectionSegments
[i
].Attributes
= 0;
2810 SectionSegments
[i
].RawLength
= ImageSections
[i
-1].SizeOfRawData
;
2811 if (ImageSections
[i
-1].Misc
.VirtualSize
!= 0)
2813 SectionSegments
[i
].Length
= ImageSections
[i
-1].Misc
.VirtualSize
;
2817 SectionSegments
[i
].Length
= ImageSections
[i
-1].SizeOfRawData
;
2819 SectionSegments
[i
].Flags
= 0;
2820 SectionSegments
[i
].ReferenceCount
= 1;
2821 SectionSegments
[i
].VirtualAddress
= (PVOID
)ImageSections
[i
-1].VirtualAddress
;
2822 ExInitializeFastMutex(&SectionSegments
[i
].Lock
);
2823 RtlZeroMemory(&SectionSegments
[i
].PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2825 if (0 != InterlockedCompareExchange((PLONG
)&FileObject
->SectionObjectPointer
->ImageSectionObject
,
2826 (LONG
)ImageSectionObject
, 0))
2829 * An other thread has initialized the some image in the background
2831 ExFreePool(ImageSectionObject
);
2832 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
2833 Section
->ImageSection
= ImageSectionObject
;
2834 SectionSegments
= ImageSectionObject
->Segments
;
2836 for (i
= 0; i
< NrSegments
; i
++)
2838 InterlockedIncrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2841 ExFreePool(ImageSections
);
2846 * Create the section
2848 Status
= ObCreateObject (ExGetPreviousMode(),
2849 MmSectionObjectType
,
2851 ExGetPreviousMode(),
2853 sizeof(SECTION_OBJECT
),
2857 if (!NT_SUCCESS(Status
))
2859 ObDereferenceObject(FileObject
);
2866 Section
->SectionPageProtection
= SectionPageProtection
;
2867 Section
->AllocationAttributes
= AllocationAttributes
;
2868 InitializeListHead(&Section
->ViewListHead
);
2869 KeInitializeSpinLock(&Section
->ViewListLock
);
2872 * Check file access required
2874 if (SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
2876 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2880 FileAccess
= FILE_READ_DATA
;
2886 Status
= MmspWaitForFileLock(FileObject
);
2887 if (Status
!= STATUS_SUCCESS
)
2889 ObDereferenceObject(Section
);
2890 ObDereferenceObject(FileObject
);
2894 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
2895 Section
->ImageSection
= ImageSectionObject
;
2896 SectionSegments
= ImageSectionObject
->Segments
;
2897 NrSegments
= ImageSectionObject
->NrSegments
;
2900 * Otherwise just reference all the section segments
2902 for (i
= 0; i
< NrSegments
; i
++)
2904 InterlockedIncrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2908 Section
->FileObject
= FileObject
;
2909 CcRosReferenceCache(FileObject
);
2910 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2911 *SectionObject
= Section
;
2912 return(STATUS_SUCCESS
);
2919 NtCreateSection (OUT PHANDLE SectionHandle
,
2920 IN ACCESS_MASK DesiredAccess
,
2921 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
2922 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
2923 IN ULONG SectionPageProtection OPTIONAL
,
2924 IN ULONG AllocationAttributes
,
2925 IN HANDLE FileHandle OPTIONAL
)
2927 PSECTION_OBJECT SectionObject
;
2930 Status
= MmCreateSection(&SectionObject
,
2934 SectionPageProtection
,
2935 AllocationAttributes
,
2939 if (NT_SUCCESS(Status
))
2941 Status
= ObInsertObject ((PVOID
)SectionObject
,
2947 ObDereferenceObject(SectionObject
);
2954 /**********************************************************************
2972 NtOpenSection(PHANDLE SectionHandle
,
2973 ACCESS_MASK DesiredAccess
,
2974 POBJECT_ATTRIBUTES ObjectAttributes
)
2980 Status
= ObOpenObjectByName(ObjectAttributes
,
2981 MmSectionObjectType
,
2992 MmMapViewOfSegment(PEPROCESS Process
,
2993 PMADDRESS_SPACE AddressSpace
,
2994 PSECTION_OBJECT Section
,
2995 PMM_SECTION_SEGMENT Segment
,
3005 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3007 BoundaryAddressMultiple
.QuadPart
= 0;
3009 Status
= MmCreateMemoryArea(Process
,
3011 MEMORY_AREA_SECTION_VIEW
,
3018 BoundaryAddressMultiple
);
3019 if (!NT_SUCCESS(Status
))
3021 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
3022 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
);
3026 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3027 InsertTailList(&Section
->ViewListHead
,
3028 &MArea
->Data
.SectionData
.ViewListEntry
);
3029 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3031 ObReferenceObjectByPointer((PVOID
)Section
,
3034 ExGetPreviousMode());
3035 MArea
->Data
.SectionData
.Segment
= Segment
;
3036 MArea
->Data
.SectionData
.Section
= Section
;
3037 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3038 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3039 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3040 ViewSize
, 0, Protect
);
3042 return(STATUS_SUCCESS
);
3046 /**********************************************************************
3048 * NtMapViewOfSection
3051 * Maps a view of a section into the virtual address space of a
3056 * Handle of the section.
3059 * Handle of the process.
3062 * Desired base address (or NULL) on entry;
3063 * Actual base address of the view on exit.
3066 * Number of high order address bits that must be zero.
3069 * Size in bytes of the initially committed section of
3073 * Offset in bytes from the beginning of the section
3074 * to the beginning of the view.
3077 * Desired length of map (or zero to map all) on entry
3078 * Actual length mapped on exit.
3080 * InheritDisposition
3081 * Specified how the view is to be shared with
3085 * Type of allocation for the pages.
3088 * Protection for the committed region of the view.
3096 NtMapViewOfSection(HANDLE SectionHandle
,
3097 HANDLE ProcessHandle
,
3101 PLARGE_INTEGER SectionOffset
,
3103 SECTION_INHERIT InheritDisposition
,
3104 ULONG AllocationType
,
3107 PSECTION_OBJECT Section
;
3110 PMADDRESS_SPACE AddressSpace
;
3112 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3113 PROCESS_VM_OPERATION
,
3118 if (!NT_SUCCESS(Status
))
3123 AddressSpace
= &Process
->AddressSpace
;
3125 Status
= ObReferenceObjectByHandle(SectionHandle
,
3127 MmSectionObjectType
,
3131 if (!(NT_SUCCESS(Status
)))
3133 DPRINT("ObReference failed rc=%x\n",Status
);
3134 ObDereferenceObject(Process
);
3138 Status
= MmMapViewOfSection(Section
,
3149 ObDereferenceObject(Section
);
3150 ObDereferenceObject(Process
);
3156 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3157 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3161 PFILE_OBJECT FileObject
;
3164 SWAPENTRY SavedSwapEntry
;
3167 PSECTION_OBJECT Section
;
3168 PMM_SECTION_SEGMENT Segment
;
3170 MArea
= (PMEMORY_AREA
)Context
;
3172 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3174 Offset
= ((ULONG
)Address
- (ULONG
)MArea
->BaseAddress
);
3176 Section
= MArea
->Data
.SectionData
.Section
;
3177 Segment
= MArea
->Data
.SectionData
.Segment
;
3180 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3184 MmUnlockSectionSegment(Segment
);
3185 MmUnlockAddressSpace(&MArea
->Process
->AddressSpace
);
3187 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3188 if (Status
!= STATUS_SUCCESS
)
3190 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3194 MmLockAddressSpace(&MArea
->Process
->AddressSpace
);
3195 MmLockSectionSegment(Segment
);
3196 MmspCompleteAndReleasePageOp(PageOp
);
3197 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3200 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3203 * For a dirty, datafile, non-private page mark it as dirty in the
3206 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3208 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3210 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3211 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3212 CcRosMarkDirtyCacheSegment(Bcb
, Offset
);
3213 assert(SwapEntry
== 0);
3222 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3224 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3227 MmFreeSwapPage(SwapEntry
);
3231 if (IS_SWAP_FROM_SSE(Entry
) ||
3232 Page
!= PFN_FROM_SSE(Entry
))
3237 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3239 DPRINT1("Found a private page in a pagefile section.\n");
3243 * Just dereference private pages
3245 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3246 if (SavedSwapEntry
!= 0)
3248 MmFreeSwapPage(SavedSwapEntry
);
3249 MmSetSavedSwapEntryPage(Page
, 0);
3251 MmDeleteRmap(Page
, MArea
->Process
, Address
);
3252 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3256 MmDeleteRmap(Page
, MArea
->Process
, Address
);
3257 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3263 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3267 PMEMORY_AREA MemoryArea
;
3268 PSECTION_OBJECT Section
;
3269 PMM_SECTION_SEGMENT Segment
;
3271 PLIST_ENTRY CurrentEntry
;
3272 PMM_REGION CurrentRegion
;
3273 PLIST_ENTRY RegionListHead
;
3275 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
3277 if (MemoryArea
== NULL
)
3279 return(STATUS_UNSUCCESSFUL
);
3282 MemoryArea
->DeleteInProgress
= TRUE
;
3283 Section
= MemoryArea
->Data
.SectionData
.Section
;
3284 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3286 MmLockSectionSegment(Segment
);
3287 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3288 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
3289 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3291 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3292 while (!IsListEmpty(RegionListHead
))
3294 CurrentEntry
= RemoveHeadList(RegionListHead
);
3295 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3296 ExFreePool(CurrentRegion
);
3299 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3301 Status
= MmFreeMemoryArea(AddressSpace
,
3309 Status
= MmFreeMemoryArea(AddressSpace
,
3315 MmUnlockSectionSegment(Segment
);
3316 ObDereferenceObject(Section
);
3317 return(STATUS_SUCCESS
);
3324 MmUnmapViewOfSection(PEPROCESS Process
,
3328 PMEMORY_AREA MemoryArea
;
3329 PMADDRESS_SPACE AddressSpace
;
3330 PSECTION_OBJECT Section
;
3332 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3333 Process
, BaseAddress
);
3337 AddressSpace
= &Process
->AddressSpace
;
3338 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
3340 if (MemoryArea
== NULL
)
3342 return(STATUS_UNSUCCESSFUL
);
3345 Section
= MemoryArea
->Data
.SectionData
.Section
;
3347 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3351 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3352 PMM_SECTION_SEGMENT SectionSegments
;
3353 PVOID ImageBaseAddress
= 0;
3354 PMM_SECTION_SEGMENT Segment
;
3356 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3357 ImageSectionObject
= Section
->ImageSection
;
3358 SectionSegments
= ImageSectionObject
->Segments
;
3359 NrSegments
= ImageSectionObject
->NrSegments
;
3361 /* Search for the current segment within the section segments
3362 * and calculate the image base address */
3363 for (i
= 0; i
< NrSegments
; i
++)
3365 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3367 if (Segment
== &SectionSegments
[i
])
3369 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3374 if (i
>= NrSegments
)
3379 for (i
= 0; i
< NrSegments
; i
++)
3381 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3383 PVOID SBaseAddress
= (PVOID
)
3384 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3386 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
3392 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
3394 return(STATUS_SUCCESS
);
3397 /**********************************************************************
3399 * NtUnmapViewOfSection
3414 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3420 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3421 ProcessHandle
, BaseAddress
);
3423 DPRINT("Referencing process\n");
3424 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3425 PROCESS_VM_OPERATION
,
3430 if (!NT_SUCCESS(Status
))
3432 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3436 MmLockAddressSpace(&Process
->AddressSpace
);
3437 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3438 MmUnlockAddressSpace(&Process
->AddressSpace
);
3440 ObDereferenceObject(Process
);
3447 NtQuerySection (IN HANDLE SectionHandle
,
3448 IN CINT SectionInformationClass
,
3449 OUT PVOID SectionInformation
,
3451 OUT PULONG ResultLength
)
3453 * FUNCTION: Queries the information of a section object.
3455 * SectionHandle = Handle to the section link object
3456 * SectionInformationClass = Index to a certain information structure
3457 * SectionInformation (OUT)= Caller supplies storage for resulting
3459 * Length = Size of the supplied storage
3460 * ResultLength = Data written
3465 PSECTION_OBJECT Section
;
3468 Status
= ObReferenceObjectByHandle(SectionHandle
,
3470 MmSectionObjectType
,
3474 if (!(NT_SUCCESS(Status
)))
3479 switch (SectionInformationClass
)
3481 case SectionBasicInformation
:
3483 PSECTION_BASIC_INFORMATION Sbi
;
3485 if (Length
!= sizeof(SECTION_BASIC_INFORMATION
))
3487 ObDereferenceObject(Section
);
3488 return(STATUS_INFO_LENGTH_MISMATCH
);
3491 Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
3493 Sbi
->BaseAddress
= 0;
3494 Sbi
->Attributes
= 0;
3495 Sbi
->Size
.QuadPart
= 0;
3497 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
3498 Status
= STATUS_SUCCESS
;
3502 case SectionImageInformation
:
3504 PSECTION_IMAGE_INFORMATION Sii
;
3506 if (Length
!= sizeof(SECTION_IMAGE_INFORMATION
))
3508 ObDereferenceObject(Section
);
3509 return(STATUS_INFO_LENGTH_MISMATCH
);
3512 Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
3513 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
3514 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3516 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3517 ImageSectionObject
= Section
->ImageSection
;
3519 Sii
->EntryPoint
= ImageSectionObject
->EntryPoint
;
3520 Sii
->StackReserve
= ImageSectionObject
->StackReserve
;
3521 Sii
->StackCommit
= ImageSectionObject
->StackCommit
;
3522 Sii
->Subsystem
= ImageSectionObject
->Subsystem
;
3523 Sii
->MinorSubsystemVersion
= (USHORT
)ImageSectionObject
->MinorSubsystemVersion
;
3524 Sii
->MajorSubsystemVersion
= (USHORT
)ImageSectionObject
->MajorSubsystemVersion
;
3525 Sii
->Characteristics
= ImageSectionObject
->ImageCharacteristics
;
3526 Sii
->ImageNumber
= ImageSectionObject
->Machine
;
3527 Sii
->Executable
= ImageSectionObject
->Executable
;
3529 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
3530 Status
= STATUS_SUCCESS
;
3536 Status
= STATUS_INVALID_INFO_CLASS
;
3538 ObDereferenceObject(Section
);
3544 NtExtendSection(IN HANDLE SectionHandle
,
3545 IN ULONG NewMaximumSize
)
3548 return(STATUS_NOT_IMPLEMENTED
);
3552 /**********************************************************************
3554 * MmAllocateSection@4
3564 * Code taken from ntoskrnl/mm/special.c.
3569 MmAllocateSection (IN ULONG Length
)
3575 PMADDRESS_SPACE AddressSpace
;
3576 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3578 DPRINT("MmAllocateSection(Length %x)\n",Length
);
3580 BoundaryAddressMultiple
.QuadPart
= 0;
3582 AddressSpace
= MmGetKernelAddressSpace();
3584 MmLockAddressSpace(AddressSpace
);
3585 Status
= MmCreateMemoryArea (NULL
,
3594 BoundaryAddressMultiple
);
3595 MmUnlockAddressSpace(AddressSpace
);
3597 if (!NT_SUCCESS(Status
))
3601 DPRINT("Result %p\n",Result
);
3602 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
3606 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
3607 if (!NT_SUCCESS(Status
))
3609 DbgPrint("Unable to allocate page\n");
3612 Status
= MmCreateVirtualMapping (NULL
,
3613 ((char*)Result
+ (i
* PAGE_SIZE
)),
3617 if (!NT_SUCCESS(Status
))
3619 DbgPrint("Unable to create virtual mapping\n");
3623 return ((PVOID
)Result
);
3627 /**********************************************************************
3629 * MmMapViewOfSection
3632 * Maps a view of a section into the virtual address space of a
3637 * Pointer to the section object.
3640 * Pointer to the process.
3643 * Desired base address (or NULL) on entry;
3644 * Actual base address of the view on exit.
3647 * Number of high order address bits that must be zero.
3650 * Size in bytes of the initially committed section of
3654 * Offset in bytes from the beginning of the section
3655 * to the beginning of the view.
3658 * Desired length of map (or zero to map all) on entry
3659 * Actual length mapped on exit.
3661 * InheritDisposition
3662 * Specified how the view is to be shared with
3666 * Type of allocation for the pages.
3669 * Protection for the committed region of the view.
3677 MmMapViewOfSection(IN PVOID SectionObject
,
3678 IN PEPROCESS Process
,
3679 IN OUT PVOID
*BaseAddress
,
3681 IN ULONG CommitSize
,
3682 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3683 IN OUT PULONG ViewSize
,
3684 IN SECTION_INHERIT InheritDisposition
,
3685 IN ULONG AllocationType
,
3688 PSECTION_OBJECT Section
;
3689 PMADDRESS_SPACE AddressSpace
;
3691 NTSTATUS Status
= STATUS_SUCCESS
;
3695 Section
= (PSECTION_OBJECT
)SectionObject
;
3696 AddressSpace
= &Process
->AddressSpace
;
3698 MmLockAddressSpace(AddressSpace
);
3700 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3706 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3707 PMM_SECTION_SEGMENT SectionSegments
;
3709 ImageSectionObject
= Section
->ImageSection
;
3710 SectionSegments
= ImageSectionObject
->Segments
;
3711 NrSegments
= ImageSectionObject
->NrSegments
;
3714 ImageBase
= *BaseAddress
;
3715 if (ImageBase
== NULL
)
3717 ImageBase
= ImageSectionObject
->ImageBase
;
3721 for (i
= 0; i
< NrSegments
; i
++)
3723 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3726 MaxExtent
= (ULONG
)((char*)SectionSegments
[i
].VirtualAddress
+
3727 SectionSegments
[i
].Length
);
3728 ImageSize
= max(ImageSize
, MaxExtent
);
3732 /* Check there is enough space to map the section at that point. */
3733 if (MmOpenMemoryAreaByRegion(AddressSpace
, ImageBase
,
3734 PAGE_ROUND_UP(ImageSize
)) != NULL
)
3736 /* Fail if the user requested a fixed base address. */
3737 if ((*BaseAddress
) != NULL
)
3739 MmUnlockAddressSpace(AddressSpace
);
3740 return(STATUS_UNSUCCESSFUL
);
3742 /* Otherwise find a gap to map the image. */
3743 ImageBase
= MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), FALSE
);
3744 if (ImageBase
== NULL
)
3746 MmUnlockAddressSpace(AddressSpace
);
3747 return(STATUS_UNSUCCESSFUL
);
3751 for (i
= 0; i
< NrSegments
; i
++)
3753 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3755 PVOID SBaseAddress
= (PVOID
)
3756 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3757 MmLockSectionSegment(&SectionSegments
[i
]);
3758 Status
= MmMapViewOfSegment(Process
,
3761 &SectionSegments
[i
],
3763 SectionSegments
[i
].Length
,
3764 SectionSegments
[i
].Protection
,
3765 (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
,
3767 MmUnlockSectionSegment(&SectionSegments
[i
]);
3768 if (!NT_SUCCESS(Status
))
3770 MmUnlockAddressSpace(AddressSpace
);
3776 *BaseAddress
= ImageBase
;
3780 if (ViewSize
== NULL
)
3782 /* Following this pointer would lead to us to the dark side */
3783 /* What to do? Bugcheck? Return status? Do the mambo? */
3784 KEBUGCHECK(MEMORY_MANAGEMENT
);
3787 if (SectionOffset
== NULL
)
3793 ViewOffset
= SectionOffset
->u
.LowPart
;
3796 if ((ViewOffset
% PAGE_SIZE
) != 0)
3798 MmUnlockAddressSpace(AddressSpace
);
3799 return(STATUS_MAPPED_ALIGNMENT
);
3802 if ((*ViewSize
) == 0)
3804 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
3806 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
3808 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
3811 MmLockSectionSegment(Section
->Segment
);
3812 Status
= MmMapViewOfSegment(Process
,
3820 (AllocationType
& MEM_TOP_DOWN
));
3821 MmUnlockSectionSegment(Section
->Segment
);
3822 if (!NT_SUCCESS(Status
))
3824 MmUnlockAddressSpace(AddressSpace
);
3829 MmUnlockAddressSpace(AddressSpace
);
3831 return(STATUS_SUCCESS
);
3838 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
3839 IN PLARGE_INTEGER NewFileSize
)
3850 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
3860 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
3861 IN MMFLUSH_TYPE FlushType
)
3865 case MmFlushForDelete
:
3866 if (SectionObjectPointer
->ImageSectionObject
||
3867 SectionObjectPointer
->DataSectionObject
)
3871 CcRosSetRemoveOnClose(SectionObjectPointer
);
3873 case MmFlushForWrite
:
3883 MmForceSectionClosed (DWORD Unknown0
,
3895 MmMapViewInSystemSpace (IN PVOID SectionObject
,
3896 OUT PVOID
* MappedBase
,
3897 IN OUT PULONG ViewSize
)
3899 PSECTION_OBJECT Section
;
3900 PMADDRESS_SPACE AddressSpace
;
3903 DPRINT("MmMapViewInSystemSpace() called\n");
3905 Section
= (PSECTION_OBJECT
)SectionObject
;
3906 AddressSpace
= MmGetKernelAddressSpace();
3908 MmLockAddressSpace(AddressSpace
);
3911 if ((*ViewSize
) == 0)
3913 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
3915 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
3917 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
3920 MmLockSectionSegment(Section
->Segment
);
3923 Status
= MmMapViewOfSegment(NULL
,
3933 MmUnlockSectionSegment(Section
->Segment
);
3934 MmUnlockAddressSpace(AddressSpace
);
3944 MmMapViewInSessionSpace (
3946 OUT PVOID
*MappedBase
,
3947 IN OUT PSIZE_T ViewSize
3951 return STATUS_NOT_IMPLEMENTED
;
3959 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
3961 PMADDRESS_SPACE AddressSpace
;
3964 DPRINT("MmUnmapViewInSystemSpace() called\n");
3966 AddressSpace
= MmGetKernelAddressSpace();
3968 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
3978 MmUnmapViewInSessionSpace (
3983 return STATUS_NOT_IMPLEMENTED
;
3990 MmSetBankedSection (DWORD Unknown0
,
3998 return (STATUS_NOT_IMPLEMENTED
);
4002 /**********************************************************************
4007 * Creates a section object.
4010 * SectionObject (OUT)
4011 * Caller supplied storage for the resulting pointer
4012 * to a SECTION_OBJECT instance;
4015 * Specifies the desired access to the section can be a
4017 * STANDARD_RIGHTS_REQUIRED |
4019 * SECTION_MAP_WRITE |
4020 * SECTION_MAP_READ |
4021 * SECTION_MAP_EXECUTE
4023 * ObjectAttributes [OPTIONAL]
4024 * Initialized attributes for the object can be used
4025 * to create a named section;
4028 * Maximizes the size of the memory section. Must be
4029 * non-NULL for a page-file backed section.
4030 * If value specified for a mapped file and the file is
4031 * not large enough, file will be extended.
4033 * SectionPageProtection
4034 * Can be a combination of:
4040 * AllocationAttributes
4041 * Can be a combination of:
4046 * Handle to a file to create a section mapped to a file
4047 * instead of a memory backed section;
4058 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4059 IN ACCESS_MASK DesiredAccess
,
4060 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4061 IN PLARGE_INTEGER MaximumSize
,
4062 IN ULONG SectionPageProtection
,
4063 IN ULONG AllocationAttributes
,
4064 IN HANDLE FileHandle OPTIONAL
,
4065 IN PFILE_OBJECT File OPTIONAL
)
4067 if (AllocationAttributes
& SEC_IMAGE
)
4069 return(MmCreateImageSection(SectionObject
,
4073 SectionPageProtection
,
4074 AllocationAttributes
,
4078 if (FileHandle
!= NULL
)
4080 return(MmCreateDataFileSection(SectionObject
,
4084 SectionPageProtection
,
4085 AllocationAttributes
,
4089 return(MmCreatePageFileSection(SectionObject
,
4093 SectionPageProtection
,
4094 AllocationAttributes
));