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.129 2003/10/07 14:00:10 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 *****************************************************************/
32 #define NTOS_MODE_KERNEL
34 #include <internal/mm.h>
35 #include <internal/io.h>
36 #include <internal/ps.h>
37 #include <internal/pool.h>
38 #include <internal/cc.h>
39 #include <ddk/ntifs.h>
40 #include <ntos/minmax.h>
43 #include <internal/debug.h>
45 /* TYPES *********************************************************************/
49 PSECTION_OBJECT Section
;
50 PMM_SECTION_SEGMENT Segment
;
54 } MM_SECTION_PAGEOUT_CONTEXT
;
56 /* GLOBALS *******************************************************************/
58 POBJECT_TYPE EXPORTED MmSectionObjectType
= NULL
;
60 static GENERIC_MAPPING MmpSectionMapping
= {
61 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
62 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
63 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
66 #define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S')
67 #define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T')
69 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
70 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
71 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
72 #define MAX_SHARE_COUNT 0x7FF
73 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
74 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
75 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
77 /* FUNCTIONS *****************************************************************/
80 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
83 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
85 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
87 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
89 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
96 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
98 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
100 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
101 PMM_SECTION_SEGMENT SectionSegments
;
105 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
106 NrSegments
= ImageSectionObject
->NrSegments
;
107 SectionSegments
= ImageSectionObject
->Segments
;
108 for (i
= 0; i
< NrSegments
; i
++)
110 if (SectionSegments
[i
].ReferenceCount
!= 0)
112 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
113 SectionSegments
[i
].ReferenceCount
);
116 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
118 ExFreePool(ImageSectionObject
);
119 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
121 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
123 PMM_SECTION_SEGMENT Segment
;
125 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
128 if (Segment
->ReferenceCount
!= 0)
130 DPRINT1("Data segment still referenced\n");
133 MmFreePageTablesSectionSegment(Segment
);
135 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
140 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
142 ExAcquireFastMutex(&Segment
->Lock
);
146 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
148 ExReleaseFastMutex(&Segment
->Lock
);
152 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
156 PSECTION_PAGE_TABLE Table
;
157 ULONG DirectoryOffset
;
160 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
162 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
166 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
167 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
171 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
172 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
173 TAG_SECTION_PAGE_TABLE
);
178 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
179 DPRINT("Table %x\n", Table
);
182 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
183 Table
->Entry
[TableOffset
] = Entry
;
188 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
191 PSECTION_PAGE_TABLE Table
;
193 ULONG DirectoryOffset
;
196 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
198 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
200 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
204 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
205 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
206 DPRINT("Table %x\n", Table
);
212 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
213 Entry
= Table
->Entry
[TableOffset
];
218 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
223 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
226 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
229 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
231 DPRINT1("Maximum share count reached\n");
234 if (IS_SWAP_FROM_SSE(Entry
))
238 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
239 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
243 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section
,
244 PMM_SECTION_SEGMENT Segment
,
250 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
253 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
256 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
258 DPRINT1("Zero share count for unshare\n");
261 if (IS_SWAP_FROM_SSE(Entry
))
265 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
267 * If we reducing the share count of this entry to zero then set the entry
268 * to zero and tell the cache the page is no longer mapped.
270 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
272 PFILE_OBJECT FileObject
;
274 SWAPENTRY SavedSwapEntry
;
275 PHYSICAL_ADDRESS Page
;
276 BOOLEAN IsImageSection
;
279 FileOffset
= Offset
+ Segment
->FileOffset
;
281 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
283 Page
= (PHYSICAL_ADDRESS
)(LONGLONG
)PAGE_FROM_SSE(Entry
);
284 FileObject
= Section
->FileObject
;
285 if (FileObject
!= NULL
)
288 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
289 (FileOffset
% PAGE_SIZE
) == 0 &&
290 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
293 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
294 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
295 if (!NT_SUCCESS(Status
))
297 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
303 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
304 if (SavedSwapEntry
== 0)
306 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
310 * Try to page out this page and set the swap entry
311 * within the section segment. There exist no rmap entry
312 * for this page. The pager thread can't page out a
313 * page without a rmap entry.
315 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
316 MmReferencePage(Page
);
320 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
325 MmSetSavedSwapEntryPage(Page
, 0);
326 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
328 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
332 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
333 MmFreeSwapPage(SavedSwapEntry
);
339 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
341 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
344 BOOL
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
348 PCACHE_SEGMENT CacheSeg
;
350 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
351 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
354 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
361 MiReadPage(PMEMORY_AREA MemoryArea
,
363 PHYSICAL_ADDRESS
* Page
)
365 * FUNCTION: Read a page for a section backed memory area.
367 * MemoryArea - Memory area to read the page for.
368 * Offset - Offset of the page to read.
369 * Page - Variable that receives a page contains the read data.
376 PCACHE_SEGMENT CacheSeg
;
377 PFILE_OBJECT FileObject
;
381 BOOLEAN IsImageSection
;
384 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
385 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
386 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
387 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
388 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
392 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
395 * If the file system is letting us go directly to the cache and the
396 * memory area was mapped at an offset in the file which is page aligned
397 * then get the related cache segment.
399 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
400 (FileOffset
% PAGE_SIZE
) == 0 &&
401 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
))
403 PHYSICAL_ADDRESS Addr
;
406 * Get the related cache segment; we use a lower level interface than
407 * filesystems do because it is safe for us to use an offset with a
408 * alignment less than the file system block size.
410 Status
= CcRosGetCacheSegment(Bcb
,
416 if (!NT_SUCCESS(Status
))
423 * If the cache segment isn't up to date then call the file
424 * system to read in the data.
426 Status
= ReadCacheSegment(CacheSeg
);
427 if (!NT_SUCCESS(Status
))
429 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
434 * Retrieve the page from the cache segment that we actually want.
436 Addr
= MmGetPhysicalAddress(BaseAddress
+
437 FileOffset
- BaseOffset
);
439 MmReferencePage((*Page
));
441 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
446 ULONG CacheSegOffset
;
448 * Allocate a page, this is rather complicated by the possibility
449 * we might have to move other things out of memory
451 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
452 if (!NT_SUCCESS(Status
))
456 Status
= CcRosGetCacheSegment(Bcb
,
462 if (!NT_SUCCESS(Status
))
469 * If the cache segment isn't up to date then call the file
470 * system to read in the data.
472 Status
= ReadCacheSegment(CacheSeg
);
473 if (!NT_SUCCESS(Status
))
475 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
479 PageAddr
= ExAllocatePageWithPhysPage(*Page
);
480 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
481 Length
= RawLength
- SegOffset
;
482 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
484 memcpy(PageAddr
, BaseAddress
+ FileOffset
- BaseOffset
, Length
);
486 else if (CacheSegOffset
>= PAGE_SIZE
)
488 memcpy(PageAddr
, BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
492 memcpy(PageAddr
, BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
493 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
494 Status
= CcRosGetCacheSegment(Bcb
,
495 FileOffset
+ CacheSegOffset
,
500 if (!NT_SUCCESS(Status
))
502 ExUnmapPage(PageAddr
);
508 * If the cache segment isn't up to date then call the file
509 * system to read in the data.
511 Status
= ReadCacheSegment(CacheSeg
);
512 if (!NT_SUCCESS(Status
))
514 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
515 ExUnmapPage(PageAddr
);
519 if (Length
< PAGE_SIZE
)
521 memcpy(PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
525 memcpy(PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
528 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
529 ExUnmapPage(PageAddr
);
531 return(STATUS_SUCCESS
);
535 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
536 MEMORY_AREA
* MemoryArea
,
544 PSECTION_OBJECT Section
;
545 PMM_SECTION_SEGMENT Segment
;
551 LARGE_INTEGER Timeout
;
554 * There is a window between taking the page fault and locking the
555 * address space when another thread could load the page so we check
558 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
562 MmLockPage(MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
));
564 return(STATUS_SUCCESS
);
567 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
568 Offset
= PAddress
- (ULONG
)MemoryArea
->BaseAddress
;
570 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
571 Section
= MemoryArea
->Data
.SectionData
.Section
;
572 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
573 &MemoryArea
->Data
.SectionData
.RegionListHead
,
578 MmLockSectionSegment(Segment
);
581 * Check if this page needs to be mapped COW
583 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
584 (Region
->Protect
== PAGE_READWRITE
||
585 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
587 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
591 Attributes
= Region
->Protect
;
595 * Get or create a page operation descriptor
597 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
);
600 DPRINT1("MmGetPageOp failed\n");
605 * Check if someone else is already handling this fault, if so wait
608 if (PageOp
->Thread
!= PsGetCurrentThread())
610 MmUnlockSectionSegment(Segment
);
611 MmUnlockAddressSpace(AddressSpace
);
612 Timeout
.QuadPart
= -100000000LL; // 10 sec
613 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
620 * Check for various strange conditions
622 if (Status
!= STATUS_SUCCESS
)
624 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
627 if (PageOp
->Status
== STATUS_PENDING
)
629 DPRINT1("Woke for page op before completion\n");
632 MmLockAddressSpace(AddressSpace
);
634 * If this wasn't a pagein then restart the operation
636 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
638 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
639 MmReleasePageOp(PageOp
);
640 DPRINT("Address 0x%.8X\n", Address
);
641 return(STATUS_MM_RESTART_OPERATION
);
645 * If the thread handling this fault has failed then we don't retry
647 if (!NT_SUCCESS(PageOp
->Status
))
649 Status
= PageOp
->Status
;
650 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
651 MmReleasePageOp(PageOp
);
652 DPRINT("Address 0x%.8X\n", Address
);
655 MmLockSectionSegment(Segment
);
657 * If the completed fault was for another address space then set the
660 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
662 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
665 MmUnlockSectionSegment(Segment
);
666 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
667 MmReleasePageOp(PageOp
);
668 return(STATUS_MM_RESTART_OPERATION
);
671 Page
= (LARGE_INTEGER
)(LONGLONG
)(PAGE_FROM_SSE(Entry
));
672 MmReferencePage(Page
);
673 MmSharePageEntrySectionSegment(Segment
, Offset
);
675 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
680 if (Status
== STATUS_NO_MEMORY
)
682 MmUnlockAddressSpace(AddressSpace
);
683 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
688 MmLockAddressSpace(AddressSpace
);
691 if (!NT_SUCCESS(Status
))
693 DbgPrint("Unable to create virtual mapping\n");
696 MmInsertRmap(Page
, MemoryArea
->Process
, (PVOID
)PAddress
);
702 MmUnlockSectionSegment(Segment
);
703 PageOp
->Status
= STATUS_SUCCESS
;
704 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
705 MmReleasePageOp(PageOp
);
706 DPRINT("Address 0x%.8X\n", Address
);
707 return(STATUS_SUCCESS
);
711 * Must be private page we have swapped out.
713 if (MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
))
721 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
723 DPRINT1("Found a swaped out private page in a pagefile section.\n");
727 MmUnlockSectionSegment(Segment
);
728 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
730 MmUnlockAddressSpace(AddressSpace
);
731 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
732 if (!NT_SUCCESS(Status
))
737 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
738 MmBuildMdlFromPages(Mdl
, (PULONG
)&Page
);
739 Status
= MmReadFromSwapPage(SwapEntry
, Mdl
);
740 if (!NT_SUCCESS(Status
))
742 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
745 MmLockAddressSpace(AddressSpace
);
746 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
751 if (Status
== STATUS_NO_MEMORY
)
753 MmUnlockAddressSpace(AddressSpace
);
754 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
759 MmLockAddressSpace(AddressSpace
);
761 if (!NT_SUCCESS(Status
))
763 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
769 * Store the swap entry for later use.
771 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
774 * Add the page to the process's working set
776 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
779 * Finish the operation
783 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
785 PageOp
->Status
= STATUS_SUCCESS
;
786 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
787 MmReleasePageOp(PageOp
);
788 DPRINT("Address 0x%.8X\n", Address
);
789 return(STATUS_SUCCESS
);
793 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
795 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
797 MmUnlockSectionSegment(Segment
);
799 * Just map the desired physical page
801 Page
.QuadPart
= Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
;
802 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
807 if (Status
== STATUS_NO_MEMORY
)
809 MmUnlockAddressSpace(AddressSpace
);
810 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
815 MmLockAddressSpace(AddressSpace
);
817 if (!NT_SUCCESS(Status
))
819 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
824 * Don't add an rmap entry since the page mapped could be for
833 * Cleanup and release locks
835 PageOp
->Status
= STATUS_SUCCESS
;
836 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
837 MmReleasePageOp(PageOp
);
838 DPRINT("Address 0x%.8X\n", Address
);
839 return(STATUS_SUCCESS
);
843 * Map anonymous memory for BSS sections
845 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
)
847 MmUnlockSectionSegment(Segment
);
848 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
849 if (!NT_SUCCESS(Status
))
851 MmUnlockAddressSpace(AddressSpace
);
852 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
853 MmLockAddressSpace(AddressSpace
);
855 if (!NT_SUCCESS(Status
))
859 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
864 if (Status
== STATUS_NO_MEMORY
)
866 MmUnlockAddressSpace(AddressSpace
);
867 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
872 MmLockAddressSpace(AddressSpace
);
875 if (!NT_SUCCESS(Status
))
877 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
881 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
888 * Cleanup and release locks
890 PageOp
->Status
= STATUS_SUCCESS
;
891 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
892 MmReleasePageOp(PageOp
);
893 DPRINT("Address 0x%.8X\n", Address
);
894 return(STATUS_SUCCESS
);
898 * Get the entry corresponding to the offset within the section
900 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
905 * If the entry is zero (and it can't change because we have
906 * locked the segment) then we need to load the page.
910 * Release all our locks and read in the page from disk
912 MmUnlockSectionSegment(Segment
);
913 MmUnlockAddressSpace(AddressSpace
);
915 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
916 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
918 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
919 if (!NT_SUCCESS(Status
))
921 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
926 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
927 if (!NT_SUCCESS(Status
))
929 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
932 if (!NT_SUCCESS(Status
))
935 * FIXME: What do we know in this case?
938 * Cleanup and release locks
940 MmLockAddressSpace(AddressSpace
);
941 PageOp
->Status
= Status
;
942 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
943 MmReleasePageOp(PageOp
);
944 DPRINT("Address 0x%.8X\n", Address
);
948 * Relock the address space and segment
950 MmLockAddressSpace(AddressSpace
);
951 MmLockSectionSegment(Segment
);
954 * Check the entry. No one should change the status of a page
955 * that has a pending page-in.
957 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
960 DbgPrint("Someone changed ppte entry while we slept\n");
965 * Mark the offset within the section as having valid, in-memory
968 Entry
= MAKE_SSE(Page
.u
.LowPart
, 1);
969 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
970 MmUnlockSectionSegment(Segment
);
972 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
977 if (Status
== STATUS_NO_MEMORY
)
979 MmUnlockAddressSpace(AddressSpace
);
980 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
985 MmLockAddressSpace(AddressSpace
);
987 if (!NT_SUCCESS(Status
))
989 DbgPrint("Unable to create virtual mapping\n");
992 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
998 PageOp
->Status
= STATUS_SUCCESS
;
999 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1000 MmReleasePageOp(PageOp
);
1001 DPRINT("Address 0x%.8X\n", Address
);
1002 return(STATUS_SUCCESS
);
1004 else if (IS_SWAP_FROM_SSE(Entry
))
1006 SWAPENTRY SwapEntry
;
1009 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1012 * Release all our locks and read in the page from disk
1014 MmUnlockSectionSegment(Segment
);
1016 MmUnlockAddressSpace(AddressSpace
);
1018 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1019 if (!NT_SUCCESS(Status
))
1024 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1025 MmBuildMdlFromPages(Mdl
, (PULONG
)&Page
);
1026 Status
= MmReadFromSwapPage(SwapEntry
, Mdl
);
1027 if (!NT_SUCCESS(Status
))
1033 * Relock the address space and segment
1035 MmLockAddressSpace(AddressSpace
);
1036 MmLockSectionSegment(Segment
);
1039 * Check the entry. No one should change the status of a page
1040 * that has a pending page-in.
1042 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1043 if (Entry
!= Entry1
)
1045 DbgPrint("Someone changed ppte entry while we slept\n");
1050 * Mark the offset within the section as having valid, in-memory
1053 Entry
= MAKE_SSE(Page
.u
.LowPart
, 1);
1054 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1055 MmUnlockSectionSegment(Segment
);
1058 * Save the swap entry.
1060 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1061 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1066 if (Status
== STATUS_NO_MEMORY
)
1068 MmUnlockAddressSpace(AddressSpace
);
1069 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1074 MmLockAddressSpace(AddressSpace
);
1076 if (!NT_SUCCESS(Status
))
1078 DbgPrint("Unable to create virtual mapping\n");
1081 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1086 PageOp
->Status
= STATUS_SUCCESS
;
1087 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1088 MmReleasePageOp(PageOp
);
1089 DPRINT("Address 0x%.8X\n", Address
);
1090 return(STATUS_SUCCESS
);
1095 * If the section offset is already in-memory and valid then just
1096 * take another reference to the page
1099 Page
= (LARGE_INTEGER
)(LONGLONG
)PAGE_FROM_SSE(Entry
);
1100 MmReferencePage(Page
);
1101 MmSharePageEntrySectionSegment(Segment
, Offset
);
1102 MmUnlockSectionSegment(Segment
);
1104 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1109 if (Status
== STATUS_NO_MEMORY
)
1111 MmUnlockAddressSpace(AddressSpace
);
1112 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1117 MmLockAddressSpace(AddressSpace
);
1119 if (!NT_SUCCESS(Status
))
1121 DbgPrint("Unable to create virtual mapping\n");
1124 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1129 PageOp
->Status
= STATUS_SUCCESS
;
1130 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1131 MmReleasePageOp(PageOp
);
1132 DPRINT("Address 0x%.8X\n", Address
);
1133 return(STATUS_SUCCESS
);
1138 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1139 MEMORY_AREA
* MemoryArea
,
1143 PMM_SECTION_SEGMENT Segment
;
1144 PSECTION_OBJECT Section
;
1145 PHYSICAL_ADDRESS OldPage
;
1146 PHYSICAL_ADDRESS NewPage
;
1153 LARGE_INTEGER Timeout
;
1156 * Check if the page has been paged out or has already been set readwrite
1158 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1159 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1161 DPRINT("Address 0x%.8X\n", Address
);
1162 return(STATUS_SUCCESS
);
1166 * Find the offset of the page
1168 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
1169 Offset
= PAddress
- (ULONG
)MemoryArea
->BaseAddress
;
1171 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1172 Section
= MemoryArea
->Data
.SectionData
.Section
;
1173 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1174 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1179 MmLockSectionSegment(Segment
);
1184 if (MmGetPageEntrySectionSegment(Segment
, Offset
) == 0)
1186 DPRINT1("COW fault for page with PESS 0. Address was 0x%.8X\n",
1189 MmUnlockSectionSegment(Segment
);
1191 * Check if we are doing COW
1193 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1194 (Region
->Protect
== PAGE_READWRITE
||
1195 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1197 DPRINT("Address 0x%.8X\n", Address
);
1198 return(STATUS_UNSUCCESSFUL
);
1202 * Get or create a pageop
1204 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
,
1205 MM_PAGEOP_ACCESSFAULT
);
1208 DPRINT1("MmGetPageOp failed\n");
1213 * Wait for any other operations to complete
1215 if (PageOp
->Thread
!= PsGetCurrentThread())
1217 MmUnlockAddressSpace(AddressSpace
);
1218 Timeout
.QuadPart
= -100000000LL; // 10 sec
1219 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
1225 * Check for various strange conditions
1227 if (Status
== STATUS_TIMEOUT
)
1229 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1232 if (PageOp
->Status
== STATUS_PENDING
)
1234 DPRINT1("Woke for page op before completion\n");
1238 * Restart the operation
1240 MmLockAddressSpace(AddressSpace
);
1241 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1242 MmReleasePageOp(PageOp
);
1243 DPRINT("Address 0x%.8X\n", Address
);
1244 return(STATUS_MM_RESTART_OPERATION
);
1248 * Release locks now we have the pageop
1250 MmUnlockAddressSpace(AddressSpace
);
1255 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1256 if (!NT_SUCCESS(Status
))
1264 OldPage
= MmGetPhysicalAddressForProcess(NULL
, Address
);
1266 NewAddress
= ExAllocatePageWithPhysPage(NewPage
);
1267 memcpy(NewAddress
, (PVOID
)PAddress
, PAGE_SIZE
);
1268 ExUnmapPage(NewAddress
);
1271 * Delete the old entry.
1273 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1276 * Set the PTE to point to the new page
1278 MmLockAddressSpace(AddressSpace
);
1279 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1284 if (Status
== STATUS_NO_MEMORY
)
1286 MmUnlockAddressSpace(AddressSpace
);
1287 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1292 MmLockAddressSpace(AddressSpace
);
1294 if (!NT_SUCCESS(Status
))
1296 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1300 MmInsertRmap(NewPage
, AddressSpace
->Process
, (PVOID
)PAddress
);
1301 if (!NT_SUCCESS(Status
))
1303 DbgPrint("Unable to create virtual mapping\n");
1308 MmLockPage(NewPage
);
1312 * Unshare the old page.
1314 MmDeleteRmap(OldPage
, AddressSpace
->Process
, (PVOID
)PAddress
);
1315 MmLockSectionSegment(Segment
);
1316 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
);
1317 MmUnlockSectionSegment(Segment
);
1318 MmReleasePageMemoryConsumer(MC_USER
, OldPage
);
1320 PageOp
->Status
= STATUS_SUCCESS
;
1321 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1322 MmReleasePageOp(PageOp
);
1323 DPRINT("Address 0x%.8X\n", Address
);
1324 return(STATUS_SUCCESS
);
1328 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1330 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1332 PHYSICAL_ADDRESS Page
;
1334 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1335 MmDeleteVirtualMapping(Process
,
1342 PageOutContext
->WasDirty
= TRUE
;
1344 if (!PageOutContext
->Private
)
1346 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1347 PageOutContext
->Segment
,
1348 PageOutContext
->Offset
,
1349 PageOutContext
->WasDirty
);
1351 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1352 DPRINT("PhysicalAddress %I64x, Address %x\n", Page
, Address
);
1356 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1357 MEMORY_AREA
* MemoryArea
,
1361 PHYSICAL_ADDRESS PhysicalAddress
;
1362 MM_SECTION_PAGEOUT_CONTEXT Context
;
1363 SWAPENTRY SwapEntry
;
1368 PFILE_OBJECT FileObject
;
1370 BOOLEAN DirectMapped
;
1371 BOOLEAN IsImageSection
;
1373 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1376 * Get the segment and section.
1378 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1379 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1381 Context
.Offset
= (ULONG
)(Address
- (ULONG
)MemoryArea
->BaseAddress
);
1382 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1384 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1386 FileObject
= Context
.Section
->FileObject
;
1387 DirectMapped
= FALSE
;
1388 if (FileObject
!= NULL
)
1390 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1393 * If the file system is letting us go directly to the cache and the
1394 * memory area was mapped at an offset in the file which is page aligned
1395 * then note this is a direct mapped page.
1397 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
1398 (FileOffset
% PAGE_SIZE
) == 0 &&
1399 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1401 DirectMapped
= TRUE
;
1407 * This should never happen since mappings of physical memory are never
1408 * placed in the rmap lists.
1410 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1412 DPRINT1("Trying to page out from physical memory section address 0x%X "
1413 "process %d\n", Address
,
1414 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1419 * Get the section segment entry and the physical address.
1421 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1422 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1424 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1425 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1429 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1430 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1433 * Prepare the context structure for the rmap delete call.
1435 Context
.WasDirty
= FALSE
;
1436 if (Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1437 IS_SWAP_FROM_SSE(Entry
) ||
1438 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
)
1440 Context
.Private
= TRUE
;
1444 Context
.Private
= FALSE
;
1448 * Paging out data mapped read-only is easy.
1450 if (Context
.Segment
->Protection
& (PAGE_READONLY
|PAGE_EXECUTE_READ
))
1453 * Read-only data should never be in the swapfile.
1457 DPRINT1("SwapEntry != 0 was 0x%.8X at address 0x%.8X, "
1458 "paddress 0x%.8X\n", SwapEntry
, Address
,
1464 * Read-only data should never be COWed
1466 if (Context
.Private
)
1468 DPRINT1("Had private copy of read-only page.\n");
1473 * Delete all mappings of this page.
1475 MmDeleteAllRmaps(PhysicalAddress
, (PVOID
)&Context
,
1476 MmPageOutDeleteMapping
);
1477 if (Context
.WasDirty
)
1479 DPRINT1("Had a dirty page of a read-only page.\n");
1483 PageOp
->Status
= STATUS_SUCCESS
;
1484 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1485 MmReleasePageOp(PageOp
);
1486 return(STATUS_SUCCESS
);
1490 * Otherwise we have read-write data.
1494 * Take an additional reference to the page or the cache segment.
1496 if (DirectMapped
&& !Context
.Private
)
1498 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1500 DPRINT1("Direct mapped non private page is not associated with the cache.\n")
1506 MmReferencePage(PhysicalAddress
);
1509 MmDeleteAllRmaps(PhysicalAddress
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1512 * If this wasn't a private page then we should have reduced the entry to
1513 * zero by deleting all the rmaps.
1515 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1517 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
))
1525 * If the page wasn't dirty then we can just free it as for a readonly page.
1526 * Since we unmapped all the mappings above we know it will not suddenly
1528 * If the page is from a pagefile section and has no swap entry,
1529 * we can't free the page at this point.
1531 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1532 if (!Context
.WasDirty
&&
1533 !(SwapEntry
== 0 && Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
))
1536 if (Context
.Private
)
1538 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
1539 if (!(Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
) &&
1542 DPRINT1("Private page, non-dirty but not swapped out "
1543 "process %d address 0x%.8X\n",
1544 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0,
1550 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1553 if (!NT_SUCCESS(Status
))
1559 if (DirectMapped
&& !Context
.Private
)
1561 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1562 if (!NT_SUCCESS(Status
))
1564 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1570 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1573 PageOp
->Status
= STATUS_SUCCESS
;
1574 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1575 MmReleasePageOp(PageOp
);
1576 return(STATUS_SUCCESS
);
1580 * If this page was direct mapped from the cache then the cache manager
1581 * will already have taken care of writing it back.
1583 if (DirectMapped
&& !Context
.Private
)
1585 assert(SwapEntry
== 0);
1586 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1587 if (!NT_SUCCESS(Status
))
1589 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
1592 PageOp
->Status
= STATUS_SUCCESS
;
1593 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1594 MmReleasePageOp(PageOp
);
1595 return(STATUS_SUCCESS
);
1599 * If necessary, allocate an entry in the paging file for this page
1603 SwapEntry
= MmAllocSwapPage();
1606 MmShowOutOfSpaceMessagePagingFile();
1609 * For private pages restore the old mappings.
1611 if (Context
.Private
)
1613 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1615 MemoryArea
->Attributes
,
1618 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1619 MmInsertRmap(PhysicalAddress
,
1620 MemoryArea
->Process
,
1626 * For non-private pages if the page wasn't direct mapped then
1627 * set it back into the section segment entry so we don't loose
1628 * our copy. Otherwise it will be handled by the cache manager.
1630 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1632 MemoryArea
->Attributes
,
1635 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1636 MmInsertRmap(PhysicalAddress
,
1637 MemoryArea
->Process
,
1639 Entry
= MAKE_SSE(PhysicalAddress
.u
.LowPart
, 1);
1640 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1642 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1643 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1644 MmReleasePageOp(PageOp
);
1645 return(STATUS_PAGEFILE_QUOTA
);
1650 * Write the page to the pagefile
1652 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1653 MmBuildMdlFromPages(Mdl
, (PULONG
)&PhysicalAddress
);
1654 Status
= MmWriteToSwapPage(SwapEntry
, Mdl
);
1655 if (!NT_SUCCESS(Status
))
1657 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1660 * As above: undo our actions.
1661 * FIXME: Also free the swap page.
1663 if (Context
.Private
)
1665 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1667 MemoryArea
->Attributes
,
1670 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1671 MmInsertRmap(PhysicalAddress
,
1672 MemoryArea
->Process
,
1677 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1679 MemoryArea
->Attributes
,
1682 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1683 MmInsertRmap(PhysicalAddress
,
1684 MemoryArea
->Process
,
1686 Entry
= MAKE_SSE(PhysicalAddress
.u
.LowPart
, 1);
1687 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1689 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1690 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1691 MmReleasePageOp(PageOp
);
1692 return(STATUS_UNSUCCESSFUL
);
1696 * Otherwise we have succeeded.
1698 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress
);
1699 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
1700 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1702 if (Context
.Private
)
1704 Status
= MmCreatePageFileMapping(MemoryArea
->Process
,
1707 if (!NT_SUCCESS(Status
))
1714 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1715 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1718 PageOp
->Status
= STATUS_SUCCESS
;
1719 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1720 MmReleasePageOp(PageOp
);
1721 return(STATUS_SUCCESS
);
1725 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1726 PMEMORY_AREA MemoryArea
,
1731 PSECTION_OBJECT Section
;
1732 PMM_SECTION_SEGMENT Segment
;
1733 PHYSICAL_ADDRESS PhysicalAddress
;
1734 SWAPENTRY SwapEntry
;
1739 PFILE_OBJECT FileObject
;
1741 BOOLEAN DirectMapped
;
1742 BOOLEAN IsImageSection
;
1744 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1746 Offset
= (ULONG
)(Address
- (ULONG
)MemoryArea
->BaseAddress
);
1749 * Get the segment and section.
1751 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1752 Section
= MemoryArea
->Data
.SectionData
.Section
;
1753 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1755 FileObject
= Section
->FileObject
;
1756 DirectMapped
= FALSE
;
1757 if (FileObject
!= NULL
)
1759 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1762 * If the file system is letting us go directly to the cache and the
1763 * memory area was mapped at an offset in the file which is page aligned
1764 * then note this is a direct mapped page.
1766 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
1767 (Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
% PAGE_SIZE
) == 0 &&
1768 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1770 DirectMapped
= TRUE
;
1775 * This should never happen since mappings of physical memory are never
1776 * placed in the rmap lists.
1778 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1780 DPRINT1("Trying to write back page from physical memory mapped at %X "
1781 "process %d\n", Address
,
1782 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1787 * Get the section segment entry and the physical address.
1789 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1790 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1792 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1793 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1797 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1798 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1801 * Check for a private (COWed) page.
1803 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1804 IS_SWAP_FROM_SSE(Entry
) ||
1805 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
)
1815 * Speculatively set all mappings of the page to clean.
1817 MmSetCleanAllRmaps(PhysicalAddress
);
1820 * If this page was direct mapped from the cache then the cache manager
1821 * will take care of writing it back to disk.
1823 if (DirectMapped
&& !Private
)
1825 assert(SwapEntry
== 0);
1826 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
1827 PageOp
->Status
= STATUS_SUCCESS
;
1828 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1829 MmReleasePageOp(PageOp
);
1830 return(STATUS_SUCCESS
);
1834 * If necessary, allocate an entry in the paging file for this page
1838 SwapEntry
= MmAllocSwapPage();
1841 MmSetDirtyAllRmaps(PhysicalAddress
);
1842 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1843 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1844 MmReleasePageOp(PageOp
);
1845 return(STATUS_PAGEFILE_QUOTA
);
1850 * Write the page to the pagefile
1852 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1853 MmBuildMdlFromPages(Mdl
, (PULONG
)&PhysicalAddress
);
1854 Status
= MmWriteToSwapPage(SwapEntry
, Mdl
);
1855 if (!NT_SUCCESS(Status
))
1857 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1859 MmSetDirtyAllRmaps(PhysicalAddress
);
1860 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1861 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1862 MmReleasePageOp(PageOp
);
1863 return(STATUS_UNSUCCESSFUL
);
1867 * Otherwise we have succeeded.
1869 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress
);
1870 MmSetSavedSwapEntryPage(PhysicalAddress
, SwapEntry
);
1871 PageOp
->Status
= STATUS_SUCCESS
;
1872 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1873 MmReleasePageOp(PageOp
);
1874 return(STATUS_SUCCESS
);
1878 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1886 PMEMORY_AREA MemoryArea
;
1887 PMM_SECTION_SEGMENT Segment
;
1891 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1892 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1894 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1895 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1900 if (OldProtect
!= NewProtect
)
1902 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1904 PVOID Address
= BaseAddress
+ (i
* PAGE_SIZE
);
1905 ULONG Protect
= NewProtect
;
1908 * If we doing COW for this segment then check if the page is
1911 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1915 LARGE_INTEGER PhysicalAddress
;
1917 Offset
= (ULONG
)Address
- (ULONG
)MemoryArea
->BaseAddress
;
1918 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1920 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1922 Protect
= PAGE_READONLY
;
1923 if ((Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1924 IS_SWAP_FROM_SSE(Entry
) ||
1925 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
))
1927 Protect
= NewProtect
;
1931 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1933 MmSetPageProtect(AddressSpace
->Process
, BaseAddress
,
1941 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1942 PMEMORY_AREA MemoryArea
,
1952 min(Length
, (ULONG
) (MemoryArea
->BaseAddress
+ MemoryArea
->Length
- BaseAddress
));
1953 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1954 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1956 *OldProtect
= Region
->Protect
;
1957 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->BaseAddress
,
1958 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1959 BaseAddress
, Length
, Region
->Type
, Protect
,
1960 MmAlterViewAttributes
);
1966 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
1968 PMEMORY_BASIC_INFORMATION Info
,
1969 PULONG ResultLength
)
1972 PVOID RegionBaseAddress
;
1974 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1975 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1976 Address
, &RegionBaseAddress
);
1979 return STATUS_UNSUCCESSFUL
;
1981 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1982 Info
->AllocationBase
= MemoryArea
->BaseAddress
;
1983 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1984 Info
->RegionSize
= MemoryArea
->Length
;
1985 Info
->State
= MEM_COMMIT
;
1986 Info
->Protect
= Region
->Protect
;
1987 if (MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
)
1989 Info
->Type
= MEM_IMAGE
;
1993 Info
->Type
= MEM_MAPPED
;
1996 return(STATUS_SUCCESS
);
2000 MmpDeleteSection(PVOID ObjectBody
)
2002 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
2004 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2005 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2009 PMM_SECTION_SEGMENT SectionSegments
;
2011 SectionSegments
= Section
->ImageSection
->Segments
;
2012 NrSegments
= Section
->ImageSection
->NrSegments
;
2014 for (i
= 0; i
< NrSegments
; i
++)
2016 InterlockedDecrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2021 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2026 PMM_SECTION_SEGMENT Segment
;
2028 Segment
= Section
->Segment
;
2029 Length
= PAGE_ROUND_UP(Segment
->Length
);
2031 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2033 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2036 if (IS_SWAP_FROM_SSE(Entry
))
2038 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2042 PHYSICAL_ADDRESS Page
= (PHYSICAL_ADDRESS
)(LONGLONG
)PAGE_FROM_SSE(Entry
);
2043 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2047 MmFreePageTablesSectionSegment(Section
->Segment
);
2048 ExFreePool(Section
->Segment
);
2049 Section
->Segment
= NULL
;
2053 InterlockedDecrement((LONG
*)&Section
->Segment
->ReferenceCount
);
2056 if (Section
->FileObject
!= NULL
)
2058 CcRosDereferenceCache(Section
->FileObject
);
2059 ObDereferenceObject(Section
->FileObject
);
2060 Section
->FileObject
= NULL
;
2065 MmpCloseSection(PVOID ObjectBody
,
2068 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2069 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2073 MmpCreateSection(PVOID ObjectBody
,
2075 PWSTR RemainingPath
,
2076 POBJECT_ATTRIBUTES ObjectAttributes
)
2078 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2079 ObjectBody
, Parent
, RemainingPath
);
2081 if (RemainingPath
== NULL
)
2083 return(STATUS_SUCCESS
);
2086 if (wcschr(RemainingPath
+1, L
'\\') != NULL
)
2088 return(STATUS_UNSUCCESSFUL
);
2090 return(STATUS_SUCCESS
);
2094 MmCreatePhysicalMemorySection(VOID
)
2096 HANDLE PhysSectionH
;
2097 PSECTION_OBJECT PhysSection
;
2099 OBJECT_ATTRIBUTES Obj
;
2100 UNICODE_STRING Name
= UNICODE_STRING_INITIALIZER(L
"\\Device\\PhysicalMemory");
2101 LARGE_INTEGER SectionSize
;
2104 * Create the section mapping physical memory
2106 SectionSize
.QuadPart
= 0xFFFFFFFF;
2107 InitializeObjectAttributes(&Obj
,
2112 Status
= NtCreateSection(&PhysSectionH
,
2116 PAGE_EXECUTE_READWRITE
,
2119 if (!NT_SUCCESS(Status
))
2121 DbgPrint("Failed to create PhysicalMemory section\n");
2124 Status
= ObReferenceObjectByHandle(PhysSectionH
,
2128 (PVOID
*)&PhysSection
,
2130 if (!NT_SUCCESS(Status
))
2132 DbgPrint("Failed to reference PhysicalMemory section\n");
2135 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2136 ObDereferenceObject((PVOID
)PhysSection
);
2138 return(STATUS_SUCCESS
);
2142 MmInitSectionImplementation(VOID
)
2144 MmSectionObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
2146 RtlInitUnicodeStringFromLiteral(&MmSectionObjectType
->TypeName
, L
"Section");
2148 MmSectionObjectType
->Tag
= TAG('S', 'E', 'C', 'T');
2149 MmSectionObjectType
->TotalObjects
= 0;
2150 MmSectionObjectType
->TotalHandles
= 0;
2151 MmSectionObjectType
->MaxObjects
= ULONG_MAX
;
2152 MmSectionObjectType
->MaxHandles
= ULONG_MAX
;
2153 MmSectionObjectType
->PagedPoolCharge
= 0;
2154 MmSectionObjectType
->NonpagedPoolCharge
= sizeof(SECTION_OBJECT
);
2155 MmSectionObjectType
->Mapping
= &MmpSectionMapping
;
2156 MmSectionObjectType
->Dump
= NULL
;
2157 MmSectionObjectType
->Open
= NULL
;
2158 MmSectionObjectType
->Close
= MmpCloseSection
;
2159 MmSectionObjectType
->Delete
= MmpDeleteSection
;
2160 MmSectionObjectType
->Parse
= NULL
;
2161 MmSectionObjectType
->Security
= NULL
;
2162 MmSectionObjectType
->QueryName
= NULL
;
2163 MmSectionObjectType
->OkayToClose
= NULL
;
2164 MmSectionObjectType
->Create
= MmpCreateSection
;
2165 MmSectionObjectType
->DuplicationNotify
= NULL
;
2168 * NOTE: Do not register the section object type here because
2169 * the object manager it not initialized yet!
2170 * The section object type will be created in ObInit().
2173 return(STATUS_SUCCESS
);
2177 MmCreatePageFileSection(PHANDLE SectionHandle
,
2178 ACCESS_MASK DesiredAccess
,
2179 POBJECT_ATTRIBUTES ObjectAttributes
,
2180 PLARGE_INTEGER UMaximumSize
,
2181 ULONG SectionPageProtection
,
2182 ULONG AllocationAttributes
)
2184 * Create a section which is backed by the pagefile
2187 LARGE_INTEGER MaximumSize
;
2188 PSECTION_OBJECT Section
;
2189 PMM_SECTION_SEGMENT Segment
;
2192 if (UMaximumSize
== NULL
)
2194 return(STATUS_UNSUCCESSFUL
);
2196 MaximumSize
= *UMaximumSize
;
2199 * Check the protection
2201 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2202 SectionPageProtection
)
2204 return(STATUS_INVALID_PAGE_PROTECTION
);
2208 * Create the section
2210 Status
= ObCreateObject(ExGetPreviousMode(),
2211 MmSectionObjectType
,
2213 ExGetPreviousMode(),
2215 sizeof(SECTION_OBJECT
),
2219 if (!NT_SUCCESS(Status
))
2224 Status
= ObInsertObject ((PVOID
)Section
,
2230 if (!NT_SUCCESS(Status
))
2232 ObDereferenceObject(Section
);
2239 Section
->SectionPageProtection
= SectionPageProtection
;
2240 Section
->AllocationAttributes
= AllocationAttributes
;
2241 InitializeListHead(&Section
->ViewListHead
);
2242 KeInitializeSpinLock(&Section
->ViewListLock
);
2243 Section
->FileObject
= NULL
;
2244 Section
->MaximumSize
= MaximumSize
;
2245 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2246 TAG_MM_SECTION_SEGMENT
);
2247 if (Segment
== NULL
)
2249 ZwClose(*SectionHandle
);
2250 ObDereferenceObject(Section
);
2251 return(STATUS_NO_MEMORY
);
2253 Section
->Segment
= Segment
;
2254 Segment
->ReferenceCount
= 1;
2255 ExInitializeFastMutex(&Segment
->Lock
);
2256 Segment
->FileOffset
= 0;
2257 Segment
->Protection
= SectionPageProtection
;
2258 Segment
->Attributes
= AllocationAttributes
;
2259 Segment
->Length
= MaximumSize
.u
.LowPart
;
2260 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2261 Segment
->WriteCopy
= FALSE
;
2262 ObDereferenceObject(Section
);
2263 return(STATUS_SUCCESS
);
2268 MmCreateDataFileSection(PHANDLE SectionHandle
,
2269 ACCESS_MASK DesiredAccess
,
2270 POBJECT_ATTRIBUTES ObjectAttributes
,
2271 PLARGE_INTEGER UMaximumSize
,
2272 ULONG SectionPageProtection
,
2273 ULONG AllocationAttributes
,
2276 * Create a section backed by a data file
2279 PSECTION_OBJECT Section
;
2281 LARGE_INTEGER MaximumSize
;
2282 PFILE_OBJECT FileObject
;
2283 PMM_SECTION_SEGMENT Segment
;
2285 IO_STATUS_BLOCK Iosb
;
2286 LARGE_INTEGER Offset
;
2290 * Check the protection
2292 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2293 SectionPageProtection
)
2295 return(STATUS_INVALID_PAGE_PROTECTION
);
2299 * Read a bit so caching is initiated for the file object.
2300 * This is only needed because MiReadPage currently cannot
2301 * handle non-cached streams.
2303 Offset
.QuadPart
= 0;
2304 Status
= ZwReadFile(FileHandle
,
2313 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2319 * Create the section
2321 Status
= ObCreateObject(ExGetPreviousMode(),
2322 MmSectionObjectType
,
2324 ExGetPreviousMode(),
2326 sizeof(SECTION_OBJECT
),
2330 if (!NT_SUCCESS(Status
))
2335 Status
= ObInsertObject ((PVOID
)Section
,
2341 if (!NT_SUCCESS(Status
))
2343 ObDereferenceObject(Section
);
2350 Section
->SectionPageProtection
= SectionPageProtection
;
2351 Section
->AllocationAttributes
= AllocationAttributes
;
2352 InitializeListHead(&Section
->ViewListHead
);
2353 KeInitializeSpinLock(&Section
->ViewListLock
);
2356 * Check file access required
2358 if (SectionPageProtection
& PAGE_READWRITE
||
2359 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2361 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2365 FileAccess
= FILE_READ_DATA
;
2369 * Reference the file handle
2371 Status
= ObReferenceObjectByHandle(FileHandle
,
2375 (PVOID
*)&FileObject
,
2377 if (!NT_SUCCESS(Status
))
2379 ZwClose(*SectionHandle
);
2380 ObDereferenceObject(Section
);
2385 * We can't do memory mappings if the file system doesn't support the
2388 if (!(FileObject
->Flags
& FO_FCB_IS_VALID
))
2390 ZwClose(*SectionHandle
);
2391 ObDereferenceObject(Section
);
2392 ObDereferenceObject(FileObject
);
2393 return(STATUS_INVALID_FILE_FOR_SECTION
);
2397 * FIXME: Revise this once a locking order for file size changes is
2400 if (UMaximumSize
!= NULL
)
2402 MaximumSize
= *UMaximumSize
;
2407 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
;
2410 if (MaximumSize
.QuadPart
>
2411 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
.QuadPart
)
2413 IO_STATUS_BLOCK Iosb
;
2414 Status
= NtSetInformationFile(FileHandle
,
2417 sizeof(LARGE_INTEGER
),
2418 FileAllocationInformation
);
2419 if (!NT_SUCCESS(Status
))
2421 ZwClose(*SectionHandle
);
2422 ObDereferenceObject(Section
);
2423 ObDereferenceObject(FileObject
);
2424 return(STATUS_SECTION_NOT_EXTENDED
);
2431 Status
= KeWaitForSingleObject((PVOID
)&FileObject
->Lock
,
2436 if (Status
!= STATUS_SUCCESS
)
2438 ZwClose(*SectionHandle
);
2439 ObDereferenceObject(Section
);
2440 ObDereferenceObject(FileObject
);
2445 * If this file hasn't been mapped as a data file before then allocate a
2446 * section segment to describe the data file mapping
2448 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2450 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2451 TAG_MM_SECTION_SEGMENT
);
2452 if (Segment
== NULL
)
2454 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2455 ZwClose(*SectionHandle
);
2456 ObDereferenceObject(Section
);
2457 ObDereferenceObject(FileObject
);
2458 return(STATUS_NO_MEMORY
);
2460 Section
->Segment
= Segment
;
2461 Segment
->ReferenceCount
= 1;
2462 ExInitializeFastMutex(&Segment
->Lock
);
2464 * Set the lock before assigning the segment to the file object
2466 ExAcquireFastMutex(&Segment
->Lock
);
2467 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2469 Segment
->FileOffset
= 0;
2470 Segment
->Protection
= 0;
2471 Segment
->Attributes
= 0;
2472 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2473 Segment
->Characteristics
= 0;
2474 Segment
->WriteCopy
= FALSE
;
2475 if (AllocationAttributes
& SEC_RESERVE
)
2477 Segment
->Length
= Segment
->RawLength
= 0;
2481 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2482 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2484 Segment
->VirtualAddress
= NULL
;
2489 * If the file is already mapped as a data file then we may need
2493 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2495 Section
->Segment
= Segment
;
2496 InterlockedIncrement((PLONG
)&Segment
->ReferenceCount
);
2497 MmLockSectionSegment(Segment
);
2499 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2500 !(AllocationAttributes
& SEC_RESERVE
))
2502 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2503 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2506 MmUnlockSectionSegment(Segment
);
2507 Section
->FileObject
= FileObject
;
2508 Section
->MaximumSize
= MaximumSize
;
2509 CcRosReferenceCache(FileObject
);
2510 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2511 ObDereferenceObject(Section
);
2512 return(STATUS_SUCCESS
);
2515 static ULONG SectionCharacteristicsToProtect
[16] =
2517 PAGE_NOACCESS
, // 0 = NONE
2518 PAGE_NOACCESS
, // 1 = SHARED
2519 PAGE_EXECUTE
, // 2 = EXECUTABLE
2520 PAGE_EXECUTE
, // 3 = EXECUTABLE, SHARED
2521 PAGE_READONLY
, // 4 = READABLE
2522 PAGE_READONLY
, // 5 = READABLE, SHARED
2523 PAGE_EXECUTE_READ
, // 6 = READABLE, EXECUTABLE
2524 PAGE_EXECUTE_READ
, // 7 = READABLE, EXECUTABLE, SHARED
2525 PAGE_READWRITE
, // 8 = WRITABLE
2526 PAGE_READWRITE
, // 9 = WRITABLE, SHARED
2527 PAGE_EXECUTE_READWRITE
, // 10 = WRITABLE, EXECUTABLE
2528 PAGE_EXECUTE_READWRITE
, // 11 = WRITABLE, EXECUTABLE, SHARED
2529 PAGE_READWRITE
, // 12 = WRITABLE, READABLE
2530 PAGE_READWRITE
, // 13 = WRITABLE, READABLE, SHARED
2531 PAGE_EXECUTE_READWRITE
, // 14 = WRITABLE, READABLE, EXECUTABLE,
2532 PAGE_EXECUTE_READWRITE
, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
2536 MmCreateImageSection(PHANDLE SectionHandle
,
2537 ACCESS_MASK DesiredAccess
,
2538 POBJECT_ATTRIBUTES ObjectAttributes
,
2539 PLARGE_INTEGER UMaximumSize
,
2540 ULONG SectionPageProtection
,
2541 ULONG AllocationAttributes
,
2544 PSECTION_OBJECT Section
;
2546 PFILE_OBJECT FileObject
;
2547 IMAGE_DOS_HEADER DosHeader
;
2548 IO_STATUS_BLOCK Iosb
;
2549 LARGE_INTEGER Offset
;
2550 IMAGE_NT_HEADERS PEHeader
;
2551 PIMAGE_SECTION_HEADER ImageSections
;
2552 PMM_SECTION_SEGMENT SectionSegments
;
2554 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
2557 ULONG Characteristics
;
2558 ULONG FileAccess
= 0;
2560 * Check the protection
2562 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2563 SectionPageProtection
)
2565 return(STATUS_INVALID_PAGE_PROTECTION
);
2569 * Specifying a maximum size is meaningless for an image section
2571 if (UMaximumSize
!= NULL
)
2573 return(STATUS_INVALID_PARAMETER_4
);
2577 * Reference the file handle
2579 Status
= ObReferenceObjectByHandle(FileHandle
,
2583 (PVOID
*)&FileObject
,
2585 if (!NT_SUCCESS(Status
))
2591 * Initialized caching for this file object if previously caching
2592 * was initialized for the same on disk file
2594 Status
= CcTryToInitializeFileCache(FileObject
);
2596 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
2599 * Read the dos header and check the DOS signature
2601 Offset
.QuadPart
= 0;
2602 Status
= ZwReadFile(FileHandle
,
2611 if (!NT_SUCCESS(Status
))
2613 ObDereferenceObject(FileObject
);
2618 * Check the DOS signature
2620 if (Iosb
.Information
!= sizeof(DosHeader
) ||
2621 DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
)
2623 ObDereferenceObject(FileObject
);
2624 return(STATUS_INVALID_IMAGE_FORMAT
);
2628 * Read the PE header
2630 Offset
.QuadPart
= DosHeader
.e_lfanew
;
2631 Status
= ZwReadFile(FileHandle
,
2640 if (!NT_SUCCESS(Status
))
2642 ObDereferenceObject(FileObject
);
2647 * Check the signature
2649 if (Iosb
.Information
!= sizeof(PEHeader
) ||
2650 PEHeader
.Signature
!= IMAGE_NT_SIGNATURE
)
2652 ObDereferenceObject(FileObject
);
2653 return(STATUS_INVALID_IMAGE_FORMAT
);
2657 * Read in the section headers
2659 Offset
.QuadPart
= DosHeader
.e_lfanew
+ sizeof(PEHeader
);
2660 ImageSections
= ExAllocatePool(NonPagedPool
,
2661 PEHeader
.FileHeader
.NumberOfSections
*
2662 sizeof(IMAGE_SECTION_HEADER
));
2663 if (ImageSections
== NULL
)
2665 ObDereferenceObject(FileObject
);
2666 return(STATUS_NO_MEMORY
);
2669 Status
= ZwReadFile(FileHandle
,
2675 PEHeader
.FileHeader
.NumberOfSections
*
2676 sizeof(IMAGE_SECTION_HEADER
),
2679 if (!NT_SUCCESS(Status
))
2681 ObDereferenceObject(FileObject
);
2682 ExFreePool(ImageSections
);
2685 if (Iosb
.Information
!= (PEHeader
.FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
)))
2687 ObDereferenceObject(FileObject
);
2688 ExFreePool(ImageSections
);
2689 return(STATUS_INVALID_IMAGE_FORMAT
);
2693 * Create the section
2695 Status
= ObCreateObject (ExGetPreviousMode(),
2696 MmSectionObjectType
,
2698 ExGetPreviousMode(),
2700 sizeof(SECTION_OBJECT
),
2704 if (!NT_SUCCESS(Status
))
2706 ObDereferenceObject(FileObject
);
2707 ExFreePool(ImageSections
);
2711 Status
= ObInsertObject ((PVOID
)Section
,
2717 if (!NT_SUCCESS(Status
))
2719 ObDereferenceObject(Section
);
2720 ObDereferenceObject(FileObject
);
2721 ExFreePool(ImageSections
);
2728 Section
->SectionPageProtection
= SectionPageProtection
;
2729 Section
->AllocationAttributes
= AllocationAttributes
;
2730 InitializeListHead(&Section
->ViewListHead
);
2731 KeInitializeSpinLock(&Section
->ViewListLock
);
2734 * Check file access required
2736 if (SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
2738 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2742 FileAccess
= FILE_READ_DATA
;
2746 * We can't do memory mappings if the file system doesn't support the
2749 if (!(FileObject
->Flags
& FO_FCB_IS_VALID
))
2751 ZwClose(*SectionHandle
);
2752 ObDereferenceObject(Section
);
2753 ObDereferenceObject(FileObject
);
2754 ExFreePool(ImageSections
);
2755 return(STATUS_INVALID_FILE_FOR_SECTION
);
2761 Status
= KeWaitForSingleObject((PVOID
)&FileObject
->Lock
,
2766 if (Status
!= STATUS_SUCCESS
)
2768 ZwClose(*SectionHandle
);
2769 ObDereferenceObject(Section
);
2770 ObDereferenceObject(FileObject
);
2771 ExFreePool(ImageSections
);
2776 * allocate the section segments to describe the mapping
2778 NrSegments
= PEHeader
.FileHeader
.NumberOfSections
+ 1;
2779 Size
= sizeof(MM_IMAGE_SECTION_OBJECT
) + sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2780 ImageSectionObject
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_MM_SECTION_SEGMENT
);
2781 if (ImageSectionObject
== NULL
)
2783 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2784 ZwClose(*SectionHandle
);
2785 ObDereferenceObject(Section
);
2786 ObDereferenceObject(FileObject
);
2787 ExFreePool(ImageSections
);
2788 return(STATUS_NO_MEMORY
);
2790 Section
->ImageSection
= ImageSectionObject
;
2791 ImageSectionObject
->NrSegments
= NrSegments
;
2792 ImageSectionObject
->ImageBase
= (PVOID
)PEHeader
.OptionalHeader
.ImageBase
;
2793 ImageSectionObject
->EntryPoint
= (PVOID
)PEHeader
.OptionalHeader
.AddressOfEntryPoint
;
2794 ImageSectionObject
->StackReserve
= PEHeader
.OptionalHeader
.SizeOfStackReserve
;
2795 ImageSectionObject
->StackCommit
= PEHeader
.OptionalHeader
.SizeOfStackCommit
;
2796 ImageSectionObject
->Subsystem
= PEHeader
.OptionalHeader
.Subsystem
;
2797 ImageSectionObject
->MinorSubsystemVersion
= PEHeader
.OptionalHeader
.MinorSubsystemVersion
;
2798 ImageSectionObject
->MajorSubsystemVersion
= PEHeader
.OptionalHeader
.MajorSubsystemVersion
;
2799 ImageSectionObject
->ImageCharacteristics
= PEHeader
.FileHeader
.Characteristics
;
2800 ImageSectionObject
->Machine
= PEHeader
.FileHeader
.Machine
;
2801 ImageSectionObject
->Executable
= (PEHeader
.OptionalHeader
.SizeOfCode
!= 0);
2803 SectionSegments
= ImageSectionObject
->Segments
;
2804 SectionSegments
[0].FileOffset
= 0;
2805 SectionSegments
[0].Characteristics
= IMAGE_SECTION_CHAR_DATA
;
2806 SectionSegments
[0].Protection
= PAGE_READONLY
;
2807 SectionSegments
[0].RawLength
= PAGE_SIZE
;
2808 SectionSegments
[0].Length
= PAGE_SIZE
;
2809 SectionSegments
[0].Flags
= 0;
2810 SectionSegments
[0].ReferenceCount
= 1;
2811 SectionSegments
[0].VirtualAddress
= 0;
2812 SectionSegments
[0].WriteCopy
= FALSE
;
2813 ExInitializeFastMutex(&SectionSegments
[0].Lock
);
2814 for (i
= 1; i
< NrSegments
; i
++)
2816 SectionSegments
[i
].FileOffset
= ImageSections
[i
-1].PointerToRawData
;
2817 SectionSegments
[i
].Characteristics
= ImageSections
[i
-1].Characteristics
;
2820 * Set up the protection and write copy variables.
2822 Characteristics
= ImageSections
[i
- 1].Characteristics
;
2823 if (Characteristics
& (IMAGE_SECTION_CHAR_READABLE
|IMAGE_SECTION_CHAR_WRITABLE
|IMAGE_SECTION_CHAR_EXECUTABLE
))
2825 SectionSegments
[i
].Protection
= SectionCharacteristicsToProtect
[Characteristics
>> 28];
2826 SectionSegments
[i
].WriteCopy
= !(Characteristics
& IMAGE_SECTION_CHAR_SHARED
);
2828 else if (Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2830 SectionSegments
[i
].Protection
= PAGE_EXECUTE_READ
;
2831 SectionSegments
[i
].WriteCopy
= TRUE
;
2833 else if (Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2835 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2836 SectionSegments
[i
].WriteCopy
= TRUE
;
2838 else if (Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2840 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2841 SectionSegments
[i
].WriteCopy
= TRUE
;
2845 SectionSegments
[i
].Protection
= PAGE_NOACCESS
;
2846 SectionSegments
[i
].WriteCopy
= TRUE
;
2850 * Set up the attributes.
2852 if (Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2854 SectionSegments
[i
].Attributes
= 0;
2856 else if (Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2858 SectionSegments
[i
].Attributes
= 0;
2860 else if (Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2862 SectionSegments
[i
].Attributes
= MM_SECTION_SEGMENT_BSS
;
2866 SectionSegments
[i
].Attributes
= 0;
2869 SectionSegments
[i
].RawLength
= ImageSections
[i
-1].SizeOfRawData
;
2870 SectionSegments
[i
].Length
= ImageSections
[i
-1].Misc
.VirtualSize
;
2871 SectionSegments
[i
].Flags
= 0;
2872 SectionSegments
[i
].ReferenceCount
= 1;
2873 SectionSegments
[i
].VirtualAddress
= (PVOID
)ImageSections
[i
-1].VirtualAddress
;
2874 ExInitializeFastMutex(&SectionSegments
[i
].Lock
);
2876 if (0 != InterlockedCompareExchange((PLONG
)&FileObject
->SectionObjectPointer
->ImageSectionObject
,
2877 (LONG
)ImageSectionObject
, 0))
2880 * An other thread has initialized the some image in the background
2882 ExFreePool(ImageSectionObject
);
2883 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
2884 Section
->ImageSection
= ImageSectionObject
;
2885 SectionSegments
= ImageSectionObject
->Segments
;
2887 for (i
= 0; i
< NrSegments
; i
++)
2889 InterlockedIncrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2892 ExFreePool(ImageSections
);
2897 * Create the section
2899 Status
= ObCreateObject (ExGetPreviousMode(),
2900 MmSectionObjectType
,
2902 ExGetPreviousMode(),
2904 sizeof(SECTION_OBJECT
),
2908 if (!NT_SUCCESS(Status
))
2910 ObDereferenceObject(FileObject
);
2914 Status
= ObInsertObject ((PVOID
)Section
,
2920 if (!NT_SUCCESS(Status
))
2922 ObDereferenceObject(Section
);
2923 ObDereferenceObject(FileObject
);
2930 Section
->SectionPageProtection
= SectionPageProtection
;
2931 Section
->AllocationAttributes
= AllocationAttributes
;
2932 InitializeListHead(&Section
->ViewListHead
);
2933 KeInitializeSpinLock(&Section
->ViewListLock
);
2936 * Check file access required
2938 if (SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
2940 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2944 FileAccess
= FILE_READ_DATA
;
2950 Status
= KeWaitForSingleObject((PVOID
)&FileObject
->Lock
,
2955 if (Status
!= STATUS_SUCCESS
)
2957 ZwClose(*SectionHandle
);
2958 ObDereferenceObject(Section
);
2959 ObDereferenceObject(FileObject
);
2963 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
2964 Section
->ImageSection
= ImageSectionObject
;
2965 SectionSegments
= ImageSectionObject
->Segments
;
2966 NrSegments
= ImageSectionObject
->NrSegments
;
2969 * Otherwise just reference all the section segments
2971 for (i
= 0; i
< NrSegments
; i
++)
2973 InterlockedIncrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2977 Section
->FileObject
= FileObject
;
2978 CcRosReferenceCache(FileObject
);
2979 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2980 ObDereferenceObject(Section
);
2981 return(STATUS_SUCCESS
);
2988 NtCreateSection (OUT PHANDLE SectionHandle
,
2989 IN ACCESS_MASK DesiredAccess
,
2990 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
2991 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
2992 IN ULONG SectionPageProtection OPTIONAL
,
2993 IN ULONG AllocationAttributes
,
2994 IN HANDLE FileHandle OPTIONAL
)
2996 if (AllocationAttributes
& SEC_IMAGE
)
2998 return(MmCreateImageSection(SectionHandle
,
3002 SectionPageProtection
,
3003 AllocationAttributes
,
3006 else if (FileHandle
!= NULL
)
3008 return(MmCreateDataFileSection(SectionHandle
,
3012 SectionPageProtection
,
3013 AllocationAttributes
,
3018 return(MmCreatePageFileSection(SectionHandle
,
3022 SectionPageProtection
,
3023 AllocationAttributes
));
3028 /**********************************************************************
3046 NtOpenSection(PHANDLE SectionHandle
,
3047 ACCESS_MASK DesiredAccess
,
3048 POBJECT_ATTRIBUTES ObjectAttributes
)
3054 Status
= ObOpenObjectByName(ObjectAttributes
,
3055 MmSectionObjectType
,
3066 MmMapViewOfSegment(PEPROCESS Process
,
3067 PMADDRESS_SPACE AddressSpace
,
3068 PSECTION_OBJECT Section
,
3069 PMM_SECTION_SEGMENT Segment
,
3080 Status
= MmCreateMemoryArea(Process
,
3082 MEMORY_AREA_SECTION_VIEW
,
3089 if (!NT_SUCCESS(Status
))
3091 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
3092 (*BaseAddress
), (*BaseAddress
) + ViewSize
);
3096 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3097 InsertTailList(&Section
->ViewListHead
,
3098 &MArea
->Data
.SectionData
.ViewListEntry
);
3099 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3101 ObReferenceObjectByPointer((PVOID
)Section
,
3104 ExGetPreviousMode());
3105 MArea
->Data
.SectionData
.Segment
= Segment
;
3106 MArea
->Data
.SectionData
.Section
= Section
;
3107 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3108 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3109 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3110 ViewSize
, 0, Protect
);
3112 return(STATUS_SUCCESS
);
3116 /**********************************************************************
3118 * NtMapViewOfSection
3121 * Maps a view of a section into the virtual address space of a
3126 * Handle of the section.
3129 * Handle of the process.
3132 * Desired base address (or NULL) on entry;
3133 * Actual base address of the view on exit.
3136 * Number of high order address bits that must be zero.
3139 * Size in bytes of the initially committed section of
3143 * Offset in bytes from the beginning of the section
3144 * to the beginning of the view.
3147 * Desired length of map (or zero to map all) on entry
3148 * Actual length mapped on exit.
3150 * InheritDisposition
3151 * Specified how the view is to be shared with
3155 * Type of allocation for the pages.
3158 * Protection for the committed region of the view.
3166 NtMapViewOfSection(HANDLE SectionHandle
,
3167 HANDLE ProcessHandle
,
3171 PLARGE_INTEGER SectionOffset
,
3173 SECTION_INHERIT InheritDisposition
,
3174 ULONG AllocationType
,
3177 PSECTION_OBJECT Section
;
3180 PMADDRESS_SPACE AddressSpace
;
3182 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3183 PROCESS_VM_OPERATION
,
3188 if (!NT_SUCCESS(Status
))
3193 AddressSpace
= &Process
->AddressSpace
;
3195 Status
= ObReferenceObjectByHandle(SectionHandle
,
3197 MmSectionObjectType
,
3201 if (!(NT_SUCCESS(Status
)))
3203 DPRINT("ObReference failed rc=%x\n",Status
);
3204 ObDereferenceObject(Process
);
3208 Status
= MmMapViewOfSection(Section
,
3219 ObDereferenceObject(Section
);
3220 ObDereferenceObject(Process
);
3226 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3227 PHYSICAL_ADDRESS PhysAddr
, SWAPENTRY SwapEntry
,
3232 PFILE_OBJECT FileObject
;
3235 SWAPENTRY SavedSwapEntry
;
3237 LARGE_INTEGER Timeout
;
3239 PSECTION_OBJECT Section
;
3240 PMM_SECTION_SEGMENT Segment
;
3242 MArea
= (PMEMORY_AREA
)Context
;
3244 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3246 Offset
= ((ULONG
)Address
- (ULONG
)MArea
->BaseAddress
);
3248 Section
= MArea
->Data
.SectionData
.Section
;
3249 Segment
= MArea
->Data
.SectionData
.Segment
;
3252 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3256 MmUnlockSectionSegment(Segment
);
3257 MmUnlockAddressSpace(&MArea
->Process
->AddressSpace
);
3259 Timeout
.QuadPart
= -100000000LL; // 10 sec
3260 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
3265 if (Status
!= STATUS_SUCCESS
)
3267 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3271 MmLockAddressSpace(&MArea
->Process
->AddressSpace
);
3272 MmLockSectionSegment(Segment
);
3273 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
3274 MmReleasePageOp(PageOp
);
3275 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3278 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3281 * For a dirty, datafile, non-private page mark it as dirty in the
3284 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3286 if (PhysAddr
.QuadPart
== PAGE_FROM_SSE(Entry
) && Dirty
)
3288 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3289 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3290 CcRosMarkDirtyCacheSegment(Bcb
, Offset
);
3291 assert(SwapEntry
== 0);
3300 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3302 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3305 MmFreeSwapPage(SwapEntry
);
3307 else if (PhysAddr
.QuadPart
!= 0)
3309 if (IS_SWAP_FROM_SSE(Entry
) ||
3310 PhysAddr
.QuadPart
!= (PAGE_FROM_SSE(Entry
)))
3315 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3317 DPRINT1("Found a private page in a pagefile section.\n");
3321 * Just dereference private pages
3323 SavedSwapEntry
= MmGetSavedSwapEntryPage(PhysAddr
);
3324 if (SavedSwapEntry
!= 0)
3326 MmFreeSwapPage(SavedSwapEntry
);
3327 MmSetSavedSwapEntryPage(PhysAddr
, 0);
3329 MmDeleteRmap(PhysAddr
, MArea
->Process
, Address
);
3330 MmReleasePageMemoryConsumer(MC_USER
, PhysAddr
);
3334 MmDeleteRmap(PhysAddr
, MArea
->Process
, Address
);
3335 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
);
3336 MmReleasePageMemoryConsumer(MC_USER
, PhysAddr
);
3342 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3346 PMEMORY_AREA MemoryArea
;
3347 PSECTION_OBJECT Section
;
3348 PMM_SECTION_SEGMENT Segment
;
3350 PLIST_ENTRY CurrentEntry
;
3351 PMM_REGION CurrentRegion
;
3352 PLIST_ENTRY RegionListHead
;
3354 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
3356 if (MemoryArea
== NULL
)
3358 return(STATUS_UNSUCCESSFUL
);
3361 MemoryArea
->DeleteInProgress
= TRUE
;
3362 Section
= MemoryArea
->Data
.SectionData
.Section
;
3363 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3365 MmLockSectionSegment(Segment
);
3366 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3367 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
3368 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3370 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3371 while (!IsListEmpty(RegionListHead
))
3373 CurrentEntry
= RemoveHeadList(RegionListHead
);
3374 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3375 ExFreePool(CurrentRegion
);
3378 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3380 Status
= MmFreeMemoryArea(AddressSpace
,
3388 Status
= MmFreeMemoryArea(AddressSpace
,
3394 MmUnlockSectionSegment(Segment
);
3395 ObDereferenceObject(Section
);
3396 return(STATUS_SUCCESS
);
3403 MmUnmapViewOfSection(PEPROCESS Process
,
3407 PMEMORY_AREA MemoryArea
;
3408 PMADDRESS_SPACE AddressSpace
;
3409 PSECTION_OBJECT Section
;
3411 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3412 Process
, BaseAddress
);
3416 AddressSpace
= &Process
->AddressSpace
;
3417 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
3419 if (MemoryArea
== NULL
)
3421 return(STATUS_UNSUCCESSFUL
);
3424 Section
= MemoryArea
->Data
.SectionData
.Section
;
3426 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3430 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3431 PMM_SECTION_SEGMENT SectionSegments
;
3432 PVOID ImageBaseAddress
;
3433 PMM_SECTION_SEGMENT Segment
;
3435 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3436 ImageSectionObject
= Section
->ImageSection
;
3437 SectionSegments
= ImageSectionObject
->Segments
;
3438 NrSegments
= ImageSectionObject
->NrSegments
;
3440 /* Search for the current segment within the section segments
3441 * and calculate the image base address */
3442 for (i
= 0; i
< NrSegments
; i
++)
3444 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3446 if (Segment
== &SectionSegments
[i
])
3448 ImageBaseAddress
= BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3453 if (i
>= NrSegments
)
3458 for (i
= 0; i
< NrSegments
; i
++)
3460 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3462 PVOID SBaseAddress
= (PVOID
)
3463 (ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3465 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
3471 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
3473 return(STATUS_SUCCESS
);
3476 /**********************************************************************
3478 * NtUnmapViewOfSection
3493 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3499 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3500 ProcessHandle
, BaseAddress
);
3502 DPRINT("Referencing process\n");
3503 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3504 PROCESS_VM_OPERATION
,
3509 if (!NT_SUCCESS(Status
))
3511 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3515 MmLockAddressSpace(&Process
->AddressSpace
);
3516 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3517 MmUnlockAddressSpace(&Process
->AddressSpace
);
3519 ObDereferenceObject(Process
);
3526 NtQuerySection (IN HANDLE SectionHandle
,
3527 IN CINT SectionInformationClass
,
3528 OUT PVOID SectionInformation
,
3530 OUT PULONG ResultLength
)
3532 * FUNCTION: Queries the information of a section object.
3534 * SectionHandle = Handle to the section link object
3535 * SectionInformationClass = Index to a certain information structure
3536 * SectionInformation (OUT)= Caller supplies storage for resulting
3538 * Length = Size of the supplied storage
3539 * ResultLength = Data written
3544 PSECTION_OBJECT Section
;
3547 Status
= ObReferenceObjectByHandle(SectionHandle
,
3549 MmSectionObjectType
,
3553 if (!(NT_SUCCESS(Status
)))
3558 switch (SectionInformationClass
)
3560 case SectionBasicInformation
:
3562 PSECTION_BASIC_INFORMATION Sbi
;
3564 if (Length
!= sizeof(SECTION_BASIC_INFORMATION
))
3566 ObDereferenceObject(Section
);
3567 return(STATUS_INFO_LENGTH_MISMATCH
);
3570 Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
3572 Sbi
->BaseAddress
= 0;
3573 Sbi
->Attributes
= 0;
3574 Sbi
->Size
.QuadPart
= 0;
3576 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
3577 Status
= STATUS_SUCCESS
;
3581 case SectionImageInformation
:
3583 PSECTION_IMAGE_INFORMATION Sii
;
3585 if (Length
!= sizeof(SECTION_IMAGE_INFORMATION
))
3587 ObDereferenceObject(Section
);
3588 return(STATUS_INFO_LENGTH_MISMATCH
);
3591 Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
3592 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
3593 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3595 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3596 ImageSectionObject
= Section
->ImageSection
;
3598 Sii
->EntryPoint
= ImageSectionObject
->EntryPoint
;
3599 Sii
->StackReserve
= ImageSectionObject
->StackReserve
;
3600 Sii
->StackCommit
= ImageSectionObject
->StackCommit
;
3601 Sii
->Subsystem
= ImageSectionObject
->Subsystem
;
3602 Sii
->MinorSubsystemVersion
= ImageSectionObject
->MinorSubsystemVersion
;
3603 Sii
->MajorSubsystemVersion
= ImageSectionObject
->MajorSubsystemVersion
;
3604 Sii
->Characteristics
= ImageSectionObject
->ImageCharacteristics
;
3605 Sii
->ImageNumber
= ImageSectionObject
->Machine
;
3606 Sii
->Executable
= ImageSectionObject
->Executable
;
3608 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
3609 Status
= STATUS_SUCCESS
;
3615 Status
= STATUS_INVALID_INFO_CLASS
;
3617 ObDereferenceObject(Section
);
3623 NtExtendSection(IN HANDLE SectionHandle
,
3624 IN ULONG NewMaximumSize
)
3627 return(STATUS_NOT_IMPLEMENTED
);
3631 /**********************************************************************
3633 * MmAllocateSection@4
3643 * Code taken from ntoskrnl/mm/special.c.
3648 MmAllocateSection (IN ULONG Length
)
3654 PMADDRESS_SPACE AddressSpace
;
3656 DPRINT("MmAllocateSection(Length %x)\n",Length
);
3658 AddressSpace
= MmGetKernelAddressSpace();
3660 MmLockAddressSpace(AddressSpace
);
3661 Status
= MmCreateMemoryArea (NULL
,
3670 if (!NT_SUCCESS(Status
))
3672 MmUnlockAddressSpace(AddressSpace
);
3675 MmUnlockAddressSpace(AddressSpace
);
3676 DPRINT("Result %p\n",Result
);
3677 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
3679 PHYSICAL_ADDRESS Page
;
3681 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
3682 if (!NT_SUCCESS(Status
))
3684 DbgPrint("Unable to allocate page\n");
3687 Status
= MmCreateVirtualMapping (NULL
,
3688 (Result
+ (i
* PAGE_SIZE
)),
3692 if (!NT_SUCCESS(Status
))
3694 DbgPrint("Unable to create virtual mapping\n");
3698 return ((PVOID
)Result
);
3702 /**********************************************************************
3704 * MmMapViewOfSection
3707 * Maps a view of a section into the virtual address space of a
3712 * Pointer to the section object.
3715 * Pointer to the process.
3718 * Desired base address (or NULL) on entry;
3719 * Actual base address of the view on exit.
3722 * Number of high order address bits that must be zero.
3725 * Size in bytes of the initially committed section of
3729 * Offset in bytes from the beginning of the section
3730 * to the beginning of the view.
3733 * Desired length of map (or zero to map all) on entry
3734 * Actual length mapped on exit.
3736 * InheritDisposition
3737 * Specified how the view is to be shared with
3741 * Type of allocation for the pages.
3744 * Protection for the committed region of the view.
3752 MmMapViewOfSection(IN PVOID SectionObject
,
3753 IN PEPROCESS Process
,
3754 IN OUT PVOID
*BaseAddress
,
3756 IN ULONG CommitSize
,
3757 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3758 IN OUT PULONG ViewSize
,
3759 IN SECTION_INHERIT InheritDisposition
,
3760 IN ULONG AllocationType
,
3763 PSECTION_OBJECT Section
;
3764 PMADDRESS_SPACE AddressSpace
;
3766 NTSTATUS Status
= STATUS_SUCCESS
;
3770 Section
= (PSECTION_OBJECT
)SectionObject
;
3771 AddressSpace
= &Process
->AddressSpace
;
3773 MmLockAddressSpace(AddressSpace
);
3775 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3781 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3782 PMM_SECTION_SEGMENT SectionSegments
;
3784 ImageSectionObject
= Section
->ImageSection
;
3785 SectionSegments
= ImageSectionObject
->Segments
;
3786 NrSegments
= ImageSectionObject
->NrSegments
;
3789 ImageBase
= *BaseAddress
;
3790 if (ImageBase
== NULL
)
3792 ImageBase
= ImageSectionObject
->ImageBase
;
3796 for (i
= 0; i
< NrSegments
; i
++)
3798 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3801 MaxExtent
= (ULONG
)(SectionSegments
[i
].VirtualAddress
+
3802 SectionSegments
[i
].Length
);
3803 ImageSize
= max(ImageSize
, MaxExtent
);
3807 /* Check there is enough space to map the section at that point. */
3808 if (MmOpenMemoryAreaByRegion(AddressSpace
, ImageBase
,
3809 PAGE_ROUND_UP(ImageSize
)) != NULL
)
3811 /* Fail if the user requested a fixed base address. */
3812 if ((*BaseAddress
) != NULL
)
3814 MmUnlockAddressSpace(AddressSpace
);
3815 return(STATUS_UNSUCCESSFUL
);
3817 /* Otherwise find a gap to map the image. */
3818 ImageBase
= MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), FALSE
);
3819 if (ImageBase
== NULL
)
3821 MmUnlockAddressSpace(AddressSpace
);
3822 return(STATUS_UNSUCCESSFUL
);
3826 for (i
= 0; i
< NrSegments
; i
++)
3830 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3832 SBaseAddress
= (PVOID
)
3833 (ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3834 MmLockSectionSegment(&SectionSegments
[i
]);
3835 Status
= MmMapViewOfSegment(Process
,
3838 &SectionSegments
[i
],
3840 SectionSegments
[i
].Length
,
3841 SectionSegments
[i
].Protection
,
3842 (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
,
3844 MmUnlockSectionSegment(&SectionSegments
[i
]);
3845 if (!NT_SUCCESS(Status
))
3847 MmUnlockAddressSpace(AddressSpace
);
3853 *BaseAddress
= ImageBase
;
3857 if (SectionOffset
== NULL
)
3863 ViewOffset
= SectionOffset
->u
.LowPart
;
3866 if ((ViewOffset
% PAGE_SIZE
) != 0)
3868 MmUnlockAddressSpace(AddressSpace
);
3869 return(STATUS_MAPPED_ALIGNMENT
);
3872 if ((*ViewSize
) == 0)
3874 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
3876 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
3878 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
3881 MmLockSectionSegment(Section
->Segment
);
3882 Status
= MmMapViewOfSegment(Process
,
3890 (AllocationType
& MEM_TOP_DOWN
));
3891 MmUnlockSectionSegment(Section
->Segment
);
3892 if (!NT_SUCCESS(Status
))
3894 MmUnlockAddressSpace(AddressSpace
);
3899 MmUnlockAddressSpace(AddressSpace
);
3901 return(STATUS_SUCCESS
);
3908 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
3909 IN PLARGE_INTEGER NewFileSize
)
3920 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
3930 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
3931 IN MMFLUSH_TYPE FlushType
)
3935 case MmFlushForDelete
:
3936 if (SectionObjectPointer
->ImageSectionObject
||
3937 SectionObjectPointer
->DataSectionObject
)
3941 CcRosSetRemoveOnClose(SectionObjectPointer
);
3943 case MmFlushForWrite
:
3953 MmForceSectionClosed (DWORD Unknown0
,
3965 MmMapViewInSystemSpace (IN PVOID SectionObject
,
3966 OUT PVOID
* MappedBase
,
3967 IN OUT PULONG ViewSize
)
3969 PSECTION_OBJECT Section
;
3970 PMADDRESS_SPACE AddressSpace
;
3973 DPRINT("MmMapViewInSystemSpace() called\n");
3975 Section
= (PSECTION_OBJECT
)SectionObject
;
3976 AddressSpace
= MmGetKernelAddressSpace();
3978 MmLockAddressSpace(AddressSpace
);
3981 if ((*ViewSize
) == 0)
3983 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
3985 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
3987 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
3990 MmLockSectionSegment(Section
->Segment
);
3993 Status
= MmMapViewOfSegment(NULL
,
4003 MmUnlockSectionSegment(Section
->Segment
);
4004 MmUnlockAddressSpace(AddressSpace
);
4014 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4016 PMADDRESS_SPACE AddressSpace
;
4019 DPRINT("MmUnmapViewInSystemSpace() called\n");
4021 AddressSpace
= MmGetKernelAddressSpace();
4023 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4033 MmSetBankedSection (DWORD Unknown0
,
4041 return (STATUS_NOT_IMPLEMENTED
);
4045 /**********************************************************************
4050 * Creates a section object.
4053 * SectionObjiect (OUT)
4054 * Caller supplied storage for the resulting pointer
4055 * to a SECTION_OBJECT instance;
4058 * Specifies the desired access to the section can be a
4060 * STANDARD_RIGHTS_REQUIRED |
4062 * SECTION_MAP_WRITE |
4063 * SECTION_MAP_READ |
4064 * SECTION_MAP_EXECUTE
4066 * ObjectAttributes [OPTIONAL]
4067 * Initialized attributes for the object can be used
4068 * to create a named section;
4071 * Maximizes the size of the memory section. Must be
4072 * non-NULL for a page-file backed section.
4073 * If value specified for a mapped file and the file is
4074 * not large enough, file will be extended.
4076 * SectionPageProtection
4077 * Can be a combination of:
4083 * AllocationAttributes
4084 * Can be a combination of:
4089 * Handle to a file to create a section mapped to a file
4090 * instead of a memory backed section;
4101 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4102 IN ACCESS_MASK DesiredAccess
,
4103 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4104 IN PLARGE_INTEGER MaximumSize
,
4105 IN ULONG SectionPageProtection
,
4106 IN ULONG AllocationAttributes
,
4107 IN HANDLE FileHandle OPTIONAL
,
4108 IN PFILE_OBJECT File OPTIONAL
)
4110 return (STATUS_NOT_IMPLEMENTED
);