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.145 2004/03/04 00:07:02 navaraf 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 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
383 (Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
391 * We hold all locks. Nobody can do something with the current
392 * process and the current segment (also not within an other process).
396 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
397 MmBuildMdlFromPages(Mdl
, (PULONG
)&Page
);
398 Status
= MmWriteToSwapPage(SavedSwapEntry
, Mdl
);
399 if (!NT_SUCCESS(Status
))
401 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
405 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
406 MmSetSavedSwapEntryPage(Page
, 0);
408 MmReleasePageMemoryConsumer(MC_USER
, Page
);
412 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
419 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
421 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
424 BOOL
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
427 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
430 PCACHE_SEGMENT CacheSeg
;
431 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
432 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
435 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
443 MiReadPage(PMEMORY_AREA MemoryArea
,
445 PHYSICAL_ADDRESS
* Page
)
447 * FUNCTION: Read a page for a section backed memory area.
449 * MemoryArea - Memory area to read the page for.
450 * Offset - Offset of the page to read.
451 * Page - Variable that receives a page contains the read data.
458 PCACHE_SEGMENT CacheSeg
;
459 PFILE_OBJECT FileObject
;
463 BOOLEAN IsImageSection
;
466 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
467 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
468 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
469 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
470 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
474 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
477 * If the file system is letting us go directly to the cache and the
478 * memory area was mapped at an offset in the file which is page aligned
479 * then get the related cache segment.
481 if ((FileOffset
% PAGE_SIZE
) == 0 &&
482 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
483 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
487 * Get the related cache segment; we use a lower level interface than
488 * filesystems do because it is safe for us to use an offset with a
489 * alignment less than the file system block size.
491 Status
= CcRosGetCacheSegment(Bcb
,
497 if (!NT_SUCCESS(Status
))
504 * If the cache segment isn't up to date then call the file
505 * system to read in the data.
507 Status
= ReadCacheSegment(CacheSeg
);
508 if (!NT_SUCCESS(Status
))
510 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
515 * Retrieve the page from the cache segment that we actually want.
517 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
518 FileOffset
- BaseOffset
);
520 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
525 ULONG CacheSegOffset
;
527 * Allocate a page, this is rather complicated by the possibility
528 * we might have to move other things out of memory
530 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
531 if (!NT_SUCCESS(Status
))
535 Status
= CcRosGetCacheSegment(Bcb
,
541 if (!NT_SUCCESS(Status
))
548 * If the cache segment isn't up to date then call the file
549 * system to read in the data.
551 Status
= ReadCacheSegment(CacheSeg
);
552 if (!NT_SUCCESS(Status
))
554 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
558 PageAddr
= ExAllocatePageWithPhysPage(*Page
);
559 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
560 Length
= RawLength
- SegOffset
;
561 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
563 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
565 else if (CacheSegOffset
>= PAGE_SIZE
)
567 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
571 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
572 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
573 Status
= CcRosGetCacheSegment(Bcb
,
574 FileOffset
+ CacheSegOffset
,
579 if (!NT_SUCCESS(Status
))
581 ExUnmapPage(PageAddr
);
587 * If the cache segment isn't up to date then call the file
588 * system to read in the data.
590 Status
= ReadCacheSegment(CacheSeg
);
591 if (!NT_SUCCESS(Status
))
593 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
594 ExUnmapPage(PageAddr
);
598 if (Length
< PAGE_SIZE
)
600 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
604 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
607 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
608 ExUnmapPage(PageAddr
);
610 return(STATUS_SUCCESS
);
614 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
615 MEMORY_AREA
* MemoryArea
,
623 PSECTION_OBJECT Section
;
624 PMM_SECTION_SEGMENT Segment
;
633 * There is a window between taking the page fault and locking the
634 * address space when another thread could load the page so we check
637 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
641 MmLockPage(MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
));
643 return(STATUS_SUCCESS
);
646 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
647 Offset
= PAddress
- (ULONG
)MemoryArea
->BaseAddress
;
649 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
650 Section
= MemoryArea
->Data
.SectionData
.Section
;
651 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
652 &MemoryArea
->Data
.SectionData
.RegionListHead
,
657 MmLockSectionSegment(Segment
);
660 * Check if this page needs to be mapped COW
662 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
663 (Region
->Protect
== PAGE_READWRITE
||
664 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
666 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
670 Attributes
= Region
->Protect
;
674 * Get or create a page operation descriptor
676 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
);
679 DPRINT1("MmGetPageOp failed\n");
684 * Check if someone else is already handling this fault, if so wait
687 if (PageOp
->Thread
!= PsGetCurrentThread())
689 MmUnlockSectionSegment(Segment
);
690 MmUnlockAddressSpace(AddressSpace
);
691 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
693 * Check for various strange conditions
695 if (Status
!= STATUS_SUCCESS
)
697 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
700 if (PageOp
->Status
== STATUS_PENDING
)
702 DPRINT1("Woke for page op before completion\n");
705 MmLockAddressSpace(AddressSpace
);
707 * If this wasn't a pagein then restart the operation
709 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
711 MmspCompleteAndReleasePageOp(PageOp
);
712 DPRINT("Address 0x%.8X\n", Address
);
713 return(STATUS_MM_RESTART_OPERATION
);
717 * If the thread handling this fault has failed then we don't retry
719 if (!NT_SUCCESS(PageOp
->Status
))
721 Status
= PageOp
->Status
;
722 MmspCompleteAndReleasePageOp(PageOp
);
723 DPRINT("Address 0x%.8X\n", Address
);
726 MmLockSectionSegment(Segment
);
728 * If the completed fault was for another address space then set the
731 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
733 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
734 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
736 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
739 * The page was a private page in another or in our address space
741 MmUnlockSectionSegment(Segment
);
742 MmspCompleteAndReleasePageOp(PageOp
);
743 return(STATUS_MM_RESTART_OPERATION
);
746 Page
.QuadPart
= (LONGLONG
)(PAGE_FROM_SSE(Entry
));
748 MmSharePageEntrySectionSegment(Segment
, Offset
);
750 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
755 if (Status
== STATUS_NO_MEMORY
)
757 MmUnlockAddressSpace(AddressSpace
);
758 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
763 MmLockAddressSpace(AddressSpace
);
766 if (!NT_SUCCESS(Status
))
768 DbgPrint("Unable to create virtual mapping\n");
771 MmInsertRmap(Page
, MemoryArea
->Process
, (PVOID
)PAddress
);
777 MmUnlockSectionSegment(Segment
);
778 PageOp
->Status
= STATUS_SUCCESS
;
779 MmspCompleteAndReleasePageOp(PageOp
);
780 DPRINT("Address 0x%.8X\n", Address
);
781 return(STATUS_SUCCESS
);
784 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
788 * Must be private page we have swapped out.
796 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
798 DPRINT1("Found a swaped out private page in a pagefile section.\n");
802 MmUnlockSectionSegment(Segment
);
803 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
805 MmUnlockAddressSpace(AddressSpace
);
806 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
807 if (!NT_SUCCESS(Status
))
812 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
813 MmBuildMdlFromPages(Mdl
, (PULONG
)&Page
);
814 Status
= MmReadFromSwapPage(SwapEntry
, Mdl
);
815 if (!NT_SUCCESS(Status
))
817 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
820 MmLockAddressSpace(AddressSpace
);
821 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
826 if (Status
== STATUS_NO_MEMORY
)
828 MmUnlockAddressSpace(AddressSpace
);
829 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
834 MmLockAddressSpace(AddressSpace
);
836 if (!NT_SUCCESS(Status
))
838 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
844 * Store the swap entry for later use.
846 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
849 * Add the page to the process's working set
851 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
854 * Finish the operation
858 MmLockPage(MmGetPhysicalAddressForProcess(NULL
, Address
));
860 PageOp
->Status
= STATUS_SUCCESS
;
861 MmspCompleteAndReleasePageOp(PageOp
);
862 DPRINT("Address 0x%.8X\n", Address
);
863 return(STATUS_SUCCESS
);
867 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
869 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
871 MmUnlockSectionSegment(Segment
);
873 * Just map the desired physical page
875 Page
.QuadPart
= Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
;
876 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
881 if (Status
== STATUS_NO_MEMORY
)
883 MmUnlockAddressSpace(AddressSpace
);
884 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
889 MmLockAddressSpace(AddressSpace
);
891 if (!NT_SUCCESS(Status
))
893 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
898 * Don't add an rmap entry since the page mapped could be for
907 * Cleanup and release locks
909 PageOp
->Status
= STATUS_SUCCESS
;
910 MmspCompleteAndReleasePageOp(PageOp
);
911 DPRINT("Address 0x%.8X\n", Address
);
912 return(STATUS_SUCCESS
);
916 * Map anonymous memory for BSS sections
918 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
)
920 MmUnlockSectionSegment(Segment
);
921 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
922 if (!NT_SUCCESS(Status
))
924 MmUnlockAddressSpace(AddressSpace
);
925 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
926 MmLockAddressSpace(AddressSpace
);
928 if (!NT_SUCCESS(Status
))
932 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
937 if (Status
== STATUS_NO_MEMORY
)
939 MmUnlockAddressSpace(AddressSpace
);
940 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
945 MmLockAddressSpace(AddressSpace
);
948 if (!NT_SUCCESS(Status
))
950 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
954 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
961 * Cleanup and release locks
963 PageOp
->Status
= STATUS_SUCCESS
;
964 MmspCompleteAndReleasePageOp(PageOp
);
965 DPRINT("Address 0x%.8X\n", Address
);
966 return(STATUS_SUCCESS
);
970 * Get the entry corresponding to the offset within the section
972 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
977 * If the entry is zero (and it can't change because we have
978 * locked the segment) then we need to load the page.
982 * Release all our locks and read in the page from disk
984 MmUnlockSectionSegment(Segment
);
985 MmUnlockAddressSpace(AddressSpace
);
987 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
988 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
990 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
991 if (!NT_SUCCESS(Status
))
993 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
998 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
999 if (!NT_SUCCESS(Status
))
1001 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1004 if (!NT_SUCCESS(Status
))
1007 * FIXME: What do we know in this case?
1010 * Cleanup and release locks
1012 MmLockAddressSpace(AddressSpace
);
1013 PageOp
->Status
= Status
;
1014 MmspCompleteAndReleasePageOp(PageOp
);
1015 DPRINT("Address 0x%.8X\n", Address
);
1019 * Relock the address space and segment
1021 MmLockAddressSpace(AddressSpace
);
1022 MmLockSectionSegment(Segment
);
1025 * Check the entry. No one should change the status of a page
1026 * that has a pending page-in.
1028 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1029 if (Entry
!= Entry1
)
1031 DbgPrint("Someone changed ppte entry while we slept\n");
1036 * Mark the offset within the section as having valid, in-memory
1039 Entry
= MAKE_SSE(Page
.u
.LowPart
, 1);
1040 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1041 MmUnlockSectionSegment(Segment
);
1043 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1048 if (Status
== STATUS_NO_MEMORY
)
1050 MmUnlockAddressSpace(AddressSpace
);
1051 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1056 MmLockAddressSpace(AddressSpace
);
1058 if (!NT_SUCCESS(Status
))
1060 DbgPrint("Unable to create virtual mapping\n");
1063 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1069 PageOp
->Status
= STATUS_SUCCESS
;
1070 MmspCompleteAndReleasePageOp(PageOp
);
1071 DPRINT("Address 0x%.8X\n", Address
);
1072 return(STATUS_SUCCESS
);
1074 else if (IS_SWAP_FROM_SSE(Entry
))
1076 SWAPENTRY SwapEntry
;
1079 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1082 * Release all our locks and read in the page from disk
1084 MmUnlockSectionSegment(Segment
);
1086 MmUnlockAddressSpace(AddressSpace
);
1088 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1089 if (!NT_SUCCESS(Status
))
1094 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1095 MmBuildMdlFromPages(Mdl
, (PULONG
)&Page
);
1096 Status
= MmReadFromSwapPage(SwapEntry
, Mdl
);
1097 if (!NT_SUCCESS(Status
))
1103 * Relock the address space and segment
1105 MmLockAddressSpace(AddressSpace
);
1106 MmLockSectionSegment(Segment
);
1109 * Check the entry. No one should change the status of a page
1110 * that has a pending page-in.
1112 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1113 if (Entry
!= Entry1
)
1115 DbgPrint("Someone changed ppte entry while we slept\n");
1120 * Mark the offset within the section as having valid, in-memory
1123 Entry
= MAKE_SSE(Page
.u
.LowPart
, 1);
1124 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1125 MmUnlockSectionSegment(Segment
);
1128 * Save the swap entry.
1130 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1131 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1136 if (Status
== STATUS_NO_MEMORY
)
1138 MmUnlockAddressSpace(AddressSpace
);
1139 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1144 MmLockAddressSpace(AddressSpace
);
1146 if (!NT_SUCCESS(Status
))
1148 DbgPrint("Unable to create virtual mapping\n");
1151 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1156 PageOp
->Status
= STATUS_SUCCESS
;
1157 MmspCompleteAndReleasePageOp(PageOp
);
1158 DPRINT("Address 0x%.8X\n", Address
);
1159 return(STATUS_SUCCESS
);
1164 * If the section offset is already in-memory and valid then just
1165 * take another reference to the page
1168 Page
.QuadPart
= (LONGLONG
)PAGE_FROM_SSE(Entry
);
1170 MmSharePageEntrySectionSegment(Segment
, Offset
);
1171 MmUnlockSectionSegment(Segment
);
1173 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1178 if (Status
== STATUS_NO_MEMORY
)
1180 MmUnlockAddressSpace(AddressSpace
);
1181 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1186 MmLockAddressSpace(AddressSpace
);
1188 if (!NT_SUCCESS(Status
))
1190 DbgPrint("Unable to create virtual mapping\n");
1193 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1198 PageOp
->Status
= STATUS_SUCCESS
;
1199 MmspCompleteAndReleasePageOp(PageOp
);
1200 DPRINT("Address 0x%.8X\n", Address
);
1201 return(STATUS_SUCCESS
);
1206 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1207 MEMORY_AREA
* MemoryArea
,
1211 PMM_SECTION_SEGMENT Segment
;
1212 PSECTION_OBJECT Section
;
1213 PHYSICAL_ADDRESS OldPage
;
1214 PHYSICAL_ADDRESS NewPage
;
1224 * Check if the page has been paged out or has already been set readwrite
1226 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1227 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1229 DPRINT("Address 0x%.8X\n", Address
);
1230 return(STATUS_SUCCESS
);
1234 * Find the offset of the page
1236 PAddress
= (ULONG
)PAGE_ROUND_DOWN(((ULONG
)Address
));
1237 Offset
= PAddress
- (ULONG
)MemoryArea
->BaseAddress
;
1239 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1240 Section
= MemoryArea
->Data
.SectionData
.Section
;
1241 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1242 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1247 MmLockSectionSegment(Segment
);
1249 OldPage
= MmGetPhysicalAddressForProcess(NULL
, Address
);
1250 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1252 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
);
1265 if (IS_SWAP_FROM_SSE(Entry
) ||
1266 PAGE_FROM_SSE(Entry
) != OldPage
.u
.LowPart
)
1268 /* This is a private page. We must only change the page protection. */
1269 MmSetPageProtect(AddressSpace
->Process
, (PVOID
)PAddress
, Region
->Protect
);
1270 return(STATUS_SUCCESS
);
1274 * Get or create a pageop
1276 PageOp
= MmGetPageOp(MemoryArea
, 0, 0, Segment
, Offset
,
1277 MM_PAGEOP_ACCESSFAULT
);
1280 DPRINT1("MmGetPageOp failed\n");
1285 * Wait for any other operations to complete
1287 if (PageOp
->Thread
!= PsGetCurrentThread())
1289 MmUnlockAddressSpace(AddressSpace
);
1290 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1292 * Check for various strange conditions
1294 if (Status
== STATUS_TIMEOUT
)
1296 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1299 if (PageOp
->Status
== STATUS_PENDING
)
1301 DPRINT1("Woke for page op before completion\n");
1305 * Restart the operation
1307 MmLockAddressSpace(AddressSpace
);
1308 MmspCompleteAndReleasePageOp(PageOp
);
1309 DPRINT("Address 0x%.8X\n", Address
);
1310 return(STATUS_MM_RESTART_OPERATION
);
1314 * Release locks now we have the pageop
1316 MmUnlockAddressSpace(AddressSpace
);
1321 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1322 if (!NT_SUCCESS(Status
))
1331 NewAddress
= ExAllocatePageWithPhysPage(NewPage
);
1332 memcpy(NewAddress
, (PVOID
)PAddress
, PAGE_SIZE
);
1333 ExUnmapPage(NewAddress
);
1336 * Delete the old entry.
1338 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1341 * Set the PTE to point to the new page
1343 MmLockAddressSpace(AddressSpace
);
1344 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1349 if (Status
== STATUS_NO_MEMORY
)
1351 MmUnlockAddressSpace(AddressSpace
);
1352 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1357 MmLockAddressSpace(AddressSpace
);
1359 if (!NT_SUCCESS(Status
))
1361 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1365 MmInsertRmap(NewPage
, AddressSpace
->Process
, (PVOID
)PAddress
);
1366 if (!NT_SUCCESS(Status
))
1368 DbgPrint("Unable to create virtual mapping\n");
1373 MmLockPage(NewPage
);
1374 MmUnlockPage(OldPage
);
1378 * Unshare the old page.
1380 MmDeleteRmap(OldPage
, AddressSpace
->Process
, (PVOID
)PAddress
);
1381 MmLockSectionSegment(Segment
);
1382 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1383 MmUnlockSectionSegment(Segment
);
1385 PageOp
->Status
= STATUS_SUCCESS
;
1386 MmspCompleteAndReleasePageOp(PageOp
);
1387 DPRINT("Address 0x%.8X\n", Address
);
1388 return(STATUS_SUCCESS
);
1392 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1394 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1396 PHYSICAL_ADDRESS Page
;
1398 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1399 MmDeleteVirtualMapping(Process
,
1406 PageOutContext
->WasDirty
= TRUE
;
1408 if (!PageOutContext
->Private
)
1410 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1411 PageOutContext
->Segment
,
1412 PageOutContext
->Offset
,
1413 PageOutContext
->WasDirty
,
1418 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1421 DPRINT("PhysicalAddress %I64x, Address %x\n", Page
, Address
);
1425 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1426 MEMORY_AREA
* MemoryArea
,
1430 PHYSICAL_ADDRESS PhysicalAddress
;
1431 MM_SECTION_PAGEOUT_CONTEXT Context
;
1432 SWAPENTRY SwapEntry
;
1437 PFILE_OBJECT FileObject
;
1439 BOOLEAN DirectMapped
;
1440 BOOLEAN IsImageSection
;
1442 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1445 * Get the segment and section.
1447 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1448 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1450 Context
.Offset
= (ULONG
)((char*)Address
- (ULONG
)MemoryArea
->BaseAddress
);
1451 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1453 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1455 FileObject
= Context
.Section
->FileObject
;
1456 DirectMapped
= FALSE
;
1457 if (FileObject
!= NULL
&&
1458 !(Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
1460 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1463 * If the file system is letting us go directly to the cache and the
1464 * memory area was mapped at an offset in the file which is page aligned
1465 * then note this is a direct mapped page.
1467 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1468 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1470 DirectMapped
= TRUE
;
1476 * This should never happen since mappings of physical memory are never
1477 * placed in the rmap lists.
1479 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1481 DPRINT1("Trying to page out from physical memory section address 0x%X "
1482 "process %d\n", Address
,
1483 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1488 * Get the section segment entry and the physical address.
1490 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1491 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1493 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1494 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1498 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1499 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1502 * Prepare the context structure for the rmap delete call.
1504 Context
.WasDirty
= FALSE
;
1505 if (Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1506 IS_SWAP_FROM_SSE(Entry
) ||
1507 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
)
1509 Context
.Private
= TRUE
;
1513 Context
.Private
= FALSE
;
1517 * Take an additional reference to the page or the cache segment.
1519 if (DirectMapped
&& !Context
.Private
)
1521 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1523 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1529 MmReferencePage(PhysicalAddress
);
1532 MmDeleteAllRmaps(PhysicalAddress
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1535 * If this wasn't a private page then we should have reduced the entry to
1536 * zero by deleting all the rmaps.
1538 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1540 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1541 !(Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
1548 * If the page wasn't dirty then we can just free it as for a readonly page.
1549 * Since we unmapped all the mappings above we know it will not suddenly
1551 * If the page is from a pagefile section and has no swap entry,
1552 * we can't free the page at this point.
1554 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1555 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1557 if (Context
.Private
)
1559 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1560 Context
.WasDirty
? "dirty" : "clean", Address
);
1563 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1565 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
1566 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1567 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1568 PageOp
->Status
= STATUS_SUCCESS
;
1569 MmspCompleteAndReleasePageOp(PageOp
);
1570 return(STATUS_SUCCESS
);
1573 else if (Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
)
1575 if (Context
.Private
)
1577 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1578 Context
.WasDirty
? "dirty" : "clean", Address
);
1581 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1583 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
1586 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1588 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1589 PageOp
->Status
= STATUS_SUCCESS
;
1590 MmspCompleteAndReleasePageOp(PageOp
);
1591 return(STATUS_SUCCESS
);
1594 else if (!Context
.Private
&& DirectMapped
)
1598 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1602 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1603 if (!NT_SUCCESS(Status
))
1605 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1608 PageOp
->Status
= STATUS_SUCCESS
;
1609 MmspCompleteAndReleasePageOp(PageOp
);
1610 return(STATUS_SUCCESS
);
1612 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1616 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1620 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1621 PageOp
->Status
= STATUS_SUCCESS
;
1622 MmspCompleteAndReleasePageOp(PageOp
);
1623 return(STATUS_SUCCESS
);
1625 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1627 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
1628 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1631 if (!NT_SUCCESS(Status
))
1635 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1636 PageOp
->Status
= STATUS_SUCCESS
;
1637 MmspCompleteAndReleasePageOp(PageOp
);
1638 return(STATUS_SUCCESS
);
1642 * If necessary, allocate an entry in the paging file for this page
1646 SwapEntry
= MmAllocSwapPage();
1649 MmShowOutOfSpaceMessagePagingFile();
1652 * For private pages restore the old mappings.
1654 if (Context
.Private
)
1656 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1658 MemoryArea
->Attributes
,
1661 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1662 MmInsertRmap(PhysicalAddress
,
1663 MemoryArea
->Process
,
1669 * For non-private pages if the page wasn't direct mapped then
1670 * set it back into the section segment entry so we don't loose
1671 * our copy. Otherwise it will be handled by the cache manager.
1673 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1675 MemoryArea
->Attributes
,
1678 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1679 MmInsertRmap(PhysicalAddress
,
1680 MemoryArea
->Process
,
1682 Entry
= MAKE_SSE(PhysicalAddress
.u
.LowPart
, 1);
1683 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1685 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1686 MmspCompleteAndReleasePageOp(PageOp
);
1687 return(STATUS_PAGEFILE_QUOTA
);
1692 * Write the page to the pagefile
1694 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1695 MmBuildMdlFromPages(Mdl
, (PULONG
)&PhysicalAddress
);
1696 Status
= MmWriteToSwapPage(SwapEntry
, Mdl
);
1697 if (!NT_SUCCESS(Status
))
1699 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1702 * As above: undo our actions.
1703 * FIXME: Also free the swap page.
1705 if (Context
.Private
)
1707 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1709 MemoryArea
->Attributes
,
1712 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1713 MmInsertRmap(PhysicalAddress
,
1714 MemoryArea
->Process
,
1719 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1721 MemoryArea
->Attributes
,
1724 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1725 MmInsertRmap(PhysicalAddress
,
1726 MemoryArea
->Process
,
1728 Entry
= MAKE_SSE(PhysicalAddress
.u
.LowPart
, 1);
1729 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1731 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1732 MmspCompleteAndReleasePageOp(PageOp
);
1733 return(STATUS_UNSUCCESSFUL
);
1737 * Otherwise we have succeeded.
1739 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress
);
1740 MmSetSavedSwapEntryPage(PhysicalAddress
, 0);
1741 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1742 Context
.Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
)
1744 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1748 MmReleasePageMemoryConsumer(MC_USER
, PhysicalAddress
);
1751 if (Context
.Private
)
1753 Status
= MmCreatePageFileMapping(MemoryArea
->Process
,
1756 if (!NT_SUCCESS(Status
))
1763 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1764 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1767 PageOp
->Status
= STATUS_SUCCESS
;
1768 MmspCompleteAndReleasePageOp(PageOp
);
1769 return(STATUS_SUCCESS
);
1773 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1774 PMEMORY_AREA MemoryArea
,
1779 PSECTION_OBJECT Section
;
1780 PMM_SECTION_SEGMENT Segment
;
1781 PHYSICAL_ADDRESS PhysicalAddress
;
1782 SWAPENTRY SwapEntry
;
1787 PFILE_OBJECT FileObject
;
1789 BOOLEAN DirectMapped
;
1790 BOOLEAN IsImageSection
;
1792 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1794 Offset
= (ULONG
)((char*)Address
- (ULONG
)MemoryArea
->BaseAddress
);
1797 * Get the segment and section.
1799 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1800 Section
= MemoryArea
->Data
.SectionData
.Section
;
1801 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1803 FileObject
= Section
->FileObject
;
1804 DirectMapped
= FALSE
;
1805 if (FileObject
!= NULL
&&
1806 !(Segment
->Characteristics
& IMAGE_SECTION_CHAR_SHARED
))
1808 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1811 * If the file system is letting us go directly to the cache and the
1812 * memory area was mapped at an offset in the file which is page aligned
1813 * then note this is a direct mapped page.
1815 if ((Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
% PAGE_SIZE
) == 0 &&
1816 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1818 DirectMapped
= TRUE
;
1823 * This should never happen since mappings of physical memory are never
1824 * placed in the rmap lists.
1826 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1828 DPRINT1("Trying to write back page from physical memory mapped at %X "
1829 "process %d\n", Address
,
1830 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1835 * Get the section segment entry and the physical address.
1837 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1838 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1840 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1841 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1845 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1846 SwapEntry
= MmGetSavedSwapEntryPage(PhysicalAddress
);
1849 * Check for a private (COWed) page.
1851 if (Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1852 IS_SWAP_FROM_SSE(Entry
) ||
1853 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
)
1863 * Speculatively set all mappings of the page to clean.
1865 MmSetCleanAllRmaps(PhysicalAddress
);
1868 * If this page was direct mapped from the cache then the cache manager
1869 * will take care of writing it back to disk.
1871 if (DirectMapped
&& !Private
)
1873 assert(SwapEntry
== 0);
1874 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
1875 PageOp
->Status
= STATUS_SUCCESS
;
1876 MmspCompleteAndReleasePageOp(PageOp
);
1877 return(STATUS_SUCCESS
);
1881 * If necessary, allocate an entry in the paging file for this page
1885 SwapEntry
= MmAllocSwapPage();
1888 MmSetDirtyAllRmaps(PhysicalAddress
);
1889 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1890 MmspCompleteAndReleasePageOp(PageOp
);
1891 return(STATUS_PAGEFILE_QUOTA
);
1893 MmSetSavedSwapEntryPage(PhysicalAddress
, SwapEntry
);
1897 * Write the page to the pagefile
1899 Mdl
= MmCreateMdl(NULL
, NULL
, PAGE_SIZE
);
1900 MmBuildMdlFromPages(Mdl
, (PULONG
)&PhysicalAddress
);
1901 Status
= MmWriteToSwapPage(SwapEntry
, Mdl
);
1902 if (!NT_SUCCESS(Status
))
1904 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1906 MmSetDirtyAllRmaps(PhysicalAddress
);
1907 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1908 MmspCompleteAndReleasePageOp(PageOp
);
1909 return(STATUS_UNSUCCESSFUL
);
1913 * Otherwise we have succeeded.
1915 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", PhysicalAddress
);
1916 PageOp
->Status
= STATUS_SUCCESS
;
1917 MmspCompleteAndReleasePageOp(PageOp
);
1918 return(STATUS_SUCCESS
);
1922 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1930 PMEMORY_AREA MemoryArea
;
1931 PMM_SECTION_SEGMENT Segment
;
1935 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1936 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1938 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1939 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1944 if (OldProtect
!= NewProtect
)
1946 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1948 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1949 ULONG Protect
= NewProtect
;
1952 * If we doing COW for this segment then check if the page is
1955 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1959 LARGE_INTEGER PhysicalAddress
;
1961 Offset
= (ULONG
)Address
- (ULONG
)MemoryArea
->BaseAddress
;
1962 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1964 MmGetPhysicalAddressForProcess(AddressSpace
->Process
, Address
);
1966 Protect
= PAGE_READONLY
;
1967 if ((Segment
->Characteristics
& IMAGE_SECTION_CHAR_BSS
||
1968 IS_SWAP_FROM_SSE(Entry
) ||
1969 (LONGLONG
)PAGE_FROM_SSE(Entry
) != PhysicalAddress
.QuadPart
))
1971 Protect
= NewProtect
;
1975 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1977 MmSetPageProtect(AddressSpace
->Process
, BaseAddress
,
1985 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1986 PMEMORY_AREA MemoryArea
,
1996 min(Length
, (ULONG
) ((char*)MemoryArea
->BaseAddress
+ MemoryArea
->Length
- (char*)BaseAddress
));
1997 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
1998 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2000 *OldProtect
= Region
->Protect
;
2001 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->BaseAddress
,
2002 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2003 BaseAddress
, Length
, Region
->Type
, Protect
,
2004 MmAlterViewAttributes
);
2010 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2012 PMEMORY_BASIC_INFORMATION Info
,
2013 PULONG ResultLength
)
2016 PVOID RegionBaseAddress
;
2018 Region
= MmFindRegion(MemoryArea
->BaseAddress
,
2019 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2020 Address
, &RegionBaseAddress
);
2023 return STATUS_UNSUCCESSFUL
;
2025 Info
->BaseAddress
= (PVOID
)PAGE_ROUND_DOWN(Address
);
2026 Info
->AllocationBase
= MemoryArea
->BaseAddress
;
2027 Info
->AllocationProtect
= MemoryArea
->Attributes
;
2028 Info
->RegionSize
= MemoryArea
->Length
;
2029 Info
->State
= MEM_COMMIT
;
2030 Info
->Protect
= Region
->Protect
;
2031 if (MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
)
2033 Info
->Type
= MEM_IMAGE
;
2037 Info
->Type
= MEM_MAPPED
;
2040 return(STATUS_SUCCESS
);
2044 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2049 ULONG SavedSwapEntry
;
2050 PHYSICAL_ADDRESS Page
;
2052 Page
.u
.HighPart
= 0;
2054 Length
= PAGE_ROUND_UP(Segment
->Length
);
2055 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2057 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2060 if (IS_SWAP_FROM_SSE(Entry
))
2062 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2066 Page
.u
.LowPart
= PAGE_FROM_SSE(Entry
);
2067 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2068 if (SavedSwapEntry
!= 0)
2070 MmSetSavedSwapEntryPage(Page
, 0);
2071 MmFreeSwapPage(SavedSwapEntry
);
2073 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2075 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2081 MmpDeleteSection(PVOID ObjectBody
)
2083 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
2085 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2086 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2091 PMM_SECTION_SEGMENT SectionSegments
;
2093 SectionSegments
= Section
->ImageSection
->Segments
;
2094 NrSegments
= Section
->ImageSection
->NrSegments
;
2096 for (i
= 0; i
< NrSegments
; i
++)
2098 if (SectionSegments
[i
].Characteristics
& IMAGE_SECTION_CHAR_SHARED
)
2100 MmLockSectionSegment(&SectionSegments
[i
]);
2102 RefCount
= InterlockedDecrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2103 if (SectionSegments
[i
].Characteristics
& IMAGE_SECTION_CHAR_SHARED
)
2107 MmpFreePageFileSegment(&SectionSegments
[i
]);
2109 MmUnlockSectionSegment(&SectionSegments
[i
]);
2115 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2117 MmpFreePageFileSegment(Section
->Segment
);
2118 MmFreePageTablesSectionSegment(Section
->Segment
);
2119 ExFreePool(Section
->Segment
);
2120 Section
->Segment
= NULL
;
2124 InterlockedDecrement((LONG
*)&Section
->Segment
->ReferenceCount
);
2127 if (Section
->FileObject
!= NULL
)
2129 CcRosDereferenceCache(Section
->FileObject
);
2130 ObDereferenceObject(Section
->FileObject
);
2131 Section
->FileObject
= NULL
;
2136 MmpCloseSection(PVOID ObjectBody
,
2139 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2140 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2144 MmpCreateSection(PVOID ObjectBody
,
2146 PWSTR RemainingPath
,
2147 POBJECT_ATTRIBUTES ObjectAttributes
)
2149 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2150 ObjectBody
, Parent
, RemainingPath
);
2152 if (RemainingPath
== NULL
)
2154 return(STATUS_SUCCESS
);
2157 if (wcschr(RemainingPath
+1, L
'\\') != NULL
)
2159 return(STATUS_UNSUCCESSFUL
);
2161 return(STATUS_SUCCESS
);
2164 NTSTATUS INIT_FUNCTION
2165 MmCreatePhysicalMemorySection(VOID
)
2167 HANDLE PhysSectionH
;
2168 PSECTION_OBJECT PhysSection
;
2170 OBJECT_ATTRIBUTES Obj
;
2171 UNICODE_STRING Name
= ROS_STRING_INITIALIZER(L
"\\Device\\PhysicalMemory");
2172 LARGE_INTEGER SectionSize
;
2175 * Create the section mapping physical memory
2177 SectionSize
.QuadPart
= 0xFFFFFFFF;
2178 InitializeObjectAttributes(&Obj
,
2183 Status
= NtCreateSection(&PhysSectionH
,
2187 PAGE_EXECUTE_READWRITE
,
2190 if (!NT_SUCCESS(Status
))
2192 DbgPrint("Failed to create PhysicalMemory section\n");
2195 Status
= ObReferenceObjectByHandle(PhysSectionH
,
2199 (PVOID
*)&PhysSection
,
2201 if (!NT_SUCCESS(Status
))
2203 DbgPrint("Failed to reference PhysicalMemory section\n");
2206 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2207 ObDereferenceObject((PVOID
)PhysSection
);
2209 return(STATUS_SUCCESS
);
2212 NTSTATUS INIT_FUNCTION
2213 MmInitSectionImplementation(VOID
)
2215 MmSectionObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
2217 RtlRosInitUnicodeStringFromLiteral(&MmSectionObjectType
->TypeName
, L
"Section");
2219 MmSectionObjectType
->Tag
= TAG('S', 'E', 'C', 'T');
2220 MmSectionObjectType
->TotalObjects
= 0;
2221 MmSectionObjectType
->TotalHandles
= 0;
2222 MmSectionObjectType
->MaxObjects
= ULONG_MAX
;
2223 MmSectionObjectType
->MaxHandles
= ULONG_MAX
;
2224 MmSectionObjectType
->PagedPoolCharge
= 0;
2225 MmSectionObjectType
->NonpagedPoolCharge
= sizeof(SECTION_OBJECT
);
2226 MmSectionObjectType
->Mapping
= &MmpSectionMapping
;
2227 MmSectionObjectType
->Dump
= NULL
;
2228 MmSectionObjectType
->Open
= NULL
;
2229 MmSectionObjectType
->Close
= MmpCloseSection
;
2230 MmSectionObjectType
->Delete
= MmpDeleteSection
;
2231 MmSectionObjectType
->Parse
= NULL
;
2232 MmSectionObjectType
->Security
= NULL
;
2233 MmSectionObjectType
->QueryName
= NULL
;
2234 MmSectionObjectType
->OkayToClose
= NULL
;
2235 MmSectionObjectType
->Create
= MmpCreateSection
;
2236 MmSectionObjectType
->DuplicationNotify
= NULL
;
2239 * NOTE: Do not register the section object type here because
2240 * the object manager it not initialized yet!
2241 * The section object type will be created in ObInit().
2243 ObpCreateTypeObject(MmSectionObjectType
);
2245 return(STATUS_SUCCESS
);
2249 MmCreatePageFileSection(PHANDLE SectionHandle
,
2250 ACCESS_MASK DesiredAccess
,
2251 POBJECT_ATTRIBUTES ObjectAttributes
,
2252 PLARGE_INTEGER UMaximumSize
,
2253 ULONG SectionPageProtection
,
2254 ULONG AllocationAttributes
)
2256 * Create a section which is backed by the pagefile
2259 LARGE_INTEGER MaximumSize
;
2260 PSECTION_OBJECT Section
;
2261 PMM_SECTION_SEGMENT Segment
;
2264 if (UMaximumSize
== NULL
)
2266 return(STATUS_UNSUCCESSFUL
);
2268 MaximumSize
= *UMaximumSize
;
2271 * Check the protection
2273 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2274 SectionPageProtection
)
2276 return(STATUS_INVALID_PAGE_PROTECTION
);
2280 * Create the section
2282 Status
= ObCreateObject(ExGetPreviousMode(),
2283 MmSectionObjectType
,
2285 ExGetPreviousMode(),
2287 sizeof(SECTION_OBJECT
),
2291 if (!NT_SUCCESS(Status
))
2296 Status
= ObInsertObject ((PVOID
)Section
,
2302 if (!NT_SUCCESS(Status
))
2304 ObDereferenceObject(Section
);
2311 Section
->SectionPageProtection
= SectionPageProtection
;
2312 Section
->AllocationAttributes
= AllocationAttributes
;
2313 InitializeListHead(&Section
->ViewListHead
);
2314 KeInitializeSpinLock(&Section
->ViewListLock
);
2315 Section
->FileObject
= NULL
;
2316 Section
->MaximumSize
= MaximumSize
;
2317 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2318 TAG_MM_SECTION_SEGMENT
);
2319 if (Segment
== NULL
)
2321 ZwClose(*SectionHandle
);
2322 ObDereferenceObject(Section
);
2323 return(STATUS_NO_MEMORY
);
2325 Section
->Segment
= Segment
;
2326 Segment
->ReferenceCount
= 1;
2327 ExInitializeFastMutex(&Segment
->Lock
);
2328 Segment
->FileOffset
= 0;
2329 Segment
->Protection
= SectionPageProtection
;
2330 Segment
->Attributes
= AllocationAttributes
;
2331 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2332 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2333 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2334 Segment
->WriteCopy
= FALSE
;
2335 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2336 Segment
->VirtualAddress
= 0;
2337 Segment
->Characteristics
= 0;
2338 ObDereferenceObject(Section
);
2339 return(STATUS_SUCCESS
);
2344 MmCreateDataFileSection(PHANDLE SectionHandle
,
2345 ACCESS_MASK DesiredAccess
,
2346 POBJECT_ATTRIBUTES ObjectAttributes
,
2347 PLARGE_INTEGER UMaximumSize
,
2348 ULONG SectionPageProtection
,
2349 ULONG AllocationAttributes
,
2352 * Create a section backed by a data file
2355 PSECTION_OBJECT Section
;
2357 LARGE_INTEGER MaximumSize
;
2358 PFILE_OBJECT FileObject
;
2359 PMM_SECTION_SEGMENT Segment
;
2361 IO_STATUS_BLOCK Iosb
;
2362 LARGE_INTEGER Offset
;
2366 * Check the protection
2368 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2369 SectionPageProtection
)
2371 return(STATUS_INVALID_PAGE_PROTECTION
);
2374 * Create the section
2376 Status
= ObCreateObject(ExGetPreviousMode(),
2377 MmSectionObjectType
,
2379 ExGetPreviousMode(),
2381 sizeof(SECTION_OBJECT
),
2385 if (!NT_SUCCESS(Status
))
2390 Status
= ObInsertObject ((PVOID
)Section
,
2396 if (!NT_SUCCESS(Status
))
2398 ObDereferenceObject(Section
);
2405 Section
->SectionPageProtection
= SectionPageProtection
;
2406 Section
->AllocationAttributes
= AllocationAttributes
;
2407 InitializeListHead(&Section
->ViewListHead
);
2408 KeInitializeSpinLock(&Section
->ViewListLock
);
2411 * Check file access required
2413 if (SectionPageProtection
& PAGE_READWRITE
||
2414 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2416 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2420 FileAccess
= FILE_READ_DATA
;
2424 * Reference the file handle
2426 Status
= ObReferenceObjectByHandle(FileHandle
,
2430 (PVOID
*)&FileObject
,
2432 if (!NT_SUCCESS(Status
))
2434 ZwClose(*SectionHandle
);
2435 ObDereferenceObject(Section
);
2440 * We can't do memory mappings if the file system doesn't support the
2443 if (!(FileObject
->Flags
& FO_FCB_IS_VALID
))
2445 ZwClose(*SectionHandle
);
2446 ObDereferenceObject(Section
);
2447 ObDereferenceObject(FileObject
);
2448 return(STATUS_INVALID_FILE_FOR_SECTION
);
2452 * FIXME: Revise this once a locking order for file size changes is
2455 if (UMaximumSize
!= NULL
)
2457 MaximumSize
= *UMaximumSize
;
2462 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
;
2465 if (MaximumSize
.QuadPart
>
2466 ((PFSRTL_COMMON_FCB_HEADER
)FileObject
->FsContext
)->FileSize
.QuadPart
)
2468 Status
= NtSetInformationFile(FileHandle
,
2471 sizeof(LARGE_INTEGER
),
2472 FileAllocationInformation
);
2473 if (!NT_SUCCESS(Status
))
2475 ZwClose(*SectionHandle
);
2476 ObDereferenceObject(Section
);
2477 ObDereferenceObject(FileObject
);
2478 return(STATUS_SECTION_NOT_EXTENDED
);
2482 if (FileObject
->SectionObjectPointer
== NULL
||
2483 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2486 * Read a bit so caching is initiated for the file object.
2487 * This is only needed because MiReadPage currently cannot
2488 * handle non-cached streams.
2490 Offset
.QuadPart
= 0;
2491 Status
= ZwReadFile(FileHandle
,
2500 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2502 ZwClose(*SectionHandle
);
2503 ObDereferenceObject(Section
);
2504 ObDereferenceObject(FileObject
);
2507 if (FileObject
->SectionObjectPointer
== NULL
||
2508 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2510 /* FIXME: handle this situation */
2511 ZwClose(*SectionHandle
);
2512 ObDereferenceObject(Section
);
2513 ObDereferenceObject(FileObject
);
2514 return STATUS_INVALID_PARAMETER
;
2521 Status
= MmspWaitForFileLock(FileObject
);
2522 if (Status
!= STATUS_SUCCESS
)
2524 ZwClose(*SectionHandle
);
2525 ObDereferenceObject(Section
);
2526 ObDereferenceObject(FileObject
);
2531 * If this file hasn't been mapped as a data file before then allocate a
2532 * section segment to describe the data file mapping
2534 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2536 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2537 TAG_MM_SECTION_SEGMENT
);
2538 if (Segment
== NULL
)
2540 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2541 ZwClose(*SectionHandle
);
2542 ObDereferenceObject(Section
);
2543 ObDereferenceObject(FileObject
);
2544 return(STATUS_NO_MEMORY
);
2546 Section
->Segment
= Segment
;
2547 Segment
->ReferenceCount
= 1;
2548 ExInitializeFastMutex(&Segment
->Lock
);
2550 * Set the lock before assigning the segment to the file object
2552 ExAcquireFastMutex(&Segment
->Lock
);
2553 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2555 Segment
->FileOffset
= 0;
2556 Segment
->Protection
= SectionPageProtection
;
2557 Segment
->Attributes
= 0;
2558 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2559 Segment
->Characteristics
= 0;
2560 Segment
->WriteCopy
= FALSE
;
2561 if (AllocationAttributes
& SEC_RESERVE
)
2563 Segment
->Length
= Segment
->RawLength
= 0;
2567 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2568 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2570 Segment
->VirtualAddress
= NULL
;
2571 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2576 * If the file is already mapped as a data file then we may need
2580 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2582 Section
->Segment
= Segment
;
2583 InterlockedIncrement((PLONG
)&Segment
->ReferenceCount
);
2584 MmLockSectionSegment(Segment
);
2586 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2587 !(AllocationAttributes
& SEC_RESERVE
))
2589 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2590 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2593 MmUnlockSectionSegment(Segment
);
2594 Section
->FileObject
= FileObject
;
2595 Section
->MaximumSize
= MaximumSize
;
2596 CcRosReferenceCache(FileObject
);
2597 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2598 ObDereferenceObject(Section
);
2599 return(STATUS_SUCCESS
);
2602 static ULONG SectionCharacteristicsToProtect
[16] =
2604 PAGE_NOACCESS
, // 0 = NONE
2605 PAGE_NOACCESS
, // 1 = SHARED
2606 PAGE_EXECUTE
, // 2 = EXECUTABLE
2607 PAGE_EXECUTE
, // 3 = EXECUTABLE, SHARED
2608 PAGE_READONLY
, // 4 = READABLE
2609 PAGE_READONLY
, // 5 = READABLE, SHARED
2610 PAGE_EXECUTE_READ
, // 6 = READABLE, EXECUTABLE
2611 PAGE_EXECUTE_READ
, // 7 = READABLE, EXECUTABLE, SHARED
2612 PAGE_READWRITE
, // 8 = WRITABLE
2613 PAGE_READWRITE
, // 9 = WRITABLE, SHARED
2614 PAGE_EXECUTE_READWRITE
, // 10 = WRITABLE, EXECUTABLE
2615 PAGE_EXECUTE_READWRITE
, // 11 = WRITABLE, EXECUTABLE, SHARED
2616 PAGE_READWRITE
, // 12 = WRITABLE, READABLE
2617 PAGE_READWRITE
, // 13 = WRITABLE, READABLE, SHARED
2618 PAGE_EXECUTE_READWRITE
, // 14 = WRITABLE, READABLE, EXECUTABLE,
2619 PAGE_EXECUTE_READWRITE
, // 15 = WRITABLE, READABLE, EXECUTABLE, SHARED
2623 MmCreateImageSection(PHANDLE SectionHandle
,
2624 ACCESS_MASK DesiredAccess
,
2625 POBJECT_ATTRIBUTES ObjectAttributes
,
2626 PLARGE_INTEGER UMaximumSize
,
2627 ULONG SectionPageProtection
,
2628 ULONG AllocationAttributes
,
2631 PSECTION_OBJECT Section
;
2633 PFILE_OBJECT FileObject
;
2634 IMAGE_DOS_HEADER DosHeader
;
2635 IO_STATUS_BLOCK Iosb
;
2636 LARGE_INTEGER Offset
;
2637 IMAGE_NT_HEADERS PEHeader
;
2638 PMM_SECTION_SEGMENT SectionSegments
;
2640 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
2643 ULONG Characteristics
;
2644 ULONG FileAccess
= 0;
2646 * Check the protection
2648 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
2649 SectionPageProtection
)
2651 return(STATUS_INVALID_PAGE_PROTECTION
);
2655 * Specifying a maximum size is meaningless for an image section
2657 if (UMaximumSize
!= NULL
)
2659 return(STATUS_INVALID_PARAMETER_4
);
2663 * Reference the file handle
2665 Status
= ObReferenceObjectByHandle(FileHandle
,
2669 (PVOID
*)&FileObject
,
2671 if (!NT_SUCCESS(Status
))
2677 * Initialized caching for this file object if previously caching
2678 * was initialized for the same on disk file
2680 Status
= CcTryToInitializeFileCache(FileObject
);
2682 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
2684 PIMAGE_SECTION_HEADER ImageSections
;
2686 * Read the dos header and check the DOS signature
2688 Offset
.QuadPart
= 0;
2689 Status
= ZwReadFile(FileHandle
,
2698 if (!NT_SUCCESS(Status
))
2700 ObDereferenceObject(FileObject
);
2705 * Check the DOS signature
2707 if (Iosb
.Information
!= sizeof(DosHeader
) ||
2708 DosHeader
.e_magic
!= IMAGE_DOS_SIGNATURE
)
2710 ObDereferenceObject(FileObject
);
2711 return(STATUS_INVALID_IMAGE_FORMAT
);
2715 * Read the PE header
2717 Offset
.QuadPart
= DosHeader
.e_lfanew
;
2718 Status
= ZwReadFile(FileHandle
,
2727 if (!NT_SUCCESS(Status
))
2729 ObDereferenceObject(FileObject
);
2734 * Check the signature
2736 if (Iosb
.Information
!= sizeof(PEHeader
) ||
2737 PEHeader
.Signature
!= IMAGE_NT_SIGNATURE
)
2739 ObDereferenceObject(FileObject
);
2740 return(STATUS_INVALID_IMAGE_FORMAT
);
2744 * Read in the section headers
2746 Offset
.QuadPart
= DosHeader
.e_lfanew
+ sizeof(PEHeader
);
2747 ImageSections
= ExAllocatePool(NonPagedPool
,
2748 PEHeader
.FileHeader
.NumberOfSections
*
2749 sizeof(IMAGE_SECTION_HEADER
));
2750 if (ImageSections
== NULL
)
2752 ObDereferenceObject(FileObject
);
2753 return(STATUS_NO_MEMORY
);
2756 Status
= ZwReadFile(FileHandle
,
2762 PEHeader
.FileHeader
.NumberOfSections
*
2763 sizeof(IMAGE_SECTION_HEADER
),
2766 if (!NT_SUCCESS(Status
))
2768 ObDereferenceObject(FileObject
);
2769 ExFreePool(ImageSections
);
2772 if (Iosb
.Information
!= (PEHeader
.FileHeader
.NumberOfSections
* sizeof(IMAGE_SECTION_HEADER
)))
2774 ObDereferenceObject(FileObject
);
2775 ExFreePool(ImageSections
);
2776 return(STATUS_INVALID_IMAGE_FORMAT
);
2780 * Create the section
2782 Status
= ObCreateObject (ExGetPreviousMode(),
2783 MmSectionObjectType
,
2785 ExGetPreviousMode(),
2787 sizeof(SECTION_OBJECT
),
2791 if (!NT_SUCCESS(Status
))
2793 ObDereferenceObject(FileObject
);
2794 ExFreePool(ImageSections
);
2798 Status
= ObInsertObject ((PVOID
)Section
,
2804 if (!NT_SUCCESS(Status
))
2806 ObDereferenceObject(Section
);
2807 ObDereferenceObject(FileObject
);
2808 ExFreePool(ImageSections
);
2815 Section
->SectionPageProtection
= SectionPageProtection
;
2816 Section
->AllocationAttributes
= AllocationAttributes
;
2817 InitializeListHead(&Section
->ViewListHead
);
2818 KeInitializeSpinLock(&Section
->ViewListLock
);
2821 * Check file access required
2823 if (SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
2825 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2829 FileAccess
= FILE_READ_DATA
;
2833 * We can't do memory mappings if the file system doesn't support the
2836 if (!(FileObject
->Flags
& FO_FCB_IS_VALID
))
2838 ZwClose(*SectionHandle
);
2839 ObDereferenceObject(Section
);
2840 ObDereferenceObject(FileObject
);
2841 ExFreePool(ImageSections
);
2842 return(STATUS_INVALID_FILE_FOR_SECTION
);
2848 Status
= MmspWaitForFileLock(FileObject
);
2849 if (Status
!= STATUS_SUCCESS
)
2851 ZwClose(*SectionHandle
);
2852 ObDereferenceObject(Section
);
2853 ObDereferenceObject(FileObject
);
2854 ExFreePool(ImageSections
);
2859 * allocate the section segments to describe the mapping
2861 NrSegments
= PEHeader
.FileHeader
.NumberOfSections
+ 1;
2862 Size
= sizeof(MM_IMAGE_SECTION_OBJECT
) + sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2863 ImageSectionObject
= ExAllocatePoolWithTag(NonPagedPool
, Size
, TAG_MM_SECTION_SEGMENT
);
2864 if (ImageSectionObject
== NULL
)
2866 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2867 ZwClose(*SectionHandle
);
2868 ObDereferenceObject(Section
);
2869 ObDereferenceObject(FileObject
);
2870 ExFreePool(ImageSections
);
2871 return(STATUS_NO_MEMORY
);
2873 Section
->ImageSection
= ImageSectionObject
;
2874 ImageSectionObject
->NrSegments
= NrSegments
;
2875 ImageSectionObject
->ImageBase
= (PVOID
)PEHeader
.OptionalHeader
.ImageBase
;
2876 ImageSectionObject
->EntryPoint
= (PVOID
)PEHeader
.OptionalHeader
.AddressOfEntryPoint
;
2877 ImageSectionObject
->StackReserve
= PEHeader
.OptionalHeader
.SizeOfStackReserve
;
2878 ImageSectionObject
->StackCommit
= PEHeader
.OptionalHeader
.SizeOfStackCommit
;
2879 ImageSectionObject
->Subsystem
= PEHeader
.OptionalHeader
.Subsystem
;
2880 ImageSectionObject
->MinorSubsystemVersion
= PEHeader
.OptionalHeader
.MinorSubsystemVersion
;
2881 ImageSectionObject
->MajorSubsystemVersion
= PEHeader
.OptionalHeader
.MajorSubsystemVersion
;
2882 ImageSectionObject
->ImageCharacteristics
= PEHeader
.FileHeader
.Characteristics
;
2883 ImageSectionObject
->Machine
= PEHeader
.FileHeader
.Machine
;
2884 ImageSectionObject
->Executable
= (PEHeader
.OptionalHeader
.SizeOfCode
!= 0);
2886 SectionSegments
= ImageSectionObject
->Segments
;
2887 SectionSegments
[0].FileOffset
= 0;
2888 SectionSegments
[0].Characteristics
= IMAGE_SECTION_CHAR_DATA
;
2889 SectionSegments
[0].Protection
= PAGE_READONLY
;
2890 SectionSegments
[0].RawLength
= PAGE_SIZE
;
2891 SectionSegments
[0].Length
= PAGE_SIZE
;
2892 SectionSegments
[0].Flags
= 0;
2893 SectionSegments
[0].ReferenceCount
= 1;
2894 SectionSegments
[0].VirtualAddress
= 0;
2895 SectionSegments
[0].WriteCopy
= TRUE
;
2896 SectionSegments
[0].Attributes
= 0;
2897 ExInitializeFastMutex(&SectionSegments
[0].Lock
);
2898 RtlZeroMemory(&SectionSegments
[0].PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2899 for (i
= 1; i
< NrSegments
; i
++)
2901 SectionSegments
[i
].FileOffset
= ImageSections
[i
-1].PointerToRawData
;
2902 SectionSegments
[i
].Characteristics
= ImageSections
[i
-1].Characteristics
;
2905 * Set up the protection and write copy variables.
2907 Characteristics
= ImageSections
[i
- 1].Characteristics
;
2908 if (Characteristics
& (IMAGE_SECTION_CHAR_READABLE
|IMAGE_SECTION_CHAR_WRITABLE
|IMAGE_SECTION_CHAR_EXECUTABLE
))
2910 SectionSegments
[i
].Protection
= SectionCharacteristicsToProtect
[Characteristics
>> 28];
2911 SectionSegments
[i
].WriteCopy
= !(Characteristics
& IMAGE_SECTION_CHAR_SHARED
);
2913 else if (Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2915 SectionSegments
[i
].Protection
= PAGE_EXECUTE_READ
;
2916 SectionSegments
[i
].WriteCopy
= TRUE
;
2918 else if (Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2920 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2921 SectionSegments
[i
].WriteCopy
= TRUE
;
2923 else if (Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2925 SectionSegments
[i
].Protection
= PAGE_READWRITE
;
2926 SectionSegments
[i
].WriteCopy
= TRUE
;
2930 SectionSegments
[i
].Protection
= PAGE_NOACCESS
;
2931 SectionSegments
[i
].WriteCopy
= TRUE
;
2935 * Set up the attributes.
2937 if (Characteristics
& IMAGE_SECTION_CHAR_CODE
)
2939 SectionSegments
[i
].Attributes
= 0;
2941 else if (Characteristics
& IMAGE_SECTION_CHAR_DATA
)
2943 SectionSegments
[i
].Attributes
= 0;
2945 else if (Characteristics
& IMAGE_SECTION_CHAR_BSS
)
2947 SectionSegments
[i
].Attributes
= MM_SECTION_SEGMENT_BSS
;
2951 SectionSegments
[i
].Attributes
= 0;
2954 SectionSegments
[i
].RawLength
= ImageSections
[i
-1].SizeOfRawData
;
2955 SectionSegments
[i
].Length
= ImageSections
[i
-1].Misc
.VirtualSize
;
2956 SectionSegments
[i
].Flags
= 0;
2957 SectionSegments
[i
].ReferenceCount
= 1;
2958 SectionSegments
[i
].VirtualAddress
= (PVOID
)ImageSections
[i
-1].VirtualAddress
;
2959 ExInitializeFastMutex(&SectionSegments
[i
].Lock
);
2960 RtlZeroMemory(&SectionSegments
[i
].PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2962 if (0 != InterlockedCompareExchange((PLONG
)&FileObject
->SectionObjectPointer
->ImageSectionObject
,
2963 (LONG
)ImageSectionObject
, 0))
2966 * An other thread has initialized the some image in the background
2968 ExFreePool(ImageSectionObject
);
2969 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
2970 Section
->ImageSection
= ImageSectionObject
;
2971 SectionSegments
= ImageSectionObject
->Segments
;
2973 for (i
= 0; i
< NrSegments
; i
++)
2975 InterlockedIncrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
2978 ExFreePool(ImageSections
);
2983 * Create the section
2985 Status
= ObCreateObject (ExGetPreviousMode(),
2986 MmSectionObjectType
,
2988 ExGetPreviousMode(),
2990 sizeof(SECTION_OBJECT
),
2994 if (!NT_SUCCESS(Status
))
2996 ObDereferenceObject(FileObject
);
3000 Status
= ObInsertObject ((PVOID
)Section
,
3006 if (!NT_SUCCESS(Status
))
3008 ObDereferenceObject(Section
);
3009 ObDereferenceObject(FileObject
);
3016 Section
->SectionPageProtection
= SectionPageProtection
;
3017 Section
->AllocationAttributes
= AllocationAttributes
;
3018 InitializeListHead(&Section
->ViewListHead
);
3019 KeInitializeSpinLock(&Section
->ViewListLock
);
3022 * Check file access required
3024 if (SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
))
3026 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3030 FileAccess
= FILE_READ_DATA
;
3036 Status
= MmspWaitForFileLock(FileObject
);
3037 if (Status
!= STATUS_SUCCESS
)
3039 ZwClose(*SectionHandle
);
3040 ObDereferenceObject(Section
);
3041 ObDereferenceObject(FileObject
);
3045 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3046 Section
->ImageSection
= ImageSectionObject
;
3047 SectionSegments
= ImageSectionObject
->Segments
;
3048 NrSegments
= ImageSectionObject
->NrSegments
;
3051 * Otherwise just reference all the section segments
3053 for (i
= 0; i
< NrSegments
; i
++)
3055 InterlockedIncrement((LONG
*)&SectionSegments
[i
].ReferenceCount
);
3059 Section
->FileObject
= FileObject
;
3060 CcRosReferenceCache(FileObject
);
3061 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
3062 ObDereferenceObject(Section
);
3063 return(STATUS_SUCCESS
);
3070 NtCreateSection (OUT PHANDLE SectionHandle
,
3071 IN ACCESS_MASK DesiredAccess
,
3072 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3073 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3074 IN ULONG SectionPageProtection OPTIONAL
,
3075 IN ULONG AllocationAttributes
,
3076 IN HANDLE FileHandle OPTIONAL
)
3078 if (AllocationAttributes
& SEC_IMAGE
)
3080 return(MmCreateImageSection(SectionHandle
,
3084 SectionPageProtection
,
3085 AllocationAttributes
,
3089 if (FileHandle
!= NULL
)
3091 return(MmCreateDataFileSection(SectionHandle
,
3095 SectionPageProtection
,
3096 AllocationAttributes
,
3100 return(MmCreatePageFileSection(SectionHandle
,
3104 SectionPageProtection
,
3105 AllocationAttributes
));
3109 /**********************************************************************
3127 NtOpenSection(PHANDLE SectionHandle
,
3128 ACCESS_MASK DesiredAccess
,
3129 POBJECT_ATTRIBUTES ObjectAttributes
)
3135 Status
= ObOpenObjectByName(ObjectAttributes
,
3136 MmSectionObjectType
,
3147 MmMapViewOfSegment(PEPROCESS Process
,
3148 PMADDRESS_SPACE AddressSpace
,
3149 PSECTION_OBJECT Section
,
3150 PMM_SECTION_SEGMENT Segment
,
3160 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3162 BoundaryAddressMultiple
.QuadPart
= 0;
3164 Status
= MmCreateMemoryArea(Process
,
3166 MEMORY_AREA_SECTION_VIEW
,
3173 BoundaryAddressMultiple
);
3174 if (!NT_SUCCESS(Status
))
3176 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed.\n",
3177 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
);
3181 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3182 InsertTailList(&Section
->ViewListHead
,
3183 &MArea
->Data
.SectionData
.ViewListEntry
);
3184 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3186 ObReferenceObjectByPointer((PVOID
)Section
,
3189 ExGetPreviousMode());
3190 MArea
->Data
.SectionData
.Segment
= Segment
;
3191 MArea
->Data
.SectionData
.Section
= Section
;
3192 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3193 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3194 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3195 ViewSize
, 0, Protect
);
3197 return(STATUS_SUCCESS
);
3201 /**********************************************************************
3203 * NtMapViewOfSection
3206 * Maps a view of a section into the virtual address space of a
3211 * Handle of the section.
3214 * Handle of the process.
3217 * Desired base address (or NULL) on entry;
3218 * Actual base address of the view on exit.
3221 * Number of high order address bits that must be zero.
3224 * Size in bytes of the initially committed section of
3228 * Offset in bytes from the beginning of the section
3229 * to the beginning of the view.
3232 * Desired length of map (or zero to map all) on entry
3233 * Actual length mapped on exit.
3235 * InheritDisposition
3236 * Specified how the view is to be shared with
3240 * Type of allocation for the pages.
3243 * Protection for the committed region of the view.
3251 NtMapViewOfSection(HANDLE SectionHandle
,
3252 HANDLE ProcessHandle
,
3256 PLARGE_INTEGER SectionOffset
,
3258 SECTION_INHERIT InheritDisposition
,
3259 ULONG AllocationType
,
3262 PSECTION_OBJECT Section
;
3265 PMADDRESS_SPACE AddressSpace
;
3267 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3268 PROCESS_VM_OPERATION
,
3273 if (!NT_SUCCESS(Status
))
3278 AddressSpace
= &Process
->AddressSpace
;
3280 Status
= ObReferenceObjectByHandle(SectionHandle
,
3282 MmSectionObjectType
,
3286 if (!(NT_SUCCESS(Status
)))
3288 DPRINT("ObReference failed rc=%x\n",Status
);
3289 ObDereferenceObject(Process
);
3293 Status
= MmMapViewOfSection(Section
,
3304 ObDereferenceObject(Section
);
3305 ObDereferenceObject(Process
);
3311 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3312 PHYSICAL_ADDRESS PhysAddr
, SWAPENTRY SwapEntry
,
3317 PFILE_OBJECT FileObject
;
3320 SWAPENTRY SavedSwapEntry
;
3323 PSECTION_OBJECT Section
;
3324 PMM_SECTION_SEGMENT Segment
;
3326 MArea
= (PMEMORY_AREA
)Context
;
3328 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3330 Offset
= ((ULONG
)Address
- (ULONG
)MArea
->BaseAddress
);
3332 Section
= MArea
->Data
.SectionData
.Section
;
3333 Segment
= MArea
->Data
.SectionData
.Segment
;
3336 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3340 MmUnlockSectionSegment(Segment
);
3341 MmUnlockAddressSpace(&MArea
->Process
->AddressSpace
);
3343 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3344 if (Status
!= STATUS_SUCCESS
)
3346 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3350 MmLockAddressSpace(&MArea
->Process
->AddressSpace
);
3351 MmLockSectionSegment(Segment
);
3352 MmspCompleteAndReleasePageOp(PageOp
);
3353 PageOp
= MmCheckForPageOp(MArea
, 0, NULL
, Segment
, Offset
);
3356 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3359 * For a dirty, datafile, non-private page mark it as dirty in the
3362 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3364 if (PhysAddr
.QuadPart
== PAGE_FROM_SSE(Entry
) && Dirty
)
3366 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3367 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3368 CcRosMarkDirtyCacheSegment(Bcb
, Offset
);
3369 assert(SwapEntry
== 0);
3378 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3380 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3383 MmFreeSwapPage(SwapEntry
);
3385 else if (PhysAddr
.QuadPart
!= 0)
3387 if (IS_SWAP_FROM_SSE(Entry
) ||
3388 PhysAddr
.QuadPart
!= (PAGE_FROM_SSE(Entry
)))
3393 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3395 DPRINT1("Found a private page in a pagefile section.\n");
3399 * Just dereference private pages
3401 SavedSwapEntry
= MmGetSavedSwapEntryPage(PhysAddr
);
3402 if (SavedSwapEntry
!= 0)
3404 MmFreeSwapPage(SavedSwapEntry
);
3405 MmSetSavedSwapEntryPage(PhysAddr
, 0);
3407 MmDeleteRmap(PhysAddr
, MArea
->Process
, Address
);
3408 MmReleasePageMemoryConsumer(MC_USER
, PhysAddr
);
3412 MmDeleteRmap(PhysAddr
, MArea
->Process
, Address
);
3413 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3419 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3423 PMEMORY_AREA MemoryArea
;
3424 PSECTION_OBJECT Section
;
3425 PMM_SECTION_SEGMENT Segment
;
3427 PLIST_ENTRY CurrentEntry
;
3428 PMM_REGION CurrentRegion
;
3429 PLIST_ENTRY RegionListHead
;
3431 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
3433 if (MemoryArea
== NULL
)
3435 return(STATUS_UNSUCCESSFUL
);
3438 MemoryArea
->DeleteInProgress
= TRUE
;
3439 Section
= MemoryArea
->Data
.SectionData
.Section
;
3440 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3442 MmLockSectionSegment(Segment
);
3443 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3444 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
3445 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3447 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3448 while (!IsListEmpty(RegionListHead
))
3450 CurrentEntry
= RemoveHeadList(RegionListHead
);
3451 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3452 ExFreePool(CurrentRegion
);
3455 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3457 Status
= MmFreeMemoryArea(AddressSpace
,
3465 Status
= MmFreeMemoryArea(AddressSpace
,
3471 MmUnlockSectionSegment(Segment
);
3472 ObDereferenceObject(Section
);
3473 return(STATUS_SUCCESS
);
3480 MmUnmapViewOfSection(PEPROCESS Process
,
3484 PMEMORY_AREA MemoryArea
;
3485 PMADDRESS_SPACE AddressSpace
;
3486 PSECTION_OBJECT Section
;
3488 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3489 Process
, BaseAddress
);
3493 AddressSpace
= &Process
->AddressSpace
;
3494 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
3496 if (MemoryArea
== NULL
)
3498 return(STATUS_UNSUCCESSFUL
);
3501 Section
= MemoryArea
->Data
.SectionData
.Section
;
3503 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3507 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3508 PMM_SECTION_SEGMENT SectionSegments
;
3509 PVOID ImageBaseAddress
= 0;
3510 PMM_SECTION_SEGMENT Segment
;
3512 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3513 ImageSectionObject
= Section
->ImageSection
;
3514 SectionSegments
= ImageSectionObject
->Segments
;
3515 NrSegments
= ImageSectionObject
->NrSegments
;
3517 /* Search for the current segment within the section segments
3518 * and calculate the image base address */
3519 for (i
= 0; i
< NrSegments
; i
++)
3521 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3523 if (Segment
== &SectionSegments
[i
])
3525 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3530 if (i
>= NrSegments
)
3535 for (i
= 0; i
< NrSegments
; i
++)
3537 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3539 PVOID SBaseAddress
= (PVOID
)
3540 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3542 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
3548 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
3550 return(STATUS_SUCCESS
);
3553 /**********************************************************************
3555 * NtUnmapViewOfSection
3570 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3576 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3577 ProcessHandle
, BaseAddress
);
3579 DPRINT("Referencing process\n");
3580 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3581 PROCESS_VM_OPERATION
,
3586 if (!NT_SUCCESS(Status
))
3588 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3592 MmLockAddressSpace(&Process
->AddressSpace
);
3593 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3594 MmUnlockAddressSpace(&Process
->AddressSpace
);
3596 ObDereferenceObject(Process
);
3603 NtQuerySection (IN HANDLE SectionHandle
,
3604 IN CINT SectionInformationClass
,
3605 OUT PVOID SectionInformation
,
3607 OUT PULONG ResultLength
)
3609 * FUNCTION: Queries the information of a section object.
3611 * SectionHandle = Handle to the section link object
3612 * SectionInformationClass = Index to a certain information structure
3613 * SectionInformation (OUT)= Caller supplies storage for resulting
3615 * Length = Size of the supplied storage
3616 * ResultLength = Data written
3621 PSECTION_OBJECT Section
;
3624 Status
= ObReferenceObjectByHandle(SectionHandle
,
3626 MmSectionObjectType
,
3630 if (!(NT_SUCCESS(Status
)))
3635 switch (SectionInformationClass
)
3637 case SectionBasicInformation
:
3639 PSECTION_BASIC_INFORMATION Sbi
;
3641 if (Length
!= sizeof(SECTION_BASIC_INFORMATION
))
3643 ObDereferenceObject(Section
);
3644 return(STATUS_INFO_LENGTH_MISMATCH
);
3647 Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
3649 Sbi
->BaseAddress
= 0;
3650 Sbi
->Attributes
= 0;
3651 Sbi
->Size
.QuadPart
= 0;
3653 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
3654 Status
= STATUS_SUCCESS
;
3658 case SectionImageInformation
:
3660 PSECTION_IMAGE_INFORMATION Sii
;
3662 if (Length
!= sizeof(SECTION_IMAGE_INFORMATION
))
3664 ObDereferenceObject(Section
);
3665 return(STATUS_INFO_LENGTH_MISMATCH
);
3668 Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
3669 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
3670 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3672 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3673 ImageSectionObject
= Section
->ImageSection
;
3675 Sii
->EntryPoint
= ImageSectionObject
->EntryPoint
;
3676 Sii
->StackReserve
= ImageSectionObject
->StackReserve
;
3677 Sii
->StackCommit
= ImageSectionObject
->StackCommit
;
3678 Sii
->Subsystem
= ImageSectionObject
->Subsystem
;
3679 Sii
->MinorSubsystemVersion
= (USHORT
)ImageSectionObject
->MinorSubsystemVersion
;
3680 Sii
->MajorSubsystemVersion
= (USHORT
)ImageSectionObject
->MajorSubsystemVersion
;
3681 Sii
->Characteristics
= ImageSectionObject
->ImageCharacteristics
;
3682 Sii
->ImageNumber
= ImageSectionObject
->Machine
;
3683 Sii
->Executable
= ImageSectionObject
->Executable
;
3685 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
3686 Status
= STATUS_SUCCESS
;
3692 Status
= STATUS_INVALID_INFO_CLASS
;
3694 ObDereferenceObject(Section
);
3700 NtExtendSection(IN HANDLE SectionHandle
,
3701 IN ULONG NewMaximumSize
)
3704 return(STATUS_NOT_IMPLEMENTED
);
3708 /**********************************************************************
3710 * MmAllocateSection@4
3720 * Code taken from ntoskrnl/mm/special.c.
3725 MmAllocateSection (IN ULONG Length
)
3731 PMADDRESS_SPACE AddressSpace
;
3732 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3734 DPRINT("MmAllocateSection(Length %x)\n",Length
);
3736 BoundaryAddressMultiple
.QuadPart
= 0;
3738 AddressSpace
= MmGetKernelAddressSpace();
3740 MmLockAddressSpace(AddressSpace
);
3741 Status
= MmCreateMemoryArea (NULL
,
3750 BoundaryAddressMultiple
);
3751 MmUnlockAddressSpace(AddressSpace
);
3753 if (!NT_SUCCESS(Status
))
3757 DPRINT("Result %p\n",Result
);
3758 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
3760 PHYSICAL_ADDRESS Page
;
3762 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
3763 if (!NT_SUCCESS(Status
))
3765 DbgPrint("Unable to allocate page\n");
3768 Status
= MmCreateVirtualMapping (NULL
,
3769 ((char*)Result
+ (i
* PAGE_SIZE
)),
3773 if (!NT_SUCCESS(Status
))
3775 DbgPrint("Unable to create virtual mapping\n");
3779 return ((PVOID
)Result
);
3783 /**********************************************************************
3785 * MmMapViewOfSection
3788 * Maps a view of a section into the virtual address space of a
3793 * Pointer to the section object.
3796 * Pointer to the process.
3799 * Desired base address (or NULL) on entry;
3800 * Actual base address of the view on exit.
3803 * Number of high order address bits that must be zero.
3806 * Size in bytes of the initially committed section of
3810 * Offset in bytes from the beginning of the section
3811 * to the beginning of the view.
3814 * Desired length of map (or zero to map all) on entry
3815 * Actual length mapped on exit.
3817 * InheritDisposition
3818 * Specified how the view is to be shared with
3822 * Type of allocation for the pages.
3825 * Protection for the committed region of the view.
3833 MmMapViewOfSection(IN PVOID SectionObject
,
3834 IN PEPROCESS Process
,
3835 IN OUT PVOID
*BaseAddress
,
3837 IN ULONG CommitSize
,
3838 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3839 IN OUT PULONG ViewSize
,
3840 IN SECTION_INHERIT InheritDisposition
,
3841 IN ULONG AllocationType
,
3844 PSECTION_OBJECT Section
;
3845 PMADDRESS_SPACE AddressSpace
;
3847 NTSTATUS Status
= STATUS_SUCCESS
;
3851 Section
= (PSECTION_OBJECT
)SectionObject
;
3852 AddressSpace
= &Process
->AddressSpace
;
3854 MmLockAddressSpace(AddressSpace
);
3856 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3862 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3863 PMM_SECTION_SEGMENT SectionSegments
;
3865 ImageSectionObject
= Section
->ImageSection
;
3866 SectionSegments
= ImageSectionObject
->Segments
;
3867 NrSegments
= ImageSectionObject
->NrSegments
;
3870 ImageBase
= *BaseAddress
;
3871 if (ImageBase
== NULL
)
3873 ImageBase
= ImageSectionObject
->ImageBase
;
3877 for (i
= 0; i
< NrSegments
; i
++)
3879 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3882 MaxExtent
= (ULONG
)((char*)SectionSegments
[i
].VirtualAddress
+
3883 SectionSegments
[i
].Length
);
3884 ImageSize
= max(ImageSize
, MaxExtent
);
3888 /* Check there is enough space to map the section at that point. */
3889 if (MmOpenMemoryAreaByRegion(AddressSpace
, ImageBase
,
3890 PAGE_ROUND_UP(ImageSize
)) != NULL
)
3892 /* Fail if the user requested a fixed base address. */
3893 if ((*BaseAddress
) != NULL
)
3895 MmUnlockAddressSpace(AddressSpace
);
3896 return(STATUS_UNSUCCESSFUL
);
3898 /* Otherwise find a gap to map the image. */
3899 ImageBase
= MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), FALSE
);
3900 if (ImageBase
== NULL
)
3902 MmUnlockAddressSpace(AddressSpace
);
3903 return(STATUS_UNSUCCESSFUL
);
3907 for (i
= 0; i
< NrSegments
; i
++)
3909 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SECTION_NOLOAD
))
3911 PVOID SBaseAddress
= (PVOID
)
3912 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3913 MmLockSectionSegment(&SectionSegments
[i
]);
3914 Status
= MmMapViewOfSegment(Process
,
3917 &SectionSegments
[i
],
3919 SectionSegments
[i
].Length
,
3920 SectionSegments
[i
].Protection
,
3921 (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
,
3923 MmUnlockSectionSegment(&SectionSegments
[i
]);
3924 if (!NT_SUCCESS(Status
))
3926 MmUnlockAddressSpace(AddressSpace
);
3932 *BaseAddress
= ImageBase
;
3936 if (ViewSize
== NULL
)
3938 /* Following this pointer would lead to us to the dark side */
3939 /* What to do? Bugcheck? Return status? Do the mambo? */
3940 KEBUGCHECK(MEMORY_MANAGEMENT
);
3943 if (SectionOffset
== NULL
)
3949 ViewOffset
= SectionOffset
->u
.LowPart
;
3952 if ((ViewOffset
% PAGE_SIZE
) != 0)
3954 MmUnlockAddressSpace(AddressSpace
);
3955 return(STATUS_MAPPED_ALIGNMENT
);
3958 if ((*ViewSize
) == 0)
3960 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
3962 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
3964 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
3967 MmLockSectionSegment(Section
->Segment
);
3968 Status
= MmMapViewOfSegment(Process
,
3976 (AllocationType
& MEM_TOP_DOWN
));
3977 MmUnlockSectionSegment(Section
->Segment
);
3978 if (!NT_SUCCESS(Status
))
3980 MmUnlockAddressSpace(AddressSpace
);
3985 MmUnlockAddressSpace(AddressSpace
);
3987 return(STATUS_SUCCESS
);
3994 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
3995 IN PLARGE_INTEGER NewFileSize
)
4006 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
4016 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4017 IN MMFLUSH_TYPE FlushType
)
4021 case MmFlushForDelete
:
4022 if (SectionObjectPointer
->ImageSectionObject
||
4023 SectionObjectPointer
->DataSectionObject
)
4027 CcRosSetRemoveOnClose(SectionObjectPointer
);
4029 case MmFlushForWrite
:
4039 MmForceSectionClosed (DWORD Unknown0
,
4051 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4052 OUT PVOID
* MappedBase
,
4053 IN OUT PULONG ViewSize
)
4055 PSECTION_OBJECT Section
;
4056 PMADDRESS_SPACE AddressSpace
;
4059 DPRINT("MmMapViewInSystemSpace() called\n");
4061 Section
= (PSECTION_OBJECT
)SectionObject
;
4062 AddressSpace
= MmGetKernelAddressSpace();
4064 MmLockAddressSpace(AddressSpace
);
4067 if ((*ViewSize
) == 0)
4069 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4071 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4073 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4076 MmLockSectionSegment(Section
->Segment
);
4079 Status
= MmMapViewOfSegment(NULL
,
4089 MmUnlockSectionSegment(Section
->Segment
);
4090 MmUnlockAddressSpace(AddressSpace
);
4100 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4102 PMADDRESS_SPACE AddressSpace
;
4105 DPRINT("MmUnmapViewInSystemSpace() called\n");
4107 AddressSpace
= MmGetKernelAddressSpace();
4109 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4119 MmSetBankedSection (DWORD Unknown0
,
4127 return (STATUS_NOT_IMPLEMENTED
);
4131 /**********************************************************************
4136 * Creates a section object.
4139 * SectionObjiect (OUT)
4140 * Caller supplied storage for the resulting pointer
4141 * to a SECTION_OBJECT instance;
4144 * Specifies the desired access to the section can be a
4146 * STANDARD_RIGHTS_REQUIRED |
4148 * SECTION_MAP_WRITE |
4149 * SECTION_MAP_READ |
4150 * SECTION_MAP_EXECUTE
4152 * ObjectAttributes [OPTIONAL]
4153 * Initialized attributes for the object can be used
4154 * to create a named section;
4157 * Maximizes the size of the memory section. Must be
4158 * non-NULL for a page-file backed section.
4159 * If value specified for a mapped file and the file is
4160 * not large enough, file will be extended.
4162 * SectionPageProtection
4163 * Can be a combination of:
4169 * AllocationAttributes
4170 * Can be a combination of:
4175 * Handle to a file to create a section mapped to a file
4176 * instead of a memory backed section;
4187 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4188 IN ACCESS_MASK DesiredAccess
,
4189 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4190 IN PLARGE_INTEGER MaximumSize
,
4191 IN ULONG SectionPageProtection
,
4192 IN ULONG AllocationAttributes
,
4193 IN HANDLE FileHandle OPTIONAL
,
4194 IN PFILE_OBJECT File OPTIONAL
)
4196 return (STATUS_NOT_IMPLEMENTED
);