2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
50 #include <reactos/exeformat.h>
51 #include "ARM3/miarm.h"
53 #if defined (ALLOC_PRAGMA)
54 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
55 #pragma alloc_text(INIT, MmInitSectionImplementation)
59 /* TYPES *********************************************************************/
63 PROS_SECTION_OBJECT Section
;
64 PMM_SECTION_SEGMENT Segment
;
69 MM_SECTION_PAGEOUT_CONTEXT
;
71 /* GLOBALS *******************************************************************/
73 POBJECT_TYPE MmSectionObjectType
= NULL
;
75 ULONG_PTR MmSubsectionBase
;
77 static GENERIC_MAPPING MmpSectionMapping
= {
78 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
79 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
80 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
83 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
84 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
85 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
86 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
87 #define MAX_SHARE_COUNT 0x7FF
88 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
89 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
90 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
92 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
94 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
95 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
98 /* FUNCTIONS *****************************************************************/
102 MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section
)
107 /* Return the file object */
108 return Section
->FileObject
; // Section->ControlArea->FileObject on NT
113 MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section
,
114 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
116 POBJECT_NAME_INFORMATION ObjectNameInfo
;
120 /* Make sure it's an image section */
122 if (!(Section
->AllocationAttributes
& SEC_IMAGE
))
125 return STATUS_SECTION_NOT_IMAGE
;
128 /* Allocate memory for our structure */
129 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
,
132 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
135 Status
= ObQueryNameString(Section
->FileObject
,
139 if (!NT_SUCCESS(Status
))
141 /* Failed, free memory */
142 ExFreePoolWithTag(ObjectNameInfo
, ' mM');
147 *ModuleName
= ObjectNameInfo
;
148 return STATUS_SUCCESS
;
153 MmGetFileNameForAddress(IN PVOID Address
,
154 OUT PUNICODE_STRING ModuleName
)
156 PROS_SECTION_OBJECT Section
;
157 PMEMORY_AREA MemoryArea
;
158 PMMSUPPORT AddressSpace
;
159 POBJECT_NAME_INFORMATION ModuleNameInformation
;
160 NTSTATUS Status
= STATUS_ADDRESS_NOT_ASSOCIATED
;
162 /* Get the MM_AVL_TABLE from EPROCESS */
163 if (Address
>= MmSystemRangeStart
)
165 AddressSpace
= MmGetKernelAddressSpace();
169 AddressSpace
= &PsGetCurrentProcess()->Vm
;
172 /* Lock address space */
173 MmLockAddressSpace(AddressSpace
);
175 /* Locate the memory area for the process by address */
176 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
178 /* Make sure it's a section view type */
179 if ((MemoryArea
!= NULL
) && (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
))
181 /* Get the section pointer to the SECTION_OBJECT */
182 Section
= MemoryArea
->Data
.SectionData
.Section
;
184 /* Unlock address space */
185 MmUnlockAddressSpace(AddressSpace
);
187 /* Get the filename of the section */
188 Status
= MmGetFileNameForSection(Section
,&ModuleNameInformation
);
190 if (NT_SUCCESS(Status
))
192 /* Init modulename */
193 RtlCreateUnicodeString(ModuleName
,
194 ModuleNameInformation
->Name
.Buffer
);
196 /* Free temp taged buffer from MmGetFileNameForSection() */
197 ExFreePoolWithTag(ModuleNameInformation
, ' mM');
198 DPRINT("Found ModuleName %S by address %p\n",
199 ModuleName
->Buffer
,Address
);
204 /* Unlock address space */
205 MmUnlockAddressSpace(AddressSpace
);
211 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
214 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
215 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
216 * RETURNS: Status of the wait.
219 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
221 LARGE_INTEGER Timeout
;
222 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
224 Timeout
.QuadPart
= -100000000LL; // 10 sec
227 Timeout
.QuadPart
= -100000000; // 10 sec
230 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
235 * FUNCTION: Sets the page op completion event and releases the page op.
236 * ARGUMENTS: PMM_PAGEOP.
237 * RETURNS: In shorter time than it takes you to even read this
238 * description, so don't even think about geting a mug of coffee.
241 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
243 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
244 MmReleasePageOp(PageOp
);
249 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
250 * ARGUMENTS: PFILE_OBJECT to wait for.
251 * RETURNS: Status of the wait.
254 MmspWaitForFileLock(PFILE_OBJECT File
)
256 return STATUS_SUCCESS
;
257 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
262 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
265 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
267 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
269 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
271 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
279 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
281 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
283 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
284 PMM_SECTION_SEGMENT SectionSegments
;
288 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
289 NrSegments
= ImageSectionObject
->NrSegments
;
290 SectionSegments
= ImageSectionObject
->Segments
;
291 for (i
= 0; i
< NrSegments
; i
++)
293 if (SectionSegments
[i
].ReferenceCount
!= 0)
295 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
296 SectionSegments
[i
].ReferenceCount
);
297 KeBugCheck(MEMORY_MANAGEMENT
);
299 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
301 ExFreePool(ImageSectionObject
->Segments
);
302 ExFreePool(ImageSectionObject
);
303 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
305 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
307 PMM_SECTION_SEGMENT Segment
;
309 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
312 if (Segment
->ReferenceCount
!= 0)
314 DPRINT1("Data segment still referenced\n");
315 KeBugCheck(MEMORY_MANAGEMENT
);
317 MmFreePageTablesSectionSegment(Segment
);
319 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
325 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
327 ExAcquireFastMutex(&Segment
->Lock
);
332 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
334 ExReleaseFastMutex(&Segment
->Lock
);
339 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
343 PSECTION_PAGE_TABLE Table
;
344 ULONG DirectoryOffset
;
347 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
349 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
353 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
354 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
358 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
359 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
360 TAG_SECTION_PAGE_TABLE
);
363 KeBugCheck(MEMORY_MANAGEMENT
);
365 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
366 DPRINT("Table %x\n", Table
);
369 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
370 Table
->Entry
[TableOffset
] = Entry
;
376 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
379 PSECTION_PAGE_TABLE Table
;
381 ULONG DirectoryOffset
;
384 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
386 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
388 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
392 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
393 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
394 DPRINT("Table %x\n", Table
);
400 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
401 Entry
= Table
->Entry
[TableOffset
];
407 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
412 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
415 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
416 KeBugCheck(MEMORY_MANAGEMENT
);
418 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
420 DPRINT1("Maximum share count reached\n");
421 KeBugCheck(MEMORY_MANAGEMENT
);
423 if (IS_SWAP_FROM_SSE(Entry
))
425 KeBugCheck(MEMORY_MANAGEMENT
);
427 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
428 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
433 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
434 PMM_SECTION_SEGMENT Segment
,
440 BOOLEAN IsDirectMapped
= FALSE
;
442 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
445 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
446 KeBugCheck(MEMORY_MANAGEMENT
);
448 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
450 DPRINT1("Zero share count for unshare\n");
451 KeBugCheck(MEMORY_MANAGEMENT
);
453 if (IS_SWAP_FROM_SSE(Entry
))
455 KeBugCheck(MEMORY_MANAGEMENT
);
457 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
459 * If we reducing the share count of this entry to zero then set the entry
460 * to zero and tell the cache the page is no longer mapped.
462 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
464 PFILE_OBJECT FileObject
;
466 SWAPENTRY SavedSwapEntry
;
468 BOOLEAN IsImageSection
;
471 FileOffset
= Offset
+ Segment
->FileOffset
;
473 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
475 Page
= PFN_FROM_SSE(Entry
);
476 FileObject
= Section
->FileObject
;
477 if (FileObject
!= NULL
&&
478 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
481 if ((FileOffset
% PAGE_SIZE
) == 0 &&
482 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
485 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
486 IsDirectMapped
= TRUE
;
487 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
488 if (!NT_SUCCESS(Status
))
490 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
491 KeBugCheck(MEMORY_MANAGEMENT
);
496 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
497 if (SavedSwapEntry
== 0)
500 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
501 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
505 * Try to page out this page and set the swap entry
506 * within the section segment. There exist no rmap entry
507 * for this page. The pager thread can't page out a
508 * page without a rmap entry.
510 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
514 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
517 MmReleasePageMemoryConsumer(MC_USER
, Page
);
523 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
524 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
532 * We hold all locks. Nobody can do something with the current
533 * process and the current segment (also not within an other process).
536 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
537 if (!NT_SUCCESS(Status
))
539 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
540 KeBugCheck(MEMORY_MANAGEMENT
);
543 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
544 MmSetSavedSwapEntryPage(Page
, 0);
546 MmReleasePageMemoryConsumer(MC_USER
, Page
);
550 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
551 KeBugCheck(MEMORY_MANAGEMENT
);
557 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
559 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
562 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
565 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
568 PCACHE_SEGMENT CacheSeg
;
569 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
570 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
573 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
582 MiCopyFromUserPage(PFN_NUMBER DestPage
, PVOID SourceAddress
)
588 Process
= PsGetCurrentProcess();
589 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
590 if (TempAddress
== NULL
)
592 return(STATUS_NO_MEMORY
);
594 memcpy(TempAddress
, SourceAddress
, PAGE_SIZE
);
595 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
596 return(STATUS_SUCCESS
);
601 MiReadPage(PMEMORY_AREA MemoryArea
,
605 * FUNCTION: Read a page for a section backed memory area.
607 * MemoryArea - Memory area to read the page for.
608 * Offset - Offset of the page to read.
609 * Page - Variable that receives a page contains the read data.
616 PCACHE_SEGMENT CacheSeg
;
617 PFILE_OBJECT FileObject
;
621 BOOLEAN IsImageSection
;
624 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
625 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
626 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
627 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
628 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
632 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
635 * If the file system is letting us go directly to the cache and the
636 * memory area was mapped at an offset in the file which is page aligned
637 * then get the related cache segment.
639 if ((FileOffset
% PAGE_SIZE
) == 0 &&
640 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
641 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
645 * Get the related cache segment; we use a lower level interface than
646 * filesystems do because it is safe for us to use an offset with a
647 * alignment less than the file system block size.
649 Status
= CcRosGetCacheSegment(Bcb
,
655 if (!NT_SUCCESS(Status
))
662 * If the cache segment isn't up to date then call the file
663 * system to read in the data.
665 Status
= ReadCacheSegment(CacheSeg
);
666 if (!NT_SUCCESS(Status
))
668 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
673 * Retrieve the page from the cache segment that we actually want.
675 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
676 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
678 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
685 ULONG CacheSegOffset
;
688 * Allocate a page, this is rather complicated by the possibility
689 * we might have to move other things out of memory
691 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
692 if (!NT_SUCCESS(Status
))
696 Status
= CcRosGetCacheSegment(Bcb
,
702 if (!NT_SUCCESS(Status
))
709 * If the cache segment isn't up to date then call the file
710 * system to read in the data.
712 Status
= ReadCacheSegment(CacheSeg
);
713 if (!NT_SUCCESS(Status
))
715 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
720 Process
= PsGetCurrentProcess();
721 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
722 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
723 Length
= RawLength
- SegOffset
;
724 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
726 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
728 else if (CacheSegOffset
>= PAGE_SIZE
)
730 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
734 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
735 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
736 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
737 Status
= CcRosGetCacheSegment(Bcb
,
738 FileOffset
+ CacheSegOffset
,
743 if (!NT_SUCCESS(Status
))
750 * If the cache segment isn't up to date then call the file
751 * system to read in the data.
753 Status
= ReadCacheSegment(CacheSeg
);
754 if (!NT_SUCCESS(Status
))
756 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
760 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
761 if (Length
< PAGE_SIZE
)
763 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
767 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
770 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
771 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
773 return(STATUS_SUCCESS
);
778 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
779 MEMORY_AREA
* MemoryArea
,
787 PROS_SECTION_OBJECT Section
;
788 PMM_SECTION_SEGMENT Segment
;
794 BOOLEAN HasSwapEntry
;
795 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
798 * There is a window between taking the page fault and locking the
799 * address space when another thread could load the page so we check
802 if (MmIsPagePresent(Process
, Address
))
804 return(STATUS_SUCCESS
);
807 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
808 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
809 + MemoryArea
->Data
.SectionData
.ViewOffset
;
811 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
812 Section
= MemoryArea
->Data
.SectionData
.Section
;
813 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
814 &MemoryArea
->Data
.SectionData
.RegionListHead
,
819 MmLockSectionSegment(Segment
);
822 * Check if this page needs to be mapped COW
824 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
825 (Region
->Protect
== PAGE_READWRITE
||
826 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
828 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
832 Attributes
= Region
->Protect
;
836 * Get or create a page operation descriptor
838 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
841 DPRINT1("MmGetPageOp failed\n");
842 KeBugCheck(MEMORY_MANAGEMENT
);
846 * Check if someone else is already handling this fault, if so wait
849 if (PageOp
->Thread
!= PsGetCurrentThread())
851 MmUnlockSectionSegment(Segment
);
852 MmUnlockAddressSpace(AddressSpace
);
853 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
855 * Check for various strange conditions
857 if (Status
!= STATUS_SUCCESS
)
859 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
860 KeBugCheck(MEMORY_MANAGEMENT
);
862 if (PageOp
->Status
== STATUS_PENDING
)
864 DPRINT1("Woke for page op before completion\n");
865 KeBugCheck(MEMORY_MANAGEMENT
);
867 MmLockAddressSpace(AddressSpace
);
869 * If this wasn't a pagein then restart the operation
871 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
873 MmspCompleteAndReleasePageOp(PageOp
);
874 DPRINT("Address 0x%.8X\n", Address
);
875 return(STATUS_MM_RESTART_OPERATION
);
879 * If the thread handling this fault has failed then we don't retry
881 if (!NT_SUCCESS(PageOp
->Status
))
883 Status
= PageOp
->Status
;
884 MmspCompleteAndReleasePageOp(PageOp
);
885 DPRINT("Address 0x%.8X\n", Address
);
888 MmLockSectionSegment(Segment
);
890 * If the completed fault was for another address space then set the
893 if (!MmIsPagePresent(Process
, Address
))
895 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
896 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
898 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
901 * The page was a private page in another or in our address space
903 MmUnlockSectionSegment(Segment
);
904 MmspCompleteAndReleasePageOp(PageOp
);
905 return(STATUS_MM_RESTART_OPERATION
);
908 Page
= PFN_FROM_SSE(Entry
);
910 MmSharePageEntrySectionSegment(Segment
, Offset
);
912 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
913 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
915 Status
= MmCreateVirtualMapping(Process
,
920 if (!NT_SUCCESS(Status
))
922 DPRINT1("Unable to create virtual mapping\n");
923 KeBugCheck(MEMORY_MANAGEMENT
);
925 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
927 MmUnlockSectionSegment(Segment
);
928 PageOp
->Status
= STATUS_SUCCESS
;
929 MmspCompleteAndReleasePageOp(PageOp
);
930 DPRINT("Address 0x%.8X\n", Address
);
931 return(STATUS_SUCCESS
);
934 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
938 * Must be private page we have swapped out.
945 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
947 DPRINT1("Found a swaped out private page in a pagefile section.\n");
948 KeBugCheck(MEMORY_MANAGEMENT
);
951 MmUnlockSectionSegment(Segment
);
952 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
954 MmUnlockAddressSpace(AddressSpace
);
955 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
956 if (!NT_SUCCESS(Status
))
958 KeBugCheck(MEMORY_MANAGEMENT
);
961 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
962 if (!NT_SUCCESS(Status
))
964 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
965 KeBugCheck(MEMORY_MANAGEMENT
);
967 MmLockAddressSpace(AddressSpace
);
968 Status
= MmCreateVirtualMapping(Process
,
973 if (!NT_SUCCESS(Status
))
975 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
976 KeBugCheck(MEMORY_MANAGEMENT
);
981 * Store the swap entry for later use.
983 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
986 * Add the page to the process's working set
988 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
991 * Finish the operation
993 PageOp
->Status
= STATUS_SUCCESS
;
994 MmspCompleteAndReleasePageOp(PageOp
);
995 DPRINT("Address 0x%.8X\n", Address
);
996 return(STATUS_SUCCESS
);
1000 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1002 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1004 MmUnlockSectionSegment(Segment
);
1006 * Just map the desired physical page
1008 Page
= Offset
>> PAGE_SHIFT
;
1009 Status
= MmCreateVirtualMappingUnsafe(Process
,
1014 if (!NT_SUCCESS(Status
))
1016 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1017 KeBugCheck(MEMORY_MANAGEMENT
);
1022 * Cleanup and release locks
1024 PageOp
->Status
= STATUS_SUCCESS
;
1025 MmspCompleteAndReleasePageOp(PageOp
);
1026 DPRINT("Address 0x%.8X\n", Address
);
1027 return(STATUS_SUCCESS
);
1031 * Map anonymous memory for BSS sections
1033 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1035 MmUnlockSectionSegment(Segment
);
1036 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1037 if (!NT_SUCCESS(Status
))
1039 MmUnlockAddressSpace(AddressSpace
);
1040 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1041 MmLockAddressSpace(AddressSpace
);
1043 if (!NT_SUCCESS(Status
))
1045 KeBugCheck(MEMORY_MANAGEMENT
);
1047 Status
= MmCreateVirtualMapping(Process
,
1052 if (!NT_SUCCESS(Status
))
1054 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1055 KeBugCheck(MEMORY_MANAGEMENT
);
1058 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1061 * Cleanup and release locks
1063 PageOp
->Status
= STATUS_SUCCESS
;
1064 MmspCompleteAndReleasePageOp(PageOp
);
1065 DPRINT("Address 0x%.8X\n", Address
);
1066 return(STATUS_SUCCESS
);
1070 * Get the entry corresponding to the offset within the section
1072 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1077 * If the entry is zero (and it can't change because we have
1078 * locked the segment) then we need to load the page.
1082 * Release all our locks and read in the page from disk
1084 MmUnlockSectionSegment(Segment
);
1085 MmUnlockAddressSpace(AddressSpace
);
1087 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1088 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1090 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1091 if (!NT_SUCCESS(Status
))
1093 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1098 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1099 if (!NT_SUCCESS(Status
))
1101 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1104 if (!NT_SUCCESS(Status
))
1107 * FIXME: What do we know in this case?
1110 * Cleanup and release locks
1112 MmLockAddressSpace(AddressSpace
);
1113 PageOp
->Status
= Status
;
1114 MmspCompleteAndReleasePageOp(PageOp
);
1115 DPRINT("Address 0x%.8X\n", Address
);
1119 * Relock the address space and segment
1121 MmLockAddressSpace(AddressSpace
);
1122 MmLockSectionSegment(Segment
);
1125 * Check the entry. No one should change the status of a page
1126 * that has a pending page-in.
1128 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1129 if (Entry
!= Entry1
)
1131 DPRINT1("Someone changed ppte entry while we slept\n");
1132 KeBugCheck(MEMORY_MANAGEMENT
);
1136 * Mark the offset within the section as having valid, in-memory
1139 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1140 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1141 MmUnlockSectionSegment(Segment
);
1143 Status
= MmCreateVirtualMapping(Process
,
1148 if (!NT_SUCCESS(Status
))
1150 DPRINT1("Unable to create virtual mapping\n");
1151 KeBugCheck(MEMORY_MANAGEMENT
);
1153 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1155 PageOp
->Status
= STATUS_SUCCESS
;
1156 MmspCompleteAndReleasePageOp(PageOp
);
1157 DPRINT("Address 0x%.8X\n", Address
);
1158 return(STATUS_SUCCESS
);
1160 else if (IS_SWAP_FROM_SSE(Entry
))
1162 SWAPENTRY SwapEntry
;
1164 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1167 * Release all our locks and read in the page from disk
1169 MmUnlockSectionSegment(Segment
);
1171 MmUnlockAddressSpace(AddressSpace
);
1173 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1174 if (!NT_SUCCESS(Status
))
1176 KeBugCheck(MEMORY_MANAGEMENT
);
1179 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1180 if (!NT_SUCCESS(Status
))
1182 KeBugCheck(MEMORY_MANAGEMENT
);
1186 * Relock the address space and segment
1188 MmLockAddressSpace(AddressSpace
);
1189 MmLockSectionSegment(Segment
);
1192 * Check the entry. No one should change the status of a page
1193 * that has a pending page-in.
1195 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1196 if (Entry
!= Entry1
)
1198 DPRINT1("Someone changed ppte entry while we slept\n");
1199 KeBugCheck(MEMORY_MANAGEMENT
);
1203 * Mark the offset within the section as having valid, in-memory
1206 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1207 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1208 MmUnlockSectionSegment(Segment
);
1211 * Save the swap entry.
1213 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1214 Status
= MmCreateVirtualMapping(Process
,
1219 if (!NT_SUCCESS(Status
))
1221 DPRINT1("Unable to create virtual mapping\n");
1222 KeBugCheck(MEMORY_MANAGEMENT
);
1224 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1225 PageOp
->Status
= STATUS_SUCCESS
;
1226 MmspCompleteAndReleasePageOp(PageOp
);
1227 DPRINT("Address 0x%.8X\n", Address
);
1228 return(STATUS_SUCCESS
);
1233 * If the section offset is already in-memory and valid then just
1234 * take another reference to the page
1237 Page
= PFN_FROM_SSE(Entry
);
1239 MmSharePageEntrySectionSegment(Segment
, Offset
);
1240 MmUnlockSectionSegment(Segment
);
1242 Status
= MmCreateVirtualMapping(Process
,
1247 if (!NT_SUCCESS(Status
))
1249 DPRINT1("Unable to create virtual mapping\n");
1250 KeBugCheck(MEMORY_MANAGEMENT
);
1252 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1253 PageOp
->Status
= STATUS_SUCCESS
;
1254 MmspCompleteAndReleasePageOp(PageOp
);
1255 DPRINT("Address 0x%.8X\n", Address
);
1256 return(STATUS_SUCCESS
);
1262 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1263 MEMORY_AREA
* MemoryArea
,
1267 PMM_SECTION_SEGMENT Segment
;
1268 PROS_SECTION_OBJECT Section
;
1277 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1279 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1282 * Check if the page has been paged out or has already been set readwrite
1284 if (!MmIsPagePresent(Process
, Address
) ||
1285 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1287 DPRINT("Address 0x%.8X\n", Address
);
1288 return(STATUS_SUCCESS
);
1292 * Find the offset of the page
1294 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1295 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1296 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1298 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1299 Section
= MemoryArea
->Data
.SectionData
.Section
;
1300 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1301 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1306 MmLockSectionSegment(Segment
);
1308 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1309 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1311 MmUnlockSectionSegment(Segment
);
1314 * Check if we are doing COW
1316 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1317 (Region
->Protect
== PAGE_READWRITE
||
1318 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1320 DPRINT("Address 0x%.8X\n", Address
);
1321 return(STATUS_ACCESS_VIOLATION
);
1324 if (IS_SWAP_FROM_SSE(Entry
) ||
1325 PFN_FROM_SSE(Entry
) != OldPage
)
1327 /* This is a private page. We must only change the page protection. */
1328 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1329 return(STATUS_SUCCESS
);
1333 * Get or create a pageop
1335 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1336 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1339 DPRINT1("MmGetPageOp failed\n");
1340 KeBugCheck(MEMORY_MANAGEMENT
);
1344 * Wait for any other operations to complete
1346 if (PageOp
->Thread
!= PsGetCurrentThread())
1348 MmUnlockAddressSpace(AddressSpace
);
1349 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1351 * Check for various strange conditions
1353 if (Status
== STATUS_TIMEOUT
)
1355 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1356 KeBugCheck(MEMORY_MANAGEMENT
);
1358 if (PageOp
->Status
== STATUS_PENDING
)
1360 DPRINT1("Woke for page op before completion\n");
1361 KeBugCheck(MEMORY_MANAGEMENT
);
1364 * Restart the operation
1366 MmLockAddressSpace(AddressSpace
);
1367 MmspCompleteAndReleasePageOp(PageOp
);
1368 DPRINT("Address 0x%.8X\n", Address
);
1369 return(STATUS_MM_RESTART_OPERATION
);
1373 * Release locks now we have the pageop
1375 MmUnlockAddressSpace(AddressSpace
);
1380 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1381 if (!NT_SUCCESS(Status
))
1383 KeBugCheck(MEMORY_MANAGEMENT
);
1389 MiCopyFromUserPage(NewPage
, PAddress
);
1391 MmLockAddressSpace(AddressSpace
);
1393 * Delete the old entry.
1395 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1398 * Set the PTE to point to the new page
1400 Status
= MmCreateVirtualMapping(Process
,
1405 if (!NT_SUCCESS(Status
))
1407 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1408 KeBugCheck(MEMORY_MANAGEMENT
);
1411 if (!NT_SUCCESS(Status
))
1413 DPRINT1("Unable to create virtual mapping\n");
1414 KeBugCheck(MEMORY_MANAGEMENT
);
1418 * Unshare the old page.
1420 MmDeleteRmap(OldPage
, Process
, PAddress
);
1421 MmInsertRmap(NewPage
, Process
, PAddress
);
1422 MmLockSectionSegment(Segment
);
1423 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1424 MmUnlockSectionSegment(Segment
);
1426 PageOp
->Status
= STATUS_SUCCESS
;
1427 MmspCompleteAndReleasePageOp(PageOp
);
1428 DPRINT("Address 0x%.8X\n", Address
);
1429 return(STATUS_SUCCESS
);
1433 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1435 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1439 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1442 MmLockAddressSpace(&Process
->Vm
);
1445 MmDeleteVirtualMapping(Process
,
1452 PageOutContext
->WasDirty
= TRUE
;
1454 if (!PageOutContext
->Private
)
1456 MmLockSectionSegment(PageOutContext
->Segment
);
1457 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1458 PageOutContext
->Segment
,
1459 PageOutContext
->Offset
,
1460 PageOutContext
->WasDirty
,
1462 MmUnlockSectionSegment(PageOutContext
->Segment
);
1466 MmUnlockAddressSpace(&Process
->Vm
);
1469 if (PageOutContext
->Private
)
1471 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1474 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1479 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1480 MEMORY_AREA
* MemoryArea
,
1485 MM_SECTION_PAGEOUT_CONTEXT Context
;
1486 SWAPENTRY SwapEntry
;
1490 PFILE_OBJECT FileObject
;
1492 BOOLEAN DirectMapped
;
1493 BOOLEAN IsImageSection
;
1494 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1497 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1500 * Get the segment and section.
1502 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1503 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1505 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1506 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1507 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1509 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1511 FileObject
= Context
.Section
->FileObject
;
1512 DirectMapped
= FALSE
;
1513 if (FileObject
!= NULL
&&
1514 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1516 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1519 * If the file system is letting us go directly to the cache and the
1520 * memory area was mapped at an offset in the file which is page aligned
1521 * then note this is a direct mapped page.
1523 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1524 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1526 DirectMapped
= TRUE
;
1532 * This should never happen since mappings of physical memory are never
1533 * placed in the rmap lists.
1535 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1537 DPRINT1("Trying to page out from physical memory section address 0x%X "
1538 "process %d\n", Address
,
1539 Process
? Process
->UniqueProcessId
: 0);
1540 KeBugCheck(MEMORY_MANAGEMENT
);
1544 * Get the section segment entry and the physical address.
1546 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1547 if (!MmIsPagePresent(Process
, Address
))
1549 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1550 Process
? Process
->UniqueProcessId
: 0, Address
);
1551 KeBugCheck(MEMORY_MANAGEMENT
);
1553 Page
= MmGetPfnForProcess(Process
, Address
);
1554 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1557 * Prepare the context structure for the rmap delete call.
1559 Context
.WasDirty
= FALSE
;
1560 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1561 IS_SWAP_FROM_SSE(Entry
) ||
1562 PFN_FROM_SSE(Entry
) != Page
)
1564 Context
.Private
= TRUE
;
1568 Context
.Private
= FALSE
;
1572 * Take an additional reference to the page or the cache segment.
1574 if (DirectMapped
&& !Context
.Private
)
1576 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1578 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1579 KeBugCheck(MEMORY_MANAGEMENT
);
1584 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1585 MmReferencePage(Page
);
1586 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1589 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1592 * If this wasn't a private page then we should have reduced the entry to
1593 * zero by deleting all the rmaps.
1595 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1597 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1598 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1600 KeBugCheck(MEMORY_MANAGEMENT
);
1605 * If the page wasn't dirty then we can just free it as for a readonly page.
1606 * Since we unmapped all the mappings above we know it will not suddenly
1608 * If the page is from a pagefile section and has no swap entry,
1609 * we can't free the page at this point.
1611 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1612 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1614 if (Context
.Private
)
1616 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1617 Context
.WasDirty
? "dirty" : "clean", Address
);
1618 KeBugCheck(MEMORY_MANAGEMENT
);
1620 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1622 MmSetSavedSwapEntryPage(Page
, 0);
1623 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1624 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1625 PageOp
->Status
= STATUS_SUCCESS
;
1626 MmspCompleteAndReleasePageOp(PageOp
);
1627 return(STATUS_SUCCESS
);
1630 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1632 if (Context
.Private
)
1634 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1635 Context
.WasDirty
? "dirty" : "clean", Address
);
1636 KeBugCheck(MEMORY_MANAGEMENT
);
1638 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1640 MmSetSavedSwapEntryPage(Page
, 0);
1643 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1645 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1646 PageOp
->Status
= STATUS_SUCCESS
;
1647 MmspCompleteAndReleasePageOp(PageOp
);
1648 return(STATUS_SUCCESS
);
1651 else if (!Context
.Private
&& DirectMapped
)
1655 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1657 KeBugCheck(MEMORY_MANAGEMENT
);
1659 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1660 if (!NT_SUCCESS(Status
))
1662 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1663 KeBugCheck(MEMORY_MANAGEMENT
);
1665 PageOp
->Status
= STATUS_SUCCESS
;
1666 MmspCompleteAndReleasePageOp(PageOp
);
1667 return(STATUS_SUCCESS
);
1669 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1673 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1675 KeBugCheck(MEMORY_MANAGEMENT
);
1677 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1678 PageOp
->Status
= STATUS_SUCCESS
;
1679 MmspCompleteAndReleasePageOp(PageOp
);
1680 return(STATUS_SUCCESS
);
1682 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1684 MmSetSavedSwapEntryPage(Page
, 0);
1685 MmLockAddressSpace(AddressSpace
);
1686 Status
= MmCreatePageFileMapping(Process
,
1689 MmUnlockAddressSpace(AddressSpace
);
1690 if (!NT_SUCCESS(Status
))
1692 KeBugCheck(MEMORY_MANAGEMENT
);
1694 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1695 PageOp
->Status
= STATUS_SUCCESS
;
1696 MmspCompleteAndReleasePageOp(PageOp
);
1697 return(STATUS_SUCCESS
);
1701 * If necessary, allocate an entry in the paging file for this page
1705 SwapEntry
= MmAllocSwapPage();
1708 MmShowOutOfSpaceMessagePagingFile();
1709 MmLockAddressSpace(AddressSpace
);
1711 * For private pages restore the old mappings.
1713 if (Context
.Private
)
1715 Status
= MmCreateVirtualMapping(Process
,
1717 MemoryArea
->Protect
,
1720 MmSetDirtyPage(Process
, Address
);
1728 * For non-private pages if the page wasn't direct mapped then
1729 * set it back into the section segment entry so we don't loose
1730 * our copy. Otherwise it will be handled by the cache manager.
1732 Status
= MmCreateVirtualMapping(Process
,
1734 MemoryArea
->Protect
,
1737 MmSetDirtyPage(Process
, Address
);
1741 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1742 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1744 MmUnlockAddressSpace(AddressSpace
);
1745 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1746 MmspCompleteAndReleasePageOp(PageOp
);
1747 return(STATUS_PAGEFILE_QUOTA
);
1752 * Write the page to the pagefile
1754 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1755 if (!NT_SUCCESS(Status
))
1757 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1760 * As above: undo our actions.
1761 * FIXME: Also free the swap page.
1763 MmLockAddressSpace(AddressSpace
);
1764 if (Context
.Private
)
1766 Status
= MmCreateVirtualMapping(Process
,
1768 MemoryArea
->Protect
,
1771 MmSetDirtyPage(Process
, Address
);
1778 Status
= MmCreateVirtualMapping(Process
,
1780 MemoryArea
->Protect
,
1783 MmSetDirtyPage(Process
, Address
);
1787 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1788 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1790 MmUnlockAddressSpace(AddressSpace
);
1791 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1792 MmspCompleteAndReleasePageOp(PageOp
);
1793 return(STATUS_UNSUCCESSFUL
);
1797 * Otherwise we have succeeded.
1799 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1800 MmSetSavedSwapEntryPage(Page
, 0);
1801 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1802 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1804 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1808 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1811 if (Context
.Private
)
1813 MmLockAddressSpace(AddressSpace
);
1814 Status
= MmCreatePageFileMapping(Process
,
1817 MmUnlockAddressSpace(AddressSpace
);
1818 if (!NT_SUCCESS(Status
))
1820 KeBugCheck(MEMORY_MANAGEMENT
);
1825 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1826 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1829 PageOp
->Status
= STATUS_SUCCESS
;
1830 MmspCompleteAndReleasePageOp(PageOp
);
1831 return(STATUS_SUCCESS
);
1836 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
1837 PMEMORY_AREA MemoryArea
,
1842 PROS_SECTION_OBJECT Section
;
1843 PMM_SECTION_SEGMENT Segment
;
1845 SWAPENTRY SwapEntry
;
1849 PFILE_OBJECT FileObject
;
1851 BOOLEAN DirectMapped
;
1852 BOOLEAN IsImageSection
;
1853 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1855 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1857 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1858 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1861 * Get the segment and section.
1863 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1864 Section
= MemoryArea
->Data
.SectionData
.Section
;
1865 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1867 FileObject
= Section
->FileObject
;
1868 DirectMapped
= FALSE
;
1869 if (FileObject
!= NULL
&&
1870 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1872 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1875 * If the file system is letting us go directly to the cache and the
1876 * memory area was mapped at an offset in the file which is page aligned
1877 * then note this is a direct mapped page.
1879 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1880 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1882 DirectMapped
= TRUE
;
1887 * This should never happen since mappings of physical memory are never
1888 * placed in the rmap lists.
1890 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1892 DPRINT1("Trying to write back page from physical memory mapped at %X "
1893 "process %d\n", Address
,
1894 Process
? Process
->UniqueProcessId
: 0);
1895 KeBugCheck(MEMORY_MANAGEMENT
);
1899 * Get the section segment entry and the physical address.
1901 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1902 if (!MmIsPagePresent(Process
, Address
))
1904 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1905 Process
? Process
->UniqueProcessId
: 0, Address
);
1906 KeBugCheck(MEMORY_MANAGEMENT
);
1908 Page
= MmGetPfnForProcess(Process
, Address
);
1909 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1912 * Check for a private (COWed) page.
1914 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1915 IS_SWAP_FROM_SSE(Entry
) ||
1916 PFN_FROM_SSE(Entry
) != Page
)
1926 * Speculatively set all mappings of the page to clean.
1928 MmSetCleanAllRmaps(Page
);
1931 * If this page was direct mapped from the cache then the cache manager
1932 * will take care of writing it back to disk.
1934 if (DirectMapped
&& !Private
)
1936 ASSERT(SwapEntry
== 0);
1937 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1938 PageOp
->Status
= STATUS_SUCCESS
;
1939 MmspCompleteAndReleasePageOp(PageOp
);
1940 return(STATUS_SUCCESS
);
1944 * If necessary, allocate an entry in the paging file for this page
1948 SwapEntry
= MmAllocSwapPage();
1951 MmSetDirtyAllRmaps(Page
);
1952 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1953 MmspCompleteAndReleasePageOp(PageOp
);
1954 return(STATUS_PAGEFILE_QUOTA
);
1956 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1960 * Write the page to the pagefile
1962 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1963 if (!NT_SUCCESS(Status
))
1965 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1967 MmSetDirtyAllRmaps(Page
);
1968 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1969 MmspCompleteAndReleasePageOp(PageOp
);
1970 return(STATUS_UNSUCCESSFUL
);
1974 * Otherwise we have succeeded.
1976 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1977 PageOp
->Status
= STATUS_SUCCESS
;
1978 MmspCompleteAndReleasePageOp(PageOp
);
1979 return(STATUS_SUCCESS
);
1983 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
1991 PMEMORY_AREA MemoryArea
;
1992 PMM_SECTION_SEGMENT Segment
;
1993 BOOLEAN DoCOW
= FALSE
;
1995 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1997 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1998 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2000 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
2001 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2006 if (OldProtect
!= NewProtect
)
2008 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2010 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2011 ULONG Protect
= NewProtect
;
2014 * If we doing COW for this segment then check if the page is
2017 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2023 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2024 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2025 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2026 Page
= MmGetPfnForProcess(Process
, Address
);
2028 Protect
= PAGE_READONLY
;
2029 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2030 IS_SWAP_FROM_SSE(Entry
) ||
2031 PFN_FROM_SSE(Entry
) != Page
)
2033 Protect
= NewProtect
;
2037 if (MmIsPagePresent(Process
, Address
))
2039 MmSetPageProtect(Process
, Address
,
2048 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2049 PMEMORY_AREA MemoryArea
,
2057 ULONG_PTR MaxLength
;
2059 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2060 if (Length
> MaxLength
)
2063 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2064 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2066 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2067 Region
->Protect
!= Protect
)
2069 return STATUS_INVALID_PAGE_PROTECTION
;
2072 *OldProtect
= Region
->Protect
;
2073 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2074 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2075 BaseAddress
, Length
, Region
->Type
, Protect
,
2076 MmAlterViewAttributes
);
2082 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2084 PMEMORY_BASIC_INFORMATION Info
,
2085 PSIZE_T ResultLength
)
2088 PVOID RegionBaseAddress
;
2089 PROS_SECTION_OBJECT Section
;
2090 PMM_SECTION_SEGMENT Segment
;
2092 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2093 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2094 Address
, &RegionBaseAddress
);
2097 return STATUS_UNSUCCESSFUL
;
2100 Section
= MemoryArea
->Data
.SectionData
.Section
;
2101 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2103 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2104 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2105 Info
->Type
= MEM_IMAGE
;
2109 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2110 Info
->Type
= MEM_MAPPED
;
2112 Info
->BaseAddress
= RegionBaseAddress
;
2113 Info
->AllocationProtect
= MemoryArea
->Protect
;
2114 Info
->RegionSize
= Region
->Length
;
2115 Info
->State
= MEM_COMMIT
;
2116 Info
->Protect
= Region
->Protect
;
2118 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2119 return(STATUS_SUCCESS
);
2124 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2129 ULONG SavedSwapEntry
;
2134 Length
= PAGE_ROUND_UP(Segment
->Length
);
2135 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2137 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2140 if (IS_SWAP_FROM_SSE(Entry
))
2142 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2146 Page
= PFN_FROM_SSE(Entry
);
2147 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2148 if (SavedSwapEntry
!= 0)
2150 MmSetSavedSwapEntryPage(Page
, 0);
2151 MmFreeSwapPage(SavedSwapEntry
);
2153 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2155 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2161 MmpDeleteSection(PVOID ObjectBody
)
2163 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2165 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2166 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2171 PMM_SECTION_SEGMENT SectionSegments
;
2174 * NOTE: Section->ImageSection can be NULL for short time
2175 * during the section creating. If we fail for some reason
2176 * until the image section is properly initialized we shouldn't
2177 * process further here.
2179 if (Section
->ImageSection
== NULL
)
2182 SectionSegments
= Section
->ImageSection
->Segments
;
2183 NrSegments
= Section
->ImageSection
->NrSegments
;
2185 for (i
= 0; i
< NrSegments
; i
++)
2187 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2189 MmLockSectionSegment(&SectionSegments
[i
]);
2191 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2192 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2196 MmpFreePageFileSegment(&SectionSegments
[i
]);
2198 MmUnlockSectionSegment(&SectionSegments
[i
]);
2205 * NOTE: Section->Segment can be NULL for short time
2206 * during the section creating.
2208 if (Section
->Segment
== NULL
)
2211 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2213 MmpFreePageFileSegment(Section
->Segment
);
2214 MmFreePageTablesSectionSegment(Section
->Segment
);
2215 ExFreePool(Section
->Segment
);
2216 Section
->Segment
= NULL
;
2220 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2223 if (Section
->FileObject
!= NULL
)
2225 CcRosDereferenceCache(Section
->FileObject
);
2226 ObDereferenceObject(Section
->FileObject
);
2227 Section
->FileObject
= NULL
;
2232 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2234 IN ACCESS_MASK GrantedAccess
,
2235 IN ULONG ProcessHandleCount
,
2236 IN ULONG SystemHandleCount
)
2238 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2239 Object
, ProcessHandleCount
);
2245 MmCreatePhysicalMemorySection(VOID
)
2247 PROS_SECTION_OBJECT PhysSection
;
2249 OBJECT_ATTRIBUTES Obj
;
2250 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2251 LARGE_INTEGER SectionSize
;
2255 * Create the section mapping physical memory
2257 SectionSize
.QuadPart
= 0xFFFFFFFF;
2258 InitializeObjectAttributes(&Obj
,
2263 Status
= MmCreateSection((PVOID
)&PhysSection
,
2267 PAGE_EXECUTE_READWRITE
,
2271 if (!NT_SUCCESS(Status
))
2273 DPRINT1("Failed to create PhysicalMemory section\n");
2274 KeBugCheck(MEMORY_MANAGEMENT
);
2276 Status
= ObInsertObject(PhysSection
,
2282 if (!NT_SUCCESS(Status
))
2284 ObDereferenceObject(PhysSection
);
2286 ObCloseHandle(Handle
, KernelMode
);
2287 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2288 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2290 return(STATUS_SUCCESS
);
2296 MmInitSectionImplementation(VOID
)
2298 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2299 UNICODE_STRING Name
;
2301 DPRINT("Creating Section Object Type\n");
2303 /* Initialize the Section object type */
2304 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2305 RtlInitUnicodeString(&Name
, L
"Section");
2306 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2307 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2308 ObjectTypeInitializer
.PoolType
= PagedPool
;
2309 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2310 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2311 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2312 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2313 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2314 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2316 MmCreatePhysicalMemorySection();
2318 return(STATUS_SUCCESS
);
2323 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2324 ACCESS_MASK DesiredAccess
,
2325 POBJECT_ATTRIBUTES ObjectAttributes
,
2326 PLARGE_INTEGER UMaximumSize
,
2327 ULONG SectionPageProtection
,
2328 ULONG AllocationAttributes
)
2330 * Create a section which is backed by the pagefile
2333 LARGE_INTEGER MaximumSize
;
2334 PROS_SECTION_OBJECT Section
;
2335 PMM_SECTION_SEGMENT Segment
;
2338 if (UMaximumSize
== NULL
)
2340 return(STATUS_UNSUCCESSFUL
);
2342 MaximumSize
= *UMaximumSize
;
2345 * Create the section
2347 Status
= ObCreateObject(ExGetPreviousMode(),
2348 MmSectionObjectType
,
2350 ExGetPreviousMode(),
2352 sizeof(ROS_SECTION_OBJECT
),
2355 (PVOID
*)(PVOID
)&Section
);
2356 if (!NT_SUCCESS(Status
))
2364 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2365 Section
->SectionPageProtection
= SectionPageProtection
;
2366 Section
->AllocationAttributes
= AllocationAttributes
;
2367 Section
->MaximumSize
= MaximumSize
;
2368 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2369 TAG_MM_SECTION_SEGMENT
);
2370 if (Segment
== NULL
)
2372 ObDereferenceObject(Section
);
2373 return(STATUS_NO_MEMORY
);
2375 Section
->Segment
= Segment
;
2376 Segment
->ReferenceCount
= 1;
2377 ExInitializeFastMutex(&Segment
->Lock
);
2378 Segment
->FileOffset
= 0;
2379 Segment
->Protection
= SectionPageProtection
;
2380 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2381 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2382 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2383 Segment
->WriteCopy
= FALSE
;
2384 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2385 Segment
->VirtualAddress
= 0;
2386 Segment
->Characteristics
= 0;
2387 *SectionObject
= Section
;
2388 return(STATUS_SUCCESS
);
2394 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2395 ACCESS_MASK DesiredAccess
,
2396 POBJECT_ATTRIBUTES ObjectAttributes
,
2397 PLARGE_INTEGER UMaximumSize
,
2398 ULONG SectionPageProtection
,
2399 ULONG AllocationAttributes
,
2402 * Create a section backed by a data file
2405 PROS_SECTION_OBJECT Section
;
2407 LARGE_INTEGER MaximumSize
;
2408 PFILE_OBJECT FileObject
;
2409 PMM_SECTION_SEGMENT Segment
;
2411 IO_STATUS_BLOCK Iosb
;
2412 LARGE_INTEGER Offset
;
2414 FILE_STANDARD_INFORMATION FileInfo
;
2418 * Create the section
2420 Status
= ObCreateObject(ExGetPreviousMode(),
2421 MmSectionObjectType
,
2423 ExGetPreviousMode(),
2425 sizeof(ROS_SECTION_OBJECT
),
2428 (PVOID
*)(PVOID
)&Section
);
2429 if (!NT_SUCCESS(Status
))
2436 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2437 Section
->SectionPageProtection
= SectionPageProtection
;
2438 Section
->AllocationAttributes
= AllocationAttributes
;
2441 * Check file access required
2443 if (SectionPageProtection
& PAGE_READWRITE
||
2444 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2446 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2450 FileAccess
= FILE_READ_DATA
;
2454 * Reference the file handle
2456 Status
= ObReferenceObjectByHandle(FileHandle
,
2459 ExGetPreviousMode(),
2460 (PVOID
*)(PVOID
)&FileObject
,
2462 if (!NT_SUCCESS(Status
))
2464 ObDereferenceObject(Section
);
2469 * FIXME: This is propably not entirely correct. We can't look into
2470 * the standard FCB header because it might not be initialized yet
2471 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2472 * standard file information is filled on first request).
2474 Status
= IoQueryFileInformation(FileObject
,
2475 FileStandardInformation
,
2476 sizeof(FILE_STANDARD_INFORMATION
),
2479 Iosb
.Information
= Length
;
2480 if (!NT_SUCCESS(Status
))
2482 ObDereferenceObject(Section
);
2483 ObDereferenceObject(FileObject
);
2488 * FIXME: Revise this once a locking order for file size changes is
2491 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2493 MaximumSize
= *UMaximumSize
;
2497 MaximumSize
= FileInfo
.EndOfFile
;
2498 /* Mapping zero-sized files isn't allowed. */
2499 if (MaximumSize
.QuadPart
== 0)
2501 ObDereferenceObject(Section
);
2502 ObDereferenceObject(FileObject
);
2503 return STATUS_FILE_INVALID
;
2507 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2509 Status
= IoSetInformation(FileObject
,
2510 FileAllocationInformation
,
2511 sizeof(LARGE_INTEGER
),
2513 if (!NT_SUCCESS(Status
))
2515 ObDereferenceObject(Section
);
2516 ObDereferenceObject(FileObject
);
2517 return(STATUS_SECTION_NOT_EXTENDED
);
2521 if (FileObject
->SectionObjectPointer
== NULL
||
2522 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2525 * Read a bit so caching is initiated for the file object.
2526 * This is only needed because MiReadPage currently cannot
2527 * handle non-cached streams.
2529 Offset
.QuadPart
= 0;
2530 Status
= ZwReadFile(FileHandle
,
2539 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2541 ObDereferenceObject(Section
);
2542 ObDereferenceObject(FileObject
);
2545 if (FileObject
->SectionObjectPointer
== NULL
||
2546 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2548 /* FIXME: handle this situation */
2549 ObDereferenceObject(Section
);
2550 ObDereferenceObject(FileObject
);
2551 return STATUS_INVALID_PARAMETER
;
2558 Status
= MmspWaitForFileLock(FileObject
);
2559 if (Status
!= STATUS_SUCCESS
)
2561 ObDereferenceObject(Section
);
2562 ObDereferenceObject(FileObject
);
2567 * If this file hasn't been mapped as a data file before then allocate a
2568 * section segment to describe the data file mapping
2570 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2572 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2573 TAG_MM_SECTION_SEGMENT
);
2574 if (Segment
== NULL
)
2576 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2577 ObDereferenceObject(Section
);
2578 ObDereferenceObject(FileObject
);
2579 return(STATUS_NO_MEMORY
);
2581 Section
->Segment
= Segment
;
2582 Segment
->ReferenceCount
= 1;
2583 ExInitializeFastMutex(&Segment
->Lock
);
2585 * Set the lock before assigning the segment to the file object
2587 ExAcquireFastMutex(&Segment
->Lock
);
2588 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2590 Segment
->FileOffset
= 0;
2591 Segment
->Protection
= SectionPageProtection
;
2592 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2593 Segment
->Characteristics
= 0;
2594 Segment
->WriteCopy
= FALSE
;
2595 if (AllocationAttributes
& SEC_RESERVE
)
2597 Segment
->Length
= Segment
->RawLength
= 0;
2601 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2602 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2604 Segment
->VirtualAddress
= 0;
2605 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2610 * If the file is already mapped as a data file then we may need
2614 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2616 Section
->Segment
= Segment
;
2617 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2618 MmLockSectionSegment(Segment
);
2620 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2621 !(AllocationAttributes
& SEC_RESERVE
))
2623 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2624 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2627 MmUnlockSectionSegment(Segment
);
2628 Section
->FileObject
= FileObject
;
2629 Section
->MaximumSize
= MaximumSize
;
2630 CcRosReferenceCache(FileObject
);
2631 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2632 *SectionObject
= Section
;
2633 return(STATUS_SUCCESS
);
2637 TODO: not that great (declaring loaders statically, having to declare all of
2638 them, having to keep them extern, etc.), will fix in the future
2640 extern NTSTATUS NTAPI PeFmtCreateSection
2642 IN CONST VOID
* FileHeader
,
2643 IN SIZE_T FileHeaderSize
,
2645 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2647 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2648 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2651 extern NTSTATUS NTAPI ElfFmtCreateSection
2653 IN CONST VOID
* FileHeader
,
2654 IN SIZE_T FileHeaderSize
,
2656 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2658 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2659 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2662 /* TODO: this is a standard DDK/PSDK macro */
2663 #ifndef RTL_NUMBER_OF
2664 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2667 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2678 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2680 SIZE_T SizeOfSegments
;
2681 PMM_SECTION_SEGMENT Segments
;
2683 /* TODO: check for integer overflow */
2684 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2686 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2688 TAG_MM_SECTION_SEGMENT
);
2691 RtlZeroMemory(Segments
, SizeOfSegments
);
2699 ExeFmtpReadFile(IN PVOID File
,
2700 IN PLARGE_INTEGER Offset
,
2703 OUT PVOID
* AllocBase
,
2704 OUT PULONG ReadSize
)
2707 LARGE_INTEGER FileOffset
;
2709 ULONG OffsetAdjustment
;
2714 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2718 KeBugCheck(MEMORY_MANAGEMENT
);
2721 FileOffset
= *Offset
;
2723 /* Negative/special offset: it cannot be used in this context */
2724 if(FileOffset
.u
.HighPart
< 0)
2726 KeBugCheck(MEMORY_MANAGEMENT
);
2729 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2730 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2731 FileOffset
.u
.LowPart
= AdjustOffset
;
2733 BufferSize
= Length
+ OffsetAdjustment
;
2734 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2737 * It's ok to use paged pool, because this is a temporary buffer only used in
2738 * the loading of executables. The assumption is that MmCreateSection is
2739 * always called at low IRQLs and that these buffers don't survive a brief
2740 * initialization phase
2742 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2747 KeBugCheck(MEMORY_MANAGEMENT
);
2753 Status
= MmspPageRead(File
,
2760 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2761 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2762 * to initialize internal state is even worse. Our cache manager is in need of
2766 IO_STATUS_BLOCK Iosb
;
2768 Status
= ZwReadFile(File
,
2778 if(NT_SUCCESS(Status
))
2780 UsedSize
= Iosb
.Information
;
2785 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2787 Status
= STATUS_IN_PAGE_ERROR
;
2788 ASSERT(!NT_SUCCESS(Status
));
2791 if(NT_SUCCESS(Status
))
2793 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2794 *AllocBase
= Buffer
;
2795 *ReadSize
= UsedSize
- OffsetAdjustment
;
2799 ExFreePoolWithTag(Buffer
, 'rXmM');
2806 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2807 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2808 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2813 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2817 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2819 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2820 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2827 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2831 MmspAssertSegmentsSorted(ImageSectionObject
);
2833 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2835 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2839 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2840 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2841 ImageSectionObject
->Segments
[i
- 1].Length
));
2849 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2853 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2855 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2856 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2864 MmspCompareSegments(const void * x
,
2867 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2868 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2871 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2872 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2876 * Ensures an image section's segments are sorted in memory
2881 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2884 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2886 MmspAssertSegmentsSorted(ImageSectionObject
);
2890 qsort(ImageSectionObject
->Segments
,
2891 ImageSectionObject
->NrSegments
,
2892 sizeof(ImageSectionObject
->Segments
[0]),
2893 MmspCompareSegments
);
2899 * Ensures an image section's segments don't overlap in memory and don't have
2900 * gaps and don't have a null size. We let them map to overlapping file regions,
2901 * though - that's not necessarily an error
2906 MmspCheckSegmentBounds
2908 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2914 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2916 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2920 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2922 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2924 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2932 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2933 * page could be OK (Windows seems to be OK with them), and larger gaps
2934 * could lead to image sections spanning several discontiguous regions
2935 * (NtMapViewOfSection could then refuse to map them, and they could
2936 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2938 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2939 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2940 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2951 * Merges and pads an image section's segments until they all are page-aligned
2952 * and have a size that is a multiple of the page size
2957 MmspPageAlignSegments
2959 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2965 BOOLEAN Initialized
;
2966 PMM_SECTION_SEGMENT EffectiveSegment
;
2968 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2970 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2974 Initialized
= FALSE
;
2976 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2978 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2981 * The first segment requires special handling
2985 ULONG_PTR VirtualAddress
;
2986 ULONG_PTR VirtualOffset
;
2988 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2990 /* Round down the virtual address to the nearest page */
2991 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2993 /* Round up the virtual size to the nearest page */
2994 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2995 EffectiveSegment
->VirtualAddress
;
2997 /* Adjust the raw address and size */
2998 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3000 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3006 * Garbage in, garbage out: unaligned base addresses make the file
3007 * offset point in curious and odd places, but that's what we were
3010 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3011 EffectiveSegment
->RawLength
+= VirtualOffset
;
3015 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3016 ULONG_PTR EndOfEffectiveSegment
;
3018 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3019 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3022 * The current segment begins exactly where the current effective
3023 * segment ended, therefore beginning a new effective segment
3025 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3028 ASSERT(LastSegment
<= i
);
3029 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3031 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3033 if (LastSegment
!= i
)
3036 * Copy the current segment. If necessary, the effective segment
3037 * will be expanded later
3039 *EffectiveSegment
= *Segment
;
3043 * Page-align the virtual size. We know for sure the virtual address
3046 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3047 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3050 * The current segment is still part of the current effective segment:
3051 * extend the effective segment to reflect this
3053 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3055 static const ULONG FlagsToProtection
[16] =
3063 PAGE_EXECUTE_READWRITE
,
3064 PAGE_EXECUTE_READWRITE
,
3069 PAGE_EXECUTE_WRITECOPY
,
3070 PAGE_EXECUTE_WRITECOPY
,
3071 PAGE_EXECUTE_WRITECOPY
,
3072 PAGE_EXECUTE_WRITECOPY
3075 unsigned ProtectionFlags
;
3078 * Extend the file size
3081 /* Unaligned segments must be contiguous within the file */
3082 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3083 EffectiveSegment
->RawLength
))
3088 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3091 * Extend the virtual size
3093 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3095 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3096 EffectiveSegment
->VirtualAddress
;
3099 * Merge the protection
3101 EffectiveSegment
->Protection
|= Segment
->Protection
;
3103 /* Clean up redundance */
3104 ProtectionFlags
= 0;
3106 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3107 ProtectionFlags
|= 1 << 0;
3109 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3110 ProtectionFlags
|= 1 << 1;
3112 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3113 ProtectionFlags
|= 1 << 2;
3115 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3116 ProtectionFlags
|= 1 << 3;
3118 ASSERT(ProtectionFlags
< 16);
3119 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3121 /* If a segment was required to be shared and cannot, fail */
3122 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3123 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3129 * We assume no holes between segments at this point
3133 KeBugCheck(MEMORY_MANAGEMENT
);
3137 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3143 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3144 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3146 LARGE_INTEGER Offset
;
3148 PVOID FileHeaderBuffer
;
3149 ULONG FileHeaderSize
;
3151 ULONG OldNrSegments
;
3156 * Read the beginning of the file (2 pages). Should be enough to contain
3157 * all (or most) of the headers
3159 Offset
.QuadPart
= 0;
3161 /* FIXME: use FileObject instead of FileHandle */
3162 Status
= ExeFmtpReadFile (FileHandle
,
3169 if (!NT_SUCCESS(Status
))
3172 if (FileHeaderSize
== 0)
3174 ExFreePool(FileHeaderBuffer
);
3175 return STATUS_UNSUCCESSFUL
;
3179 * Look for a loader that can handle this executable
3181 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3183 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3186 /* FIXME: use FileObject instead of FileHandle */
3187 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3193 ExeFmtpAllocateSegments
);
3195 if (!NT_SUCCESS(Status
))
3197 if (ImageSectionObject
->Segments
)
3199 ExFreePool(ImageSectionObject
->Segments
);
3200 ImageSectionObject
->Segments
= NULL
;
3204 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3208 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3211 * No loader handled the format
3213 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3215 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3216 ASSERT(!NT_SUCCESS(Status
));
3219 if (!NT_SUCCESS(Status
))
3222 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3227 /* FIXME? are these values platform-dependent? */
3228 if(ImageSectionObject
->StackReserve
== 0)
3229 ImageSectionObject
->StackReserve
= 0x40000;
3231 if(ImageSectionObject
->StackCommit
== 0)
3232 ImageSectionObject
->StackCommit
= 0x1000;
3234 if(ImageSectionObject
->ImageBase
== 0)
3236 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3237 ImageSectionObject
->ImageBase
= 0x10000000;
3239 ImageSectionObject
->ImageBase
= 0x00400000;
3243 * And now the fun part: fixing the segments
3246 /* Sort them by virtual address */
3247 MmspSortSegments(ImageSectionObject
, Flags
);
3249 /* Ensure they don't overlap in memory */
3250 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3251 return STATUS_INVALID_IMAGE_FORMAT
;
3253 /* Ensure they are aligned */
3254 OldNrSegments
= ImageSectionObject
->NrSegments
;
3256 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3257 return STATUS_INVALID_IMAGE_FORMAT
;
3259 /* Trim them if the alignment phase merged some of them */
3260 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3262 PMM_SECTION_SEGMENT Segments
;
3263 SIZE_T SizeOfSegments
;
3265 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3267 Segments
= ExAllocatePoolWithTag(PagedPool
,
3269 TAG_MM_SECTION_SEGMENT
);
3271 if (Segments
== NULL
)
3272 return STATUS_INSUFFICIENT_RESOURCES
;
3274 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3275 ExFreePool(ImageSectionObject
->Segments
);
3276 ImageSectionObject
->Segments
= Segments
;
3279 /* And finish their initialization */
3280 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3282 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3283 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3285 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3286 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3289 ASSERT(NT_SUCCESS(Status
));
3294 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3295 ACCESS_MASK DesiredAccess
,
3296 POBJECT_ATTRIBUTES ObjectAttributes
,
3297 PLARGE_INTEGER UMaximumSize
,
3298 ULONG SectionPageProtection
,
3299 ULONG AllocationAttributes
,
3302 PROS_SECTION_OBJECT Section
;
3304 PFILE_OBJECT FileObject
;
3305 PMM_SECTION_SEGMENT SectionSegments
;
3306 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3308 ULONG FileAccess
= 0;
3311 * Specifying a maximum size is meaningless for an image section
3313 if (UMaximumSize
!= NULL
)
3315 return(STATUS_INVALID_PARAMETER_4
);
3319 * Check file access required
3321 if (SectionPageProtection
& PAGE_READWRITE
||
3322 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3324 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3328 FileAccess
= FILE_READ_DATA
;
3332 * Reference the file handle
3334 Status
= ObReferenceObjectByHandle(FileHandle
,
3337 ExGetPreviousMode(),
3338 (PVOID
*)(PVOID
)&FileObject
,
3341 if (!NT_SUCCESS(Status
))
3347 * Create the section
3349 Status
= ObCreateObject (ExGetPreviousMode(),
3350 MmSectionObjectType
,
3352 ExGetPreviousMode(),
3354 sizeof(ROS_SECTION_OBJECT
),
3357 (PVOID
*)(PVOID
)&Section
);
3358 if (!NT_SUCCESS(Status
))
3360 ObDereferenceObject(FileObject
);
3367 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3368 Section
->SectionPageProtection
= SectionPageProtection
;
3369 Section
->AllocationAttributes
= AllocationAttributes
;
3372 * Initialized caching for this file object if previously caching
3373 * was initialized for the same on disk file
3375 Status
= CcTryToInitializeFileCache(FileObject
);
3377 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3379 NTSTATUS StatusExeFmt
;
3381 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3382 if (ImageSectionObject
== NULL
)
3384 ObDereferenceObject(FileObject
);
3385 ObDereferenceObject(Section
);
3386 return(STATUS_NO_MEMORY
);
3389 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3391 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3393 if (!NT_SUCCESS(StatusExeFmt
))
3395 if(ImageSectionObject
->Segments
!= NULL
)
3396 ExFreePool(ImageSectionObject
->Segments
);
3398 ExFreePool(ImageSectionObject
);
3399 ObDereferenceObject(Section
);
3400 ObDereferenceObject(FileObject
);
3401 return(StatusExeFmt
);
3404 Section
->ImageSection
= ImageSectionObject
;
3405 ASSERT(ImageSectionObject
->Segments
);
3410 Status
= MmspWaitForFileLock(FileObject
);
3411 if (!NT_SUCCESS(Status
))
3413 ExFreePool(ImageSectionObject
->Segments
);
3414 ExFreePool(ImageSectionObject
);
3415 ObDereferenceObject(Section
);
3416 ObDereferenceObject(FileObject
);
3420 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3421 ImageSectionObject
, NULL
))
3424 * An other thread has initialized the same image in the background
3426 ExFreePool(ImageSectionObject
->Segments
);
3427 ExFreePool(ImageSectionObject
);
3428 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3429 Section
->ImageSection
= ImageSectionObject
;
3430 SectionSegments
= ImageSectionObject
->Segments
;
3432 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3434 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3438 Status
= StatusExeFmt
;
3445 Status
= MmspWaitForFileLock(FileObject
);
3446 if (Status
!= STATUS_SUCCESS
)
3448 ObDereferenceObject(Section
);
3449 ObDereferenceObject(FileObject
);
3453 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3454 Section
->ImageSection
= ImageSectionObject
;
3455 SectionSegments
= ImageSectionObject
->Segments
;
3458 * Otherwise just reference all the section segments
3460 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3462 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3465 Status
= STATUS_SUCCESS
;
3467 Section
->FileObject
= FileObject
;
3468 CcRosReferenceCache(FileObject
);
3469 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3470 *SectionObject
= Section
;
3478 NtCreateSection (OUT PHANDLE SectionHandle
,
3479 IN ACCESS_MASK DesiredAccess
,
3480 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3481 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3482 IN ULONG SectionPageProtection OPTIONAL
,
3483 IN ULONG AllocationAttributes
,
3484 IN HANDLE FileHandle OPTIONAL
)
3486 LARGE_INTEGER SafeMaximumSize
;
3487 PVOID SectionObject
;
3488 KPROCESSOR_MODE PreviousMode
;
3491 PreviousMode
= ExGetPreviousMode();
3493 if(PreviousMode
!= KernelMode
)
3497 if (MaximumSize
!= NULL
)
3499 /* make a copy on the stack */
3500 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3501 MaximumSize
= &SafeMaximumSize
;
3503 ProbeForWriteHandle(SectionHandle
);
3505 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3507 /* Return the exception code */
3508 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3513 Status
= MmCreateSection(&SectionObject
,
3517 SectionPageProtection
,
3518 AllocationAttributes
,
3521 if (NT_SUCCESS(Status
))
3523 Status
= ObInsertObject ((PVOID
)SectionObject
,
3535 /**********************************************************************
3553 NtOpenSection(PHANDLE SectionHandle
,
3554 ACCESS_MASK DesiredAccess
,
3555 POBJECT_ATTRIBUTES ObjectAttributes
)
3558 KPROCESSOR_MODE PreviousMode
;
3561 PreviousMode
= ExGetPreviousMode();
3563 if(PreviousMode
!= KernelMode
)
3567 ProbeForWriteHandle(SectionHandle
);
3569 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3571 /* Return the exception code */
3572 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3577 Status
= ObOpenObjectByName(ObjectAttributes
,
3578 MmSectionObjectType
,
3585 if(NT_SUCCESS(Status
))
3589 *SectionHandle
= hSection
;
3591 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3593 Status
= _SEH2_GetExceptionCode();
3602 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3603 PROS_SECTION_OBJECT Section
,
3604 PMM_SECTION_SEGMENT Segment
,
3609 ULONG AllocationType
)
3613 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3615 BoundaryAddressMultiple
.QuadPart
= 0;
3617 Status
= MmCreateMemoryArea(AddressSpace
,
3618 MEMORY_AREA_SECTION_VIEW
,
3625 BoundaryAddressMultiple
);
3626 if (!NT_SUCCESS(Status
))
3628 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3629 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3633 ObReferenceObject((PVOID
)Section
);
3635 MArea
->Data
.SectionData
.Segment
= Segment
;
3636 MArea
->Data
.SectionData
.Section
= Section
;
3637 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3638 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3639 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3640 ViewSize
, 0, Protect
);
3642 return(STATUS_SUCCESS
);
3646 /**********************************************************************
3648 * NtMapViewOfSection
3651 * Maps a view of a section into the virtual address space of a
3656 * Handle of the section.
3659 * Handle of the process.
3662 * Desired base address (or NULL) on entry;
3663 * Actual base address of the view on exit.
3666 * Number of high order address bits that must be zero.
3669 * Size in bytes of the initially committed section of
3673 * Offset in bytes from the beginning of the section
3674 * to the beginning of the view.
3677 * Desired length of map (or zero to map all) on entry
3678 * Actual length mapped on exit.
3680 * InheritDisposition
3681 * Specified how the view is to be shared with
3685 * Type of allocation for the pages.
3688 * Protection for the committed region of the view.
3696 NtMapViewOfSection(IN HANDLE SectionHandle
,
3697 IN HANDLE ProcessHandle
,
3698 IN OUT PVOID
* BaseAddress OPTIONAL
,
3699 IN ULONG_PTR ZeroBits OPTIONAL
,
3700 IN SIZE_T CommitSize
,
3701 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3702 IN OUT PSIZE_T ViewSize
,
3703 IN SECTION_INHERIT InheritDisposition
,
3704 IN ULONG AllocationType OPTIONAL
,
3707 PVOID SafeBaseAddress
;
3708 LARGE_INTEGER SafeSectionOffset
;
3709 SIZE_T SafeViewSize
;
3710 PROS_SECTION_OBJECT Section
;
3712 KPROCESSOR_MODE PreviousMode
;
3713 PMMSUPPORT AddressSpace
;
3716 ACCESS_MASK DesiredAccess
;
3719 * Check the protection
3721 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3723 return STATUS_INVALID_PARAMETER_10
;
3726 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3727 if (tmpProtect
!= PAGE_NOACCESS
&&
3728 tmpProtect
!= PAGE_READONLY
&&
3729 tmpProtect
!= PAGE_READWRITE
&&
3730 tmpProtect
!= PAGE_WRITECOPY
&&
3731 tmpProtect
!= PAGE_EXECUTE
&&
3732 tmpProtect
!= PAGE_EXECUTE_READ
&&
3733 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3734 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3736 return STATUS_INVALID_PAGE_PROTECTION
;
3739 PreviousMode
= ExGetPreviousMode();
3741 if(PreviousMode
!= KernelMode
)
3743 SafeBaseAddress
= NULL
;
3744 SafeSectionOffset
.QuadPart
= 0;
3749 if(BaseAddress
!= NULL
)
3751 ProbeForWritePointer(BaseAddress
);
3752 SafeBaseAddress
= *BaseAddress
;
3754 if(SectionOffset
!= NULL
)
3756 ProbeForWriteLargeInteger(SectionOffset
);
3757 SafeSectionOffset
= *SectionOffset
;
3759 ProbeForWriteSize_t(ViewSize
);
3760 SafeViewSize
= *ViewSize
;
3762 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3764 /* Return the exception code */
3765 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3771 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3772 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3773 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3776 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3778 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3779 PROCESS_VM_OPERATION
,
3782 (PVOID
*)(PVOID
)&Process
,
3784 if (!NT_SUCCESS(Status
))
3789 AddressSpace
= &Process
->Vm
;
3791 /* Convert NT Protection Attr to Access Mask */
3792 if (Protect
== PAGE_READONLY
)
3794 DesiredAccess
= SECTION_MAP_READ
;
3796 else if (Protect
== PAGE_READWRITE
)
3798 DesiredAccess
= SECTION_MAP_WRITE
;
3800 else if (Protect
== PAGE_WRITECOPY
)
3802 DesiredAccess
= SECTION_QUERY
;
3804 /* FIXME: Handle other Protection Attributes. For now keep previous behavior */
3807 DesiredAccess
= SECTION_MAP_READ
;
3810 Status
= ObReferenceObjectByHandle(SectionHandle
,
3812 MmSectionObjectType
,
3814 (PVOID
*)(PVOID
)&Section
,
3816 if (!(NT_SUCCESS(Status
)))
3818 DPRINT("ObReference failed rc=%x\n",Status
);
3819 ObDereferenceObject(Process
);
3823 Status
= MmMapViewOfSection(Section
,
3825 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3828 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3829 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3834 /* Check if this is an image for the current process */
3835 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3836 (Process
== PsGetCurrentProcess()) &&
3837 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3839 /* Notify the debugger */
3840 DbgkMapViewOfSection(Section
,
3842 SafeSectionOffset
.LowPart
,
3846 ObDereferenceObject(Section
);
3847 ObDereferenceObject(Process
);
3849 if(NT_SUCCESS(Status
))
3851 /* copy parameters back to the caller */
3854 if(BaseAddress
!= NULL
)
3856 *BaseAddress
= SafeBaseAddress
;
3858 if(SectionOffset
!= NULL
)
3860 *SectionOffset
= SafeSectionOffset
;
3862 if(ViewSize
!= NULL
)
3864 *ViewSize
= SafeViewSize
;
3867 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3869 Status
= _SEH2_GetExceptionCode();
3878 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3879 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3882 PFILE_OBJECT FileObject
;
3885 SWAPENTRY SavedSwapEntry
;
3888 PROS_SECTION_OBJECT Section
;
3889 PMM_SECTION_SEGMENT Segment
;
3890 PMMSUPPORT AddressSpace
;
3893 AddressSpace
= (PMMSUPPORT
)Context
;
3894 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3896 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3898 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3899 MemoryArea
->Data
.SectionData
.ViewOffset
;
3901 Section
= MemoryArea
->Data
.SectionData
.Section
;
3902 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3904 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3908 MmUnlockSectionSegment(Segment
);
3909 MmUnlockAddressSpace(AddressSpace
);
3911 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3912 if (Status
!= STATUS_SUCCESS
)
3914 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3915 KeBugCheck(MEMORY_MANAGEMENT
);
3918 MmLockAddressSpace(AddressSpace
);
3919 MmLockSectionSegment(Segment
);
3920 MmspCompleteAndReleasePageOp(PageOp
);
3921 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3924 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3927 * For a dirty, datafile, non-private page mark it as dirty in the
3930 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3932 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3934 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3935 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3936 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3937 ASSERT(SwapEntry
== 0);
3946 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3948 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3949 KeBugCheck(MEMORY_MANAGEMENT
);
3951 MmFreeSwapPage(SwapEntry
);
3955 if (IS_SWAP_FROM_SSE(Entry
) ||
3956 Page
!= PFN_FROM_SSE(Entry
))
3961 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3963 DPRINT1("Found a private page in a pagefile section.\n");
3964 KeBugCheck(MEMORY_MANAGEMENT
);
3967 * Just dereference private pages
3969 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3970 if (SavedSwapEntry
!= 0)
3972 MmFreeSwapPage(SavedSwapEntry
);
3973 MmSetSavedSwapEntryPage(Page
, 0);
3975 MmDeleteRmap(Page
, Process
, Address
);
3976 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3980 MmDeleteRmap(Page
, Process
, Address
);
3981 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3987 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
3991 PMEMORY_AREA MemoryArea
;
3992 PROS_SECTION_OBJECT Section
;
3993 PMM_SECTION_SEGMENT Segment
;
3994 PLIST_ENTRY CurrentEntry
;
3995 PMM_REGION CurrentRegion
;
3996 PLIST_ENTRY RegionListHead
;
3998 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4000 if (MemoryArea
== NULL
)
4002 return(STATUS_UNSUCCESSFUL
);
4005 MemoryArea
->DeleteInProgress
= TRUE
;
4006 Section
= MemoryArea
->Data
.SectionData
.Section
;
4007 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4009 MmLockSectionSegment(Segment
);
4011 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4012 while (!IsListEmpty(RegionListHead
))
4014 CurrentEntry
= RemoveHeadList(RegionListHead
);
4015 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4016 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4019 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4021 Status
= MmFreeMemoryArea(AddressSpace
,
4028 Status
= MmFreeMemoryArea(AddressSpace
,
4033 MmUnlockSectionSegment(Segment
);
4034 ObDereferenceObject(Section
);
4035 return(STATUS_SUCCESS
);
4042 MmUnmapViewOfSection(PEPROCESS Process
,
4046 PMEMORY_AREA MemoryArea
;
4047 PMMSUPPORT AddressSpace
;
4048 PROS_SECTION_OBJECT Section
;
4051 PVOID ImageBaseAddress
= 0;
4053 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4054 Process
, BaseAddress
);
4058 AddressSpace
= &Process
->Vm
;
4060 MmLockAddressSpace(AddressSpace
);
4061 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4063 if (MemoryArea
== NULL
||
4064 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4065 MemoryArea
->DeleteInProgress
)
4067 MmUnlockAddressSpace(AddressSpace
);
4068 return STATUS_NOT_MAPPED_VIEW
;
4071 MemoryArea
->DeleteInProgress
= TRUE
;
4073 while (MemoryArea
->PageOpCount
)
4075 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4079 Offset
-= PAGE_SIZE
;
4080 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4081 MemoryArea
->Data
.SectionData
.Segment
,
4082 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4085 MmUnlockAddressSpace(AddressSpace
);
4086 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4087 if (Status
!= STATUS_SUCCESS
)
4089 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4090 KeBugCheck(MEMORY_MANAGEMENT
);
4092 MmLockAddressSpace(AddressSpace
);
4093 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4095 if (MemoryArea
== NULL
||
4096 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4098 MmUnlockAddressSpace(AddressSpace
);
4099 return STATUS_NOT_MAPPED_VIEW
;
4106 Section
= MemoryArea
->Data
.SectionData
.Section
;
4108 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4112 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4113 PMM_SECTION_SEGMENT SectionSegments
;
4114 PMM_SECTION_SEGMENT Segment
;
4116 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4117 ImageSectionObject
= Section
->ImageSection
;
4118 SectionSegments
= ImageSectionObject
->Segments
;
4119 NrSegments
= ImageSectionObject
->NrSegments
;
4121 /* Search for the current segment within the section segments
4122 * and calculate the image base address */
4123 for (i
= 0; i
< NrSegments
; i
++)
4125 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4127 if (Segment
== &SectionSegments
[i
])
4129 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4134 if (i
>= NrSegments
)
4136 KeBugCheck(MEMORY_MANAGEMENT
);
4139 for (i
= 0; i
< NrSegments
; i
++)
4141 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4143 PVOID SBaseAddress
= (PVOID
)
4144 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4146 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4152 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4155 MmUnlockAddressSpace(AddressSpace
);
4157 /* Notify debugger */
4158 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4160 return(STATUS_SUCCESS
);
4163 /**********************************************************************
4165 * NtUnmapViewOfSection
4180 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4184 KPROCESSOR_MODE PreviousMode
;
4187 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4188 ProcessHandle
, BaseAddress
);
4190 PreviousMode
= ExGetPreviousMode();
4192 DPRINT("Referencing process\n");
4193 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4194 PROCESS_VM_OPERATION
,
4197 (PVOID
*)(PVOID
)&Process
,
4199 if (!NT_SUCCESS(Status
))
4201 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4205 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4207 ObDereferenceObject(Process
);
4214 * Queries the information of a section object.
4216 * @param SectionHandle
4217 * Handle to the section object. It must be opened with SECTION_QUERY
4219 * @param SectionInformationClass
4220 * Index to a certain information structure. Can be either
4221 * SectionBasicInformation or SectionImageInformation. The latter
4222 * is valid only for sections that were created with the SEC_IMAGE
4224 * @param SectionInformation
4225 * Caller supplies storage for resulting information.
4227 * Size of the supplied storage.
4228 * @param ResultLength
4236 NtQuerySection(IN HANDLE SectionHandle
,
4237 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4238 OUT PVOID SectionInformation
,
4239 IN SIZE_T SectionInformationLength
,
4240 OUT PSIZE_T ResultLength OPTIONAL
)
4242 PROS_SECTION_OBJECT Section
;
4243 KPROCESSOR_MODE PreviousMode
;
4247 PreviousMode
= ExGetPreviousMode();
4249 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4251 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4253 SectionInformationLength
,
4258 if(!NT_SUCCESS(Status
))
4260 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4264 Status
= ObReferenceObjectByHandle(SectionHandle
,
4266 MmSectionObjectType
,
4268 (PVOID
*)(PVOID
)&Section
,
4270 if (NT_SUCCESS(Status
))
4272 switch (SectionInformationClass
)
4274 case SectionBasicInformation
:
4276 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4280 Sbi
->Attributes
= Section
->AllocationAttributes
;
4281 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4283 Sbi
->BaseAddress
= 0;
4284 Sbi
->Size
.QuadPart
= 0;
4288 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4289 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4292 if (ResultLength
!= NULL
)
4294 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4296 Status
= STATUS_SUCCESS
;
4298 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4300 Status
= _SEH2_GetExceptionCode();
4307 case SectionImageInformation
:
4309 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4313 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4314 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4316 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4317 ImageSectionObject
= Section
->ImageSection
;
4319 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4320 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4321 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4322 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4323 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4324 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4325 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4326 Sii
->Machine
= ImageSectionObject
->Machine
;
4327 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4330 if (ResultLength
!= NULL
)
4332 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4334 Status
= STATUS_SUCCESS
;
4336 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4338 Status
= _SEH2_GetExceptionCode();
4346 ObDereferenceObject(Section
);
4354 * Extends size of file backed section.
4356 * @param SectionHandle
4357 * Handle to the section object. It must be opened with
4358 * SECTION_EXTEND_SIZE access.
4359 * @param NewMaximumSize
4360 * New maximum size of the section in bytes.
4364 * @todo Move the actual code to internal function MmExtendSection.
4368 NtExtendSection(IN HANDLE SectionHandle
,
4369 IN PLARGE_INTEGER NewMaximumSize
)
4371 LARGE_INTEGER SafeNewMaximumSize
;
4372 PROS_SECTION_OBJECT Section
;
4373 KPROCESSOR_MODE PreviousMode
;
4376 PreviousMode
= ExGetPreviousMode();
4378 if(PreviousMode
!= KernelMode
)
4382 /* make a copy on the stack */
4383 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4384 NewMaximumSize
= &SafeNewMaximumSize
;
4386 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4388 /* Return the exception code */
4389 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4394 Status
= ObReferenceObjectByHandle(SectionHandle
,
4395 SECTION_EXTEND_SIZE
,
4396 MmSectionObjectType
,
4400 if (!NT_SUCCESS(Status
))
4405 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4407 ObDereferenceObject(Section
);
4408 return STATUS_INVALID_PARAMETER
;
4412 * - Acquire file extneding resource.
4413 * - Check if we're not resizing the section below it's actual size!
4414 * - Extend segments if needed.
4415 * - Set file information (FileAllocationInformation) to the new size.
4416 * - Release file extending resource.
4419 ObDereferenceObject(Section
);
4421 return STATUS_NOT_IMPLEMENTED
;
4424 /**********************************************************************
4426 * MmMapViewOfSection
4429 * Maps a view of a section into the virtual address space of a
4434 * Pointer to the section object.
4437 * Pointer to the process.
4440 * Desired base address (or NULL) on entry;
4441 * Actual base address of the view on exit.
4444 * Number of high order address bits that must be zero.
4447 * Size in bytes of the initially committed section of
4451 * Offset in bytes from the beginning of the section
4452 * to the beginning of the view.
4455 * Desired length of map (or zero to map all) on entry
4456 * Actual length mapped on exit.
4458 * InheritDisposition
4459 * Specified how the view is to be shared with
4463 * Type of allocation for the pages.
4466 * Protection for the committed region of the view.
4474 MmMapViewOfSection(IN PVOID SectionObject
,
4475 IN PEPROCESS Process
,
4476 IN OUT PVOID
*BaseAddress
,
4477 IN ULONG_PTR ZeroBits
,
4478 IN SIZE_T CommitSize
,
4479 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4480 IN OUT PSIZE_T ViewSize
,
4481 IN SECTION_INHERIT InheritDisposition
,
4482 IN ULONG AllocationType
,
4485 PROS_SECTION_OBJECT Section
;
4486 PMMSUPPORT AddressSpace
;
4488 NTSTATUS Status
= STATUS_SUCCESS
;
4492 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4494 return STATUS_INVALID_PAGE_PROTECTION
;
4498 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4499 AddressSpace
= &Process
->Vm
;
4501 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4503 MmLockAddressSpace(AddressSpace
);
4505 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4509 ULONG_PTR ImageBase
;
4511 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4512 PMM_SECTION_SEGMENT SectionSegments
;
4514 ImageSectionObject
= Section
->ImageSection
;
4515 SectionSegments
= ImageSectionObject
->Segments
;
4516 NrSegments
= ImageSectionObject
->NrSegments
;
4519 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4522 ImageBase
= ImageSectionObject
->ImageBase
;
4526 for (i
= 0; i
< NrSegments
; i
++)
4528 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4530 ULONG_PTR MaxExtent
;
4531 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4532 SectionSegments
[i
].Length
;
4533 ImageSize
= max(ImageSize
, MaxExtent
);
4537 ImageSectionObject
->ImageSize
= ImageSize
;
4539 /* Check there is enough space to map the section at that point. */
4540 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4541 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4543 /* Fail if the user requested a fixed base address. */
4544 if ((*BaseAddress
) != NULL
)
4546 MmUnlockAddressSpace(AddressSpace
);
4547 return(STATUS_UNSUCCESSFUL
);
4549 /* Otherwise find a gap to map the image. */
4550 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4553 MmUnlockAddressSpace(AddressSpace
);
4554 return(STATUS_UNSUCCESSFUL
);
4558 for (i
= 0; i
< NrSegments
; i
++)
4560 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4562 PVOID SBaseAddress
= (PVOID
)
4563 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4564 MmLockSectionSegment(&SectionSegments
[i
]);
4565 Status
= MmMapViewOfSegment(AddressSpace
,
4567 &SectionSegments
[i
],
4569 SectionSegments
[i
].Length
,
4570 SectionSegments
[i
].Protection
,
4573 MmUnlockSectionSegment(&SectionSegments
[i
]);
4574 if (!NT_SUCCESS(Status
))
4576 MmUnlockAddressSpace(AddressSpace
);
4582 *BaseAddress
= (PVOID
)ImageBase
;
4586 /* check for write access */
4587 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4588 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4590 MmUnlockAddressSpace(AddressSpace
);
4591 return STATUS_SECTION_PROTECTION
;
4593 /* check for read access */
4594 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4595 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4597 MmUnlockAddressSpace(AddressSpace
);
4598 return STATUS_SECTION_PROTECTION
;
4600 /* check for execute access */
4601 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4602 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4604 MmUnlockAddressSpace(AddressSpace
);
4605 return STATUS_SECTION_PROTECTION
;
4608 if (ViewSize
== NULL
)
4610 /* Following this pointer would lead to us to the dark side */
4611 /* What to do? Bugcheck? Return status? Do the mambo? */
4612 KeBugCheck(MEMORY_MANAGEMENT
);
4615 if (SectionOffset
== NULL
)
4621 ViewOffset
= SectionOffset
->u
.LowPart
;
4624 if ((ViewOffset
% PAGE_SIZE
) != 0)
4626 MmUnlockAddressSpace(AddressSpace
);
4627 return(STATUS_MAPPED_ALIGNMENT
);
4630 if ((*ViewSize
) == 0)
4632 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4634 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4636 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4639 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4641 MmLockSectionSegment(Section
->Segment
);
4642 Status
= MmMapViewOfSegment(AddressSpace
,
4649 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4650 MmUnlockSectionSegment(Section
->Segment
);
4651 if (!NT_SUCCESS(Status
))
4653 MmUnlockAddressSpace(AddressSpace
);
4658 MmUnlockAddressSpace(AddressSpace
);
4660 return(STATUS_SUCCESS
);
4667 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4668 IN PLARGE_INTEGER NewFileSize
)
4670 /* Check whether an ImageSectionObject exists */
4671 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4673 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4677 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4679 PMM_SECTION_SEGMENT Segment
;
4681 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4684 if (Segment
->ReferenceCount
!= 0)
4686 /* Check size of file */
4687 if (SectionObjectPointer
->SharedCacheMap
)
4689 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4690 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4698 /* Something must gone wrong
4699 * how can we have a Section but no
4701 DPRINT("ERROR: DataSectionObject without reference!\n");
4705 DPRINT("FIXME: didn't check for outstanding write probes\n");
4715 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4725 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4726 IN MMFLUSH_TYPE FlushType
)
4730 case MmFlushForDelete
:
4731 if (SectionObjectPointer
->ImageSectionObject
||
4732 SectionObjectPointer
->DataSectionObject
)
4736 CcRosSetRemoveOnClose(SectionObjectPointer
);
4738 case MmFlushForWrite
:
4748 MmForceSectionClosed (
4749 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4750 IN BOOLEAN DelayClose
)
4761 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4762 OUT PVOID
* MappedBase
,
4763 IN OUT PSIZE_T ViewSize
)
4765 PROS_SECTION_OBJECT Section
;
4766 PMMSUPPORT AddressSpace
;
4769 DPRINT("MmMapViewInSystemSpace() called\n");
4771 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4772 AddressSpace
= MmGetKernelAddressSpace();
4774 MmLockAddressSpace(AddressSpace
);
4777 if ((*ViewSize
) == 0)
4779 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4781 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4783 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4786 MmLockSectionSegment(Section
->Segment
);
4789 Status
= MmMapViewOfSegment(AddressSpace
,
4798 MmUnlockSectionSegment(Section
->Segment
);
4799 MmUnlockAddressSpace(AddressSpace
);
4809 MmMapViewInSessionSpace (
4811 OUT PVOID
*MappedBase
,
4812 IN OUT PSIZE_T ViewSize
4816 return STATUS_NOT_IMPLEMENTED
;
4824 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4826 PMMSUPPORT AddressSpace
;
4829 DPRINT("MmUnmapViewInSystemSpace() called\n");
4831 AddressSpace
= MmGetKernelAddressSpace();
4833 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4843 MmUnmapViewInSessionSpace (
4848 return STATUS_NOT_IMPLEMENTED
;
4851 /**********************************************************************
4856 * Creates a section object.
4859 * SectionObject (OUT)
4860 * Caller supplied storage for the resulting pointer
4861 * to a SECTION_OBJECT instance;
4864 * Specifies the desired access to the section can be a
4866 * STANDARD_RIGHTS_REQUIRED |
4868 * SECTION_MAP_WRITE |
4869 * SECTION_MAP_READ |
4870 * SECTION_MAP_EXECUTE
4872 * ObjectAttributes [OPTIONAL]
4873 * Initialized attributes for the object can be used
4874 * to create a named section;
4877 * Maximizes the size of the memory section. Must be
4878 * non-NULL for a page-file backed section.
4879 * If value specified for a mapped file and the file is
4880 * not large enough, file will be extended.
4882 * SectionPageProtection
4883 * Can be a combination of:
4889 * AllocationAttributes
4890 * Can be a combination of:
4895 * Handle to a file to create a section mapped to a file
4896 * instead of a memory backed section;
4907 MmCreateSection (OUT PVOID
* Section
,
4908 IN ACCESS_MASK DesiredAccess
,
4909 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4910 IN PLARGE_INTEGER MaximumSize
,
4911 IN ULONG SectionPageProtection
,
4912 IN ULONG AllocationAttributes
,
4913 IN HANDLE FileHandle OPTIONAL
,
4914 IN PFILE_OBJECT File OPTIONAL
)
4917 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4920 * Check the protection
4922 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4923 if (Protection
!= PAGE_READONLY
&&
4924 Protection
!= PAGE_READWRITE
&&
4925 Protection
!= PAGE_WRITECOPY
&&
4926 Protection
!= PAGE_EXECUTE
&&
4927 Protection
!= PAGE_EXECUTE_READ
&&
4928 Protection
!= PAGE_EXECUTE_READWRITE
&&
4929 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4931 return STATUS_INVALID_PAGE_PROTECTION
;
4934 if (AllocationAttributes
& SEC_IMAGE
)
4936 return(MmCreateImageSection(SectionObject
,
4940 SectionPageProtection
,
4941 AllocationAttributes
,
4945 if (FileHandle
!= NULL
)
4947 return(MmCreateDataFileSection(SectionObject
,
4951 SectionPageProtection
,
4952 AllocationAttributes
,
4956 return(MmCreatePageFileSection(SectionObject
,
4960 SectionPageProtection
,
4961 AllocationAttributes
));
4966 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
4967 IN PVOID File2MappedAsFile
)
4970 return STATUS_NOT_IMPLEMENTED
;