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.123 2003/07/14 20:14:11 hbirr 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
> Segment
->RawLength
&& Section
->AllocationAttributes
& SEC_IMAGE
))
918 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
922 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
924 if (!NT_SUCCESS(Status
) && Status
!= STATUS_END_OF_FILE
)
927 * FIXME: What do we know in this case?
929 DPRINT1("MiReadPage or MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
931 * Cleanup and release locks
933 MmLockAddressSpace(AddressSpace
);
934 PageOp
->Status
= Status
;
935 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
936 MmReleasePageOp(PageOp
);
937 DPRINT("Address 0x%.8X\n", Address
);
941 * Relock the address space and segment
943 MmLockAddressSpace(AddressSpace
);
944 MmLockSectionSegment(Segment
);
947 * Check the entry. No one should change the status of a page
948 * that has a pending page-in.
950 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
953 DbgPrint("Someone changed ppte entry while we slept\n");
958 * Mark the offset within the section as having valid, in-memory
961 Entry
= MAKE_SSE(Page
.u
.LowPart
, 1);
962 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
963 MmUnlockSectionSegment(Segment
);
965 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
970 if (Status
== STATUS_NO_MEMORY
)
972 MmUnlockAddressSpace(AddressSpace
);
973 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
978 MmLockAddressSpace(AddressSpace
);
980 if (!NT_SUCCESS(Status
))
982 DbgPrint("Unable to create virtual mapping\n");
985 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
991 PageOp
->Status
= STATUS_SUCCESS
;
992 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
993 MmReleasePageOp(PageOp
);
994 DPRINT("Address 0x%.8X\n", Address
);
995 return(STATUS_SUCCESS
);
997 else if (IS_SWAP_FROM_SSE(Entry
))
1002 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1005 * Release all our locks and read in the page from disk
1007 MmUnlockSectionSegment(Segment
);
1009 MmUnlockAddressSpace(AddressSpace
);
1011 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1012 if (!NT_SUCCESS(Status
))
1017 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1018 MmBuildMdlFromPages(Mdl
, (PULONG
)&Page
);
1019 Status
= MmReadFromSwapPage(SwapEntry
, Mdl
);
1020 if (!NT_SUCCESS(Status
))
1026 * Relock the address space and segment
1028 MmLockAddressSpace(AddressSpace
);
1029 MmLockSectionSegment(Segment
);
1032 * Check the entry. No one should change the status of a page
1033 * that has a pending page-in.
1035 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1036 if (Entry
!= Entry1
)
1038 DbgPrint("Someone changed ppte entry while we slept\n");
1043 * Mark the offset within the section as having valid, in-memory
1046 Entry
= MAKE_SSE(Page
.u
.LowPart
, 1);
1047 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1048 MmUnlockSectionSegment(Segment
);
1051 * Save the swap entry.
1053 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1054 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1059 if (Status
== STATUS_NO_MEMORY
)
1061 MmUnlockAddressSpace(AddressSpace
);
1062 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1067 MmLockAddressSpace(AddressSpace
);
1069 if (!NT_SUCCESS(Status
))
1071 DbgPrint("Unable to create virtual mapping\n");
1074 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1079 PageOp
->Status
= STATUS_SUCCESS
;
1080 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1081 MmReleasePageOp(PageOp
);
1082 DPRINT("Address 0x%.8X\n", Address
);
1083 return(STATUS_SUCCESS
);
1088 * If the section offset is already in-memory and valid then just
1089 * take another reference to the page
1092 Page
= (LARGE_INTEGER
)(LONGLONG
)PAGE_FROM_SSE(Entry
);
1093 MmReferencePage(Page
);
1094 MmSharePageEntrySectionSegment(Segment
, Offset
);
1095 MmUnlockSectionSegment(Segment
);
1097 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1102 if (Status
== STATUS_NO_MEMORY
)
1104 MmUnlockAddressSpace(AddressSpace
);
1105 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1110 MmLockAddressSpace(AddressSpace
);
1112 if (!NT_SUCCESS(Status
))
1114 DbgPrint("Unable to create virtual mapping\n");
1117 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1122 PageOp
->Status
= STATUS_SUCCESS
;
1123 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1124 MmReleasePageOp(PageOp
);
1125 DPRINT("Address 0x%.8X\n", Address
);
1126 return(STATUS_SUCCESS
);
1131 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1132 MEMORY_AREA
* MemoryArea
,
1136 PMM_SECTION_SEGMENT Segment
;
1137 PSECTION_OBJECT Section
;
1138 PHYSICAL_ADDRESS OldPage
;
1139 PHYSICAL_ADDRESS NewPage
;
1146 LARGE_INTEGER Timeout
;
1149 * Check if the page has been paged out or has already been set readwrite
1151 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1152 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1154 DPRINT("Address 0x%.8X\n", Address
);
1155 return(STATUS_SUCCESS
);
1159 * Find the offset of the page
1161 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
1162 Offset
= PAddress
- (ULONG
)MemoryArea
->BaseAddress
;
1164 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1165 Section
= MemoryArea
->Data
.SectionData
.Section
;
1166 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1167 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1172 MmLockSectionSegment(Segment
);
1177 if (MmGetPageEntrySectionSegment(Segment
, Offset
) == 0)
1179 DPRINT1("COW fault for page with PESS 0. Address was 0x%.8X\n",
1182 MmUnlockSectionSegment(Segment
);
1184 * Check if we are doing COW
1186 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1187 (Region
->Protect
== PAGE_READWRITE
||
1188 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1190 DPRINT("Address 0x%.8X\n", Address
);
1191 return(STATUS_UNSUCCESSFUL
);
1195 * Get or create a pageop
1197 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
,
1198 MM_PAGEOP_ACCESSFAULT
);
1201 DPRINT1("MmGetPageOp failed\n");
1206 * Wait for any other operations to complete
1208 if (PageOp
->Thread
!= PsGetCurrentThread())
1210 MmUnlockAddressSpace(AddressSpace
);
1211 Timeout
.QuadPart
= -100000000LL; // 10 sec
1212 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
1218 * Check for various strange conditions
1220 if (Status
== STATUS_TIMEOUT
)
1222 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1225 if (PageOp
->Status
== STATUS_PENDING
)
1227 DPRINT1("Woke for page op before completion\n");
1231 * Restart the operation
1233 MmLockAddressSpace(AddressSpace
);
1234 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1235 MmReleasePageOp(PageOp
);
1236 DPRINT("Address 0x%.8X\n", Address
);
1237 return(STATUS_MM_RESTART_OPERATION
);
1241 * Release locks now we have the pageop
1243 MmUnlockAddressSpace(AddressSpace
);
1248 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1249 if (!NT_SUCCESS(Status
))
1257 OldPage
= MmGetPhysicalAddressForProcess(NULL
, Address
);
1259 NewAddress
= ExAllocatePageWithPhysPage(NewPage
);
1260 memcpy(NewAddress
, (PVOID
)PAddress
, PAGE_SIZE
);
1261 ExUnmapPage(NewAddress
);
1264 * Delete the old entry.
1266 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1269 * Set the PTE to point to the new page
1271 MmLockAddressSpace(AddressSpace
);
1272 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1277 if (Status
== STATUS_NO_MEMORY
)
1279 MmUnlockAddressSpace(AddressSpace
);
1280 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1285 MmLockAddressSpace(AddressSpace
);
1287 if (!NT_SUCCESS(Status
))
1289 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1293 MmInsertRmap(NewPage
, AddressSpace
->Process
, (PVOID
)PAddress
);
1294 if (!NT_SUCCESS(Status
))
1296 DbgPrint("Unable to create virtual mapping\n");
1301 MmLockPage(NewPage
);
1305 * Unshare the old page.
1307 MmDeleteRmap(OldPage
, AddressSpace
->Process
, (PVOID
)PAddress
);
1308 MmLockSectionSegment(Segment
);
1309 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
);
1310 MmUnlockSectionSegment(Segment
);
1311 MmReleasePageMemoryConsumer(MC_USER
, OldPage
);
1313 PageOp
->Status
= STATUS_SUCCESS
;
1314 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1315 MmReleasePageOp(PageOp
);
1316 DPRINT("Address 0x%.8X\n", Address
);
1317 return(STATUS_SUCCESS
);
1321 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1323 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1325 PHYSICAL_ADDRESS Page
;
1327 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1328 MmDeleteVirtualMapping(Process
,
1335 PageOutContext
->WasDirty
= TRUE
;
1337 if (!PageOutContext
->Private
)
1339 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1340 PageOutContext
->Segment
,
1341 PageOutContext
->Offset
,
1342 PageOutContext
->WasDirty
);
1344 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1345 DPRINT("PhysicalAddress %I64x, Address %x\n", Page
, Address
);
1349 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1350 MEMORY_AREA
* MemoryArea
,
1354 PHYSICAL_ADDRESS PhysicalAddress
;
1355 MM_SECTION_PAGEOUT_CONTEXT Context
;
1356 SWAPENTRY SwapEntry
;
1361 PFILE_OBJECT FileObject
;
1363 BOOLEAN DirectMapped
;
1364 BOOLEAN IsImageSection
;
1366 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1369 * Get the segment and section.
1371 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1372 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1374 Context
.Offset
= (ULONG
)(Address
- (ULONG
)MemoryArea
->BaseAddress
);
1375 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1377 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1379 FileObject
= Context
.Section
->FileObject
;
1380 DirectMapped
= FALSE
;
1381 if (FileObject
!= NULL
)
1383 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1386 * If the file system is letting us go directly to the cache and the
1387 * memory area was mapped at an offset in the file which is page aligned
1388 * then note this is a direct mapped page.
1390 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
1391 (FileOffset
% PAGE_SIZE
) == 0 &&
1392 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1394 DirectMapped
= TRUE
;
1400 * This should never happen since mappings of physical memory are never
1401 * placed in the rmap lists.
1403 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1405 DPRINT1("Trying to page out from physical memory section address 0x%X "
1406 "process %d\n", Address
,
1407 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1412 * Get the section segment entry and the physical address.
1414 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1415 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1417 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1418 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1422 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1423 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1426 * Prepare the context structure for the rmap delete call.
1428 Context
.WasDirty
= FALSE
;
1429 if (Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1430 IS_SWAP_FROM_SSE(Entry
) ||
1431 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
)
1433 Context
.Private
= TRUE
;
1437 Context
.Private
= FALSE
;
1441 * Paging out data mapped read-only is easy.
1443 if (Context
.Segment
->Protection
& (PAGE_READONLY
|PAGE_EXECUTE_READ
))
1446 * Read-only data should never be in the swapfile.
1450 DPRINT1("SwapEntry != 0 was 0x%.8X at address 0x%.8X, "
1451 "paddress 0x%.8X\n", SwapEntry
, Address
,
1457 * Read-only data should never be COWed
1459 if (Context
.Private
)
1461 DPRINT1("Had private copy of read-only page.\n");
1466 * Delete all mappings of this page.
1468 MmDeleteAllRmaps(PhysicalAddress
, (PVOID
)&Context
,
1469 MmPageOutDeleteMapping
);
1470 if (Context
.WasDirty
)
1472 DPRINT1("Had a dirty page of a read-only page.\n");
1476 PageOp
->Status
= STATUS_SUCCESS
;
1477 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1478 MmReleasePageOp(PageOp
);
1479 return(STATUS_SUCCESS
);
1483 * Otherwise we have read-write data.
1487 * Take an additional reference to the page or the cache segment.
1489 if (DirectMapped
&& !Context
.Private
)
1491 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1493 DPRINT1("Direct mapped non private page is not associated with the cache.\n")
1499 MmReferencePage(PhysicalAddress
);
1502 MmDeleteAllRmaps(PhysicalAddress
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1505 * If this wasn't a private page then we should have reduced the entry to
1506 * zero by deleting all the rmaps.
1508 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1510 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
))
1518 * If the page wasn't dirty then we can just free it as for a readonly page.
1519 * Since we unmapped all the mappings above we know it will not suddenly
1521 * If the page is from a pagefile section and has no swap entry,
1522 * we can't free the page at this point.
1524 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1525 if (!Context
.WasDirty
&&
1526 !(SwapEntry
== 0 && Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
))
1529 if (Context
.Private
)
1531 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
1532 if (!(Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
) &&
1535 DPRINT1("Private page, non-dirty but not swapped out "
1536 "process %d address 0x%.8X\n",
1537 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0,
1543 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1546 if (!NT_SUCCESS(Status
))
1552 if (DirectMapped
&& !Context
.Private
)
1554 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1555 if (!NT_SUCCESS(Status
))
1557 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1563 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1566 PageOp
->Status
= STATUS_SUCCESS
;
1567 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1568 MmReleasePageOp(PageOp
);
1569 return(STATUS_SUCCESS
);
1573 * If this page was direct mapped from the cache then the cache manager
1574 * will already have taken care of writing it back.
1576 if (DirectMapped
&& !Context
.Private
)
1578 assert(SwapEntry
== 0);
1579 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1580 if (!NT_SUCCESS(Status
))
1582 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
1585 PageOp
->Status
= STATUS_SUCCESS
;
1586 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1587 MmReleasePageOp(PageOp
);
1588 return(STATUS_SUCCESS
);
1592 * If necessary, allocate an entry in the paging file for this page
1596 SwapEntry
= MmAllocSwapPage();
1599 MmShowOutOfSpaceMessagePagingFile();
1602 * For private pages restore the old mappings.
1604 if (Context
.Private
)
1606 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1608 MemoryArea
->Attributes
,
1611 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1612 MmInsertRmap(PhysicalAddress
,
1613 MemoryArea
->Process
,
1619 * For non-private pages if the page wasn't direct mapped then
1620 * set it back into the section segment entry so we don't loose
1621 * our copy. Otherwise it will be handled by the cache manager.
1623 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1625 MemoryArea
->Attributes
,
1628 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1629 MmInsertRmap(PhysicalAddress
,
1630 MemoryArea
->Process
,
1632 Entry
= MAKE_SSE(PhysicalAddress
.u
.LowPart
, 1);
1633 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1635 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1636 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1637 MmReleasePageOp(PageOp
);
1638 return(STATUS_PAGEFILE_QUOTA
);
1643 * Write the page to the pagefile
1645 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1646 MmBuildMdlFromPages(Mdl
, (PULONG
)&PhysicalAddress
);
1647 Status
= MmWriteToSwapPage(SwapEntry
, Mdl
);
1648 if (!NT_SUCCESS(Status
))
1650 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1653 * As above: undo our actions.
1654 * FIXME: Also free the swap page.
1656 if (Context
.Private
)
1658 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1660 MemoryArea
->Attributes
,
1663 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1664 MmInsertRmap(PhysicalAddress
,
1665 MemoryArea
->Process
,
1670 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1672 MemoryArea
->Attributes
,
1675 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1676 MmInsertRmap(PhysicalAddress
,
1677 MemoryArea
->Process
,
1679 Entry
= MAKE_SSE(PhysicalAddress
.u
.LowPart
, 1);
1680 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1682 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1683 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1684 MmReleasePageOp(PageOp
);
1685 return(STATUS_UNSUCCESSFUL
);
1689 * Otherwise we have succeeded.
1691 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress
);
1692 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
1693 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1695 if (Context
.Private
)
1697 Status
= MmCreatePageFileMapping(MemoryArea
->Process
,
1700 if (!NT_SUCCESS(Status
))
1707 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1708 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1711 PageOp
->Status
= STATUS_SUCCESS
;
1712 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1713 MmReleasePageOp(PageOp
);
1714 return(STATUS_SUCCESS
);
1718 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1719 PMEMORY_AREA MemoryArea
,
1724 PSECTION_OBJECT Section
;
1725 PMM_SECTION_SEGMENT Segment
;
1726 PHYSICAL_ADDRESS PhysicalAddress
;
1727 SWAPENTRY SwapEntry
;
1732 PFILE_OBJECT FileObject
;
1734 BOOLEAN DirectMapped
;
1735 BOOLEAN IsImageSection
;
1737 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1739 Offset
= (ULONG
)(Address
- (ULONG
)MemoryArea
->BaseAddress
);
1742 * Get the segment and section.
1744 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1745 Section
= MemoryArea
->Data
.SectionData
.Section
;
1746 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1748 FileObject
= Section
->FileObject
;
1749 DirectMapped
= FALSE
;
1750 if (FileObject
!= NULL
)
1752 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1755 * If the file system is letting us go directly to the cache and the
1756 * memory area was mapped at an offset in the file which is page aligned
1757 * then note this is a direct mapped page.
1759 if (FileObject
->Flags
& FO_DIRECT_CACHE_PAGING_READ
&&
1760 (Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
% PAGE_SIZE
) == 0 &&
1761 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1763 DirectMapped
= TRUE
;
1768 * This should never happen since mappings of physical memory are never
1769 * placed in the rmap lists.
1771 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1773 DPRINT1("Trying to write back page from physical memory mapped at %X "
1774 "process %d\n", Address
,
1775 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1780 * Get the section segment entry and the physical address.
1782 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1783 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1785 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1786 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1790 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1791 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1794 * Check for a private (COWed) page.
1796 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1797 IS_SWAP_FROM_SSE(Entry
) ||
1798 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
)
1808 * Speculatively set all mappings of the page to clean.
1810 MmSetCleanAllRmaps(PhysicalAddress
);
1813 * If this page was direct mapped from the cache then the cache manager
1814 * will take care of writing it back to disk.
1816 if (DirectMapped
&& !Private
)
1818 assert(SwapEntry
== 0);
1819 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
1820 PageOp
->Status
= STATUS_SUCCESS
;
1821 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1822 MmReleasePageOp(PageOp
);
1823 return(STATUS_SUCCESS
);
1827 * If necessary, allocate an entry in the paging file for this page
1831 SwapEntry
= MmAllocSwapPage();
1834 MmSetDirtyAllRmaps(PhysicalAddress
);
1835 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1836 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1837 MmReleasePageOp(PageOp
);
1838 return(STATUS_PAGEFILE_QUOTA
);
1843 * Write the page to the pagefile
1845 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1846 MmBuildMdlFromPages(Mdl
, (PULONG
)&PhysicalAddress
);
1847 Status
= MmWriteToSwapPage(SwapEntry
, Mdl
);
1848 if (!NT_SUCCESS(Status
))
1850 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1852 MmSetDirtyAllRmaps(PhysicalAddress
);
1853 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1854 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1855 MmReleasePageOp(PageOp
);
1856 return(STATUS_UNSUCCESSFUL
);
1860 * Otherwise we have succeeded.
1862 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress
);
1863 MmSetSavedSwapEntryPage(PhysicalAddress
, SwapEntry
);
1864 PageOp
->Status
= STATUS_SUCCESS
;
1865 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
1866 MmReleasePageOp(PageOp
);
1867 return(STATUS_SUCCESS
);
1871 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1879 PMEMORY_AREA MemoryArea
;
1880 PMM_SECTION_SEGMENT Segment
;
1884 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1885 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1887 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1888 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1893 if (OldProtect
!= NewProtect
)
1895 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1897 PVOID Address
= BaseAddress
+ (i
* PAGE_SIZE
);
1898 ULONG Protect
= NewProtect
;
1901 * If we doing COW for this segment then check if the page is
1904 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1908 LARGE_INTEGER PhysicalAddress
;
1910 Offset
= (ULONG
)Address
- (ULONG
)MemoryArea
->BaseAddress
;
1911 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1913 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1915 Protect
= PAGE_READONLY
;
1916 if ((Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1917 IS_SWAP_FROM_SSE(Entry
) ||
1918 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
))
1920 Protect
= NewProtect
;
1924 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1926 MmSetPageProtect(AddressSpace
->Process
, BaseAddress
,
1934 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1935 PMEMORY_AREA MemoryArea
,
1945 min(Length
, (ULONG
) (MemoryArea
->BaseAddress
+ MemoryArea
->Length
- BaseAddress
));
1946 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1947 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1949 *OldProtect
= Region
->Protect
;
1950 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->BaseAddress
,
1951 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1952 BaseAddress
, Length
, Region
->Type
, Protect
,
1953 MmAlterViewAttributes
);
1959 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
1961 PMEMORY_BASIC_INFORMATION Info
,
1962 PULONG ResultLength
)
1965 PVOID RegionBaseAddress
;
1967 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1968 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1969 Address
, &RegionBaseAddress
);
1972 return STATUS_UNSUCCESSFUL
;
1974 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1975 Info
->AllocationBase
= MemoryArea
->BaseAddress
;
1976 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1977 Info
->RegionSize
= MemoryArea
->Length
;
1978 Info
->State
= MEM_COMMIT
;
1979 Info
->Protect
= Region
->Protect
;
1980 if (MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
)
1982 Info
->Type
= MEM_IMAGE
;
1986 Info
->Type
= MEM_MAPPED
;
1989 return(STATUS_SUCCESS
);
1993 MmpDeleteSection(PVOID ObjectBody
)
1995 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
1997 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
1998 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2002 PMM_SECTION_SEGMENT SectionSegments
;
2004 SectionSegments
= Section
->ImageSection
->Segments
;
2005 NrSegments
= Section
->ImageSection
->NrSegments
;
2007 for (i
= 0; i
< NrSegments
; i
++)
2009 InterlockedDecrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2014 InterlockedDecrement((LONG
*)&Section
->Segment
->ReferenceCount
);
2016 if (Section
->FileObject
!= NULL
)
2018 CcRosDereferenceCache(Section
->FileObject
);
2019 ObDereferenceObject(Section
->FileObject
);
2020 Section
->FileObject
= NULL
;
2023 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2028 PMM_SECTION_SEGMENT Segment
;
2030 Segment
= Section
->Segment
;
2031 Length
= PAGE_ROUND_UP(Segment
->Length
);
2033 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2035 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2038 if (IS_SWAP_FROM_SSE(Entry
))
2040 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2044 PHYSICAL_ADDRESS Page
= (PHYSICAL_ADDRESS
)(LONGLONG
)PAGE_FROM_SSE(Entry
);
2045 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2049 MmFreePageTablesSectionSegment(Section
->Segment
);
2050 ExFreePool(Section
->Segment
);
2055 MmpCloseSection(PVOID ObjectBody
,
2058 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2059 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2063 MmpCreateSection(PVOID ObjectBody
,
2065 PWSTR RemainingPath
,
2066 POBJECT_ATTRIBUTES ObjectAttributes
)
2068 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2069 ObjectBody
, Parent
, RemainingPath
);
2071 if (RemainingPath
== NULL
)
2073 return(STATUS_SUCCESS
);
2076 if (wcschr(RemainingPath
+1, L
'\\') != NULL
)
2078 return(STATUS_UNSUCCESSFUL
);
2080 return(STATUS_SUCCESS
);
2084 MmCreatePhysicalMemorySection(VOID
)
2086 HANDLE PhysSectionH
;
2087 PSECTION_OBJECT PhysSection
;
2089 OBJECT_ATTRIBUTES Obj
;
2090 UNICODE_STRING Name
= UNICODE_STRING_INITIALIZER(L
"\\Device\\PhysicalMemory");
2091 LARGE_INTEGER SectionSize
;
2094 * Create the section mapping physical memory
2096 SectionSize
.QuadPart
= 0xFFFFFFFF;
2097 InitializeObjectAttributes(&Obj
,
2102 Status
= NtCreateSection(&PhysSectionH
,
2106 PAGE_EXECUTE_READWRITE
,
2109 if (!NT_SUCCESS(Status
))
2111 DbgPrint("Failed to create PhysicalMemory section\n");
2114 Status
= ObReferenceObjectByHandle(PhysSectionH
,
2118 (PVOID
*)&PhysSection
,
2120 if (!NT_SUCCESS(Status
))
2122 DbgPrint("Failed to reference PhysicalMemory section\n");
2125 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2126 ObDereferenceObject((PVOID
)PhysSection
);
2128 return(STATUS_SUCCESS
);
2132 MmInitSectionImplementation(VOID
)
2134 MmSectionObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
2136 RtlInitUnicodeStringFromLiteral(&MmSectionObjectType
->TypeName
, L
"Section");
2138 MmSectionObjectType
->Tag
= TAG('S', 'E', 'C', 'T');
2139 MmSectionObjectType
->TotalObjects
= 0;
2140 MmSectionObjectType
->TotalHandles
= 0;
2141 MmSectionObjectType
->MaxObjects
= ULONG_MAX
;
2142 MmSectionObjectType
->MaxHandles
= ULONG_MAX
;
2143 MmSectionObjectType
->PagedPoolCharge
= 0;
2144 MmSectionObjectType
->NonpagedPoolCharge
= sizeof(SECTION_OBJECT
);
2145 MmSectionObjectType
->Mapping
= &MmpSectionMapping
;
2146 MmSectionObjectType
->Dump
= NULL
;
2147 MmSectionObjectType
->Open
= NULL
;
2148 MmSectionObjectType
->Close
= MmpCloseSection
;
2149 MmSectionObjectType
->Delete
= MmpDeleteSection
;
2150 MmSectionObjectType
->Parse
= NULL
;
2151 MmSectionObjectType
->Security
= NULL
;
2152 MmSectionObjectType
->QueryName
= NULL
;
2153 MmSectionObjectType
->OkayToClose
= NULL
;
2154 MmSectionObjectType
->Create
= MmpCreateSection
;
2155 MmSectionObjectType
->DuplicationNotify
= NULL
;
2157 return(STATUS_SUCCESS
);
2161 MmCreatePageFileSection(PHANDLE SectionHandle
,
2162 ACCESS_MASK DesiredAccess
,
2163 POBJECT_ATTRIBUTES ObjectAttributes
,
2164 PLARGE_INTEGER UMaximumSize
,
2165 ULONG SectionPageProtection
,
2166 ULONG AllocationAttributes
)
2168 * Create a section which is backed by the pagefile
2171 LARGE_INTEGER MaximumSize
;
2172 PSECTION_OBJECT Section
;
2173 PMM_SECTION_SEGMENT Segment
;
2176 if (UMaximumSize
== NULL
)
2178 return(STATUS_UNSUCCESSFUL
);
2180 MaximumSize
= *UMaximumSize
;
2183 * Check the protection
2185 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2186 SectionPageProtection
)
2188 return(STATUS_INVALID_PAGE_PROTECTION
);
2192 * Create the section
2194 Status
= ObRosCreateObject(SectionHandle
,
2197 MmSectionObjectType
,
2199 if (!NT_SUCCESS(Status
))
2207 Section
->SectionPageProtection
= SectionPageProtection
;
2208 Section
->AllocationAttributes
= AllocationAttributes
;
2209 InitializeListHead(&Section
->ViewListHead
);
2210 KeInitializeSpinLock(&Section
->ViewListLock
);
2211 Section
->FileObject
= NULL
;
2212 Section
->MaximumSize
= MaximumSize
;
2213 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2214 TAG_MM_SECTION_SEGMENT
);
2215 if (Segment
== NULL
)
2217 ZwClose(*SectionHandle
);
2218 ObDereferenceObject(Section
);
2219 return(STATUS_NO_MEMORY
);
2221 Section
->Segment
= Segment
;
2222 Segment
->ReferenceCount
= 1;
2223 ExInitializeFastMutex(&Segment
->Lock
);
2224 Segment
->FileOffset
= 0;
2225 Segment
->Protection
= SectionPageProtection
;
2226 Segment
->Attributes
= AllocationAttributes
;
2227 Segment
->Length
= MaximumSize
.u
.LowPart
;
2228 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2229 Segment
->WriteCopy
= FALSE
;
2230 ObDereferenceObject(Section
);
2231 return(STATUS_SUCCESS
);
2236 MmCreateDataFileSection(PHANDLE SectionHandle
,
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
);
2267 * Read a bit so caching is initiated for the file object.
2268 * This is only needed because MiReadPage currently cannot
2269 * handle non-cached streams.
2271 Offset
.QuadPart
= 0;
2272 Status
= ZwReadFile(FileHandle
,
2281 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2287 * Create the section
2289 Status
= ObRosCreateObject(SectionHandle
,
2292 MmSectionObjectType
,
2294 if (!NT_SUCCESS(Status
))
2302 Section
->SectionPageProtection
= SectionPageProtection
;
2303 Section
->AllocationAttributes
= AllocationAttributes
;
2304 InitializeListHead(&Section
->ViewListHead
);
2305 KeInitializeSpinLock(&Section
->ViewListLock
);
2308 * Check file access required
2310 if (SectionPageProtection
& PAGE_READWRITE
||
2311 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2313 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2317 FileAccess
= FILE_READ_DATA
;
2321 * Reference the file handle
2323 Status
= ObReferenceObjectByHandle(FileHandle
,
2327 (PVOID
*)&FileObject
,
2329 if (!NT_SUCCESS(Status
))
2331 ZwClose(*SectionHandle
);
2332 ObDereferenceObject(Section
);
2337 * We can't do memory mappings if the file system doesn't support the
2340 if (!(FileObject
->Flags
& FO_FCB_IS_VALID
))
2342 ZwClose(*SectionHandle
);
2343 ObDereferenceObject(Section
);
2344 ObDereferenceObject(FileObject
);
2345 return(STATUS_INVALID_FILE_FOR_SECTION
);
2349 * FIXME: Revise this once a locking order for file size changes is
2352 if (UMaximumSize
!= NULL
)
2354 MaximumSize
= *UMaximumSize
;
2359 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
;
2362 if (MaximumSize
.QuadPart
>
2363 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
.QuadPart
)
2365 IO_STATUS_BLOCK Iosb
;
2366 Status
= NtSetInformationFile(FileHandle
,
2369 sizeof(LARGE_INTEGER
),
2370 FileAllocationInformation
);
2371 if (!NT_SUCCESS(Status
))
2373 ZwClose(*SectionHandle
);
2374 ObDereferenceObject(Section
);
2375 ObDereferenceObject(FileObject
);
2376 return(STATUS_SECTION_NOT_EXTENDED
);
2383 Status
= KeWaitForSingleObject((PVOID
)&FileObject
->Lock
,
2388 if (Status
!= STATUS_SUCCESS
)
2390 ZwClose(*SectionHandle
);
2391 ObDereferenceObject(Section
);
2392 ObDereferenceObject(FileObject
);
2397 * If this file hasn't been mapped as a data file before then allocate a
2398 * section segment to describe the data file mapping
2400 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2402 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2403 TAG_MM_SECTION_SEGMENT
);
2404 if (Segment
== NULL
)
2406 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2407 ZwClose(*SectionHandle
);
2408 ObDereferenceObject(Section
);
2409 ObDereferenceObject(FileObject
);
2410 return(STATUS_NO_MEMORY
);
2412 Section
->Segment
= Segment
;
2413 Segment
->ReferenceCount
= 1;
2414 ExInitializeFastMutex(&Segment
->Lock
);
2416 * Set the lock before assigning the segment to the file object
2418 ExAcquireFastMutex(&Segment
->Lock
);
2419 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2421 Segment
->FileOffset
= 0;
2422 Segment
->Protection
= 0;
2423 Segment
->Attributes
= 0;
2424 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2425 Segment
->Characteristics
= 0;
2426 Segment
->WriteCopy
= FALSE
;
2427 if (AllocationAttributes
& SEC_RESERVE
)
2429 Segment
->Length
= Segment
->RawLength
= 0;
2433 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2434 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2436 Segment
->VirtualAddress
= NULL
;
2441 * If the file is already mapped as a data file then we may need
2445 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2447 Section
->Segment
= Segment
;
2448 InterlockedIncrement((PLONG
)&Segment
->ReferenceCount
);
2449 MmLockSectionSegment(Segment
);
2451 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2452 !(AllocationAttributes
& SEC_RESERVE
))
2454 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2455 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2458 MmUnlockSectionSegment(Segment
);
2459 Section
->FileObject
= FileObject
;
2460 Section
->MaximumSize
= MaximumSize
;
2461 CcRosReferenceCache(FileObject
);
2462 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2463 ObDereferenceObject(Section
);
2464 return(STATUS_SUCCESS
);
2467 static ULONG SectionCharacteristicsToProtect
[16] =
2469 PAGE_NOACCESS
, // 0 = NONE
2470 PAGE_NOACCESS
, // 1 = SHARED
2471 PAGE_EXECUTE
, // 2 = EXECUTABLE
2472 PAGE_EXECUTE
, // 3 = EXECUTABLE, SHARED
2473 PAGE_READONLY
, // 4 = READABLE
2474 PAGE_READONLY
, // 5 = READABLE, SHARED
2475 PAGE_EXECUTE_READ
, // 6 = READABLE, EXECUTABLE
2476 PAGE_EXECUTE_READ
, // 7 = READABLE, EXECUTABLE, SHARED
2477 PAGE_READWRITE
, // 8 = WRITABLE
2478 PAGE_READWRITE
, // 9 = WRITABLE, SHARED
2479 PAGE_EXECUTE_READWRITE
, // 10 = WRITABLE, EXECUTABLE
2480 PAGE_EXECUTE_READWRITE
, // 11 = WRITABLE, EXECUTABLE, SHARED
2481 PAGE_READWRITE
, // 12 = WRITABLE, READABLE
2482 PAGE_READWRITE
, // 13 = WRITABLE, READABLE, SHARED
2483 PAGE_EXECUTE_READWRITE
, // 14 = WRITABLE, READABLE, EXECUTABLE,
2484 PAGE_EXECUTE_READWRITE
, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
2488 MmCreateImageSection(PHANDLE SectionHandle
,
2489 ACCESS_MASK DesiredAccess
,
2490 POBJECT_ATTRIBUTES ObjectAttributes
,
2491 PLARGE_INTEGER UMaximumSize
,
2492 ULONG SectionPageProtection
,
2493 ULONG AllocationAttributes
,
2496 PSECTION_OBJECT Section
;
2498 PFILE_OBJECT FileObject
;
2499 IMAGE_DOS_HEADER DosHeader
;
2500 IO_STATUS_BLOCK Iosb
;
2501 LARGE_INTEGER Offset
;
2502 IMAGE_NT_HEADERS PEHeader
;
2503 PIMAGE_SECTION_HEADER ImageSections
;
2504 PMM_SECTION_SEGMENT SectionSegments
;
2506 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
2509 ULONG Characteristics
;
2510 ULONG FileAccess
= 0;
2512 * Check the protection
2514 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2515 SectionPageProtection
)
2517 return(STATUS_INVALID_PAGE_PROTECTION
);
2521 * Specifying a maximum size is meaningless for an image section
2523 if (UMaximumSize
!= NULL
)
2525 return(STATUS_INVALID_PARAMETER_4
);
2529 * Reference the file handle
2531 Status
= ObReferenceObjectByHandle(FileHandle
,
2535 (PVOID
*)&FileObject
,
2537 if (!NT_SUCCESS(Status
))
2543 * Initialized caching for this file object if previously caching
2544 * was initialized for the same on disk file
2546 Status
= CcTryToInitializeFileCache(FileObject
);
2548 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
2551 * Read the dos header and check the DOS signature
2553 Offset
.QuadPart
= 0;
2554 Status
= ZwReadFile(FileHandle
,
2563 if (!NT_SUCCESS(Status
))
2565 ObDereferenceObject(FileObject
);
2570 * Check the DOS signature
2572 if (Iosb
.Information
!= sizeof(DosHeader
) ||
2573 DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
)
2575 ObDereferenceObject(FileObject
);
2576 return(STATUS_INVALID_IMAGE_FORMAT
);
2580 * Read the PE header
2582 Offset
.QuadPart
= DosHeader
.e_lfanew
;
2583 Status
= ZwReadFile(FileHandle
,
2592 if (!NT_SUCCESS(Status
))
2594 ObDereferenceObject(FileObject
);
2599 * Check the signature
2601 if (Iosb
.Information
!= sizeof(PEHeader
) ||
2602 PEHeader
.Signature
!= IMAGE_NT_SIGNATURE
)
2604 ObDereferenceObject(FileObject
);
2605 return(STATUS_INVALID_IMAGE_FORMAT
);
2609 * Read in the section headers
2611 Offset
.QuadPart
= DosHeader
.e_lfanew
+ sizeof(PEHeader
);
2612 ImageSections
= ExAllocatePool(NonPagedPool
,
2613 PEHeader
.FileHeader
.NumberOfSections
*
2614 sizeof(IMAGE_SECTION_HEADER
));
2615 if (ImageSections
== NULL
)
2617 ObDereferenceObject(FileObject
);
2618 return(STATUS_NO_MEMORY
);
2621 Status
= ZwReadFile(FileHandle
,
2627 PEHeader
.FileHeader
.NumberOfSections
*
2628 sizeof(IMAGE_SECTION_HEADER
),
2631 if (!NT_SUCCESS(Status
))
2633 ObDereferenceObject(FileObject
);
2634 ExFreePool(ImageSections
);
2637 if (Iosb
.Information
!= (PEHeader
.FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
)))
2639 ObDereferenceObject(FileObject
);
2640 ExFreePool(ImageSections
);
2641 return(STATUS_INVALID_IMAGE_FORMAT
);
2645 * Create the section
2647 Status
= ObRosCreateObject(SectionHandle
,
2650 MmSectionObjectType
,
2652 if (!NT_SUCCESS(Status
))
2654 ObDereferenceObject(FileObject
);
2655 ExFreePool(ImageSections
);
2662 Section
->SectionPageProtection
= SectionPageProtection
;
2663 Section
->AllocationAttributes
= AllocationAttributes
;
2664 InitializeListHead(&Section
->ViewListHead
);
2665 KeInitializeSpinLock(&Section
->ViewListLock
);
2668 * Check file access required
2670 if (SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
2672 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2676 FileAccess
= FILE_READ_DATA
;
2680 * We can't do memory mappings if the file system doesn't support the
2683 if (!(FileObject
->Flags
& FO_FCB_IS_VALID
))
2685 ZwClose(*SectionHandle
);
2686 ObDereferenceObject(Section
);
2687 ObDereferenceObject(FileObject
);
2688 ExFreePool(ImageSections
);
2689 return(STATUS_INVALID_FILE_FOR_SECTION
);
2695 Status
= KeWaitForSingleObject((PVOID
)&FileObject
->Lock
,
2700 if (Status
!= STATUS_SUCCESS
)
2702 ZwClose(*SectionHandle
);
2703 ObDereferenceObject(Section
);
2704 ObDereferenceObject(FileObject
);
2705 ExFreePool(ImageSections
);
2710 * allocate the section segments to describe the mapping
2712 NrSegments
= PEHeader
.FileHeader
.NumberOfSections
+ 1;
2713 Size
= sizeof(MM_IMAGE_SECTION_OBJECT
) + sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2714 ImageSectionObject
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_MM_SECTION_SEGMENT
);
2715 if (ImageSectionObject
== NULL
)
2717 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2718 ZwClose(*SectionHandle
);
2719 ObDereferenceObject(Section
);
2720 ObDereferenceObject(FileObject
);
2721 ExFreePool(ImageSections
);
2722 return(STATUS_NO_MEMORY
);
2724 Section
->ImageSection
= ImageSectionObject
;
2725 ImageSectionObject
->NrSegments
= NrSegments
;
2726 ImageSectionObject
->ImageBase
= (PVOID
)PEHeader
.OptionalHeader
.ImageBase
;
2727 ImageSectionObject
->EntryPoint
= (PVOID
)PEHeader
.OptionalHeader
.AddressOfEntryPoint
;
2728 ImageSectionObject
->StackReserve
= PEHeader
.OptionalHeader
.SizeOfStackReserve
;
2729 ImageSectionObject
->StackCommit
= PEHeader
.OptionalHeader
.SizeOfStackCommit
;
2730 ImageSectionObject
->Subsystem
= PEHeader
.OptionalHeader
.Subsystem
;
2731 ImageSectionObject
->MinorSubsystemVersion
= PEHeader
.OptionalHeader
.MinorSubsystemVersion
;
2732 ImageSectionObject
->MajorSubsystemVersion
= PEHeader
.OptionalHeader
.MajorSubsystemVersion
;
2733 ImageSectionObject
->ImageCharacteristics
= PEHeader
.FileHeader
.Characteristics
;
2734 ImageSectionObject
->Machine
= PEHeader
.FileHeader
.Machine
;
2735 ImageSectionObject
->Executable
= (PEHeader
.OptionalHeader
.SizeOfCode
!= 0);
2737 SectionSegments
= ImageSectionObject
->Segments
;
2738 SectionSegments
[0].FileOffset
= 0;
2739 SectionSegments
[0].Characteristics
= IMAGE_SECTION_CHAR_DATA
;
2740 SectionSegments
[0].Protection
= PAGE_READONLY
;
2741 SectionSegments
[0].RawLength
= PAGE_SIZE
;
2742 SectionSegments
[0].Length
= PAGE_SIZE
;
2743 SectionSegments
[0].Flags
= 0;
2744 SectionSegments
[0].ReferenceCount
= 1;
2745 SectionSegments
[0].VirtualAddress
= 0;
2746 SectionSegments
[0].WriteCopy
= FALSE
;
2747 ExInitializeFastMutex(&SectionSegments
[0].Lock
);
2748 for (i
= 1; i
< NrSegments
; i
++)
2750 SectionSegments
[i
].FileOffset
= ImageSections
[i
-1].PointerToRawData
;
2751 SectionSegments
[i
].Characteristics
= ImageSections
[i
-1].Characteristics
;
2754 * Set up the protection and write copy variables.
2756 Characteristics
= ImageSections
[i
- 1].Characteristics
;
2757 if (Characteristics
& (IMAGE_SECTION_CHAR_READABLE
|IMAGE_SECTION_CHAR_WRITABLE
|IMAGE_SECTION_CHAR_EXECUTABLE
))
2759 SectionSegments
[i
].Protection
= SectionCharacteristicsToProtect
[Characteristics
>> 28];
2760 SectionSegments
[i
].WriteCopy
= !(Characteristics
& IMAGE_SECTION_CHAR_SHARED
);
2762 else if (Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2764 SectionSegments
[i
].Protection
= PAGE_EXECUTE_READ
;
2765 SectionSegments
[i
].WriteCopy
= TRUE
;
2767 else if (Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2769 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2770 SectionSegments
[i
].WriteCopy
= TRUE
;
2772 else if (Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2774 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2775 SectionSegments
[i
].WriteCopy
= TRUE
;
2779 SectionSegments
[i
].Protection
= PAGE_NOACCESS
;
2780 SectionSegments
[i
].WriteCopy
= TRUE
;
2784 * Set up the attributes.
2786 if (Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2788 SectionSegments
[i
].Attributes
= 0;
2790 else if (Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2792 SectionSegments
[i
].Attributes
= 0;
2794 else if (Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2796 SectionSegments
[i
].Attributes
= MM_SECTION_SEGMENT_BSS
;
2800 SectionSegments
[i
].Attributes
= 0;
2803 SectionSegments
[i
].RawLength
= ImageSections
[i
-1].SizeOfRawData
;
2804 SectionSegments
[i
].Length
= ImageSections
[i
-1].Misc
.VirtualSize
;
2805 SectionSegments
[i
].Flags
= 0;
2806 SectionSegments
[i
].ReferenceCount
= 1;
2807 SectionSegments
[i
].VirtualAddress
= (PVOID
)ImageSections
[i
-1].VirtualAddress
;
2808 ExInitializeFastMutex(&SectionSegments
[i
].Lock
);
2810 if (0 != InterlockedCompareExchange((PLONG
)&FileObject
->SectionObjectPointer
->ImageSectionObject
,
2811 (LONG
)ImageSectionObject
, 0))
2814 * An other thread has initialized the some image in the background
2816 ExFreePool(ImageSectionObject
);
2817 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
2818 Section
->ImageSection
= ImageSectionObject
;
2819 SectionSegments
= ImageSectionObject
->Segments
;
2821 for (i
= 0; i
< NrSegments
; i
++)
2823 InterlockedIncrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2826 ExFreePool(ImageSections
);
2831 * Create the section
2833 Status
= ObRosCreateObject(SectionHandle
,
2836 MmSectionObjectType
,
2838 if (!NT_SUCCESS(Status
))
2840 ObDereferenceObject(FileObject
);
2847 Section
->SectionPageProtection
= SectionPageProtection
;
2848 Section
->AllocationAttributes
= AllocationAttributes
;
2849 InitializeListHead(&Section
->ViewListHead
);
2850 KeInitializeSpinLock(&Section
->ViewListLock
);
2853 * Check file access required
2855 if (SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
2857 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2861 FileAccess
= FILE_READ_DATA
;
2867 Status
= KeWaitForSingleObject((PVOID
)&FileObject
->Lock
,
2872 if (Status
!= STATUS_SUCCESS
)
2874 ZwClose(*SectionHandle
);
2875 ObDereferenceObject(Section
);
2876 ObDereferenceObject(FileObject
);
2880 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
2881 Section
->ImageSection
= ImageSectionObject
;
2882 SectionSegments
= ImageSectionObject
->Segments
;
2883 NrSegments
= ImageSectionObject
->NrSegments
;
2886 * Otherwise just reference all the section segments
2888 for (i
= 0; i
< NrSegments
; i
++)
2890 InterlockedIncrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2894 Section
->FileObject
= FileObject
;
2895 CcRosReferenceCache(FileObject
);
2896 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2897 ObDereferenceObject(Section
);
2898 return(STATUS_SUCCESS
);
2905 NtCreateSection (OUT PHANDLE SectionHandle
,
2906 IN ACCESS_MASK DesiredAccess
,
2907 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
2908 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
2909 IN ULONG SectionPageProtection OPTIONAL
,
2910 IN ULONG AllocationAttributes
,
2911 IN HANDLE FileHandle OPTIONAL
)
2913 if (AllocationAttributes
& SEC_IMAGE
)
2915 return(MmCreateImageSection(SectionHandle
,
2919 SectionPageProtection
,
2920 AllocationAttributes
,
2923 else if (FileHandle
!= NULL
)
2925 return(MmCreateDataFileSection(SectionHandle
,
2929 SectionPageProtection
,
2930 AllocationAttributes
,
2935 return(MmCreatePageFileSection(SectionHandle
,
2939 SectionPageProtection
,
2940 AllocationAttributes
));
2945 /**********************************************************************
2963 NtOpenSection(PHANDLE SectionHandle
,
2964 ACCESS_MASK DesiredAccess
,
2965 POBJECT_ATTRIBUTES ObjectAttributes
)
2971 Status
= ObOpenObjectByName(ObjectAttributes
,
2972 MmSectionObjectType
,
2983 MmMapViewOfSegment(PEPROCESS Process
,
2984 PMADDRESS_SPACE AddressSpace
,
2985 PSECTION_OBJECT Section
,
2986 PMM_SECTION_SEGMENT Segment
,
2997 Status
= MmCreateMemoryArea(Process
,
2999 MEMORY_AREA_SECTION_VIEW
,
3006 if (!NT_SUCCESS(Status
))
3008 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
3009 (*BaseAddress
), (*BaseAddress
) + ViewSize
);
3013 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3014 InsertTailList(&Section
->ViewListHead
,
3015 &MArea
->Data
.SectionData
.ViewListEntry
);
3016 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3018 ObReferenceObjectByPointer((PVOID
)Section
,
3021 ExGetPreviousMode());
3022 MArea
->Data
.SectionData
.Segment
= Segment
;
3023 MArea
->Data
.SectionData
.Section
= Section
;
3024 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3025 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3026 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3027 ViewSize
, 0, Protect
);
3029 return(STATUS_SUCCESS
);
3033 /**********************************************************************
3035 * NtMapViewOfSection
3038 * Maps a view of a section into the virtual address space of a
3043 * Handle of the section.
3046 * Handle of the process.
3049 * Desired base address (or NULL) on entry;
3050 * Actual base address of the view on exit.
3053 * Number of high order address bits that must be zero.
3056 * Size in bytes of the initially committed section of
3060 * Offset in bytes from the beginning of the section
3061 * to the beginning of the view.
3064 * Desired length of map (or zero to map all) on entry
3065 * Actual length mapped on exit.
3067 * InheritDisposition
3068 * Specified how the view is to be shared with
3072 * Type of allocation for the pages.
3075 * Protection for the committed region of the view.
3083 NtMapViewOfSection(HANDLE SectionHandle
,
3084 HANDLE ProcessHandle
,
3088 PLARGE_INTEGER SectionOffset
,
3090 SECTION_INHERIT InheritDisposition
,
3091 ULONG AllocationType
,
3094 PSECTION_OBJECT Section
;
3097 PMADDRESS_SPACE AddressSpace
;
3099 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3100 PROCESS_VM_OPERATION
,
3105 if (!NT_SUCCESS(Status
))
3110 AddressSpace
= &Process
->AddressSpace
;
3112 Status
= ObReferenceObjectByHandle(SectionHandle
,
3114 MmSectionObjectType
,
3118 if (!(NT_SUCCESS(Status
)))
3120 DPRINT("ObReference failed rc=%x\n",Status
);
3121 ObDereferenceObject(Process
);
3125 Status
= MmMapViewOfSection(Section
,
3136 ObDereferenceObject(Section
);
3137 ObDereferenceObject(Process
);
3143 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3144 PHYSICAL_ADDRESS PhysAddr
, SWAPENTRY SwapEntry
,
3149 PFILE_OBJECT FileObject
;
3152 SWAPENTRY SavedSwapEntry
;
3154 LARGE_INTEGER Timeout
;
3156 PSECTION_OBJECT Section
;
3157 PMM_SECTION_SEGMENT Segment
;
3159 MArea
= (PMEMORY_AREA
)Context
;
3161 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3163 Offset
= ((ULONG
)Address
- (ULONG
)MArea
->BaseAddress
);
3165 Section
= MArea
->Data
.SectionData
.Section
;
3166 Segment
= MArea
->Data
.SectionData
.Segment
;
3169 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3173 MmUnlockSectionSegment(Segment
);
3174 MmUnlockAddressSpace(&MArea
->Process
->AddressSpace
);
3176 Timeout
.QuadPart
= -100000000LL; // 10 sec
3177 Status
= KeWaitForSingleObject(&PageOp
->CompletionEvent
,
3182 if (Status
!= STATUS_SUCCESS
)
3184 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3188 MmLockAddressSpace(&MArea
->Process
->AddressSpace
);
3189 MmLockSectionSegment(Segment
);
3190 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
3191 MmReleasePageOp(PageOp
);
3192 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3195 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3198 * For a dirty, datafile, non-private page mark it as dirty in the
3201 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3203 if (PhysAddr
.QuadPart
== PAGE_FROM_SSE(Entry
) && Dirty
)
3205 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3206 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3207 CcRosMarkDirtyCacheSegment(Bcb
, Offset
);
3208 assert(SwapEntry
== 0);
3217 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3219 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3222 MmFreeSwapPage(SwapEntry
);
3224 else if (PhysAddr
.QuadPart
!= 0)
3226 if (IS_SWAP_FROM_SSE(Entry
) ||
3227 PhysAddr
.QuadPart
!= (PAGE_FROM_SSE(Entry
)))
3232 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3234 DPRINT1("Found a private page in a pagefile section.\n");
3238 * Just dereference private pages
3240 SavedSwapEntry
= MmGetSavedSwapEntryPage(PhysAddr
);
3241 if (SavedSwapEntry
!= 0)
3243 MmFreeSwapPage(SavedSwapEntry
);
3244 MmSetSavedSwapEntryPage(PhysAddr
, 0);
3246 MmDeleteRmap(PhysAddr
, MArea
->Process
, Address
);
3247 MmReleasePageMemoryConsumer(MC_USER
, PhysAddr
);
3251 MmDeleteRmap(PhysAddr
, MArea
->Process
, Address
);
3252 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
);
3253 MmReleasePageMemoryConsumer(MC_USER
, PhysAddr
);
3262 MmUnmapViewOfSection(PEPROCESS Process
,
3266 PMEMORY_AREA MemoryArea
;
3267 PMADDRESS_SPACE AddressSpace
;
3268 PSECTION_OBJECT Section
;
3269 PMM_SECTION_SEGMENT Segment
;
3271 PLIST_ENTRY CurrentEntry
;
3272 PMM_REGION CurrentRegion
;
3276 AddressSpace
= &Process
->AddressSpace
;
3278 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3279 Process
, BaseAddress
);
3280 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
3282 if (MemoryArea
== NULL
)
3284 return(STATUS_UNSUCCESSFUL
);
3287 MemoryArea
->DeleteInProgress
= TRUE
;
3288 Section
= MemoryArea
->Data
.SectionData
.Section
;
3289 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3291 MmLockSectionSegment(Segment
);
3292 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3293 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
3294 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3296 CurrentEntry
= MemoryArea
->Data
.SectionData
.RegionListHead
.Flink
;
3297 while (CurrentEntry
!= &MemoryArea
->Data
.SectionData
.RegionListHead
)
3300 CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3301 CurrentEntry
= CurrentEntry
->Flink
;
3302 ExFreePool(CurrentRegion
);
3305 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3307 Status
= MmFreeMemoryArea(&Process
->AddressSpace
,
3315 Status
= MmFreeMemoryArea(&Process
->AddressSpace
,
3321 MmUnlockSectionSegment(Segment
);
3322 ObDereferenceObject(Section
);
3323 return(STATUS_SUCCESS
);
3326 /**********************************************************************
3328 * NtUnmapViewOfSection
3343 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3349 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3350 ProcessHandle
, BaseAddress
);
3352 DPRINT("Referencing process\n");
3353 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3354 PROCESS_VM_OPERATION
,
3359 if (!NT_SUCCESS(Status
))
3361 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3365 MmLockAddressSpace(&Process
->AddressSpace
);
3366 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3367 MmUnlockAddressSpace(&Process
->AddressSpace
);
3369 ObDereferenceObject(Process
);
3376 NtQuerySection (IN HANDLE SectionHandle
,
3377 IN CINT SectionInformationClass
,
3378 OUT PVOID SectionInformation
,
3380 OUT PULONG ResultLength
)
3382 * FUNCTION: Queries the information of a section object.
3384 * SectionHandle = Handle to the section link object
3385 * SectionInformationClass = Index to a certain information structure
3386 * SectionInformation (OUT)= Caller supplies storage for resulting
3388 * Length = Size of the supplied storage
3389 * ResultLength = Data written
3394 PSECTION_OBJECT Section
;
3397 Status
= ObReferenceObjectByHandle(SectionHandle
,
3399 MmSectionObjectType
,
3403 if (!(NT_SUCCESS(Status
)))
3408 switch (SectionInformationClass
)
3410 case SectionBasicInformation
:
3412 PSECTION_BASIC_INFORMATION Sbi
;
3414 if (Length
!= sizeof(SECTION_BASIC_INFORMATION
))
3416 ObDereferenceObject(Section
);
3417 return(STATUS_INFO_LENGTH_MISMATCH
);
3420 Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
3422 Sbi
->BaseAddress
= 0;
3423 Sbi
->Attributes
= 0;
3424 Sbi
->Size
.QuadPart
= 0;
3426 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
3427 Status
= STATUS_SUCCESS
;
3431 case SectionImageInformation
:
3433 PSECTION_IMAGE_INFORMATION Sii
;
3435 if (Length
!= sizeof(SECTION_IMAGE_INFORMATION
))
3437 ObDereferenceObject(Section
);
3438 return(STATUS_INFO_LENGTH_MISMATCH
);
3441 Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
3442 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
3443 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3445 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3446 ImageSectionObject
= Section
->ImageSection
;
3448 Sii
->EntryPoint
= ImageSectionObject
->EntryPoint
;
3449 Sii
->StackReserve
= ImageSectionObject
->StackReserve
;
3450 Sii
->StackCommit
= ImageSectionObject
->StackCommit
;
3451 Sii
->Subsystem
= ImageSectionObject
->Subsystem
;
3452 Sii
->MinorSubsystemVersion
= ImageSectionObject
->MinorSubsystemVersion
;
3453 Sii
->MajorSubsystemVersion
= ImageSectionObject
->MajorSubsystemVersion
;
3454 Sii
->Characteristics
= ImageSectionObject
->ImageCharacteristics
;
3455 Sii
->ImageNumber
= ImageSectionObject
->Machine
;
3456 Sii
->Executable
= ImageSectionObject
->Executable
;
3458 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
3459 Status
= STATUS_SUCCESS
;
3465 Status
= STATUS_INVALID_INFO_CLASS
;
3467 ObDereferenceObject(Section
);
3473 NtExtendSection(IN HANDLE SectionHandle
,
3474 IN ULONG NewMaximumSize
)
3477 return(STATUS_NOT_IMPLEMENTED
);
3481 /**********************************************************************
3483 * MmAllocateSection@4
3493 * Code taken from ntoskrnl/mm/special.c.
3498 MmAllocateSection (IN ULONG Length
)
3504 PMADDRESS_SPACE AddressSpace
;
3506 DPRINT("MmAllocateSection(Length %x)\n",Length
);
3508 AddressSpace
= MmGetKernelAddressSpace();
3510 MmLockAddressSpace(AddressSpace
);
3511 Status
= MmCreateMemoryArea (NULL
,
3520 if (!NT_SUCCESS(Status
))
3522 MmUnlockAddressSpace(AddressSpace
);
3525 MmUnlockAddressSpace(AddressSpace
);
3526 DPRINT("Result %p\n",Result
);
3527 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
3529 PHYSICAL_ADDRESS Page
;
3531 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
3532 if (!NT_SUCCESS(Status
))
3534 DbgPrint("Unable to allocate page\n");
3537 Status
= MmCreateVirtualMapping (NULL
,
3538 (Result
+ (i
* PAGE_SIZE
)),
3542 if (!NT_SUCCESS(Status
))
3544 DbgPrint("Unable to create virtual mapping\n");
3548 return ((PVOID
)Result
);
3552 /**********************************************************************
3554 * MmMapViewOfSection
3557 * Maps a view of a section into the virtual address space of a
3562 * Pointer to the section object.
3565 * Pointer to the process.
3568 * Desired base address (or NULL) on entry;
3569 * Actual base address of the view on exit.
3572 * Number of high order address bits that must be zero.
3575 * Size in bytes of the initially committed section of
3579 * Offset in bytes from the beginning of the section
3580 * to the beginning of the view.
3583 * Desired length of map (or zero to map all) on entry
3584 * Actual length mapped on exit.
3586 * InheritDisposition
3587 * Specified how the view is to be shared with
3591 * Type of allocation for the pages.
3594 * Protection for the committed region of the view.
3602 MmMapViewOfSection(IN PVOID SectionObject
,
3603 IN PEPROCESS Process
,
3604 IN OUT PVOID
*BaseAddress
,
3606 IN ULONG CommitSize
,
3607 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3608 IN OUT PULONG ViewSize
,
3609 IN SECTION_INHERIT InheritDisposition
,
3610 IN ULONG AllocationType
,
3613 PSECTION_OBJECT Section
;
3614 PMADDRESS_SPACE AddressSpace
;
3616 NTSTATUS Status
= STATUS_SUCCESS
;
3620 Section
= (PSECTION_OBJECT
)SectionObject
;
3621 AddressSpace
= &Process
->AddressSpace
;
3623 MmLockAddressSpace(AddressSpace
);
3625 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3631 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3632 PMM_SECTION_SEGMENT SectionSegments
;
3634 ImageSectionObject
= Section
->ImageSection
;
3635 SectionSegments
= ImageSectionObject
->Segments
;
3636 NrSegments
= ImageSectionObject
->NrSegments
;
3639 ImageBase
= *BaseAddress
;
3640 if (ImageBase
== NULL
)
3642 ImageBase
= ImageSectionObject
->ImageBase
;
3646 for (i
= 0; i
< NrSegments
; i
++)
3648 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3651 MaxExtent
= (ULONG
)(SectionSegments
[i
].VirtualAddress
+
3652 SectionSegments
[i
].Length
);
3653 ImageSize
= max(ImageSize
, MaxExtent
);
3657 /* Check there is enough space to map the section at that point. */
3658 if (MmOpenMemoryAreaByRegion(AddressSpace
, ImageBase
,
3659 PAGE_ROUND_UP(ImageSize
)) != NULL
)
3661 /* Fail if the user requested a fixed base address. */
3662 if ((*BaseAddress
) != NULL
)
3664 MmUnlockAddressSpace(AddressSpace
);
3665 return(STATUS_UNSUCCESSFUL
);
3667 /* Otherwise find a gap to map the image. */
3668 ImageBase
= MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), FALSE
);
3669 if (ImageBase
== NULL
)
3671 MmUnlockAddressSpace(AddressSpace
);
3672 return(STATUS_UNSUCCESSFUL
);
3676 for (i
= 0; i
< NrSegments
; i
++)
3680 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3682 SBaseAddress
= (PVOID
)
3683 (ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3684 MmLockSectionSegment(&SectionSegments
[i
]);
3685 Status
= MmMapViewOfSegment(Process
,
3688 &SectionSegments
[i
],
3690 SectionSegments
[i
].Length
,
3691 SectionSegments
[i
].Protection
,
3692 (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
,
3694 MmUnlockSectionSegment(&SectionSegments
[i
]);
3695 if (!NT_SUCCESS(Status
))
3697 MmUnlockAddressSpace(AddressSpace
);
3703 *BaseAddress
= ImageBase
;
3707 if (SectionOffset
== NULL
)
3713 ViewOffset
= SectionOffset
->u
.LowPart
;
3716 if ((ViewOffset
% PAGE_SIZE
) != 0)
3718 MmUnlockAddressSpace(AddressSpace
);
3719 return(STATUS_MAPPED_ALIGNMENT
);
3722 if ((*ViewSize
) == 0)
3724 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
3726 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
3728 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
3731 MmLockSectionSegment(Section
->Segment
);
3732 Status
= MmMapViewOfSegment(Process
,
3740 (AllocationType
& MEM_TOP_DOWN
));
3741 MmUnlockSectionSegment(Section
->Segment
);
3742 if (!NT_SUCCESS(Status
))
3744 MmUnlockAddressSpace(AddressSpace
);
3749 MmUnlockAddressSpace(AddressSpace
);
3751 return(STATUS_SUCCESS
);
3758 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
3759 IN PLARGE_INTEGER NewFileSize
)
3770 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
3780 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
3781 IN MMFLUSH_TYPE FlushType
)
3785 case MmFlushForDelete
:
3786 if (SectionObjectPointer
->ImageSectionObject
||
3787 SectionObjectPointer
->DataSectionObject
)
3791 CcRosSetRemoveOnClose(SectionObjectPointer
);
3793 case MmFlushForWrite
:
3803 MmForceSectionClosed (DWORD Unknown0
,
3815 MmMapViewInSystemSpace (IN PVOID SectionObject
,
3816 OUT PVOID
* MappedBase
,
3817 IN OUT PULONG ViewSize
)
3819 PSECTION_OBJECT Section
;
3820 PMADDRESS_SPACE AddressSpace
;
3823 DPRINT("MmMapViewInSystemSpace() called\n");
3825 Section
= (PSECTION_OBJECT
)SectionObject
;
3826 AddressSpace
= MmGetKernelAddressSpace();
3828 MmLockAddressSpace(AddressSpace
);
3831 if ((*ViewSize
) == 0)
3833 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
3835 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
3837 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
3840 MmLockSectionSegment(Section
->Segment
);
3843 Status
= MmMapViewOfSegment(NULL
,
3853 MmUnlockSectionSegment(Section
->Segment
);
3854 MmUnlockAddressSpace(AddressSpace
);
3864 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
3866 PMEMORY_AREA MemoryArea
;
3867 PMADDRESS_SPACE AddressSpace
;
3868 PSECTION_OBJECT Section
;
3869 PMM_SECTION_SEGMENT Segment
;
3871 PLIST_ENTRY CurrentEntry
;
3872 PMM_REGION CurrentRegion
;
3875 DPRINT("MmUnmapViewInSystemSpace() called\n");
3877 AddressSpace
= MmGetKernelAddressSpace();
3879 DPRINT("Opening memory area at base address %x\n",
3881 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
3883 if (MemoryArea
== NULL
)
3885 return STATUS_UNSUCCESSFUL
;
3888 MemoryArea
->DeleteInProgress
= TRUE
;
3889 Section
= MemoryArea
->Data
.SectionData
.Section
;
3890 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3892 MmLockSectionSegment(Segment
);
3893 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3894 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
3895 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3897 CurrentEntry
= MemoryArea
->Data
.SectionData
.RegionListHead
.Flink
;
3898 while (CurrentEntry
!= &MemoryArea
->Data
.SectionData
.RegionListHead
)
3901 CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3902 CurrentEntry
= CurrentEntry
->Flink
;
3903 ExFreePool(CurrentRegion
);
3906 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3908 Status
= MmFreeMemoryArea(AddressSpace
,
3916 Status
= MmFreeMemoryArea(AddressSpace
,
3923 MmUnlockSectionSegment(Segment
);
3924 ObDereferenceObject(Section
);
3926 return(STATUS_SUCCESS
);
3934 MmSetBankedSection (DWORD Unknown0
,
3942 return (STATUS_NOT_IMPLEMENTED
);
3946 /**********************************************************************
3951 * Creates a section object.
3954 * SectionObjiect (OUT)
3955 * Caller supplied storage for the resulting pointer
3956 * to a SECTION_OBJECT instance;
3959 * Specifies the desired access to the section can be a
3961 * STANDARD_RIGHTS_REQUIRED |
3963 * SECTION_MAP_WRITE |
3964 * SECTION_MAP_READ |
3965 * SECTION_MAP_EXECUTE
3967 * ObjectAttributes [OPTIONAL]
3968 * Initialized attributes for the object can be used
3969 * to create a named section;
3972 * Maximizes the size of the memory section. Must be
3973 * non-NULL for a page-file backed section.
3974 * If value specified for a mapped file and the file is
3975 * not large enough, file will be extended.
3977 * SectionPageProtection
3978 * Can be a combination of:
3984 * AllocationAttributes
3985 * Can be a combination of:
3990 * Handle to a file to create a section mapped to a file
3991 * instead of a memory backed section;
4002 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4003 IN ACCESS_MASK DesiredAccess
,
4004 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4005 IN PLARGE_INTEGER MaximumSize
,
4006 IN ULONG SectionPageProtection
,
4007 IN ULONG AllocationAttributes
,
4008 IN HANDLE FileHandle OPTIONAL
,
4009 IN PFILE_OBJECT File OPTIONAL
)
4011 return (STATUS_NOT_IMPLEMENTED
);