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.140 2003/12/31 14:52:06 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/ob.h>
37 #include <internal/ps.h>
38 #include <internal/pool.h>
39 #include <internal/cc.h>
40 #include <ddk/ntifs.h>
41 #include <ntos/minmax.h>
42 #include <rosrtl/string.h>
43 #include <reactos/bugcodes.h>
46 #include <internal/debug.h>
48 /* TYPES *********************************************************************/
52 PSECTION_OBJECT Section
;
53 PMM_SECTION_SEGMENT Segment
;
57 } MM_SECTION_PAGEOUT_CONTEXT
;
59 /* GLOBALS *******************************************************************/
61 POBJECT_TYPE EXPORTED MmSectionObjectType
= NULL
;
63 static GENERIC_MAPPING MmpSectionMapping
= {
64 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
65 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
66 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
69 #define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S')
70 #define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T')
72 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
73 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
74 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
75 #define MAX_SHARE_COUNT 0x7FF
76 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
77 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
78 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
80 /* FUNCTIONS *****************************************************************/
82 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
85 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
86 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
87 * RETURNS: Status of the wait.
90 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
92 LARGE_INTEGER Timeout
;
93 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
94 Timeout
.QuadPart
= -100000000LL; // 10 sec
96 Timeout
.QuadPart
= -100000000; // 10 sec
98 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
103 * FUNCTION: Sets the page op completion event and releases the page op.
104 * ARGUMENTS: PMM_PAGEOP.
105 * RETURNS: In shorter time than it takes you to even read this
106 * description, so don't even think about geting a mug of coffee.
109 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
111 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
112 MmReleasePageOp(PageOp
);
117 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
118 * ARGUMENTS: PFILE_OBJECT to wait for.
119 * RETURNS: Status of the wait.
122 MmspWaitForFileLock(PFILE_OBJECT File
)
124 return KeWaitForSingleObject(&File
->Lock
, 0, KernelMode
, FALSE
, NULL
);
129 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
132 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
134 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
136 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
138 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
145 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
147 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
149 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
150 PMM_SECTION_SEGMENT SectionSegments
;
154 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
155 NrSegments
= ImageSectionObject
->NrSegments
;
156 SectionSegments
= ImageSectionObject
->Segments
;
157 for (i
= 0; i
< NrSegments
; i
++)
159 if (SectionSegments
[i
].ReferenceCount
!= 0)
161 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
162 SectionSegments
[i
].ReferenceCount
);
165 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
167 ExFreePool(ImageSectionObject
);
168 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
170 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
172 PMM_SECTION_SEGMENT Segment
;
174 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
177 if (Segment
->ReferenceCount
!= 0)
179 DPRINT1("Data segment still referenced\n");
182 MmFreePageTablesSectionSegment(Segment
);
184 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
189 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
191 ExAcquireFastMutex(&Segment
->Lock
);
195 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
197 ExReleaseFastMutex(&Segment
->Lock
);
201 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
205 PSECTION_PAGE_TABLE Table
;
206 ULONG DirectoryOffset
;
209 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
211 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
215 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
216 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
220 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
221 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
222 TAG_SECTION_PAGE_TABLE
);
227 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
228 DPRINT("Table %x\n", Table
);
231 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
232 Table
->Entry
[TableOffset
] = Entry
;
237 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
240 PSECTION_PAGE_TABLE Table
;
242 ULONG DirectoryOffset
;
245 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
247 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
249 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
253 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
254 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
255 DPRINT("Table %x\n", Table
);
261 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
262 Entry
= Table
->Entry
[TableOffset
];
267 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
272 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
275 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
278 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
280 DPRINT1("Maximum share count reached\n");
283 if (IS_SWAP_FROM_SSE(Entry
))
287 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
288 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
292 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section
,
293 PMM_SECTION_SEGMENT Segment
,
299 BOOLEAN IsDirectMapped
= FALSE
;
301 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
304 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
307 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
309 DPRINT1("Zero share count for unshare\n");
312 if (IS_SWAP_FROM_SSE(Entry
))
316 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
318 * If we reducing the share count of this entry to zero then set the entry
319 * to zero and tell the cache the page is no longer mapped.
321 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
323 PFILE_OBJECT FileObject
;
325 SWAPENTRY SavedSwapEntry
;
326 PHYSICAL_ADDRESS Page
;
327 BOOLEAN IsImageSection
;
330 FileOffset
= Offset
+ Segment
->FileOffset
;
332 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
334 Page
.QuadPart
= (LONGLONG
)PAGE_FROM_SSE(Entry
);
335 FileObject
= Section
->FileObject
;
336 if (FileObject
!= NULL
&&
337 !(Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
340 if ((FileOffset
% PAGE_SIZE
) == 0 &&
341 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
344 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
345 IsDirectMapped
= TRUE
;
346 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
347 if (!NT_SUCCESS(Status
))
349 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
355 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
356 if (SavedSwapEntry
== 0)
359 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
360 (Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
)))
364 * Try to page out this page and set the swap entry
365 * within the section segment. There exist no rmap entry
366 * for this page. The pager thread can't page out a
367 * page without a rmap entry.
369 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
373 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
376 MmReleasePageMemoryConsumer(MC_USER
, Page
);
382 MmSetSavedSwapEntryPage(Page
, 0);
383 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
384 (Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
386 if (Dirty
&& !PageOut
)
390 * We hold all locks. Nobody can do something with the current
391 * process and the current segment (also not within an other process).
395 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
396 MmBuildMdlFromPages(Mdl
, (PULONG
)&Page
);
397 Status
= MmWriteToSwapPage(SavedSwapEntry
, Mdl
);
398 if (!NT_SUCCESS(Status
))
400 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
403 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
407 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
408 MmFreeSwapPage(SavedSwapEntry
);
410 MmReleasePageMemoryConsumer(MC_USER
, Page
);
415 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
417 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
420 BOOL
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
423 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
426 PCACHE_SEGMENT CacheSeg
;
427 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
428 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
431 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
439 MiReadPage(PMEMORY_AREA MemoryArea
,
441 PHYSICAL_ADDRESS
* Page
)
443 * FUNCTION: Read a page for a section backed memory area.
445 * MemoryArea - Memory area to read the page for.
446 * Offset - Offset of the page to read.
447 * Page - Variable that receives a page contains the read data.
454 PCACHE_SEGMENT CacheSeg
;
455 PFILE_OBJECT FileObject
;
459 BOOLEAN IsImageSection
;
462 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
463 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
464 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
465 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
466 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
470 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
473 * If the file system is letting us go directly to the cache and the
474 * memory area was mapped at an offset in the file which is page aligned
475 * then get the related cache segment.
477 if ((FileOffset
% PAGE_SIZE
) == 0 &&
478 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
479 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
483 * Get the related cache segment; we use a lower level interface than
484 * filesystems do because it is safe for us to use an offset with a
485 * alignment less than the file system block size.
487 Status
= CcRosGetCacheSegment(Bcb
,
493 if (!NT_SUCCESS(Status
))
500 * If the cache segment isn't up to date then call the file
501 * system to read in the data.
503 Status
= ReadCacheSegment(CacheSeg
);
504 if (!NT_SUCCESS(Status
))
506 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
511 * Retrieve the page from the cache segment that we actually want.
513 (*Page
) = MmGetPhysicalAddress(BaseAddress
+
514 FileOffset
- BaseOffset
);
516 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
521 ULONG CacheSegOffset
;
523 * Allocate a page, this is rather complicated by the possibility
524 * we might have to move other things out of memory
526 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
527 if (!NT_SUCCESS(Status
))
531 Status
= CcRosGetCacheSegment(Bcb
,
537 if (!NT_SUCCESS(Status
))
544 * If the cache segment isn't up to date then call the file
545 * system to read in the data.
547 Status
= ReadCacheSegment(CacheSeg
);
548 if (!NT_SUCCESS(Status
))
550 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
554 PageAddr
= ExAllocatePageWithPhysPage(*Page
);
555 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
556 Length
= RawLength
- SegOffset
;
557 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
559 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
561 else if (CacheSegOffset
>= PAGE_SIZE
)
563 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
567 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
568 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
569 Status
= CcRosGetCacheSegment(Bcb
,
570 FileOffset
+ CacheSegOffset
,
575 if (!NT_SUCCESS(Status
))
577 ExUnmapPage(PageAddr
);
583 * If the cache segment isn't up to date then call the file
584 * system to read in the data.
586 Status
= ReadCacheSegment(CacheSeg
);
587 if (!NT_SUCCESS(Status
))
589 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
590 ExUnmapPage(PageAddr
);
594 if (Length
< PAGE_SIZE
)
596 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
600 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
603 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
604 ExUnmapPage(PageAddr
);
606 return(STATUS_SUCCESS
);
610 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
611 MEMORY_AREA
* MemoryArea
,
619 PSECTION_OBJECT Section
;
620 PMM_SECTION_SEGMENT Segment
;
628 * There is a window between taking the page fault and locking the
629 * address space when another thread could load the page so we check
632 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
636 MmLockPage(MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
));
638 return(STATUS_SUCCESS
);
641 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
642 Offset
= PAddress
- (ULONG
)MemoryArea
->BaseAddress
;
644 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
645 Section
= MemoryArea
->Data
.SectionData
.Section
;
646 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
647 &MemoryArea
->Data
.SectionData
.RegionListHead
,
652 MmLockSectionSegment(Segment
);
655 * Check if this page needs to be mapped COW
657 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
658 (Region
->Protect
== PAGE_READWRITE
||
659 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
661 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
665 Attributes
= Region
->Protect
;
669 * Get or create a page operation descriptor
671 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
);
674 DPRINT1("MmGetPageOp failed\n");
679 * Check if someone else is already handling this fault, if so wait
682 if (PageOp
->Thread
!= PsGetCurrentThread())
684 MmUnlockSectionSegment(Segment
);
685 MmUnlockAddressSpace(AddressSpace
);
686 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
688 * Check for various strange conditions
690 if (Status
!= STATUS_SUCCESS
)
692 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
695 if (PageOp
->Status
== STATUS_PENDING
)
697 DPRINT1("Woke for page op before completion\n");
700 MmLockAddressSpace(AddressSpace
);
702 * If this wasn't a pagein then restart the operation
704 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
706 MmspCompleteAndReleasePageOp(PageOp
);
707 DPRINT("Address 0x%.8X\n", Address
);
708 return(STATUS_MM_RESTART_OPERATION
);
712 * If the thread handling this fault has failed then we don't retry
714 if (!NT_SUCCESS(PageOp
->Status
))
716 Status
= PageOp
->Status
;
717 MmspCompleteAndReleasePageOp(PageOp
);
718 DPRINT("Address 0x%.8X\n", Address
);
721 MmLockSectionSegment(Segment
);
723 * If the completed fault was for another address space then set the
726 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
728 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
731 MmUnlockSectionSegment(Segment
);
732 MmspCompleteAndReleasePageOp(PageOp
);
733 return(STATUS_MM_RESTART_OPERATION
);
736 Page
.QuadPart
= (LONGLONG
)(PAGE_FROM_SSE(Entry
));
738 MmSharePageEntrySectionSegment(Segment
, Offset
);
740 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
745 if (Status
== STATUS_NO_MEMORY
)
747 MmUnlockAddressSpace(AddressSpace
);
748 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
753 MmLockAddressSpace(AddressSpace
);
756 if (!NT_SUCCESS(Status
))
758 DbgPrint("Unable to create virtual mapping\n");
761 MmInsertRmap(Page
, MemoryArea
->Process
, (PVOID
)PAddress
);
767 MmUnlockSectionSegment(Segment
);
768 PageOp
->Status
= STATUS_SUCCESS
;
769 MmspCompleteAndReleasePageOp(PageOp
);
770 DPRINT("Address 0x%.8X\n", Address
);
771 return(STATUS_SUCCESS
);
775 * Must be private page we have swapped out.
777 if (MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
))
785 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
787 DPRINT1("Found a swaped out private page in a pagefile section.\n");
791 MmUnlockSectionSegment(Segment
);
792 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
794 MmUnlockAddressSpace(AddressSpace
);
795 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
796 if (!NT_SUCCESS(Status
))
801 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
802 MmBuildMdlFromPages(Mdl
, (PULONG
)&Page
);
803 Status
= MmReadFromSwapPage(SwapEntry
, Mdl
);
804 if (!NT_SUCCESS(Status
))
806 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
809 MmLockAddressSpace(AddressSpace
);
810 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
815 if (Status
== STATUS_NO_MEMORY
)
817 MmUnlockAddressSpace(AddressSpace
);
818 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
823 MmLockAddressSpace(AddressSpace
);
825 if (!NT_SUCCESS(Status
))
827 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
833 * Store the swap entry for later use.
835 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
838 * Add the page to the process's working set
840 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
843 * Finish the operation
847 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
849 PageOp
->Status
= STATUS_SUCCESS
;
850 MmspCompleteAndReleasePageOp(PageOp
);
851 DPRINT("Address 0x%.8X\n", Address
);
852 return(STATUS_SUCCESS
);
856 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
858 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
860 MmUnlockSectionSegment(Segment
);
862 * Just map the desired physical page
864 Page
.QuadPart
= Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
;
865 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
870 if (Status
== STATUS_NO_MEMORY
)
872 MmUnlockAddressSpace(AddressSpace
);
873 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
878 MmLockAddressSpace(AddressSpace
);
880 if (!NT_SUCCESS(Status
))
882 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
887 * Don't add an rmap entry since the page mapped could be for
896 * Cleanup and release locks
898 PageOp
->Status
= STATUS_SUCCESS
;
899 MmspCompleteAndReleasePageOp(PageOp
);
900 DPRINT("Address 0x%.8X\n", Address
);
901 return(STATUS_SUCCESS
);
905 * Map anonymous memory for BSS sections
907 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
)
909 MmUnlockSectionSegment(Segment
);
910 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
911 if (!NT_SUCCESS(Status
))
913 MmUnlockAddressSpace(AddressSpace
);
914 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
915 MmLockAddressSpace(AddressSpace
);
917 if (!NT_SUCCESS(Status
))
921 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
926 if (Status
== STATUS_NO_MEMORY
)
928 MmUnlockAddressSpace(AddressSpace
);
929 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
934 MmLockAddressSpace(AddressSpace
);
937 if (!NT_SUCCESS(Status
))
939 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
943 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
950 * Cleanup and release locks
952 PageOp
->Status
= STATUS_SUCCESS
;
953 MmspCompleteAndReleasePageOp(PageOp
);
954 DPRINT("Address 0x%.8X\n", Address
);
955 return(STATUS_SUCCESS
);
959 * Get the entry corresponding to the offset within the section
961 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
966 * If the entry is zero (and it can't change because we have
967 * locked the segment) then we need to load the page.
971 * Release all our locks and read in the page from disk
973 MmUnlockSectionSegment(Segment
);
974 MmUnlockAddressSpace(AddressSpace
);
976 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
977 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
979 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
980 if (!NT_SUCCESS(Status
))
982 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
987 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
988 if (!NT_SUCCESS(Status
))
990 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
993 if (!NT_SUCCESS(Status
))
996 * FIXME: What do we know in this case?
999 * Cleanup and release locks
1001 MmLockAddressSpace(AddressSpace
);
1002 PageOp
->Status
= Status
;
1003 MmspCompleteAndReleasePageOp(PageOp
);
1004 DPRINT("Address 0x%.8X\n", Address
);
1008 * Relock the address space and segment
1010 MmLockAddressSpace(AddressSpace
);
1011 MmLockSectionSegment(Segment
);
1014 * Check the entry. No one should change the status of a page
1015 * that has a pending page-in.
1017 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1018 if (Entry
!= Entry1
)
1020 DbgPrint("Someone changed ppte entry while we slept\n");
1025 * Mark the offset within the section as having valid, in-memory
1028 Entry
= MAKE_SSE(Page
.u
.LowPart
, 1);
1029 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1030 MmUnlockSectionSegment(Segment
);
1032 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1037 if (Status
== STATUS_NO_MEMORY
)
1039 MmUnlockAddressSpace(AddressSpace
);
1040 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1045 MmLockAddressSpace(AddressSpace
);
1047 if (!NT_SUCCESS(Status
))
1049 DbgPrint("Unable to create virtual mapping\n");
1052 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1058 PageOp
->Status
= STATUS_SUCCESS
;
1059 MmspCompleteAndReleasePageOp(PageOp
);
1060 DPRINT("Address 0x%.8X\n", Address
);
1061 return(STATUS_SUCCESS
);
1063 else if (IS_SWAP_FROM_SSE(Entry
))
1065 SWAPENTRY SwapEntry
;
1068 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1071 * Release all our locks and read in the page from disk
1073 MmUnlockSectionSegment(Segment
);
1075 MmUnlockAddressSpace(AddressSpace
);
1077 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1078 if (!NT_SUCCESS(Status
))
1083 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1084 MmBuildMdlFromPages(Mdl
, (PULONG
)&Page
);
1085 Status
= MmReadFromSwapPage(SwapEntry
, Mdl
);
1086 if (!NT_SUCCESS(Status
))
1092 * Relock the address space and segment
1094 MmLockAddressSpace(AddressSpace
);
1095 MmLockSectionSegment(Segment
);
1098 * Check the entry. No one should change the status of a page
1099 * that has a pending page-in.
1101 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1102 if (Entry
!= Entry1
)
1104 DbgPrint("Someone changed ppte entry while we slept\n");
1109 * Mark the offset within the section as having valid, in-memory
1112 Entry
= MAKE_SSE(Page
.u
.LowPart
, 1);
1113 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1114 MmUnlockSectionSegment(Segment
);
1117 * Save the swap entry.
1119 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1120 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1125 if (Status
== STATUS_NO_MEMORY
)
1127 MmUnlockAddressSpace(AddressSpace
);
1128 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1133 MmLockAddressSpace(AddressSpace
);
1135 if (!NT_SUCCESS(Status
))
1137 DbgPrint("Unable to create virtual mapping\n");
1140 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1145 PageOp
->Status
= STATUS_SUCCESS
;
1146 MmspCompleteAndReleasePageOp(PageOp
);
1147 DPRINT("Address 0x%.8X\n", Address
);
1148 return(STATUS_SUCCESS
);
1153 * If the section offset is already in-memory and valid then just
1154 * take another reference to the page
1157 Page
.QuadPart
= (LONGLONG
)PAGE_FROM_SSE(Entry
);
1159 MmSharePageEntrySectionSegment(Segment
, Offset
);
1160 MmUnlockSectionSegment(Segment
);
1162 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1167 if (Status
== STATUS_NO_MEMORY
)
1169 MmUnlockAddressSpace(AddressSpace
);
1170 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1175 MmLockAddressSpace(AddressSpace
);
1177 if (!NT_SUCCESS(Status
))
1179 DbgPrint("Unable to create virtual mapping\n");
1182 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1187 PageOp
->Status
= STATUS_SUCCESS
;
1188 MmspCompleteAndReleasePageOp(PageOp
);
1189 DPRINT("Address 0x%.8X\n", Address
);
1190 return(STATUS_SUCCESS
);
1195 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1196 MEMORY_AREA
* MemoryArea
,
1200 PMM_SECTION_SEGMENT Segment
;
1201 PSECTION_OBJECT Section
;
1202 PHYSICAL_ADDRESS OldPage
;
1203 PHYSICAL_ADDRESS NewPage
;
1212 * Check if the page has been paged out or has already been set readwrite
1214 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1216 DPRINT("Address 0x%.8X\n", Address
);
1217 return(STATUS_SUCCESS
);
1219 if (MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1221 DPRINT("Address 0x%.8X\n", Address
);
1224 MmLockPage(MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
));
1226 return(STATUS_SUCCESS
);
1230 * Find the offset of the page
1232 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
1233 Offset
= PAddress
- (ULONG
)MemoryArea
->BaseAddress
;
1235 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1236 Section
= MemoryArea
->Data
.SectionData
.Section
;
1237 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1238 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1243 MmLockSectionSegment(Segment
);
1248 if (MmGetPageEntrySectionSegment(Segment
, Offset
) == 0)
1250 DPRINT1("COW fault for page with PESS 0. Address was 0x%.8X\n",
1253 MmUnlockSectionSegment(Segment
);
1255 * Check if we are doing COW
1257 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1258 (Region
->Protect
== PAGE_READWRITE
||
1259 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1261 DPRINT("Address 0x%.8X\n", Address
);
1262 return(STATUS_UNSUCCESSFUL
);
1266 * Get or create a pageop
1268 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
,
1269 MM_PAGEOP_ACCESSFAULT
);
1272 DPRINT1("MmGetPageOp failed\n");
1277 * Wait for any other operations to complete
1279 if (PageOp
->Thread
!= PsGetCurrentThread())
1281 MmUnlockAddressSpace(AddressSpace
);
1282 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1284 * Check for various strange conditions
1286 if (Status
== STATUS_TIMEOUT
)
1288 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1291 if (PageOp
->Status
== STATUS_PENDING
)
1293 DPRINT1("Woke for page op before completion\n");
1297 * Restart the operation
1299 MmLockAddressSpace(AddressSpace
);
1300 MmspCompleteAndReleasePageOp(PageOp
);
1301 DPRINT("Address 0x%.8X\n", Address
);
1302 return(STATUS_MM_RESTART_OPERATION
);
1306 * Release locks now we have the pageop
1308 MmUnlockAddressSpace(AddressSpace
);
1313 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1314 if (!NT_SUCCESS(Status
))
1322 OldPage
= MmGetPhysicalAddressForProcess(NULL
, Address
);
1324 NewAddress
= ExAllocatePageWithPhysPage(NewPage
);
1325 memcpy(NewAddress
, (PVOID
)PAddress
, PAGE_SIZE
);
1326 ExUnmapPage(NewAddress
);
1329 * Delete the old entry.
1331 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1334 * Set the PTE to point to the new page
1336 MmLockAddressSpace(AddressSpace
);
1337 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1342 if (Status
== STATUS_NO_MEMORY
)
1344 MmUnlockAddressSpace(AddressSpace
);
1345 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1350 MmLockAddressSpace(AddressSpace
);
1352 if (!NT_SUCCESS(Status
))
1354 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1358 MmInsertRmap(NewPage
, AddressSpace
->Process
, (PVOID
)PAddress
);
1359 if (!NT_SUCCESS(Status
))
1361 DbgPrint("Unable to create virtual mapping\n");
1366 MmLockPage(NewPage
);
1367 MmUnlockPage(OldPage
);
1371 * Unshare the old page.
1373 MmDeleteRmap(OldPage
, AddressSpace
->Process
, (PVOID
)PAddress
);
1374 MmLockSectionSegment(Segment
);
1375 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1376 MmUnlockSectionSegment(Segment
);
1378 PageOp
->Status
= STATUS_SUCCESS
;
1379 MmspCompleteAndReleasePageOp(PageOp
);
1380 DPRINT("Address 0x%.8X\n", Address
);
1381 return(STATUS_SUCCESS
);
1385 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1387 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1389 PHYSICAL_ADDRESS Page
;
1391 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1392 MmDeleteVirtualMapping(Process
,
1399 PageOutContext
->WasDirty
= TRUE
;
1401 if (!PageOutContext
->Private
)
1403 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1404 PageOutContext
->Segment
,
1405 PageOutContext
->Offset
,
1406 PageOutContext
->WasDirty
,
1411 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1414 DPRINT("PhysicalAddress %I64x, Address %x\n", Page
, Address
);
1418 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1419 MEMORY_AREA
* MemoryArea
,
1423 PHYSICAL_ADDRESS PhysicalAddress
;
1424 MM_SECTION_PAGEOUT_CONTEXT Context
;
1425 SWAPENTRY SwapEntry
;
1430 PFILE_OBJECT FileObject
;
1432 BOOLEAN DirectMapped
;
1433 BOOLEAN IsImageSection
;
1435 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1438 * Get the segment and section.
1440 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1441 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1443 Context
.Offset
= (ULONG
)((char*)Address
- (ULONG
)MemoryArea
->BaseAddress
);
1444 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1446 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1448 FileObject
= Context
.Section
->FileObject
;
1449 DirectMapped
= FALSE
;
1450 if (FileObject
!= NULL
&&
1451 !(Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
1453 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1456 * If the file system is letting us go directly to the cache and the
1457 * memory area was mapped at an offset in the file which is page aligned
1458 * then note this is a direct mapped page.
1460 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1461 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1463 DirectMapped
= TRUE
;
1469 * This should never happen since mappings of physical memory are never
1470 * placed in the rmap lists.
1472 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1474 DPRINT1("Trying to page out from physical memory section address 0x%X "
1475 "process %d\n", Address
,
1476 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1481 * Get the section segment entry and the physical address.
1483 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1484 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1486 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1487 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1491 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1492 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1495 * Prepare the context structure for the rmap delete call.
1497 Context
.WasDirty
= FALSE
;
1498 if (Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1499 IS_SWAP_FROM_SSE(Entry
) ||
1500 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
)
1502 Context
.Private
= TRUE
;
1506 Context
.Private
= FALSE
;
1510 * Paging out data mapped read-only is easy.
1512 if (Context
.Segment
->Protection
& (PAGE_READONLY
|PAGE_EXECUTE_READ
))
1515 * Read-only data should never be in the swapfile.
1519 DPRINT1("SwapEntry != 0 was 0x%.8X at address 0x%.8X, "
1520 "paddress 0x%.8X\n", SwapEntry
, Address
,
1526 * Read-only data should never be COWed
1528 if (Context
.Private
)
1530 DPRINT1("Had private copy of read-only page.\n");
1535 * Delete all mappings of this page.
1537 MmDeleteAllRmaps(PhysicalAddress
, (PVOID
)&Context
,
1538 MmPageOutDeleteMapping
);
1539 if (Context
.WasDirty
)
1541 DPRINT1("Had a dirty page of a read-only page.\n");
1545 PageOp
->Status
= STATUS_SUCCESS
;
1546 MmspCompleteAndReleasePageOp(PageOp
);
1547 return(STATUS_SUCCESS
);
1551 * Otherwise we have read-write data.
1555 * Take an additional reference to the page or the cache segment.
1557 if (DirectMapped
&& !Context
.Private
)
1559 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1561 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1567 MmReferencePage(PhysicalAddress
);
1570 MmDeleteAllRmaps(PhysicalAddress
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1573 * If this wasn't a private page then we should have reduced the entry to
1574 * zero by deleting all the rmaps.
1576 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1578 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1579 !(Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
1586 * If the page wasn't dirty then we can just free it as for a readonly page.
1587 * Since we unmapped all the mappings above we know it will not suddenly
1589 * If the page is from a pagefile section and has no swap entry,
1590 * we can't free the page at this point.
1592 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1593 if (!Context
.WasDirty
&&
1595 (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1596 Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
)))
1599 if (Context
.Private
)
1601 if (!(Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
) &&
1604 DPRINT1("Private page, non-dirty but not swapped out "
1605 "process %d address 0x%.8X\n",
1606 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0,
1614 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
1615 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1618 if (!NT_SUCCESS(Status
))
1625 if (DirectMapped
&& !Context
.Private
)
1627 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1628 if (!NT_SUCCESS(Status
))
1630 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1636 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1639 PageOp
->Status
= STATUS_SUCCESS
;
1640 MmspCompleteAndReleasePageOp(PageOp
);
1641 return(STATUS_SUCCESS
);
1645 * If this page was direct mapped from the cache then the cache manager
1646 * will already have taken care of writing it back.
1648 if (DirectMapped
&& !Context
.Private
)
1650 assert(SwapEntry
== 0);
1651 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1652 if (!NT_SUCCESS(Status
))
1654 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
1657 PageOp
->Status
= STATUS_SUCCESS
;
1658 MmspCompleteAndReleasePageOp(PageOp
);
1659 return(STATUS_SUCCESS
);
1663 * If necessary, allocate an entry in the paging file for this page
1667 SwapEntry
= MmAllocSwapPage();
1670 MmShowOutOfSpaceMessagePagingFile();
1673 * For private pages restore the old mappings.
1675 if (Context
.Private
)
1677 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1679 MemoryArea
->Attributes
,
1682 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1683 MmInsertRmap(PhysicalAddress
,
1684 MemoryArea
->Process
,
1690 * For non-private pages if the page wasn't direct mapped then
1691 * set it back into the section segment entry so we don't loose
1692 * our copy. Otherwise it will be handled by the cache manager.
1694 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1696 MemoryArea
->Attributes
,
1699 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1700 MmInsertRmap(PhysicalAddress
,
1701 MemoryArea
->Process
,
1703 Entry
= MAKE_SSE(PhysicalAddress
.u
.LowPart
, 1);
1704 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1706 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1707 MmspCompleteAndReleasePageOp(PageOp
);
1708 return(STATUS_PAGEFILE_QUOTA
);
1713 * Write the page to the pagefile
1715 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1716 MmBuildMdlFromPages(Mdl
, (PULONG
)&PhysicalAddress
);
1717 Status
= MmWriteToSwapPage(SwapEntry
, Mdl
);
1718 if (!NT_SUCCESS(Status
))
1720 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1723 * As above: undo our actions.
1724 * FIXME: Also free the swap page.
1726 if (Context
.Private
)
1728 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1730 MemoryArea
->Attributes
,
1733 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1734 MmInsertRmap(PhysicalAddress
,
1735 MemoryArea
->Process
,
1740 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1742 MemoryArea
->Attributes
,
1745 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1746 MmInsertRmap(PhysicalAddress
,
1747 MemoryArea
->Process
,
1749 Entry
= MAKE_SSE(PhysicalAddress
.u
.LowPart
, 1);
1750 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1752 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1753 MmspCompleteAndReleasePageOp(PageOp
);
1754 return(STATUS_UNSUCCESSFUL
);
1758 * Otherwise we have succeeded.
1760 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress
);
1761 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
1762 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1764 if (Context
.Private
)
1766 Status
= MmCreatePageFileMapping(MemoryArea
->Process
,
1769 if (!NT_SUCCESS(Status
))
1776 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1777 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1780 PageOp
->Status
= STATUS_SUCCESS
;
1781 MmspCompleteAndReleasePageOp(PageOp
);
1782 return(STATUS_SUCCESS
);
1786 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1787 PMEMORY_AREA MemoryArea
,
1792 PSECTION_OBJECT Section
;
1793 PMM_SECTION_SEGMENT Segment
;
1794 PHYSICAL_ADDRESS PhysicalAddress
;
1795 SWAPENTRY SwapEntry
;
1800 PFILE_OBJECT FileObject
;
1802 BOOLEAN DirectMapped
;
1803 BOOLEAN IsImageSection
;
1805 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1807 Offset
= (ULONG
)((char*)Address
- (ULONG
)MemoryArea
->BaseAddress
);
1810 * Get the segment and section.
1812 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1813 Section
= MemoryArea
->Data
.SectionData
.Section
;
1814 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1816 FileObject
= Section
->FileObject
;
1817 DirectMapped
= FALSE
;
1818 if (FileObject
!= NULL
&&
1819 !(Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
1821 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1824 * If the file system is letting us go directly to the cache and the
1825 * memory area was mapped at an offset in the file which is page aligned
1826 * then note this is a direct mapped page.
1828 if ((Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
% PAGE_SIZE
) == 0 &&
1829 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1831 DirectMapped
= TRUE
;
1836 * This should never happen since mappings of physical memory are never
1837 * placed in the rmap lists.
1839 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1841 DPRINT1("Trying to write back page from physical memory mapped at %X "
1842 "process %d\n", Address
,
1843 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1848 * Get the section segment entry and the physical address.
1850 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1851 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1853 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1854 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1858 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1859 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1862 * Check for a private (COWed) page.
1864 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1865 IS_SWAP_FROM_SSE(Entry
) ||
1866 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
)
1876 * Speculatively set all mappings of the page to clean.
1878 MmSetCleanAllRmaps(PhysicalAddress
);
1881 * If this page was direct mapped from the cache then the cache manager
1882 * will take care of writing it back to disk.
1884 if (DirectMapped
&& !Private
)
1886 assert(SwapEntry
== 0);
1887 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
1888 PageOp
->Status
= STATUS_SUCCESS
;
1889 MmspCompleteAndReleasePageOp(PageOp
);
1890 return(STATUS_SUCCESS
);
1894 * If necessary, allocate an entry in the paging file for this page
1898 SwapEntry
= MmAllocSwapPage();
1901 MmSetDirtyAllRmaps(PhysicalAddress
);
1902 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1903 MmspCompleteAndReleasePageOp(PageOp
);
1904 return(STATUS_PAGEFILE_QUOTA
);
1906 MmSetSavedSwapEntryPage(PhysicalAddress
, SwapEntry
);
1910 * Write the page to the pagefile
1912 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1913 MmBuildMdlFromPages(Mdl
, (PULONG
)&PhysicalAddress
);
1914 Status
= MmWriteToSwapPage(SwapEntry
, Mdl
);
1915 if (!NT_SUCCESS(Status
))
1917 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1919 MmSetDirtyAllRmaps(PhysicalAddress
);
1920 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1921 MmspCompleteAndReleasePageOp(PageOp
);
1922 return(STATUS_UNSUCCESSFUL
);
1926 * Otherwise we have succeeded.
1928 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress
);
1929 PageOp
->Status
= STATUS_SUCCESS
;
1930 MmspCompleteAndReleasePageOp(PageOp
);
1931 return(STATUS_SUCCESS
);
1935 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1943 PMEMORY_AREA MemoryArea
;
1944 PMM_SECTION_SEGMENT Segment
;
1948 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1949 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1951 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1952 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1957 if (OldProtect
!= NewProtect
)
1959 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1961 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1962 ULONG Protect
= NewProtect
;
1965 * If we doing COW for this segment then check if the page is
1968 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1972 LARGE_INTEGER PhysicalAddress
;
1974 Offset
= (ULONG
)Address
- (ULONG
)MemoryArea
->BaseAddress
;
1975 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1977 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1979 Protect
= PAGE_READONLY
;
1980 if ((Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1981 IS_SWAP_FROM_SSE(Entry
) ||
1982 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
))
1984 Protect
= NewProtect
;
1988 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1990 MmSetPageProtect(AddressSpace
->Process
, BaseAddress
,
1998 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1999 PMEMORY_AREA MemoryArea
,
2009 min(Length
, (ULONG
) ((char*)MemoryArea
->BaseAddress
+ MemoryArea
->Length
- (char*)BaseAddress
));
2010 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
2011 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2013 *OldProtect
= Region
->Protect
;
2014 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->BaseAddress
,
2015 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2016 BaseAddress
, Length
, Region
->Type
, Protect
,
2017 MmAlterViewAttributes
);
2023 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2025 PMEMORY_BASIC_INFORMATION Info
,
2026 PULONG ResultLength
)
2029 PVOID RegionBaseAddress
;
2031 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
2032 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2033 Address
, &RegionBaseAddress
);
2036 return STATUS_UNSUCCESSFUL
;
2038 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2039 Info
->AllocationBase
= MemoryArea
->BaseAddress
;
2040 Info
->AllocationProtect
= MemoryArea
->Attributes
;
2041 Info
->RegionSize
= MemoryArea
->Length
;
2042 Info
->State
= MEM_COMMIT
;
2043 Info
->Protect
= Region
->Protect
;
2044 if (MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
)
2046 Info
->Type
= MEM_IMAGE
;
2050 Info
->Type
= MEM_MAPPED
;
2053 return(STATUS_SUCCESS
);
2057 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2062 ULONG SavedSwapEntry
;
2063 PHYSICAL_ADDRESS Page
;
2065 Page
.u
.HighPart
= 0;
2067 Length
= PAGE_ROUND_UP(Segment
->Length
);
2068 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2070 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2073 if (IS_SWAP_FROM_SSE(Entry
))
2075 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2079 Page
.u
.LowPart
= PAGE_FROM_SSE(Entry
);
2080 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2081 if (SavedSwapEntry
!= 0)
2083 MmSetSavedSwapEntryPage(Page
, 0);
2084 MmFreeSwapPage(SavedSwapEntry
);
2086 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2088 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2094 MmpDeleteSection(PVOID ObjectBody
)
2096 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
2098 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2099 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2104 PMM_SECTION_SEGMENT SectionSegments
;
2106 SectionSegments
= Section
->ImageSection
->Segments
;
2107 NrSegments
= Section
->ImageSection
->NrSegments
;
2109 for (i
= 0; i
< NrSegments
; i
++)
2111 if (SectionSegments
[i
].Characteristics
& IMAGE_SECTION_CHAR_SHARED
)
2113 MmLockSectionSegment(&SectionSegments
[i
]);
2115 RefCount
= InterlockedDecrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2116 if (SectionSegments
[i
].Characteristics
& IMAGE_SECTION_CHAR_SHARED
)
2120 MmpFreePageFileSegment(&SectionSegments
[i
]);
2122 MmUnlockSectionSegment(&SectionSegments
[i
]);
2128 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2130 MmpFreePageFileSegment(Section
->Segment
);
2131 MmFreePageTablesSectionSegment(Section
->Segment
);
2132 ExFreePool(Section
->Segment
);
2133 Section
->Segment
= NULL
;
2137 InterlockedDecrement((LONG
*)&Section
->Segment
->ReferenceCount
);
2140 if (Section
->FileObject
!= NULL
)
2142 CcRosDereferenceCache(Section
->FileObject
);
2143 ObDereferenceObject(Section
->FileObject
);
2144 Section
->FileObject
= NULL
;
2149 MmpCloseSection(PVOID ObjectBody
,
2152 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2153 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2157 MmpCreateSection(PVOID ObjectBody
,
2159 PWSTR RemainingPath
,
2160 POBJECT_ATTRIBUTES ObjectAttributes
)
2162 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2163 ObjectBody
, Parent
, RemainingPath
);
2165 if (RemainingPath
== NULL
)
2167 return(STATUS_SUCCESS
);
2170 if (wcschr(RemainingPath
+1, L
'\\') != NULL
)
2172 return(STATUS_UNSUCCESSFUL
);
2174 return(STATUS_SUCCESS
);
2177 NTSTATUS INIT_FUNCTION
2178 MmCreatePhysicalMemorySection(VOID
)
2180 HANDLE PhysSectionH
;
2181 PSECTION_OBJECT PhysSection
;
2183 OBJECT_ATTRIBUTES Obj
;
2184 UNICODE_STRING Name
= ROS_STRING_INITIALIZER(L
"\\Device\\PhysicalMemory");
2185 LARGE_INTEGER SectionSize
;
2188 * Create the section mapping physical memory
2190 SectionSize
.QuadPart
= 0xFFFFFFFF;
2191 InitializeObjectAttributes(&Obj
,
2196 Status
= NtCreateSection(&PhysSectionH
,
2200 PAGE_EXECUTE_READWRITE
,
2203 if (!NT_SUCCESS(Status
))
2205 DbgPrint("Failed to create PhysicalMemory section\n");
2208 Status
= ObReferenceObjectByHandle(PhysSectionH
,
2212 (PVOID
*)&PhysSection
,
2214 if (!NT_SUCCESS(Status
))
2216 DbgPrint("Failed to reference PhysicalMemory section\n");
2219 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2220 ObDereferenceObject((PVOID
)PhysSection
);
2222 return(STATUS_SUCCESS
);
2225 NTSTATUS INIT_FUNCTION
2226 MmInitSectionImplementation(VOID
)
2228 MmSectionObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
2230 RtlRosInitUnicodeStringFromLiteral(&MmSectionObjectType
->TypeName
, L
"Section");
2232 MmSectionObjectType
->Tag
= TAG('S', 'E', 'C', 'T');
2233 MmSectionObjectType
->TotalObjects
= 0;
2234 MmSectionObjectType
->TotalHandles
= 0;
2235 MmSectionObjectType
->MaxObjects
= ULONG_MAX
;
2236 MmSectionObjectType
->MaxHandles
= ULONG_MAX
;
2237 MmSectionObjectType
->PagedPoolCharge
= 0;
2238 MmSectionObjectType
->NonpagedPoolCharge
= sizeof(SECTION_OBJECT
);
2239 MmSectionObjectType
->Mapping
= &MmpSectionMapping
;
2240 MmSectionObjectType
->Dump
= NULL
;
2241 MmSectionObjectType
->Open
= NULL
;
2242 MmSectionObjectType
->Close
= MmpCloseSection
;
2243 MmSectionObjectType
->Delete
= MmpDeleteSection
;
2244 MmSectionObjectType
->Parse
= NULL
;
2245 MmSectionObjectType
->Security
= NULL
;
2246 MmSectionObjectType
->QueryName
= NULL
;
2247 MmSectionObjectType
->OkayToClose
= NULL
;
2248 MmSectionObjectType
->Create
= MmpCreateSection
;
2249 MmSectionObjectType
->DuplicationNotify
= NULL
;
2252 * NOTE: Do not register the section object type here because
2253 * the object manager it not initialized yet!
2254 * The section object type will be created in ObInit().
2256 ObpCreateTypeObject(MmSectionObjectType
);
2258 return(STATUS_SUCCESS
);
2262 MmCreatePageFileSection(PHANDLE SectionHandle
,
2263 ACCESS_MASK DesiredAccess
,
2264 POBJECT_ATTRIBUTES ObjectAttributes
,
2265 PLARGE_INTEGER UMaximumSize
,
2266 ULONG SectionPageProtection
,
2267 ULONG AllocationAttributes
)
2269 * Create a section which is backed by the pagefile
2272 LARGE_INTEGER MaximumSize
;
2273 PSECTION_OBJECT Section
;
2274 PMM_SECTION_SEGMENT Segment
;
2277 if (UMaximumSize
== NULL
)
2279 return(STATUS_UNSUCCESSFUL
);
2281 MaximumSize
= *UMaximumSize
;
2284 * Check the protection
2286 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2287 SectionPageProtection
)
2289 return(STATUS_INVALID_PAGE_PROTECTION
);
2293 * Create the section
2295 Status
= ObCreateObject(ExGetPreviousMode(),
2296 MmSectionObjectType
,
2298 ExGetPreviousMode(),
2300 sizeof(SECTION_OBJECT
),
2304 if (!NT_SUCCESS(Status
))
2309 Status
= ObInsertObject ((PVOID
)Section
,
2315 if (!NT_SUCCESS(Status
))
2317 ObDereferenceObject(Section
);
2324 Section
->SectionPageProtection
= SectionPageProtection
;
2325 Section
->AllocationAttributes
= AllocationAttributes
;
2326 InitializeListHead(&Section
->ViewListHead
);
2327 KeInitializeSpinLock(&Section
->ViewListLock
);
2328 Section
->FileObject
= NULL
;
2329 Section
->MaximumSize
= MaximumSize
;
2330 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2331 TAG_MM_SECTION_SEGMENT
);
2332 if (Segment
== NULL
)
2334 ZwClose(*SectionHandle
);
2335 ObDereferenceObject(Section
);
2336 return(STATUS_NO_MEMORY
);
2338 Section
->Segment
= Segment
;
2339 Segment
->ReferenceCount
= 1;
2340 ExInitializeFastMutex(&Segment
->Lock
);
2341 Segment
->FileOffset
= 0;
2342 Segment
->Protection
= SectionPageProtection
;
2343 Segment
->Attributes
= AllocationAttributes
;
2344 Segment
->Length
= MaximumSize
.u
.LowPart
;
2345 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2346 Segment
->WriteCopy
= FALSE
;
2347 ObDereferenceObject(Section
);
2348 return(STATUS_SUCCESS
);
2353 MmCreateDataFileSection(PHANDLE SectionHandle
,
2354 ACCESS_MASK DesiredAccess
,
2355 POBJECT_ATTRIBUTES ObjectAttributes
,
2356 PLARGE_INTEGER UMaximumSize
,
2357 ULONG SectionPageProtection
,
2358 ULONG AllocationAttributes
,
2361 * Create a section backed by a data file
2364 PSECTION_OBJECT Section
;
2366 LARGE_INTEGER MaximumSize
;
2367 PFILE_OBJECT FileObject
;
2368 PMM_SECTION_SEGMENT Segment
;
2370 IO_STATUS_BLOCK Iosb
;
2371 LARGE_INTEGER Offset
;
2375 * Check the protection
2377 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2378 SectionPageProtection
)
2380 return(STATUS_INVALID_PAGE_PROTECTION
);
2383 * Create the section
2385 Status
= ObCreateObject(ExGetPreviousMode(),
2386 MmSectionObjectType
,
2388 ExGetPreviousMode(),
2390 sizeof(SECTION_OBJECT
),
2394 if (!NT_SUCCESS(Status
))
2399 Status
= ObInsertObject ((PVOID
)Section
,
2405 if (!NT_SUCCESS(Status
))
2407 ObDereferenceObject(Section
);
2414 Section
->SectionPageProtection
= SectionPageProtection
;
2415 Section
->AllocationAttributes
= AllocationAttributes
;
2416 InitializeListHead(&Section
->ViewListHead
);
2417 KeInitializeSpinLock(&Section
->ViewListLock
);
2420 * Check file access required
2422 if (SectionPageProtection
& PAGE_READWRITE
||
2423 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2425 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2429 FileAccess
= FILE_READ_DATA
;
2433 * Reference the file handle
2435 Status
= ObReferenceObjectByHandle(FileHandle
,
2439 (PVOID
*)&FileObject
,
2441 if (!NT_SUCCESS(Status
))
2443 ZwClose(*SectionHandle
);
2444 ObDereferenceObject(Section
);
2449 * We can't do memory mappings if the file system doesn't support the
2452 if (!(FileObject
->Flags
& FO_FCB_IS_VALID
))
2454 ZwClose(*SectionHandle
);
2455 ObDereferenceObject(Section
);
2456 ObDereferenceObject(FileObject
);
2457 return(STATUS_INVALID_FILE_FOR_SECTION
);
2461 * FIXME: Revise this once a locking order for file size changes is
2464 if (UMaximumSize
!= NULL
)
2466 MaximumSize
= *UMaximumSize
;
2471 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
;
2474 if (MaximumSize
.QuadPart
>
2475 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
.QuadPart
)
2477 Status
= NtSetInformationFile(FileHandle
,
2480 sizeof(LARGE_INTEGER
),
2481 FileAllocationInformation
);
2482 if (!NT_SUCCESS(Status
))
2484 ZwClose(*SectionHandle
);
2485 ObDereferenceObject(Section
);
2486 ObDereferenceObject(FileObject
);
2487 return(STATUS_SECTION_NOT_EXTENDED
);
2491 if (FileObject
->SectionObjectPointer
== NULL
||
2492 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2495 * Read a bit so caching is initiated for the file object.
2496 * This is only needed because MiReadPage currently cannot
2497 * handle non-cached streams.
2499 Offset
.QuadPart
= 0;
2500 Status
= ZwReadFile(FileHandle
,
2509 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2511 ZwClose(*SectionHandle
);
2512 ObDereferenceObject(Section
);
2513 ObDereferenceObject(FileObject
);
2516 if (FileObject
->SectionObjectPointer
== NULL
||
2517 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2519 /* FIXME: handle this situation */
2520 ZwClose(*SectionHandle
);
2521 ObDereferenceObject(Section
);
2522 ObDereferenceObject(FileObject
);
2523 return STATUS_INVALID_PARAMETER
;
2530 Status
= MmspWaitForFileLock(FileObject
);
2531 if (Status
!= STATUS_SUCCESS
)
2533 ZwClose(*SectionHandle
);
2534 ObDereferenceObject(Section
);
2535 ObDereferenceObject(FileObject
);
2540 * If this file hasn't been mapped as a data file before then allocate a
2541 * section segment to describe the data file mapping
2543 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2545 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2546 TAG_MM_SECTION_SEGMENT
);
2547 if (Segment
== NULL
)
2549 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2550 ZwClose(*SectionHandle
);
2551 ObDereferenceObject(Section
);
2552 ObDereferenceObject(FileObject
);
2553 return(STATUS_NO_MEMORY
);
2555 Section
->Segment
= Segment
;
2556 Segment
->ReferenceCount
= 1;
2557 ExInitializeFastMutex(&Segment
->Lock
);
2559 * Set the lock before assigning the segment to the file object
2561 ExAcquireFastMutex(&Segment
->Lock
);
2562 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2564 Segment
->FileOffset
= 0;
2565 Segment
->Protection
= 0;
2566 Segment
->Attributes
= 0;
2567 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2568 Segment
->Characteristics
= 0;
2569 Segment
->WriteCopy
= FALSE
;
2570 if (AllocationAttributes
& SEC_RESERVE
)
2572 Segment
->Length
= Segment
->RawLength
= 0;
2576 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2577 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2579 Segment
->VirtualAddress
= NULL
;
2584 * If the file is already mapped as a data file then we may need
2588 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2590 Section
->Segment
= Segment
;
2591 InterlockedIncrement((PLONG
)&Segment
->ReferenceCount
);
2592 MmLockSectionSegment(Segment
);
2594 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2595 !(AllocationAttributes
& SEC_RESERVE
))
2597 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2598 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2601 MmUnlockSectionSegment(Segment
);
2602 Section
->FileObject
= FileObject
;
2603 Section
->MaximumSize
= MaximumSize
;
2604 CcRosReferenceCache(FileObject
);
2605 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2606 ObDereferenceObject(Section
);
2607 return(STATUS_SUCCESS
);
2610 static ULONG SectionCharacteristicsToProtect
[16] =
2612 PAGE_NOACCESS
, // 0 = NONE
2613 PAGE_NOACCESS
, // 1 = SHARED
2614 PAGE_EXECUTE
, // 2 = EXECUTABLE
2615 PAGE_EXECUTE
, // 3 = EXECUTABLE, SHARED
2616 PAGE_READONLY
, // 4 = READABLE
2617 PAGE_READONLY
, // 5 = READABLE, SHARED
2618 PAGE_EXECUTE_READ
, // 6 = READABLE, EXECUTABLE
2619 PAGE_EXECUTE_READ
, // 7 = READABLE, EXECUTABLE, SHARED
2620 PAGE_READWRITE
, // 8 = WRITABLE
2621 PAGE_READWRITE
, // 9 = WRITABLE, SHARED
2622 PAGE_EXECUTE_READWRITE
, // 10 = WRITABLE, EXECUTABLE
2623 PAGE_EXECUTE_READWRITE
, // 11 = WRITABLE, EXECUTABLE, SHARED
2624 PAGE_READWRITE
, // 12 = WRITABLE, READABLE
2625 PAGE_READWRITE
, // 13 = WRITABLE, READABLE, SHARED
2626 PAGE_EXECUTE_READWRITE
, // 14 = WRITABLE, READABLE, EXECUTABLE,
2627 PAGE_EXECUTE_READWRITE
, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
2631 MmCreateImageSection(PHANDLE SectionHandle
,
2632 ACCESS_MASK DesiredAccess
,
2633 POBJECT_ATTRIBUTES ObjectAttributes
,
2634 PLARGE_INTEGER UMaximumSize
,
2635 ULONG SectionPageProtection
,
2636 ULONG AllocationAttributes
,
2639 PSECTION_OBJECT Section
;
2641 PFILE_OBJECT FileObject
;
2642 IMAGE_DOS_HEADER DosHeader
;
2643 IO_STATUS_BLOCK Iosb
;
2644 LARGE_INTEGER Offset
;
2645 IMAGE_NT_HEADERS PEHeader
;
2646 PMM_SECTION_SEGMENT SectionSegments
;
2648 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
2651 ULONG Characteristics
;
2652 ULONG FileAccess
= 0;
2654 * Check the protection
2656 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2657 SectionPageProtection
)
2659 return(STATUS_INVALID_PAGE_PROTECTION
);
2663 * Specifying a maximum size is meaningless for an image section
2665 if (UMaximumSize
!= NULL
)
2667 return(STATUS_INVALID_PARAMETER_4
);
2671 * Reference the file handle
2673 Status
= ObReferenceObjectByHandle(FileHandle
,
2677 (PVOID
*)&FileObject
,
2679 if (!NT_SUCCESS(Status
))
2685 * Initialized caching for this file object if previously caching
2686 * was initialized for the same on disk file
2688 Status
= CcTryToInitializeFileCache(FileObject
);
2690 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
2692 PIMAGE_SECTION_HEADER ImageSections
;
2694 * Read the dos header and check the DOS signature
2696 Offset
.QuadPart
= 0;
2697 Status
= ZwReadFile(FileHandle
,
2706 if (!NT_SUCCESS(Status
))
2708 ObDereferenceObject(FileObject
);
2713 * Check the DOS signature
2715 if (Iosb
.Information
!= sizeof(DosHeader
) ||
2716 DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
)
2718 ObDereferenceObject(FileObject
);
2719 return(STATUS_INVALID_IMAGE_FORMAT
);
2723 * Read the PE header
2725 Offset
.QuadPart
= DosHeader
.e_lfanew
;
2726 Status
= ZwReadFile(FileHandle
,
2735 if (!NT_SUCCESS(Status
))
2737 ObDereferenceObject(FileObject
);
2742 * Check the signature
2744 if (Iosb
.Information
!= sizeof(PEHeader
) ||
2745 PEHeader
.Signature
!= IMAGE_NT_SIGNATURE
)
2747 ObDereferenceObject(FileObject
);
2748 return(STATUS_INVALID_IMAGE_FORMAT
);
2752 * Read in the section headers
2754 Offset
.QuadPart
= DosHeader
.e_lfanew
+ sizeof(PEHeader
);
2755 ImageSections
= ExAllocatePool(NonPagedPool
,
2756 PEHeader
.FileHeader
.NumberOfSections
*
2757 sizeof(IMAGE_SECTION_HEADER
));
2758 if (ImageSections
== NULL
)
2760 ObDereferenceObject(FileObject
);
2761 return(STATUS_NO_MEMORY
);
2764 Status
= ZwReadFile(FileHandle
,
2770 PEHeader
.FileHeader
.NumberOfSections
*
2771 sizeof(IMAGE_SECTION_HEADER
),
2774 if (!NT_SUCCESS(Status
))
2776 ObDereferenceObject(FileObject
);
2777 ExFreePool(ImageSections
);
2780 if (Iosb
.Information
!= (PEHeader
.FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
)))
2782 ObDereferenceObject(FileObject
);
2783 ExFreePool(ImageSections
);
2784 return(STATUS_INVALID_IMAGE_FORMAT
);
2788 * Create the section
2790 Status
= ObCreateObject (ExGetPreviousMode(),
2791 MmSectionObjectType
,
2793 ExGetPreviousMode(),
2795 sizeof(SECTION_OBJECT
),
2799 if (!NT_SUCCESS(Status
))
2801 ObDereferenceObject(FileObject
);
2802 ExFreePool(ImageSections
);
2806 Status
= ObInsertObject ((PVOID
)Section
,
2812 if (!NT_SUCCESS(Status
))
2814 ObDereferenceObject(Section
);
2815 ObDereferenceObject(FileObject
);
2816 ExFreePool(ImageSections
);
2823 Section
->SectionPageProtection
= SectionPageProtection
;
2824 Section
->AllocationAttributes
= AllocationAttributes
;
2825 InitializeListHead(&Section
->ViewListHead
);
2826 KeInitializeSpinLock(&Section
->ViewListLock
);
2829 * Check file access required
2831 if (SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
2833 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2837 FileAccess
= FILE_READ_DATA
;
2841 * We can't do memory mappings if the file system doesn't support the
2844 if (!(FileObject
->Flags
& FO_FCB_IS_VALID
))
2846 ZwClose(*SectionHandle
);
2847 ObDereferenceObject(Section
);
2848 ObDereferenceObject(FileObject
);
2849 ExFreePool(ImageSections
);
2850 return(STATUS_INVALID_FILE_FOR_SECTION
);
2856 Status
= MmspWaitForFileLock(FileObject
);
2857 if (Status
!= STATUS_SUCCESS
)
2859 ZwClose(*SectionHandle
);
2860 ObDereferenceObject(Section
);
2861 ObDereferenceObject(FileObject
);
2862 ExFreePool(ImageSections
);
2867 * allocate the section segments to describe the mapping
2869 NrSegments
= PEHeader
.FileHeader
.NumberOfSections
+ 1;
2870 Size
= sizeof(MM_IMAGE_SECTION_OBJECT
) + sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2871 ImageSectionObject
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_MM_SECTION_SEGMENT
);
2872 if (ImageSectionObject
== NULL
)
2874 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2875 ZwClose(*SectionHandle
);
2876 ObDereferenceObject(Section
);
2877 ObDereferenceObject(FileObject
);
2878 ExFreePool(ImageSections
);
2879 return(STATUS_NO_MEMORY
);
2881 Section
->ImageSection
= ImageSectionObject
;
2882 ImageSectionObject
->NrSegments
= NrSegments
;
2883 ImageSectionObject
->ImageBase
= (PVOID
)PEHeader
.OptionalHeader
.ImageBase
;
2884 ImageSectionObject
->EntryPoint
= (PVOID
)PEHeader
.OptionalHeader
.AddressOfEntryPoint
;
2885 ImageSectionObject
->StackReserve
= PEHeader
.OptionalHeader
.SizeOfStackReserve
;
2886 ImageSectionObject
->StackCommit
= PEHeader
.OptionalHeader
.SizeOfStackCommit
;
2887 ImageSectionObject
->Subsystem
= PEHeader
.OptionalHeader
.Subsystem
;
2888 ImageSectionObject
->MinorSubsystemVersion
= PEHeader
.OptionalHeader
.MinorSubsystemVersion
;
2889 ImageSectionObject
->MajorSubsystemVersion
= PEHeader
.OptionalHeader
.MajorSubsystemVersion
;
2890 ImageSectionObject
->ImageCharacteristics
= PEHeader
.FileHeader
.Characteristics
;
2891 ImageSectionObject
->Machine
= PEHeader
.FileHeader
.Machine
;
2892 ImageSectionObject
->Executable
= (PEHeader
.OptionalHeader
.SizeOfCode
!= 0);
2894 SectionSegments
= ImageSectionObject
->Segments
;
2895 SectionSegments
[0].FileOffset
= 0;
2896 SectionSegments
[0].Characteristics
= IMAGE_SECTION_CHAR_DATA
;
2897 SectionSegments
[0].Protection
= PAGE_READONLY
;
2898 SectionSegments
[0].RawLength
= PAGE_SIZE
;
2899 SectionSegments
[0].Length
= PAGE_SIZE
;
2900 SectionSegments
[0].Flags
= 0;
2901 SectionSegments
[0].ReferenceCount
= 1;
2902 SectionSegments
[0].VirtualAddress
= 0;
2903 SectionSegments
[0].WriteCopy
= TRUE
;
2904 ExInitializeFastMutex(&SectionSegments
[0].Lock
);
2905 for (i
= 1; i
< NrSegments
; i
++)
2907 SectionSegments
[i
].FileOffset
= ImageSections
[i
-1].PointerToRawData
;
2908 SectionSegments
[i
].Characteristics
= ImageSections
[i
-1].Characteristics
;
2911 * Set up the protection and write copy variables.
2913 Characteristics
= ImageSections
[i
- 1].Characteristics
;
2914 if (Characteristics
& (IMAGE_SECTION_CHAR_READABLE
|IMAGE_SECTION_CHAR_WRITABLE
|IMAGE_SECTION_CHAR_EXECUTABLE
))
2916 SectionSegments
[i
].Protection
= SectionCharacteristicsToProtect
[Characteristics
>> 28];
2917 SectionSegments
[i
].WriteCopy
= !(Characteristics
& IMAGE_SECTION_CHAR_SHARED
);
2919 else if (Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2921 SectionSegments
[i
].Protection
= PAGE_EXECUTE_READ
;
2922 SectionSegments
[i
].WriteCopy
= TRUE
;
2924 else if (Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2926 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2927 SectionSegments
[i
].WriteCopy
= TRUE
;
2929 else if (Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2931 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2932 SectionSegments
[i
].WriteCopy
= TRUE
;
2936 SectionSegments
[i
].Protection
= PAGE_NOACCESS
;
2937 SectionSegments
[i
].WriteCopy
= TRUE
;
2941 * Set up the attributes.
2943 if (Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2945 SectionSegments
[i
].Attributes
= 0;
2947 else if (Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2949 SectionSegments
[i
].Attributes
= 0;
2951 else if (Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2953 SectionSegments
[i
].Attributes
= MM_SECTION_SEGMENT_BSS
;
2957 SectionSegments
[i
].Attributes
= 0;
2960 SectionSegments
[i
].RawLength
= ImageSections
[i
-1].SizeOfRawData
;
2961 SectionSegments
[i
].Length
= ImageSections
[i
-1].Misc
.VirtualSize
;
2962 SectionSegments
[i
].Flags
= 0;
2963 SectionSegments
[i
].ReferenceCount
= 1;
2964 SectionSegments
[i
].VirtualAddress
= (PVOID
)ImageSections
[i
-1].VirtualAddress
;
2965 ExInitializeFastMutex(&SectionSegments
[i
].Lock
);
2967 if (0 != InterlockedCompareExchange((PLONG
)&FileObject
->SectionObjectPointer
->ImageSectionObject
,
2968 (LONG
)ImageSectionObject
, 0))
2971 * An other thread has initialized the some image in the background
2973 ExFreePool(ImageSectionObject
);
2974 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
2975 Section
->ImageSection
= ImageSectionObject
;
2976 SectionSegments
= ImageSectionObject
->Segments
;
2978 for (i
= 0; i
< NrSegments
; i
++)
2980 InterlockedIncrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2983 ExFreePool(ImageSections
);
2988 * Create the section
2990 Status
= ObCreateObject (ExGetPreviousMode(),
2991 MmSectionObjectType
,
2993 ExGetPreviousMode(),
2995 sizeof(SECTION_OBJECT
),
2999 if (!NT_SUCCESS(Status
))
3001 ObDereferenceObject(FileObject
);
3005 Status
= ObInsertObject ((PVOID
)Section
,
3011 if (!NT_SUCCESS(Status
))
3013 ObDereferenceObject(Section
);
3014 ObDereferenceObject(FileObject
);
3021 Section
->SectionPageProtection
= SectionPageProtection
;
3022 Section
->AllocationAttributes
= AllocationAttributes
;
3023 InitializeListHead(&Section
->ViewListHead
);
3024 KeInitializeSpinLock(&Section
->ViewListLock
);
3027 * Check file access required
3029 if (SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
3031 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3035 FileAccess
= FILE_READ_DATA
;
3041 Status
= MmspWaitForFileLock(FileObject
);
3042 if (Status
!= STATUS_SUCCESS
)
3044 ZwClose(*SectionHandle
);
3045 ObDereferenceObject(Section
);
3046 ObDereferenceObject(FileObject
);
3050 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3051 Section
->ImageSection
= ImageSectionObject
;
3052 SectionSegments
= ImageSectionObject
->Segments
;
3053 NrSegments
= ImageSectionObject
->NrSegments
;
3056 * Otherwise just reference all the section segments
3058 for (i
= 0; i
< NrSegments
; i
++)
3060 InterlockedIncrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
3064 Section
->FileObject
= FileObject
;
3065 CcRosReferenceCache(FileObject
);
3066 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
3067 ObDereferenceObject(Section
);
3068 return(STATUS_SUCCESS
);
3075 NtCreateSection (OUT PHANDLE SectionHandle
,
3076 IN ACCESS_MASK DesiredAccess
,
3077 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3078 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3079 IN ULONG SectionPageProtection OPTIONAL
,
3080 IN ULONG AllocationAttributes
,
3081 IN HANDLE FileHandle OPTIONAL
)
3083 if (AllocationAttributes
& SEC_IMAGE
)
3085 return(MmCreateImageSection(SectionHandle
,
3089 SectionPageProtection
,
3090 AllocationAttributes
,
3094 if (FileHandle
!= NULL
)
3096 return(MmCreateDataFileSection(SectionHandle
,
3100 SectionPageProtection
,
3101 AllocationAttributes
,
3105 return(MmCreatePageFileSection(SectionHandle
,
3109 SectionPageProtection
,
3110 AllocationAttributes
));
3114 /**********************************************************************
3132 NtOpenSection(PHANDLE SectionHandle
,
3133 ACCESS_MASK DesiredAccess
,
3134 POBJECT_ATTRIBUTES ObjectAttributes
)
3140 Status
= ObOpenObjectByName(ObjectAttributes
,
3141 MmSectionObjectType
,
3152 MmMapViewOfSegment(PEPROCESS Process
,
3153 PMADDRESS_SPACE AddressSpace
,
3154 PSECTION_OBJECT Section
,
3155 PMM_SECTION_SEGMENT Segment
,
3165 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3167 BoundaryAddressMultiple
.QuadPart
= 0;
3169 Status
= MmCreateMemoryArea(Process
,
3171 MEMORY_AREA_SECTION_VIEW
,
3178 BoundaryAddressMultiple
);
3179 if (!NT_SUCCESS(Status
))
3181 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
3182 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
);
3186 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3187 InsertTailList(&Section
->ViewListHead
,
3188 &MArea
->Data
.SectionData
.ViewListEntry
);
3189 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3191 ObReferenceObjectByPointer((PVOID
)Section
,
3194 ExGetPreviousMode());
3195 MArea
->Data
.SectionData
.Segment
= Segment
;
3196 MArea
->Data
.SectionData
.Section
= Section
;
3197 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3198 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3199 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3200 ViewSize
, 0, Protect
);
3202 return(STATUS_SUCCESS
);
3206 /**********************************************************************
3208 * NtMapViewOfSection
3211 * Maps a view of a section into the virtual address space of a
3216 * Handle of the section.
3219 * Handle of the process.
3222 * Desired base address (or NULL) on entry;
3223 * Actual base address of the view on exit.
3226 * Number of high order address bits that must be zero.
3229 * Size in bytes of the initially committed section of
3233 * Offset in bytes from the beginning of the section
3234 * to the beginning of the view.
3237 * Desired length of map (or zero to map all) on entry
3238 * Actual length mapped on exit.
3240 * InheritDisposition
3241 * Specified how the view is to be shared with
3245 * Type of allocation for the pages.
3248 * Protection for the committed region of the view.
3256 NtMapViewOfSection(HANDLE SectionHandle
,
3257 HANDLE ProcessHandle
,
3261 PLARGE_INTEGER SectionOffset
,
3263 SECTION_INHERIT InheritDisposition
,
3264 ULONG AllocationType
,
3267 PSECTION_OBJECT Section
;
3270 PMADDRESS_SPACE AddressSpace
;
3272 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3273 PROCESS_VM_OPERATION
,
3278 if (!NT_SUCCESS(Status
))
3283 AddressSpace
= &Process
->AddressSpace
;
3285 Status
= ObReferenceObjectByHandle(SectionHandle
,
3287 MmSectionObjectType
,
3291 if (!(NT_SUCCESS(Status
)))
3293 DPRINT("ObReference failed rc=%x\n",Status
);
3294 ObDereferenceObject(Process
);
3298 Status
= MmMapViewOfSection(Section
,
3309 ObDereferenceObject(Section
);
3310 ObDereferenceObject(Process
);
3316 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3317 PHYSICAL_ADDRESS PhysAddr
, SWAPENTRY SwapEntry
,
3322 PFILE_OBJECT FileObject
;
3325 SWAPENTRY SavedSwapEntry
;
3328 PSECTION_OBJECT Section
;
3329 PMM_SECTION_SEGMENT Segment
;
3331 MArea
= (PMEMORY_AREA
)Context
;
3333 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3335 Offset
= ((ULONG
)Address
- (ULONG
)MArea
->BaseAddress
);
3337 Section
= MArea
->Data
.SectionData
.Section
;
3338 Segment
= MArea
->Data
.SectionData
.Segment
;
3341 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3345 MmUnlockSectionSegment(Segment
);
3346 MmUnlockAddressSpace(&MArea
->Process
->AddressSpace
);
3348 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3349 if (Status
!= STATUS_SUCCESS
)
3351 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3355 MmLockAddressSpace(&MArea
->Process
->AddressSpace
);
3356 MmLockSectionSegment(Segment
);
3357 MmspCompleteAndReleasePageOp(PageOp
);
3358 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3361 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3364 * For a dirty, datafile, non-private page mark it as dirty in the
3367 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3369 if (PhysAddr
.QuadPart
== PAGE_FROM_SSE(Entry
) && Dirty
)
3371 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3372 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3373 CcRosMarkDirtyCacheSegment(Bcb
, Offset
);
3374 assert(SwapEntry
== 0);
3383 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3385 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3388 MmFreeSwapPage(SwapEntry
);
3390 else if (PhysAddr
.QuadPart
!= 0)
3392 if (IS_SWAP_FROM_SSE(Entry
) ||
3393 PhysAddr
.QuadPart
!= (PAGE_FROM_SSE(Entry
)))
3398 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3400 DPRINT1("Found a private page in a pagefile section.\n");
3404 * Just dereference private pages
3406 SavedSwapEntry
= MmGetSavedSwapEntryPage(PhysAddr
);
3407 if (SavedSwapEntry
!= 0)
3409 MmFreeSwapPage(SavedSwapEntry
);
3410 MmSetSavedSwapEntryPage(PhysAddr
, 0);
3412 MmDeleteRmap(PhysAddr
, MArea
->Process
, Address
);
3413 MmReleasePageMemoryConsumer(MC_USER
, PhysAddr
);
3417 MmDeleteRmap(PhysAddr
, MArea
->Process
, Address
);
3418 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3424 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3428 PMEMORY_AREA MemoryArea
;
3429 PSECTION_OBJECT Section
;
3430 PMM_SECTION_SEGMENT Segment
;
3432 PLIST_ENTRY CurrentEntry
;
3433 PMM_REGION CurrentRegion
;
3434 PLIST_ENTRY RegionListHead
;
3436 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
3438 if (MemoryArea
== NULL
)
3440 return(STATUS_UNSUCCESSFUL
);
3443 MemoryArea
->DeleteInProgress
= TRUE
;
3444 Section
= MemoryArea
->Data
.SectionData
.Section
;
3445 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3447 MmLockSectionSegment(Segment
);
3448 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3449 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
3450 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3452 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3453 while (!IsListEmpty(RegionListHead
))
3455 CurrentEntry
= RemoveHeadList(RegionListHead
);
3456 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3457 ExFreePool(CurrentRegion
);
3460 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3462 Status
= MmFreeMemoryArea(AddressSpace
,
3470 Status
= MmFreeMemoryArea(AddressSpace
,
3476 MmUnlockSectionSegment(Segment
);
3477 ObDereferenceObject(Section
);
3478 return(STATUS_SUCCESS
);
3485 MmUnmapViewOfSection(PEPROCESS Process
,
3489 PMEMORY_AREA MemoryArea
;
3490 PMADDRESS_SPACE AddressSpace
;
3491 PSECTION_OBJECT Section
;
3493 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3494 Process
, BaseAddress
);
3498 AddressSpace
= &Process
->AddressSpace
;
3499 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
3501 if (MemoryArea
== NULL
)
3503 return(STATUS_UNSUCCESSFUL
);
3506 Section
= MemoryArea
->Data
.SectionData
.Section
;
3508 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3512 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3513 PMM_SECTION_SEGMENT SectionSegments
;
3514 PVOID ImageBaseAddress
= 0;
3515 PMM_SECTION_SEGMENT Segment
;
3517 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3518 ImageSectionObject
= Section
->ImageSection
;
3519 SectionSegments
= ImageSectionObject
->Segments
;
3520 NrSegments
= ImageSectionObject
->NrSegments
;
3522 /* Search for the current segment within the section segments
3523 * and calculate the image base address */
3524 for (i
= 0; i
< NrSegments
; i
++)
3526 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3528 if (Segment
== &SectionSegments
[i
])
3530 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3535 if (i
>= NrSegments
)
3540 for (i
= 0; i
< NrSegments
; i
++)
3542 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3544 PVOID SBaseAddress
= (PVOID
)
3545 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3547 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
3553 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
3555 return(STATUS_SUCCESS
);
3558 /**********************************************************************
3560 * NtUnmapViewOfSection
3575 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3581 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3582 ProcessHandle
, BaseAddress
);
3584 DPRINT("Referencing process\n");
3585 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3586 PROCESS_VM_OPERATION
,
3591 if (!NT_SUCCESS(Status
))
3593 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3597 MmLockAddressSpace(&Process
->AddressSpace
);
3598 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3599 MmUnlockAddressSpace(&Process
->AddressSpace
);
3601 ObDereferenceObject(Process
);
3608 NtQuerySection (IN HANDLE SectionHandle
,
3609 IN CINT SectionInformationClass
,
3610 OUT PVOID SectionInformation
,
3612 OUT PULONG ResultLength
)
3614 * FUNCTION: Queries the information of a section object.
3616 * SectionHandle = Handle to the section link object
3617 * SectionInformationClass = Index to a certain information structure
3618 * SectionInformation (OUT)= Caller supplies storage for resulting
3620 * Length = Size of the supplied storage
3621 * ResultLength = Data written
3626 PSECTION_OBJECT Section
;
3629 Status
= ObReferenceObjectByHandle(SectionHandle
,
3631 MmSectionObjectType
,
3635 if (!(NT_SUCCESS(Status
)))
3640 switch (SectionInformationClass
)
3642 case SectionBasicInformation
:
3644 PSECTION_BASIC_INFORMATION Sbi
;
3646 if (Length
!= sizeof(SECTION_BASIC_INFORMATION
))
3648 ObDereferenceObject(Section
);
3649 return(STATUS_INFO_LENGTH_MISMATCH
);
3652 Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
3654 Sbi
->BaseAddress
= 0;
3655 Sbi
->Attributes
= 0;
3656 Sbi
->Size
.QuadPart
= 0;
3658 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
3659 Status
= STATUS_SUCCESS
;
3663 case SectionImageInformation
:
3665 PSECTION_IMAGE_INFORMATION Sii
;
3667 if (Length
!= sizeof(SECTION_IMAGE_INFORMATION
))
3669 ObDereferenceObject(Section
);
3670 return(STATUS_INFO_LENGTH_MISMATCH
);
3673 Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
3674 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
3675 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3677 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3678 ImageSectionObject
= Section
->ImageSection
;
3680 Sii
->EntryPoint
= ImageSectionObject
->EntryPoint
;
3681 Sii
->StackReserve
= ImageSectionObject
->StackReserve
;
3682 Sii
->StackCommit
= ImageSectionObject
->StackCommit
;
3683 Sii
->Subsystem
= ImageSectionObject
->Subsystem
;
3684 Sii
->MinorSubsystemVersion
= (USHORT
)ImageSectionObject
->MinorSubsystemVersion
;
3685 Sii
->MajorSubsystemVersion
= (USHORT
)ImageSectionObject
->MajorSubsystemVersion
;
3686 Sii
->Characteristics
= ImageSectionObject
->ImageCharacteristics
;
3687 Sii
->ImageNumber
= ImageSectionObject
->Machine
;
3688 Sii
->Executable
= ImageSectionObject
->Executable
;
3690 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
3691 Status
= STATUS_SUCCESS
;
3697 Status
= STATUS_INVALID_INFO_CLASS
;
3699 ObDereferenceObject(Section
);
3705 NtExtendSection(IN HANDLE SectionHandle
,
3706 IN ULONG NewMaximumSize
)
3709 return(STATUS_NOT_IMPLEMENTED
);
3713 /**********************************************************************
3715 * MmAllocateSection@4
3725 * Code taken from ntoskrnl/mm/special.c.
3730 MmAllocateSection (IN ULONG Length
)
3736 PMADDRESS_SPACE AddressSpace
;
3737 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3739 DPRINT("MmAllocateSection(Length %x)\n",Length
);
3741 BoundaryAddressMultiple
.QuadPart
= 0;
3742 AddressSpace
= MmGetKernelAddressSpace();
3744 MmLockAddressSpace(AddressSpace
);
3745 Status
= MmCreateMemoryArea (NULL
,
3754 BoundaryAddressMultiple
);
3755 MmUnlockAddressSpace(AddressSpace
);
3756 if (!NT_SUCCESS(Status
))
3760 DPRINT("Result %p\n",Result
);
3761 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
3763 PHYSICAL_ADDRESS Page
;
3765 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
3766 if (!NT_SUCCESS(Status
))
3768 DbgPrint("Unable to allocate page\n");
3771 Status
= MmCreateVirtualMapping (NULL
,
3772 ((char*)Result
+ (i
* PAGE_SIZE
)),
3776 if (!NT_SUCCESS(Status
))
3778 DbgPrint("Unable to create virtual mapping\n");
3782 return ((PVOID
)Result
);
3786 /**********************************************************************
3788 * MmMapViewOfSection
3791 * Maps a view of a section into the virtual address space of a
3796 * Pointer to the section object.
3799 * Pointer to the process.
3802 * Desired base address (or NULL) on entry;
3803 * Actual base address of the view on exit.
3806 * Number of high order address bits that must be zero.
3809 * Size in bytes of the initially committed section of
3813 * Offset in bytes from the beginning of the section
3814 * to the beginning of the view.
3817 * Desired length of map (or zero to map all) on entry
3818 * Actual length mapped on exit.
3820 * InheritDisposition
3821 * Specified how the view is to be shared with
3825 * Type of allocation for the pages.
3828 * Protection for the committed region of the view.
3836 MmMapViewOfSection(IN PVOID SectionObject
,
3837 IN PEPROCESS Process
,
3838 IN OUT PVOID
*BaseAddress
,
3840 IN ULONG CommitSize
,
3841 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3842 IN OUT PULONG ViewSize
,
3843 IN SECTION_INHERIT InheritDisposition
,
3844 IN ULONG AllocationType
,
3847 PSECTION_OBJECT Section
;
3848 PMADDRESS_SPACE AddressSpace
;
3850 NTSTATUS Status
= STATUS_SUCCESS
;
3854 Section
= (PSECTION_OBJECT
)SectionObject
;
3855 AddressSpace
= &Process
->AddressSpace
;
3857 MmLockAddressSpace(AddressSpace
);
3859 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3865 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3866 PMM_SECTION_SEGMENT SectionSegments
;
3868 ImageSectionObject
= Section
->ImageSection
;
3869 SectionSegments
= ImageSectionObject
->Segments
;
3870 NrSegments
= ImageSectionObject
->NrSegments
;
3873 ImageBase
= *BaseAddress
;
3874 if (ImageBase
== NULL
)
3876 ImageBase
= ImageSectionObject
->ImageBase
;
3880 for (i
= 0; i
< NrSegments
; i
++)
3882 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3885 MaxExtent
= (ULONG
)((char*)SectionSegments
[i
].VirtualAddress
+
3886 SectionSegments
[i
].Length
);
3887 ImageSize
= max(ImageSize
, MaxExtent
);
3891 /* Check there is enough space to map the section at that point. */
3892 if (MmOpenMemoryAreaByRegion(AddressSpace
, ImageBase
,
3893 PAGE_ROUND_UP(ImageSize
)) != NULL
)
3895 /* Fail if the user requested a fixed base address. */
3896 if ((*BaseAddress
) != NULL
)
3898 MmUnlockAddressSpace(AddressSpace
);
3899 return(STATUS_UNSUCCESSFUL
);
3901 /* Otherwise find a gap to map the image. */
3902 ImageBase
= MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), FALSE
);
3903 if (ImageBase
== NULL
)
3905 MmUnlockAddressSpace(AddressSpace
);
3906 return(STATUS_UNSUCCESSFUL
);
3910 for (i
= 0; i
< NrSegments
; i
++)
3912 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3914 PVOID SBaseAddress
= (PVOID
)
3915 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3916 MmLockSectionSegment(&SectionSegments
[i
]);
3917 Status
= MmMapViewOfSegment(Process
,
3920 &SectionSegments
[i
],
3922 SectionSegments
[i
].Length
,
3923 SectionSegments
[i
].Protection
,
3924 (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
,
3926 MmUnlockSectionSegment(&SectionSegments
[i
]);
3927 if (!NT_SUCCESS(Status
))
3929 MmUnlockAddressSpace(AddressSpace
);
3935 *BaseAddress
= ImageBase
;
3939 if (ViewSize
== NULL
)
3941 /* Following this pointer would lead to us to the dark side */
3942 /* What to do? Bugcheck? Return status? Do the mambo? */
3943 KEBUGCHECK(MEMORY_MANAGEMENT
);
3946 if (SectionOffset
== NULL
)
3952 ViewOffset
= SectionOffset
->u
.LowPart
;
3955 if ((ViewOffset
% PAGE_SIZE
) != 0)
3957 MmUnlockAddressSpace(AddressSpace
);
3958 return(STATUS_MAPPED_ALIGNMENT
);
3961 if ((*ViewSize
) == 0)
3963 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
3965 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
3967 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
3970 MmLockSectionSegment(Section
->Segment
);
3971 Status
= MmMapViewOfSegment(Process
,
3979 (AllocationType
& MEM_TOP_DOWN
));
3980 MmUnlockSectionSegment(Section
->Segment
);
3981 if (!NT_SUCCESS(Status
))
3983 MmUnlockAddressSpace(AddressSpace
);
3988 MmUnlockAddressSpace(AddressSpace
);
3990 return(STATUS_SUCCESS
);
3997 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
3998 IN PLARGE_INTEGER NewFileSize
)
4009 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
4019 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4020 IN MMFLUSH_TYPE FlushType
)
4024 case MmFlushForDelete
:
4025 if (SectionObjectPointer
->ImageSectionObject
||
4026 SectionObjectPointer
->DataSectionObject
)
4030 CcRosSetRemoveOnClose(SectionObjectPointer
);
4032 case MmFlushForWrite
:
4042 MmForceSectionClosed (DWORD Unknown0
,
4054 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4055 OUT PVOID
* MappedBase
,
4056 IN OUT PULONG ViewSize
)
4058 PSECTION_OBJECT Section
;
4059 PMADDRESS_SPACE AddressSpace
;
4062 DPRINT("MmMapViewInSystemSpace() called\n");
4064 Section
= (PSECTION_OBJECT
)SectionObject
;
4065 AddressSpace
= MmGetKernelAddressSpace();
4067 MmLockAddressSpace(AddressSpace
);
4070 if ((*ViewSize
) == 0)
4072 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4074 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4076 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4079 MmLockSectionSegment(Section
->Segment
);
4082 Status
= MmMapViewOfSegment(NULL
,
4092 MmUnlockSectionSegment(Section
->Segment
);
4093 MmUnlockAddressSpace(AddressSpace
);
4103 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4105 PMADDRESS_SPACE AddressSpace
;
4108 DPRINT("MmUnmapViewInSystemSpace() called\n");
4110 AddressSpace
= MmGetKernelAddressSpace();
4112 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4122 MmSetBankedSection (DWORD Unknown0
,
4130 return (STATUS_NOT_IMPLEMENTED
);
4134 /**********************************************************************
4139 * Creates a section object.
4142 * SectionObjiect (OUT)
4143 * Caller supplied storage for the resulting pointer
4144 * to a SECTION_OBJECT instance;
4147 * Specifies the desired access to the section can be a
4149 * STANDARD_RIGHTS_REQUIRED |
4151 * SECTION_MAP_WRITE |
4152 * SECTION_MAP_READ |
4153 * SECTION_MAP_EXECUTE
4155 * ObjectAttributes [OPTIONAL]
4156 * Initialized attributes for the object can be used
4157 * to create a named section;
4160 * Maximizes the size of the memory section. Must be
4161 * non-NULL for a page-file backed section.
4162 * If value specified for a mapped file and the file is
4163 * not large enough, file will be extended.
4165 * SectionPageProtection
4166 * Can be a combination of:
4172 * AllocationAttributes
4173 * Can be a combination of:
4178 * Handle to a file to create a section mapped to a file
4179 * instead of a memory backed section;
4190 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4191 IN ACCESS_MASK DesiredAccess
,
4192 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4193 IN PLARGE_INTEGER MaximumSize
,
4194 IN ULONG SectionPageProtection
,
4195 IN ULONG AllocationAttributes
,
4196 IN HANDLE FileHandle OPTIONAL
,
4197 IN PFILE_OBJECT File OPTIONAL
)
4199 return (STATUS_NOT_IMPLEMENTED
);