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>
52 #if defined (ALLOC_PRAGMA)
53 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
54 #pragma alloc_text(INIT, MmInitSectionImplementation)
58 /* TYPES *********************************************************************/
62 PROS_SECTION_OBJECT Section
;
63 PMM_SECTION_SEGMENT Segment
;
68 MM_SECTION_PAGEOUT_CONTEXT
;
70 /* GLOBALS *******************************************************************/
72 POBJECT_TYPE MmSectionObjectType
= NULL
;
74 SIZE_T MmAllocationFragment
;
76 ULONG_PTR MmSubsectionBase
;
78 static GENERIC_MAPPING MmpSectionMapping
= {
79 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
80 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
81 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
84 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
85 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
86 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
87 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
88 #define MAX_SHARE_COUNT 0x7FF
89 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
90 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
91 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
93 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
95 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
96 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
99 /* FUNCTIONS *****************************************************************/
103 MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section
)
108 /* Return the file object */
109 return Section
->FileObject
; // Section->ControlArea->FileObject on NT
114 MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section
,
115 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
117 POBJECT_NAME_INFORMATION ObjectNameInfo
;
121 /* Make sure it's an image section */
123 if (!(Section
->AllocationAttributes
& SEC_IMAGE
))
126 return STATUS_SECTION_NOT_IMAGE
;
129 /* Allocate memory for our structure */
130 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
,
133 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
136 Status
= ObQueryNameString(Section
->FileObject
,
140 if (!NT_SUCCESS(Status
))
142 /* Failed, free memory */
143 ExFreePoolWithTag(ObjectNameInfo
, ' mM');
148 *ModuleName
= ObjectNameInfo
;
149 return STATUS_SUCCESS
;
154 MmGetFileNameForAddress(IN PVOID Address
,
155 OUT PUNICODE_STRING ModuleName
)
157 PROS_SECTION_OBJECT Section
;
158 PMEMORY_AREA MemoryArea
;
159 PMMSUPPORT AddressSpace
;
160 POBJECT_NAME_INFORMATION ModuleNameInformation
;
161 NTSTATUS Status
= STATUS_ADDRESS_NOT_ASSOCIATED
;
163 /* Get the MM_AVL_TABLE from EPROCESS */
164 if (Address
>= MmSystemRangeStart
)
166 AddressSpace
= MmGetKernelAddressSpace();
170 AddressSpace
= &PsGetCurrentProcess()->Vm
;
173 /* Lock address space */
174 MmLockAddressSpace(AddressSpace
);
176 /* Locate the memory area for the process by address */
177 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
179 /* Make sure it's a section view type */
180 if ((MemoryArea
!= NULL
) && (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
))
182 /* Get the section pointer to the SECTION_OBJECT */
183 Section
= MemoryArea
->Data
.SectionData
.Section
;
185 /* Unlock address space */
186 MmUnlockAddressSpace(AddressSpace
);
188 /* Get the filename of the section */
189 Status
= MmGetFileNameForSection(Section
,&ModuleNameInformation
);
191 if (NT_SUCCESS(Status
))
193 /* Init modulename */
194 RtlCreateUnicodeString(ModuleName
,
195 ModuleNameInformation
->Name
.Buffer
);
197 /* Free temp taged buffer from MmGetFileNameForSection() */
198 ExFreePoolWithTag(ModuleNameInformation
, ' mM');
199 DPRINT("Found ModuleName %S by address %p\n",
200 ModuleName
->Buffer
,Address
);
205 /* Unlock address space */
206 MmUnlockAddressSpace(AddressSpace
);
212 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
215 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
216 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
217 * RETURNS: Status of the wait.
220 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
222 LARGE_INTEGER Timeout
;
223 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
225 Timeout
.QuadPart
= -100000000LL; // 10 sec
228 Timeout
.QuadPart
= -100000000; // 10 sec
231 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
236 * FUNCTION: Sets the page op completion event and releases the page op.
237 * ARGUMENTS: PMM_PAGEOP.
238 * RETURNS: In shorter time than it takes you to even read this
239 * description, so don't even think about geting a mug of coffee.
242 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
244 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
245 MmReleasePageOp(PageOp
);
250 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
251 * ARGUMENTS: PFILE_OBJECT to wait for.
252 * RETURNS: Status of the wait.
255 MmspWaitForFileLock(PFILE_OBJECT File
)
257 return STATUS_SUCCESS
;
258 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
263 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
266 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
268 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
270 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
272 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
280 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
282 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
284 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
285 PMM_SECTION_SEGMENT SectionSegments
;
289 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
290 NrSegments
= ImageSectionObject
->NrSegments
;
291 SectionSegments
= ImageSectionObject
->Segments
;
292 for (i
= 0; i
< NrSegments
; i
++)
294 if (SectionSegments
[i
].ReferenceCount
!= 0)
296 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
297 SectionSegments
[i
].ReferenceCount
);
298 KeBugCheck(MEMORY_MANAGEMENT
);
300 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
302 ExFreePool(ImageSectionObject
->Segments
);
303 ExFreePool(ImageSectionObject
);
304 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
306 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
308 PMM_SECTION_SEGMENT Segment
;
310 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
313 if (Segment
->ReferenceCount
!= 0)
315 DPRINT1("Data segment still referenced\n");
316 KeBugCheck(MEMORY_MANAGEMENT
);
318 MmFreePageTablesSectionSegment(Segment
);
320 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
326 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
328 ExAcquireFastMutex(&Segment
->Lock
);
333 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
335 ExReleaseFastMutex(&Segment
->Lock
);
340 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
344 PSECTION_PAGE_TABLE Table
;
345 ULONG DirectoryOffset
;
348 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
350 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
354 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
355 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
359 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
360 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
361 TAG_SECTION_PAGE_TABLE
);
364 KeBugCheck(MEMORY_MANAGEMENT
);
366 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
367 DPRINT("Table %x\n", Table
);
370 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
371 Table
->Entry
[TableOffset
] = Entry
;
377 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
380 PSECTION_PAGE_TABLE Table
;
382 ULONG DirectoryOffset
;
385 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
387 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
389 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
393 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
394 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
395 DPRINT("Table %x\n", Table
);
401 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
402 Entry
= Table
->Entry
[TableOffset
];
408 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
413 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
416 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
417 KeBugCheck(MEMORY_MANAGEMENT
);
419 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
421 DPRINT1("Maximum share count reached\n");
422 KeBugCheck(MEMORY_MANAGEMENT
);
424 if (IS_SWAP_FROM_SSE(Entry
))
426 KeBugCheck(MEMORY_MANAGEMENT
);
428 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
429 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
434 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
435 PMM_SECTION_SEGMENT Segment
,
441 BOOLEAN IsDirectMapped
= FALSE
;
443 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
446 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
447 KeBugCheck(MEMORY_MANAGEMENT
);
449 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
451 DPRINT1("Zero share count for unshare\n");
452 KeBugCheck(MEMORY_MANAGEMENT
);
454 if (IS_SWAP_FROM_SSE(Entry
))
456 KeBugCheck(MEMORY_MANAGEMENT
);
458 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
460 * If we reducing the share count of this entry to zero then set the entry
461 * to zero and tell the cache the page is no longer mapped.
463 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
465 PFILE_OBJECT FileObject
;
467 SWAPENTRY SavedSwapEntry
;
469 BOOLEAN IsImageSection
;
472 FileOffset
= Offset
+ Segment
->FileOffset
;
474 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
476 Page
= PFN_FROM_SSE(Entry
);
477 FileObject
= Section
->FileObject
;
478 if (FileObject
!= NULL
&&
479 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
482 if ((FileOffset
% PAGE_SIZE
) == 0 &&
483 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
486 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
487 IsDirectMapped
= TRUE
;
488 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
489 if (!NT_SUCCESS(Status
))
491 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
492 KeBugCheck(MEMORY_MANAGEMENT
);
497 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
498 if (SavedSwapEntry
== 0)
501 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
502 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
506 * Try to page out this page and set the swap entry
507 * within the section segment. There exist no rmap entry
508 * for this page. The pager thread can't page out a
509 * page without a rmap entry.
511 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
515 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
518 MmReleasePageMemoryConsumer(MC_USER
, Page
);
524 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
525 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
533 * We hold all locks. Nobody can do something with the current
534 * process and the current segment (also not within an other process).
537 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
538 if (!NT_SUCCESS(Status
))
540 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
541 KeBugCheck(MEMORY_MANAGEMENT
);
544 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
545 MmSetSavedSwapEntryPage(Page
, 0);
547 MmReleasePageMemoryConsumer(MC_USER
, Page
);
551 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
552 KeBugCheck(MEMORY_MANAGEMENT
);
558 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
560 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
563 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
566 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
569 PCACHE_SEGMENT CacheSeg
;
570 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
571 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
574 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
583 MiCopyFromUserPage(PFN_NUMBER DestPage
, PVOID SourceAddress
)
589 Process
= PsGetCurrentProcess();
590 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
591 if (TempAddress
== NULL
)
593 return(STATUS_NO_MEMORY
);
595 memcpy(TempAddress
, SourceAddress
, PAGE_SIZE
);
596 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
597 return(STATUS_SUCCESS
);
602 MiReadPage(PMEMORY_AREA MemoryArea
,
606 * FUNCTION: Read a page for a section backed memory area.
608 * MemoryArea - Memory area to read the page for.
609 * Offset - Offset of the page to read.
610 * Page - Variable that receives a page contains the read data.
617 PCACHE_SEGMENT CacheSeg
;
618 PFILE_OBJECT FileObject
;
622 BOOLEAN IsImageSection
;
625 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
626 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
627 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
628 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
629 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
633 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
636 * If the file system is letting us go directly to the cache and the
637 * memory area was mapped at an offset in the file which is page aligned
638 * then get the related cache segment.
640 if ((FileOffset
% PAGE_SIZE
) == 0 &&
641 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
642 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
646 * Get the related cache segment; we use a lower level interface than
647 * filesystems do because it is safe for us to use an offset with a
648 * alignment less than the file system block size.
650 Status
= CcRosGetCacheSegment(Bcb
,
656 if (!NT_SUCCESS(Status
))
663 * If the cache segment isn't up to date then call the file
664 * system to read in the data.
666 Status
= ReadCacheSegment(CacheSeg
);
667 if (!NT_SUCCESS(Status
))
669 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
674 * Retrieve the page from the cache segment that we actually want.
676 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
677 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
679 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
686 ULONG CacheSegOffset
;
689 * Allocate a page, this is rather complicated by the possibility
690 * we might have to move other things out of memory
692 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
693 if (!NT_SUCCESS(Status
))
697 Status
= CcRosGetCacheSegment(Bcb
,
703 if (!NT_SUCCESS(Status
))
710 * If the cache segment isn't up to date then call the file
711 * system to read in the data.
713 Status
= ReadCacheSegment(CacheSeg
);
714 if (!NT_SUCCESS(Status
))
716 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
721 Process
= PsGetCurrentProcess();
722 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
723 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
724 Length
= RawLength
- SegOffset
;
725 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
727 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
729 else if (CacheSegOffset
>= PAGE_SIZE
)
731 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
735 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
736 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
737 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
738 Status
= CcRosGetCacheSegment(Bcb
,
739 FileOffset
+ CacheSegOffset
,
744 if (!NT_SUCCESS(Status
))
751 * If the cache segment isn't up to date then call the file
752 * system to read in the data.
754 Status
= ReadCacheSegment(CacheSeg
);
755 if (!NT_SUCCESS(Status
))
757 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
761 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
762 if (Length
< PAGE_SIZE
)
764 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
768 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
771 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
772 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
774 return(STATUS_SUCCESS
);
779 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
780 MEMORY_AREA
* MemoryArea
,
788 PROS_SECTION_OBJECT Section
;
789 PMM_SECTION_SEGMENT Segment
;
795 BOOLEAN HasSwapEntry
;
796 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
799 * There is a window between taking the page fault and locking the
800 * address space when another thread could load the page so we check
803 if (MmIsPagePresent(Process
, Address
))
805 return(STATUS_SUCCESS
);
808 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
809 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
810 + MemoryArea
->Data
.SectionData
.ViewOffset
;
812 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
813 Section
= MemoryArea
->Data
.SectionData
.Section
;
814 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
815 &MemoryArea
->Data
.SectionData
.RegionListHead
,
820 MmLockSectionSegment(Segment
);
823 * Check if this page needs to be mapped COW
825 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
826 (Region
->Protect
== PAGE_READWRITE
||
827 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
829 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
833 Attributes
= Region
->Protect
;
837 * Get or create a page operation descriptor
839 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
842 DPRINT1("MmGetPageOp failed\n");
843 KeBugCheck(MEMORY_MANAGEMENT
);
847 * Check if someone else is already handling this fault, if so wait
850 if (PageOp
->Thread
!= PsGetCurrentThread())
852 MmUnlockSectionSegment(Segment
);
853 MmUnlockAddressSpace(AddressSpace
);
854 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
856 * Check for various strange conditions
858 if (Status
!= STATUS_SUCCESS
)
860 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
861 KeBugCheck(MEMORY_MANAGEMENT
);
863 if (PageOp
->Status
== STATUS_PENDING
)
865 DPRINT1("Woke for page op before completion\n");
866 KeBugCheck(MEMORY_MANAGEMENT
);
868 MmLockAddressSpace(AddressSpace
);
870 * If this wasn't a pagein then restart the operation
872 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
874 MmspCompleteAndReleasePageOp(PageOp
);
875 DPRINT("Address 0x%.8X\n", Address
);
876 return(STATUS_MM_RESTART_OPERATION
);
880 * If the thread handling this fault has failed then we don't retry
882 if (!NT_SUCCESS(PageOp
->Status
))
884 Status
= PageOp
->Status
;
885 MmspCompleteAndReleasePageOp(PageOp
);
886 DPRINT("Address 0x%.8X\n", Address
);
889 MmLockSectionSegment(Segment
);
891 * If the completed fault was for another address space then set the
894 if (!MmIsPagePresent(Process
, Address
))
896 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
897 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
899 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
902 * The page was a private page in another or in our address space
904 MmUnlockSectionSegment(Segment
);
905 MmspCompleteAndReleasePageOp(PageOp
);
906 return(STATUS_MM_RESTART_OPERATION
);
909 Page
= PFN_FROM_SSE(Entry
);
911 MmSharePageEntrySectionSegment(Segment
, Offset
);
913 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
914 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
916 Status
= MmCreateVirtualMapping(Process
,
921 if (!NT_SUCCESS(Status
))
923 DPRINT1("Unable to create virtual mapping\n");
924 KeBugCheck(MEMORY_MANAGEMENT
);
926 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
928 MmUnlockSectionSegment(Segment
);
929 PageOp
->Status
= STATUS_SUCCESS
;
930 MmspCompleteAndReleasePageOp(PageOp
);
931 DPRINT("Address 0x%.8X\n", Address
);
932 return(STATUS_SUCCESS
);
935 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
939 * Must be private page we have swapped out.
946 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
948 DPRINT1("Found a swaped out private page in a pagefile section.\n");
949 KeBugCheck(MEMORY_MANAGEMENT
);
952 MmUnlockSectionSegment(Segment
);
953 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
955 MmUnlockAddressSpace(AddressSpace
);
956 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
957 if (!NT_SUCCESS(Status
))
959 KeBugCheck(MEMORY_MANAGEMENT
);
962 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
963 if (!NT_SUCCESS(Status
))
965 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
966 KeBugCheck(MEMORY_MANAGEMENT
);
968 MmLockAddressSpace(AddressSpace
);
969 Status
= MmCreateVirtualMapping(Process
,
974 if (!NT_SUCCESS(Status
))
976 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
977 KeBugCheck(MEMORY_MANAGEMENT
);
982 * Store the swap entry for later use.
984 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
987 * Add the page to the process's working set
989 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
992 * Finish the operation
994 PageOp
->Status
= STATUS_SUCCESS
;
995 MmspCompleteAndReleasePageOp(PageOp
);
996 DPRINT("Address 0x%.8X\n", Address
);
997 return(STATUS_SUCCESS
);
1001 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1003 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1005 MmUnlockSectionSegment(Segment
);
1007 * Just map the desired physical page
1009 Page
= Offset
>> PAGE_SHIFT
;
1010 Status
= MmCreateVirtualMappingUnsafe(Process
,
1015 if (!NT_SUCCESS(Status
))
1017 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1018 KeBugCheck(MEMORY_MANAGEMENT
);
1023 * Cleanup and release locks
1025 PageOp
->Status
= STATUS_SUCCESS
;
1026 MmspCompleteAndReleasePageOp(PageOp
);
1027 DPRINT("Address 0x%.8X\n", Address
);
1028 return(STATUS_SUCCESS
);
1032 * Map anonymous memory for BSS sections
1034 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1036 MmUnlockSectionSegment(Segment
);
1037 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1038 if (!NT_SUCCESS(Status
))
1040 MmUnlockAddressSpace(AddressSpace
);
1041 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1042 MmLockAddressSpace(AddressSpace
);
1044 if (!NT_SUCCESS(Status
))
1046 KeBugCheck(MEMORY_MANAGEMENT
);
1048 Status
= MmCreateVirtualMapping(Process
,
1053 if (!NT_SUCCESS(Status
))
1055 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1056 KeBugCheck(MEMORY_MANAGEMENT
);
1059 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1062 * Cleanup and release locks
1064 PageOp
->Status
= STATUS_SUCCESS
;
1065 MmspCompleteAndReleasePageOp(PageOp
);
1066 DPRINT("Address 0x%.8X\n", Address
);
1067 return(STATUS_SUCCESS
);
1071 * Get the entry corresponding to the offset within the section
1073 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1078 * If the entry is zero (and it can't change because we have
1079 * locked the segment) then we need to load the page.
1083 * Release all our locks and read in the page from disk
1085 MmUnlockSectionSegment(Segment
);
1086 MmUnlockAddressSpace(AddressSpace
);
1088 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1089 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1091 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1092 if (!NT_SUCCESS(Status
))
1094 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1099 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1100 if (!NT_SUCCESS(Status
))
1102 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1105 if (!NT_SUCCESS(Status
))
1108 * FIXME: What do we know in this case?
1111 * Cleanup and release locks
1113 MmLockAddressSpace(AddressSpace
);
1114 PageOp
->Status
= Status
;
1115 MmspCompleteAndReleasePageOp(PageOp
);
1116 DPRINT("Address 0x%.8X\n", Address
);
1120 * Relock the address space and segment
1122 MmLockAddressSpace(AddressSpace
);
1123 MmLockSectionSegment(Segment
);
1126 * Check the entry. No one should change the status of a page
1127 * that has a pending page-in.
1129 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1130 if (Entry
!= Entry1
)
1132 DPRINT1("Someone changed ppte entry while we slept\n");
1133 KeBugCheck(MEMORY_MANAGEMENT
);
1137 * Mark the offset within the section as having valid, in-memory
1140 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1141 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1142 MmUnlockSectionSegment(Segment
);
1144 Status
= MmCreateVirtualMapping(Process
,
1149 if (!NT_SUCCESS(Status
))
1151 DPRINT1("Unable to create virtual mapping\n");
1152 KeBugCheck(MEMORY_MANAGEMENT
);
1154 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1156 PageOp
->Status
= STATUS_SUCCESS
;
1157 MmspCompleteAndReleasePageOp(PageOp
);
1158 DPRINT("Address 0x%.8X\n", Address
);
1159 return(STATUS_SUCCESS
);
1161 else if (IS_SWAP_FROM_SSE(Entry
))
1163 SWAPENTRY SwapEntry
;
1165 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1168 * Release all our locks and read in the page from disk
1170 MmUnlockSectionSegment(Segment
);
1172 MmUnlockAddressSpace(AddressSpace
);
1174 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1175 if (!NT_SUCCESS(Status
))
1177 KeBugCheck(MEMORY_MANAGEMENT
);
1180 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1181 if (!NT_SUCCESS(Status
))
1183 KeBugCheck(MEMORY_MANAGEMENT
);
1187 * Relock the address space and segment
1189 MmLockAddressSpace(AddressSpace
);
1190 MmLockSectionSegment(Segment
);
1193 * Check the entry. No one should change the status of a page
1194 * that has a pending page-in.
1196 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1197 if (Entry
!= Entry1
)
1199 DPRINT1("Someone changed ppte entry while we slept\n");
1200 KeBugCheck(MEMORY_MANAGEMENT
);
1204 * Mark the offset within the section as having valid, in-memory
1207 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1208 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1209 MmUnlockSectionSegment(Segment
);
1212 * Save the swap entry.
1214 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1215 Status
= MmCreateVirtualMapping(Process
,
1220 if (!NT_SUCCESS(Status
))
1222 DPRINT1("Unable to create virtual mapping\n");
1223 KeBugCheck(MEMORY_MANAGEMENT
);
1225 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1226 PageOp
->Status
= STATUS_SUCCESS
;
1227 MmspCompleteAndReleasePageOp(PageOp
);
1228 DPRINT("Address 0x%.8X\n", Address
);
1229 return(STATUS_SUCCESS
);
1234 * If the section offset is already in-memory and valid then just
1235 * take another reference to the page
1238 Page
= PFN_FROM_SSE(Entry
);
1240 MmSharePageEntrySectionSegment(Segment
, Offset
);
1241 MmUnlockSectionSegment(Segment
);
1243 Status
= MmCreateVirtualMapping(Process
,
1248 if (!NT_SUCCESS(Status
))
1250 DPRINT1("Unable to create virtual mapping\n");
1251 KeBugCheck(MEMORY_MANAGEMENT
);
1253 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1254 PageOp
->Status
= STATUS_SUCCESS
;
1255 MmspCompleteAndReleasePageOp(PageOp
);
1256 DPRINT("Address 0x%.8X\n", Address
);
1257 return(STATUS_SUCCESS
);
1263 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1264 MEMORY_AREA
* MemoryArea
,
1268 PMM_SECTION_SEGMENT Segment
;
1269 PROS_SECTION_OBJECT Section
;
1278 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1280 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1283 * Check if the page has been paged out or has already been set readwrite
1285 if (!MmIsPagePresent(Process
, Address
) ||
1286 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1288 DPRINT("Address 0x%.8X\n", Address
);
1289 return(STATUS_SUCCESS
);
1293 * Find the offset of the page
1295 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1296 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1297 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1299 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1300 Section
= MemoryArea
->Data
.SectionData
.Section
;
1301 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1302 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1307 MmLockSectionSegment(Segment
);
1309 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1310 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1312 MmUnlockSectionSegment(Segment
);
1315 * Check if we are doing COW
1317 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1318 (Region
->Protect
== PAGE_READWRITE
||
1319 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1321 DPRINT("Address 0x%.8X\n", Address
);
1322 return(STATUS_ACCESS_VIOLATION
);
1325 if (IS_SWAP_FROM_SSE(Entry
) ||
1326 PFN_FROM_SSE(Entry
) != OldPage
)
1328 /* This is a private page. We must only change the page protection. */
1329 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1330 return(STATUS_SUCCESS
);
1334 * Get or create a pageop
1336 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1337 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1340 DPRINT1("MmGetPageOp failed\n");
1341 KeBugCheck(MEMORY_MANAGEMENT
);
1345 * Wait for any other operations to complete
1347 if (PageOp
->Thread
!= PsGetCurrentThread())
1349 MmUnlockAddressSpace(AddressSpace
);
1350 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1352 * Check for various strange conditions
1354 if (Status
== STATUS_TIMEOUT
)
1356 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1357 KeBugCheck(MEMORY_MANAGEMENT
);
1359 if (PageOp
->Status
== STATUS_PENDING
)
1361 DPRINT1("Woke for page op before completion\n");
1362 KeBugCheck(MEMORY_MANAGEMENT
);
1365 * Restart the operation
1367 MmLockAddressSpace(AddressSpace
);
1368 MmspCompleteAndReleasePageOp(PageOp
);
1369 DPRINT("Address 0x%.8X\n", Address
);
1370 return(STATUS_MM_RESTART_OPERATION
);
1374 * Release locks now we have the pageop
1376 MmUnlockAddressSpace(AddressSpace
);
1381 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1382 if (!NT_SUCCESS(Status
))
1384 KeBugCheck(MEMORY_MANAGEMENT
);
1390 MiCopyFromUserPage(NewPage
, PAddress
);
1392 MmLockAddressSpace(AddressSpace
);
1394 * Delete the old entry.
1396 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1399 * Set the PTE to point to the new page
1401 Status
= MmCreateVirtualMapping(Process
,
1406 if (!NT_SUCCESS(Status
))
1408 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1409 KeBugCheck(MEMORY_MANAGEMENT
);
1412 if (!NT_SUCCESS(Status
))
1414 DPRINT1("Unable to create virtual mapping\n");
1415 KeBugCheck(MEMORY_MANAGEMENT
);
1419 * Unshare the old page.
1421 MmDeleteRmap(OldPage
, Process
, PAddress
);
1422 MmInsertRmap(NewPage
, Process
, PAddress
);
1423 MmLockSectionSegment(Segment
);
1424 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1425 MmUnlockSectionSegment(Segment
);
1427 PageOp
->Status
= STATUS_SUCCESS
;
1428 MmspCompleteAndReleasePageOp(PageOp
);
1429 DPRINT("Address 0x%.8X\n", Address
);
1430 return(STATUS_SUCCESS
);
1434 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1436 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1440 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1443 MmLockAddressSpace(&Process
->Vm
);
1446 MmDeleteVirtualMapping(Process
,
1453 PageOutContext
->WasDirty
= TRUE
;
1455 if (!PageOutContext
->Private
)
1457 MmLockSectionSegment(PageOutContext
->Segment
);
1458 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1459 PageOutContext
->Segment
,
1460 PageOutContext
->Offset
,
1461 PageOutContext
->WasDirty
,
1463 MmUnlockSectionSegment(PageOutContext
->Segment
);
1467 MmUnlockAddressSpace(&Process
->Vm
);
1470 if (PageOutContext
->Private
)
1472 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1475 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1480 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1481 MEMORY_AREA
* MemoryArea
,
1486 MM_SECTION_PAGEOUT_CONTEXT Context
;
1487 SWAPENTRY SwapEntry
;
1491 PFILE_OBJECT FileObject
;
1493 BOOLEAN DirectMapped
;
1494 BOOLEAN IsImageSection
;
1495 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1498 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1501 * Get the segment and section.
1503 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1504 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1506 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1507 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1508 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1510 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1512 FileObject
= Context
.Section
->FileObject
;
1513 DirectMapped
= FALSE
;
1514 if (FileObject
!= NULL
&&
1515 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1517 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1520 * If the file system is letting us go directly to the cache and the
1521 * memory area was mapped at an offset in the file which is page aligned
1522 * then note this is a direct mapped page.
1524 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1525 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1527 DirectMapped
= TRUE
;
1533 * This should never happen since mappings of physical memory are never
1534 * placed in the rmap lists.
1536 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1538 DPRINT1("Trying to page out from physical memory section address 0x%X "
1539 "process %d\n", Address
,
1540 Process
? Process
->UniqueProcessId
: 0);
1541 KeBugCheck(MEMORY_MANAGEMENT
);
1545 * Get the section segment entry and the physical address.
1547 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1548 if (!MmIsPagePresent(Process
, Address
))
1550 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1551 Process
? Process
->UniqueProcessId
: 0, Address
);
1552 KeBugCheck(MEMORY_MANAGEMENT
);
1554 Page
= MmGetPfnForProcess(Process
, Address
);
1555 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1558 * Prepare the context structure for the rmap delete call.
1560 Context
.WasDirty
= FALSE
;
1561 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1562 IS_SWAP_FROM_SSE(Entry
) ||
1563 PFN_FROM_SSE(Entry
) != Page
)
1565 Context
.Private
= TRUE
;
1569 Context
.Private
= FALSE
;
1573 * Take an additional reference to the page or the cache segment.
1575 if (DirectMapped
&& !Context
.Private
)
1577 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1579 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1580 KeBugCheck(MEMORY_MANAGEMENT
);
1585 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1586 MmReferencePage(Page
);
1587 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1590 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1593 * If this wasn't a private page then we should have reduced the entry to
1594 * zero by deleting all the rmaps.
1596 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1598 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1599 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1601 KeBugCheck(MEMORY_MANAGEMENT
);
1606 * If the page wasn't dirty then we can just free it as for a readonly page.
1607 * Since we unmapped all the mappings above we know it will not suddenly
1609 * If the page is from a pagefile section and has no swap entry,
1610 * we can't free the page at this point.
1612 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1613 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1615 if (Context
.Private
)
1617 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1618 Context
.WasDirty
? "dirty" : "clean", Address
);
1619 KeBugCheck(MEMORY_MANAGEMENT
);
1621 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1623 MmSetSavedSwapEntryPage(Page
, 0);
1624 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1625 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1626 PageOp
->Status
= STATUS_SUCCESS
;
1627 MmspCompleteAndReleasePageOp(PageOp
);
1628 return(STATUS_SUCCESS
);
1631 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1633 if (Context
.Private
)
1635 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1636 Context
.WasDirty
? "dirty" : "clean", Address
);
1637 KeBugCheck(MEMORY_MANAGEMENT
);
1639 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1641 MmSetSavedSwapEntryPage(Page
, 0);
1644 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1646 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1647 PageOp
->Status
= STATUS_SUCCESS
;
1648 MmspCompleteAndReleasePageOp(PageOp
);
1649 return(STATUS_SUCCESS
);
1652 else if (!Context
.Private
&& DirectMapped
)
1656 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1658 KeBugCheck(MEMORY_MANAGEMENT
);
1660 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1661 if (!NT_SUCCESS(Status
))
1663 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1664 KeBugCheck(MEMORY_MANAGEMENT
);
1666 PageOp
->Status
= STATUS_SUCCESS
;
1667 MmspCompleteAndReleasePageOp(PageOp
);
1668 return(STATUS_SUCCESS
);
1670 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1674 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1676 KeBugCheck(MEMORY_MANAGEMENT
);
1678 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1679 PageOp
->Status
= STATUS_SUCCESS
;
1680 MmspCompleteAndReleasePageOp(PageOp
);
1681 return(STATUS_SUCCESS
);
1683 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1685 MmSetSavedSwapEntryPage(Page
, 0);
1686 MmLockAddressSpace(AddressSpace
);
1687 Status
= MmCreatePageFileMapping(Process
,
1690 MmUnlockAddressSpace(AddressSpace
);
1691 if (!NT_SUCCESS(Status
))
1693 KeBugCheck(MEMORY_MANAGEMENT
);
1695 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1696 PageOp
->Status
= STATUS_SUCCESS
;
1697 MmspCompleteAndReleasePageOp(PageOp
);
1698 return(STATUS_SUCCESS
);
1702 * If necessary, allocate an entry in the paging file for this page
1706 SwapEntry
= MmAllocSwapPage();
1709 MmShowOutOfSpaceMessagePagingFile();
1710 MmLockAddressSpace(AddressSpace
);
1712 * For private pages restore the old mappings.
1714 if (Context
.Private
)
1716 Status
= MmCreateVirtualMapping(Process
,
1718 MemoryArea
->Protect
,
1721 MmSetDirtyPage(Process
, Address
);
1729 * For non-private pages if the page wasn't direct mapped then
1730 * set it back into the section segment entry so we don't loose
1731 * our copy. Otherwise it will be handled by the cache manager.
1733 Status
= MmCreateVirtualMapping(Process
,
1735 MemoryArea
->Protect
,
1738 MmSetDirtyPage(Process
, Address
);
1742 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1743 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1745 MmUnlockAddressSpace(AddressSpace
);
1746 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1747 MmspCompleteAndReleasePageOp(PageOp
);
1748 return(STATUS_PAGEFILE_QUOTA
);
1753 * Write the page to the pagefile
1755 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1756 if (!NT_SUCCESS(Status
))
1758 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1761 * As above: undo our actions.
1762 * FIXME: Also free the swap page.
1764 MmLockAddressSpace(AddressSpace
);
1765 if (Context
.Private
)
1767 Status
= MmCreateVirtualMapping(Process
,
1769 MemoryArea
->Protect
,
1772 MmSetDirtyPage(Process
, Address
);
1779 Status
= MmCreateVirtualMapping(Process
,
1781 MemoryArea
->Protect
,
1784 MmSetDirtyPage(Process
, Address
);
1788 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1789 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1791 MmUnlockAddressSpace(AddressSpace
);
1792 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1793 MmspCompleteAndReleasePageOp(PageOp
);
1794 return(STATUS_UNSUCCESSFUL
);
1798 * Otherwise we have succeeded.
1800 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1801 MmSetSavedSwapEntryPage(Page
, 0);
1802 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1803 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1805 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1809 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1812 if (Context
.Private
)
1814 MmLockAddressSpace(AddressSpace
);
1815 Status
= MmCreatePageFileMapping(Process
,
1818 MmUnlockAddressSpace(AddressSpace
);
1819 if (!NT_SUCCESS(Status
))
1821 KeBugCheck(MEMORY_MANAGEMENT
);
1826 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1827 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1830 PageOp
->Status
= STATUS_SUCCESS
;
1831 MmspCompleteAndReleasePageOp(PageOp
);
1832 return(STATUS_SUCCESS
);
1837 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
1838 PMEMORY_AREA MemoryArea
,
1843 PROS_SECTION_OBJECT Section
;
1844 PMM_SECTION_SEGMENT Segment
;
1846 SWAPENTRY SwapEntry
;
1850 PFILE_OBJECT FileObject
;
1852 BOOLEAN DirectMapped
;
1853 BOOLEAN IsImageSection
;
1854 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1856 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1858 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1859 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1862 * Get the segment and section.
1864 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1865 Section
= MemoryArea
->Data
.SectionData
.Section
;
1866 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1868 FileObject
= Section
->FileObject
;
1869 DirectMapped
= FALSE
;
1870 if (FileObject
!= NULL
&&
1871 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1873 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1876 * If the file system is letting us go directly to the cache and the
1877 * memory area was mapped at an offset in the file which is page aligned
1878 * then note this is a direct mapped page.
1880 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1881 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1883 DirectMapped
= TRUE
;
1888 * This should never happen since mappings of physical memory are never
1889 * placed in the rmap lists.
1891 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1893 DPRINT1("Trying to write back page from physical memory mapped at %X "
1894 "process %d\n", Address
,
1895 Process
? Process
->UniqueProcessId
: 0);
1896 KeBugCheck(MEMORY_MANAGEMENT
);
1900 * Get the section segment entry and the physical address.
1902 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1903 if (!MmIsPagePresent(Process
, Address
))
1905 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1906 Process
? Process
->UniqueProcessId
: 0, Address
);
1907 KeBugCheck(MEMORY_MANAGEMENT
);
1909 Page
= MmGetPfnForProcess(Process
, Address
);
1910 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1913 * Check for a private (COWed) page.
1915 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1916 IS_SWAP_FROM_SSE(Entry
) ||
1917 PFN_FROM_SSE(Entry
) != Page
)
1927 * Speculatively set all mappings of the page to clean.
1929 MmSetCleanAllRmaps(Page
);
1932 * If this page was direct mapped from the cache then the cache manager
1933 * will take care of writing it back to disk.
1935 if (DirectMapped
&& !Private
)
1937 ASSERT(SwapEntry
== 0);
1938 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1939 PageOp
->Status
= STATUS_SUCCESS
;
1940 MmspCompleteAndReleasePageOp(PageOp
);
1941 return(STATUS_SUCCESS
);
1945 * If necessary, allocate an entry in the paging file for this page
1949 SwapEntry
= MmAllocSwapPage();
1952 MmSetDirtyAllRmaps(Page
);
1953 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1954 MmspCompleteAndReleasePageOp(PageOp
);
1955 return(STATUS_PAGEFILE_QUOTA
);
1957 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1961 * Write the page to the pagefile
1963 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1964 if (!NT_SUCCESS(Status
))
1966 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1968 MmSetDirtyAllRmaps(Page
);
1969 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1970 MmspCompleteAndReleasePageOp(PageOp
);
1971 return(STATUS_UNSUCCESSFUL
);
1975 * Otherwise we have succeeded.
1977 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1978 PageOp
->Status
= STATUS_SUCCESS
;
1979 MmspCompleteAndReleasePageOp(PageOp
);
1980 return(STATUS_SUCCESS
);
1984 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
1992 PMEMORY_AREA MemoryArea
;
1993 PMM_SECTION_SEGMENT Segment
;
1994 BOOLEAN DoCOW
= FALSE
;
1996 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1998 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1999 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2001 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
2002 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2007 if (OldProtect
!= NewProtect
)
2009 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2011 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2012 ULONG Protect
= NewProtect
;
2015 * If we doing COW for this segment then check if the page is
2018 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2024 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2025 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2026 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2027 Page
= MmGetPfnForProcess(Process
, Address
);
2029 Protect
= PAGE_READONLY
;
2030 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2031 IS_SWAP_FROM_SSE(Entry
) ||
2032 PFN_FROM_SSE(Entry
) != Page
)
2034 Protect
= NewProtect
;
2038 if (MmIsPagePresent(Process
, Address
))
2040 MmSetPageProtect(Process
, Address
,
2049 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2050 PMEMORY_AREA MemoryArea
,
2058 ULONG_PTR MaxLength
;
2060 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2061 if (Length
> MaxLength
)
2064 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2065 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2067 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2068 Region
->Protect
!= Protect
)
2070 return STATUS_INVALID_PAGE_PROTECTION
;
2073 *OldProtect
= Region
->Protect
;
2074 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2075 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2076 BaseAddress
, Length
, Region
->Type
, Protect
,
2077 MmAlterViewAttributes
);
2083 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2085 PMEMORY_BASIC_INFORMATION Info
,
2086 PSIZE_T ResultLength
)
2089 PVOID RegionBaseAddress
;
2090 PROS_SECTION_OBJECT Section
;
2091 PMM_SECTION_SEGMENT Segment
;
2093 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2094 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2095 Address
, &RegionBaseAddress
);
2098 return STATUS_UNSUCCESSFUL
;
2101 Section
= MemoryArea
->Data
.SectionData
.Section
;
2102 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2104 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2105 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2106 Info
->Type
= MEM_IMAGE
;
2110 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2111 Info
->Type
= MEM_MAPPED
;
2113 Info
->BaseAddress
= RegionBaseAddress
;
2114 Info
->AllocationProtect
= MemoryArea
->Protect
;
2115 Info
->RegionSize
= Region
->Length
;
2116 Info
->State
= MEM_COMMIT
;
2117 Info
->Protect
= Region
->Protect
;
2119 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2120 return(STATUS_SUCCESS
);
2125 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2130 ULONG SavedSwapEntry
;
2135 Length
= PAGE_ROUND_UP(Segment
->Length
);
2136 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2138 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2141 if (IS_SWAP_FROM_SSE(Entry
))
2143 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2147 Page
= PFN_FROM_SSE(Entry
);
2148 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2149 if (SavedSwapEntry
!= 0)
2151 MmSetSavedSwapEntryPage(Page
, 0);
2152 MmFreeSwapPage(SavedSwapEntry
);
2154 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2156 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2162 MmpDeleteSection(PVOID ObjectBody
)
2164 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2166 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2167 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2172 PMM_SECTION_SEGMENT SectionSegments
;
2175 * NOTE: Section->ImageSection can be NULL for short time
2176 * during the section creating. If we fail for some reason
2177 * until the image section is properly initialized we shouldn't
2178 * process further here.
2180 if (Section
->ImageSection
== NULL
)
2183 SectionSegments
= Section
->ImageSection
->Segments
;
2184 NrSegments
= Section
->ImageSection
->NrSegments
;
2186 for (i
= 0; i
< NrSegments
; i
++)
2188 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2190 MmLockSectionSegment(&SectionSegments
[i
]);
2192 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2193 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2197 MmpFreePageFileSegment(&SectionSegments
[i
]);
2199 MmUnlockSectionSegment(&SectionSegments
[i
]);
2206 * NOTE: Section->Segment can be NULL for short time
2207 * during the section creating.
2209 if (Section
->Segment
== NULL
)
2212 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2214 MmpFreePageFileSegment(Section
->Segment
);
2215 MmFreePageTablesSectionSegment(Section
->Segment
);
2216 ExFreePool(Section
->Segment
);
2217 Section
->Segment
= NULL
;
2221 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2224 if (Section
->FileObject
!= NULL
)
2226 CcRosDereferenceCache(Section
->FileObject
);
2227 ObDereferenceObject(Section
->FileObject
);
2228 Section
->FileObject
= NULL
;
2233 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2235 IN ACCESS_MASK GrantedAccess
,
2236 IN ULONG ProcessHandleCount
,
2237 IN ULONG SystemHandleCount
)
2239 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2240 Object
, ProcessHandleCount
);
2246 MmCreatePhysicalMemorySection(VOID
)
2248 PROS_SECTION_OBJECT PhysSection
;
2250 OBJECT_ATTRIBUTES Obj
;
2251 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2252 LARGE_INTEGER SectionSize
;
2256 * Create the section mapping physical memory
2258 SectionSize
.QuadPart
= 0xFFFFFFFF;
2259 InitializeObjectAttributes(&Obj
,
2264 Status
= MmCreateSection((PVOID
)&PhysSection
,
2268 PAGE_EXECUTE_READWRITE
,
2272 if (!NT_SUCCESS(Status
))
2274 DPRINT1("Failed to create PhysicalMemory section\n");
2275 KeBugCheck(MEMORY_MANAGEMENT
);
2277 Status
= ObInsertObject(PhysSection
,
2283 if (!NT_SUCCESS(Status
))
2285 ObDereferenceObject(PhysSection
);
2287 ObCloseHandle(Handle
, KernelMode
);
2288 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2289 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2291 return(STATUS_SUCCESS
);
2297 MmInitSectionImplementation(VOID
)
2299 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2300 UNICODE_STRING Name
;
2302 DPRINT("Creating Section Object Type\n");
2304 /* Initialize the Section object type */
2305 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2306 RtlInitUnicodeString(&Name
, L
"Section");
2307 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2308 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2309 ObjectTypeInitializer
.PoolType
= PagedPool
;
2310 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2311 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2312 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2313 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2314 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2315 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2317 MmCreatePhysicalMemorySection();
2319 return(STATUS_SUCCESS
);
2324 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2325 ACCESS_MASK DesiredAccess
,
2326 POBJECT_ATTRIBUTES ObjectAttributes
,
2327 PLARGE_INTEGER UMaximumSize
,
2328 ULONG SectionPageProtection
,
2329 ULONG AllocationAttributes
)
2331 * Create a section which is backed by the pagefile
2334 LARGE_INTEGER MaximumSize
;
2335 PROS_SECTION_OBJECT Section
;
2336 PMM_SECTION_SEGMENT Segment
;
2339 if (UMaximumSize
== NULL
)
2341 return(STATUS_UNSUCCESSFUL
);
2343 MaximumSize
= *UMaximumSize
;
2346 * Create the section
2348 Status
= ObCreateObject(ExGetPreviousMode(),
2349 MmSectionObjectType
,
2351 ExGetPreviousMode(),
2353 sizeof(ROS_SECTION_OBJECT
),
2356 (PVOID
*)(PVOID
)&Section
);
2357 if (!NT_SUCCESS(Status
))
2365 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2366 Section
->SectionPageProtection
= SectionPageProtection
;
2367 Section
->AllocationAttributes
= AllocationAttributes
;
2368 Section
->MaximumSize
= MaximumSize
;
2369 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2370 TAG_MM_SECTION_SEGMENT
);
2371 if (Segment
== NULL
)
2373 ObDereferenceObject(Section
);
2374 return(STATUS_NO_MEMORY
);
2376 Section
->Segment
= Segment
;
2377 Segment
->ReferenceCount
= 1;
2378 ExInitializeFastMutex(&Segment
->Lock
);
2379 Segment
->FileOffset
= 0;
2380 Segment
->Protection
= SectionPageProtection
;
2381 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2382 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2383 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2384 Segment
->WriteCopy
= FALSE
;
2385 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2386 Segment
->VirtualAddress
= 0;
2387 Segment
->Characteristics
= 0;
2388 *SectionObject
= Section
;
2389 return(STATUS_SUCCESS
);
2395 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2396 ACCESS_MASK DesiredAccess
,
2397 POBJECT_ATTRIBUTES ObjectAttributes
,
2398 PLARGE_INTEGER UMaximumSize
,
2399 ULONG SectionPageProtection
,
2400 ULONG AllocationAttributes
,
2403 * Create a section backed by a data file
2406 PROS_SECTION_OBJECT Section
;
2408 LARGE_INTEGER MaximumSize
;
2409 PFILE_OBJECT FileObject
;
2410 PMM_SECTION_SEGMENT Segment
;
2412 IO_STATUS_BLOCK Iosb
;
2413 LARGE_INTEGER Offset
;
2415 FILE_STANDARD_INFORMATION FileInfo
;
2419 * Create the section
2421 Status
= ObCreateObject(ExGetPreviousMode(),
2422 MmSectionObjectType
,
2424 ExGetPreviousMode(),
2426 sizeof(ROS_SECTION_OBJECT
),
2429 (PVOID
*)(PVOID
)&Section
);
2430 if (!NT_SUCCESS(Status
))
2437 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2438 Section
->SectionPageProtection
= SectionPageProtection
;
2439 Section
->AllocationAttributes
= AllocationAttributes
;
2442 * Check file access required
2444 if (SectionPageProtection
& PAGE_READWRITE
||
2445 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2447 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2451 FileAccess
= FILE_READ_DATA
;
2455 * Reference the file handle
2457 Status
= ObReferenceObjectByHandle(FileHandle
,
2460 ExGetPreviousMode(),
2461 (PVOID
*)(PVOID
)&FileObject
,
2463 if (!NT_SUCCESS(Status
))
2465 ObDereferenceObject(Section
);
2470 * FIXME: This is propably not entirely correct. We can't look into
2471 * the standard FCB header because it might not be initialized yet
2472 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2473 * standard file information is filled on first request).
2475 Status
= IoQueryFileInformation(FileObject
,
2476 FileStandardInformation
,
2477 sizeof(FILE_STANDARD_INFORMATION
),
2480 Iosb
.Information
= Length
;
2481 if (!NT_SUCCESS(Status
))
2483 ObDereferenceObject(Section
);
2484 ObDereferenceObject(FileObject
);
2489 * FIXME: Revise this once a locking order for file size changes is
2492 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2494 MaximumSize
= *UMaximumSize
;
2498 MaximumSize
= FileInfo
.EndOfFile
;
2499 /* Mapping zero-sized files isn't allowed. */
2500 if (MaximumSize
.QuadPart
== 0)
2502 ObDereferenceObject(Section
);
2503 ObDereferenceObject(FileObject
);
2504 return STATUS_FILE_INVALID
;
2508 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2510 Status
= IoSetInformation(FileObject
,
2511 FileAllocationInformation
,
2512 sizeof(LARGE_INTEGER
),
2514 if (!NT_SUCCESS(Status
))
2516 ObDereferenceObject(Section
);
2517 ObDereferenceObject(FileObject
);
2518 return(STATUS_SECTION_NOT_EXTENDED
);
2522 if (FileObject
->SectionObjectPointer
== NULL
||
2523 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2526 * Read a bit so caching is initiated for the file object.
2527 * This is only needed because MiReadPage currently cannot
2528 * handle non-cached streams.
2530 Offset
.QuadPart
= 0;
2531 Status
= ZwReadFile(FileHandle
,
2540 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2542 ObDereferenceObject(Section
);
2543 ObDereferenceObject(FileObject
);
2546 if (FileObject
->SectionObjectPointer
== NULL
||
2547 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2549 /* FIXME: handle this situation */
2550 ObDereferenceObject(Section
);
2551 ObDereferenceObject(FileObject
);
2552 return STATUS_INVALID_PARAMETER
;
2559 Status
= MmspWaitForFileLock(FileObject
);
2560 if (Status
!= STATUS_SUCCESS
)
2562 ObDereferenceObject(Section
);
2563 ObDereferenceObject(FileObject
);
2568 * If this file hasn't been mapped as a data file before then allocate a
2569 * section segment to describe the data file mapping
2571 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2573 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2574 TAG_MM_SECTION_SEGMENT
);
2575 if (Segment
== NULL
)
2577 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2578 ObDereferenceObject(Section
);
2579 ObDereferenceObject(FileObject
);
2580 return(STATUS_NO_MEMORY
);
2582 Section
->Segment
= Segment
;
2583 Segment
->ReferenceCount
= 1;
2584 ExInitializeFastMutex(&Segment
->Lock
);
2586 * Set the lock before assigning the segment to the file object
2588 ExAcquireFastMutex(&Segment
->Lock
);
2589 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2591 Segment
->FileOffset
= 0;
2592 Segment
->Protection
= SectionPageProtection
;
2593 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2594 Segment
->Characteristics
= 0;
2595 Segment
->WriteCopy
= FALSE
;
2596 if (AllocationAttributes
& SEC_RESERVE
)
2598 Segment
->Length
= Segment
->RawLength
= 0;
2602 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2603 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2605 Segment
->VirtualAddress
= 0;
2606 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2611 * If the file is already mapped as a data file then we may need
2615 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2617 Section
->Segment
= Segment
;
2618 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2619 MmLockSectionSegment(Segment
);
2621 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2622 !(AllocationAttributes
& SEC_RESERVE
))
2624 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2625 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2628 MmUnlockSectionSegment(Segment
);
2629 Section
->FileObject
= FileObject
;
2630 Section
->MaximumSize
= MaximumSize
;
2631 CcRosReferenceCache(FileObject
);
2632 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2633 *SectionObject
= Section
;
2634 return(STATUS_SUCCESS
);
2638 TODO: not that great (declaring loaders statically, having to declare all of
2639 them, having to keep them extern, etc.), will fix in the future
2641 extern NTSTATUS NTAPI PeFmtCreateSection
2643 IN CONST VOID
* FileHeader
,
2644 IN SIZE_T FileHeaderSize
,
2646 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2648 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2649 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2652 extern NTSTATUS NTAPI ElfFmtCreateSection
2654 IN CONST VOID
* FileHeader
,
2655 IN SIZE_T FileHeaderSize
,
2657 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2659 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2660 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2663 /* TODO: this is a standard DDK/PSDK macro */
2664 #ifndef RTL_NUMBER_OF
2665 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2668 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2679 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2681 SIZE_T SizeOfSegments
;
2682 PMM_SECTION_SEGMENT Segments
;
2684 /* TODO: check for integer overflow */
2685 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2687 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2689 TAG_MM_SECTION_SEGMENT
);
2692 RtlZeroMemory(Segments
, SizeOfSegments
);
2700 ExeFmtpReadFile(IN PVOID File
,
2701 IN PLARGE_INTEGER Offset
,
2704 OUT PVOID
* AllocBase
,
2705 OUT PULONG ReadSize
)
2708 LARGE_INTEGER FileOffset
;
2710 ULONG OffsetAdjustment
;
2715 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2719 KeBugCheck(MEMORY_MANAGEMENT
);
2722 FileOffset
= *Offset
;
2724 /* Negative/special offset: it cannot be used in this context */
2725 if(FileOffset
.u
.HighPart
< 0)
2727 KeBugCheck(MEMORY_MANAGEMENT
);
2730 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2731 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2732 FileOffset
.u
.LowPart
= AdjustOffset
;
2734 BufferSize
= Length
+ OffsetAdjustment
;
2735 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2738 * It's ok to use paged pool, because this is a temporary buffer only used in
2739 * the loading of executables. The assumption is that MmCreateSection is
2740 * always called at low IRQLs and that these buffers don't survive a brief
2741 * initialization phase
2743 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2748 KeBugCheck(MEMORY_MANAGEMENT
);
2754 Status
= MmspPageRead(File
,
2761 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2762 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2763 * to initialize internal state is even worse. Our cache manager is in need of
2767 IO_STATUS_BLOCK Iosb
;
2769 Status
= ZwReadFile(File
,
2779 if(NT_SUCCESS(Status
))
2781 UsedSize
= Iosb
.Information
;
2786 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2788 Status
= STATUS_IN_PAGE_ERROR
;
2789 ASSERT(!NT_SUCCESS(Status
));
2792 if(NT_SUCCESS(Status
))
2794 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2795 *AllocBase
= Buffer
;
2796 *ReadSize
= UsedSize
- OffsetAdjustment
;
2800 ExFreePoolWithTag(Buffer
, 'rXmM');
2807 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2808 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2809 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2814 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2818 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2820 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2821 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2828 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2832 MmspAssertSegmentsSorted(ImageSectionObject
);
2834 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2836 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2840 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2841 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2842 ImageSectionObject
->Segments
[i
- 1].Length
));
2850 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2854 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2856 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2857 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2865 MmspCompareSegments(const void * x
,
2868 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2869 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2872 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2873 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2877 * Ensures an image section's segments are sorted in memory
2882 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2885 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2887 MmspAssertSegmentsSorted(ImageSectionObject
);
2891 qsort(ImageSectionObject
->Segments
,
2892 ImageSectionObject
->NrSegments
,
2893 sizeof(ImageSectionObject
->Segments
[0]),
2894 MmspCompareSegments
);
2900 * Ensures an image section's segments don't overlap in memory and don't have
2901 * gaps and don't have a null size. We let them map to overlapping file regions,
2902 * though - that's not necessarily an error
2907 MmspCheckSegmentBounds
2909 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2915 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2917 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2921 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2923 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2925 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2933 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2934 * page could be OK (Windows seems to be OK with them), and larger gaps
2935 * could lead to image sections spanning several discontiguous regions
2936 * (NtMapViewOfSection could then refuse to map them, and they could
2937 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2939 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2940 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2941 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2952 * Merges and pads an image section's segments until they all are page-aligned
2953 * and have a size that is a multiple of the page size
2958 MmspPageAlignSegments
2960 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2966 BOOLEAN Initialized
;
2967 PMM_SECTION_SEGMENT EffectiveSegment
;
2969 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2971 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2975 Initialized
= FALSE
;
2977 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2979 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2982 * The first segment requires special handling
2986 ULONG_PTR VirtualAddress
;
2987 ULONG_PTR VirtualOffset
;
2989 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2991 /* Round down the virtual address to the nearest page */
2992 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2994 /* Round up the virtual size to the nearest page */
2995 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2996 EffectiveSegment
->VirtualAddress
;
2998 /* Adjust the raw address and size */
2999 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3001 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3007 * Garbage in, garbage out: unaligned base addresses make the file
3008 * offset point in curious and odd places, but that's what we were
3011 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3012 EffectiveSegment
->RawLength
+= VirtualOffset
;
3016 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3017 ULONG_PTR EndOfEffectiveSegment
;
3019 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3020 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3023 * The current segment begins exactly where the current effective
3024 * segment ended, therefore beginning a new effective segment
3026 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3029 ASSERT(LastSegment
<= i
);
3030 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3032 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3034 if (LastSegment
!= i
)
3037 * Copy the current segment. If necessary, the effective segment
3038 * will be expanded later
3040 *EffectiveSegment
= *Segment
;
3044 * Page-align the virtual size. We know for sure the virtual address
3047 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3048 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3051 * The current segment is still part of the current effective segment:
3052 * extend the effective segment to reflect this
3054 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3056 static const ULONG FlagsToProtection
[16] =
3064 PAGE_EXECUTE_READWRITE
,
3065 PAGE_EXECUTE_READWRITE
,
3070 PAGE_EXECUTE_WRITECOPY
,
3071 PAGE_EXECUTE_WRITECOPY
,
3072 PAGE_EXECUTE_WRITECOPY
,
3073 PAGE_EXECUTE_WRITECOPY
3076 unsigned ProtectionFlags
;
3079 * Extend the file size
3082 /* Unaligned segments must be contiguous within the file */
3083 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3084 EffectiveSegment
->RawLength
))
3089 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3092 * Extend the virtual size
3094 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3096 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3097 EffectiveSegment
->VirtualAddress
;
3100 * Merge the protection
3102 EffectiveSegment
->Protection
|= Segment
->Protection
;
3104 /* Clean up redundance */
3105 ProtectionFlags
= 0;
3107 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3108 ProtectionFlags
|= 1 << 0;
3110 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3111 ProtectionFlags
|= 1 << 1;
3113 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3114 ProtectionFlags
|= 1 << 2;
3116 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3117 ProtectionFlags
|= 1 << 3;
3119 ASSERT(ProtectionFlags
< 16);
3120 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3122 /* If a segment was required to be shared and cannot, fail */
3123 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3124 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3130 * We assume no holes between segments at this point
3134 KeBugCheck(MEMORY_MANAGEMENT
);
3138 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3144 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3145 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3147 LARGE_INTEGER Offset
;
3149 PVOID FileHeaderBuffer
;
3150 ULONG FileHeaderSize
;
3152 ULONG OldNrSegments
;
3157 * Read the beginning of the file (2 pages). Should be enough to contain
3158 * all (or most) of the headers
3160 Offset
.QuadPart
= 0;
3162 /* FIXME: use FileObject instead of FileHandle */
3163 Status
= ExeFmtpReadFile (FileHandle
,
3170 if (!NT_SUCCESS(Status
))
3173 if (FileHeaderSize
== 0)
3175 ExFreePool(FileHeaderBuffer
);
3176 return STATUS_UNSUCCESSFUL
;
3180 * Look for a loader that can handle this executable
3182 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3184 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3187 /* FIXME: use FileObject instead of FileHandle */
3188 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3194 ExeFmtpAllocateSegments
);
3196 if (!NT_SUCCESS(Status
))
3198 if (ImageSectionObject
->Segments
)
3200 ExFreePool(ImageSectionObject
->Segments
);
3201 ImageSectionObject
->Segments
= NULL
;
3205 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3209 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3212 * No loader handled the format
3214 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3216 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3217 ASSERT(!NT_SUCCESS(Status
));
3220 if (!NT_SUCCESS(Status
))
3223 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3228 /* FIXME? are these values platform-dependent? */
3229 if(ImageSectionObject
->StackReserve
== 0)
3230 ImageSectionObject
->StackReserve
= 0x40000;
3232 if(ImageSectionObject
->StackCommit
== 0)
3233 ImageSectionObject
->StackCommit
= 0x1000;
3235 if(ImageSectionObject
->ImageBase
== 0)
3237 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3238 ImageSectionObject
->ImageBase
= 0x10000000;
3240 ImageSectionObject
->ImageBase
= 0x00400000;
3244 * And now the fun part: fixing the segments
3247 /* Sort them by virtual address */
3248 MmspSortSegments(ImageSectionObject
, Flags
);
3250 /* Ensure they don't overlap in memory */
3251 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3252 return STATUS_INVALID_IMAGE_FORMAT
;
3254 /* Ensure they are aligned */
3255 OldNrSegments
= ImageSectionObject
->NrSegments
;
3257 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3258 return STATUS_INVALID_IMAGE_FORMAT
;
3260 /* Trim them if the alignment phase merged some of them */
3261 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3263 PMM_SECTION_SEGMENT Segments
;
3264 SIZE_T SizeOfSegments
;
3266 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3268 Segments
= ExAllocatePoolWithTag(PagedPool
,
3270 TAG_MM_SECTION_SEGMENT
);
3272 if (Segments
== NULL
)
3273 return STATUS_INSUFFICIENT_RESOURCES
;
3275 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3276 ExFreePool(ImageSectionObject
->Segments
);
3277 ImageSectionObject
->Segments
= Segments
;
3280 /* And finish their initialization */
3281 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3283 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3284 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3286 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3287 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3290 ASSERT(NT_SUCCESS(Status
));
3295 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3296 ACCESS_MASK DesiredAccess
,
3297 POBJECT_ATTRIBUTES ObjectAttributes
,
3298 PLARGE_INTEGER UMaximumSize
,
3299 ULONG SectionPageProtection
,
3300 ULONG AllocationAttributes
,
3303 PROS_SECTION_OBJECT Section
;
3305 PFILE_OBJECT FileObject
;
3306 PMM_SECTION_SEGMENT SectionSegments
;
3307 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3309 ULONG FileAccess
= 0;
3312 * Specifying a maximum size is meaningless for an image section
3314 if (UMaximumSize
!= NULL
)
3316 return(STATUS_INVALID_PARAMETER_4
);
3320 * Check file access required
3322 if (SectionPageProtection
& PAGE_READWRITE
||
3323 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3325 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3329 FileAccess
= FILE_READ_DATA
;
3333 * Reference the file handle
3335 Status
= ObReferenceObjectByHandle(FileHandle
,
3338 ExGetPreviousMode(),
3339 (PVOID
*)(PVOID
)&FileObject
,
3342 if (!NT_SUCCESS(Status
))
3348 * Create the section
3350 Status
= ObCreateObject (ExGetPreviousMode(),
3351 MmSectionObjectType
,
3353 ExGetPreviousMode(),
3355 sizeof(ROS_SECTION_OBJECT
),
3358 (PVOID
*)(PVOID
)&Section
);
3359 if (!NT_SUCCESS(Status
))
3361 ObDereferenceObject(FileObject
);
3368 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3369 Section
->SectionPageProtection
= SectionPageProtection
;
3370 Section
->AllocationAttributes
= AllocationAttributes
;
3373 * Initialized caching for this file object if previously caching
3374 * was initialized for the same on disk file
3376 Status
= CcTryToInitializeFileCache(FileObject
);
3378 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3380 NTSTATUS StatusExeFmt
;
3382 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3383 if (ImageSectionObject
== NULL
)
3385 ObDereferenceObject(FileObject
);
3386 ObDereferenceObject(Section
);
3387 return(STATUS_NO_MEMORY
);
3390 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3392 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3394 if (!NT_SUCCESS(StatusExeFmt
))
3396 if(ImageSectionObject
->Segments
!= NULL
)
3397 ExFreePool(ImageSectionObject
->Segments
);
3399 ExFreePool(ImageSectionObject
);
3400 ObDereferenceObject(Section
);
3401 ObDereferenceObject(FileObject
);
3402 return(StatusExeFmt
);
3405 Section
->ImageSection
= ImageSectionObject
;
3406 ASSERT(ImageSectionObject
->Segments
);
3411 Status
= MmspWaitForFileLock(FileObject
);
3412 if (!NT_SUCCESS(Status
))
3414 ExFreePool(ImageSectionObject
->Segments
);
3415 ExFreePool(ImageSectionObject
);
3416 ObDereferenceObject(Section
);
3417 ObDereferenceObject(FileObject
);
3421 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3422 ImageSectionObject
, NULL
))
3425 * An other thread has initialized the same image in the background
3427 ExFreePool(ImageSectionObject
->Segments
);
3428 ExFreePool(ImageSectionObject
);
3429 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3430 Section
->ImageSection
= ImageSectionObject
;
3431 SectionSegments
= ImageSectionObject
->Segments
;
3433 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3435 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3439 Status
= StatusExeFmt
;
3446 Status
= MmspWaitForFileLock(FileObject
);
3447 if (Status
!= STATUS_SUCCESS
)
3449 ObDereferenceObject(Section
);
3450 ObDereferenceObject(FileObject
);
3454 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3455 Section
->ImageSection
= ImageSectionObject
;
3456 SectionSegments
= ImageSectionObject
->Segments
;
3459 * Otherwise just reference all the section segments
3461 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3463 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3466 Status
= STATUS_SUCCESS
;
3468 Section
->FileObject
= FileObject
;
3469 CcRosReferenceCache(FileObject
);
3470 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3471 *SectionObject
= Section
;
3479 NtCreateSection (OUT PHANDLE SectionHandle
,
3480 IN ACCESS_MASK DesiredAccess
,
3481 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3482 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3483 IN ULONG SectionPageProtection OPTIONAL
,
3484 IN ULONG AllocationAttributes
,
3485 IN HANDLE FileHandle OPTIONAL
)
3487 LARGE_INTEGER SafeMaximumSize
;
3488 PVOID SectionObject
;
3489 KPROCESSOR_MODE PreviousMode
;
3492 PreviousMode
= ExGetPreviousMode();
3494 if(PreviousMode
!= KernelMode
)
3498 if (MaximumSize
!= NULL
)
3500 /* make a copy on the stack */
3501 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3502 MaximumSize
= &SafeMaximumSize
;
3504 ProbeForWriteHandle(SectionHandle
);
3506 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3508 /* Return the exception code */
3509 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3514 Status
= MmCreateSection(&SectionObject
,
3518 SectionPageProtection
,
3519 AllocationAttributes
,
3522 if (NT_SUCCESS(Status
))
3524 Status
= ObInsertObject ((PVOID
)SectionObject
,
3536 /**********************************************************************
3554 NtOpenSection(PHANDLE SectionHandle
,
3555 ACCESS_MASK DesiredAccess
,
3556 POBJECT_ATTRIBUTES ObjectAttributes
)
3559 KPROCESSOR_MODE PreviousMode
;
3562 PreviousMode
= ExGetPreviousMode();
3564 if(PreviousMode
!= KernelMode
)
3568 ProbeForWriteHandle(SectionHandle
);
3570 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3572 /* Return the exception code */
3573 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3578 Status
= ObOpenObjectByName(ObjectAttributes
,
3579 MmSectionObjectType
,
3586 if(NT_SUCCESS(Status
))
3590 *SectionHandle
= hSection
;
3592 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3594 Status
= _SEH2_GetExceptionCode();
3603 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3604 PROS_SECTION_OBJECT Section
,
3605 PMM_SECTION_SEGMENT Segment
,
3610 ULONG AllocationType
)
3614 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3616 BoundaryAddressMultiple
.QuadPart
= 0;
3618 Status
= MmCreateMemoryArea(AddressSpace
,
3619 MEMORY_AREA_SECTION_VIEW
,
3626 BoundaryAddressMultiple
);
3627 if (!NT_SUCCESS(Status
))
3629 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3630 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3634 ObReferenceObject((PVOID
)Section
);
3636 MArea
->Data
.SectionData
.Segment
= Segment
;
3637 MArea
->Data
.SectionData
.Section
= Section
;
3638 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3639 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3640 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3641 ViewSize
, 0, Protect
);
3643 return(STATUS_SUCCESS
);
3647 /**********************************************************************
3649 * NtMapViewOfSection
3652 * Maps a view of a section into the virtual address space of a
3657 * Handle of the section.
3660 * Handle of the process.
3663 * Desired base address (or NULL) on entry;
3664 * Actual base address of the view on exit.
3667 * Number of high order address bits that must be zero.
3670 * Size in bytes of the initially committed section of
3674 * Offset in bytes from the beginning of the section
3675 * to the beginning of the view.
3678 * Desired length of map (or zero to map all) on entry
3679 * Actual length mapped on exit.
3681 * InheritDisposition
3682 * Specified how the view is to be shared with
3686 * Type of allocation for the pages.
3689 * Protection for the committed region of the view.
3697 NtMapViewOfSection(IN HANDLE SectionHandle
,
3698 IN HANDLE ProcessHandle
,
3699 IN OUT PVOID
* BaseAddress OPTIONAL
,
3700 IN ULONG_PTR ZeroBits OPTIONAL
,
3701 IN SIZE_T CommitSize
,
3702 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3703 IN OUT PSIZE_T ViewSize
,
3704 IN SECTION_INHERIT InheritDisposition
,
3705 IN ULONG AllocationType OPTIONAL
,
3708 PVOID SafeBaseAddress
;
3709 LARGE_INTEGER SafeSectionOffset
;
3710 SIZE_T SafeViewSize
;
3711 PROS_SECTION_OBJECT Section
;
3713 KPROCESSOR_MODE PreviousMode
;
3714 PMMSUPPORT AddressSpace
;
3717 ACCESS_MASK DesiredAccess
;
3720 * Check the protection
3722 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3724 return STATUS_INVALID_PARAMETER_10
;
3727 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3728 if (tmpProtect
!= PAGE_NOACCESS
&&
3729 tmpProtect
!= PAGE_READONLY
&&
3730 tmpProtect
!= PAGE_READWRITE
&&
3731 tmpProtect
!= PAGE_WRITECOPY
&&
3732 tmpProtect
!= PAGE_EXECUTE
&&
3733 tmpProtect
!= PAGE_EXECUTE_READ
&&
3734 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3735 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3737 return STATUS_INVALID_PAGE_PROTECTION
;
3740 PreviousMode
= ExGetPreviousMode();
3742 if(PreviousMode
!= KernelMode
)
3744 SafeBaseAddress
= NULL
;
3745 SafeSectionOffset
.QuadPart
= 0;
3750 if(BaseAddress
!= NULL
)
3752 ProbeForWritePointer(BaseAddress
);
3753 SafeBaseAddress
= *BaseAddress
;
3755 if(SectionOffset
!= NULL
)
3757 ProbeForWriteLargeInteger(SectionOffset
);
3758 SafeSectionOffset
= *SectionOffset
;
3760 ProbeForWriteSize_t(ViewSize
);
3761 SafeViewSize
= *ViewSize
;
3763 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3765 /* Return the exception code */
3766 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3772 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3773 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3774 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3777 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3779 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3780 PROCESS_VM_OPERATION
,
3783 (PVOID
*)(PVOID
)&Process
,
3785 if (!NT_SUCCESS(Status
))
3790 AddressSpace
= &Process
->Vm
;
3792 /* Convert NT Protection Attr to Access Mask */
3793 if (Protect
== PAGE_READONLY
)
3795 DesiredAccess
= SECTION_MAP_READ
;
3797 else if (Protect
== PAGE_READWRITE
)
3799 DesiredAccess
= SECTION_MAP_WRITE
;
3801 else if (Protect
== PAGE_WRITECOPY
)
3803 DesiredAccess
= SECTION_QUERY
;
3805 /* FIXME: Handle other Protection Attributes. For now keep previous behavior */
3808 DesiredAccess
= SECTION_MAP_READ
;
3811 Status
= ObReferenceObjectByHandle(SectionHandle
,
3813 MmSectionObjectType
,
3815 (PVOID
*)(PVOID
)&Section
,
3817 if (!(NT_SUCCESS(Status
)))
3819 DPRINT("ObReference failed rc=%x\n",Status
);
3820 ObDereferenceObject(Process
);
3824 Status
= MmMapViewOfSection(Section
,
3826 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3829 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3830 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3835 /* Check if this is an image for the current process */
3836 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3837 (Process
== PsGetCurrentProcess()) &&
3838 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3840 /* Notify the debugger */
3841 DbgkMapViewOfSection(Section
,
3843 SafeSectionOffset
.LowPart
,
3847 ObDereferenceObject(Section
);
3848 ObDereferenceObject(Process
);
3850 if(NT_SUCCESS(Status
))
3852 /* copy parameters back to the caller */
3855 if(BaseAddress
!= NULL
)
3857 *BaseAddress
= SafeBaseAddress
;
3859 if(SectionOffset
!= NULL
)
3861 *SectionOffset
= SafeSectionOffset
;
3863 if(ViewSize
!= NULL
)
3865 *ViewSize
= SafeViewSize
;
3868 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3870 Status
= _SEH2_GetExceptionCode();
3879 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3880 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3883 PFILE_OBJECT FileObject
;
3886 SWAPENTRY SavedSwapEntry
;
3889 PROS_SECTION_OBJECT Section
;
3890 PMM_SECTION_SEGMENT Segment
;
3891 PMMSUPPORT AddressSpace
;
3894 AddressSpace
= (PMMSUPPORT
)Context
;
3895 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3897 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3899 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3900 MemoryArea
->Data
.SectionData
.ViewOffset
;
3902 Section
= MemoryArea
->Data
.SectionData
.Section
;
3903 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3905 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3909 MmUnlockSectionSegment(Segment
);
3910 MmUnlockAddressSpace(AddressSpace
);
3912 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3913 if (Status
!= STATUS_SUCCESS
)
3915 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3916 KeBugCheck(MEMORY_MANAGEMENT
);
3919 MmLockAddressSpace(AddressSpace
);
3920 MmLockSectionSegment(Segment
);
3921 MmspCompleteAndReleasePageOp(PageOp
);
3922 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3925 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3928 * For a dirty, datafile, non-private page mark it as dirty in the
3931 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3933 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3935 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3936 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3937 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3938 ASSERT(SwapEntry
== 0);
3947 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3949 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3950 KeBugCheck(MEMORY_MANAGEMENT
);
3952 MmFreeSwapPage(SwapEntry
);
3956 if (IS_SWAP_FROM_SSE(Entry
) ||
3957 Page
!= PFN_FROM_SSE(Entry
))
3962 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3964 DPRINT1("Found a private page in a pagefile section.\n");
3965 KeBugCheck(MEMORY_MANAGEMENT
);
3968 * Just dereference private pages
3970 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3971 if (SavedSwapEntry
!= 0)
3973 MmFreeSwapPage(SavedSwapEntry
);
3974 MmSetSavedSwapEntryPage(Page
, 0);
3976 MmDeleteRmap(Page
, Process
, Address
);
3977 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3981 MmDeleteRmap(Page
, Process
, Address
);
3982 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3988 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
3992 PMEMORY_AREA MemoryArea
;
3993 PROS_SECTION_OBJECT Section
;
3994 PMM_SECTION_SEGMENT Segment
;
3995 PLIST_ENTRY CurrentEntry
;
3996 PMM_REGION CurrentRegion
;
3997 PLIST_ENTRY RegionListHead
;
3999 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4001 if (MemoryArea
== NULL
)
4003 return(STATUS_UNSUCCESSFUL
);
4006 MemoryArea
->DeleteInProgress
= TRUE
;
4007 Section
= MemoryArea
->Data
.SectionData
.Section
;
4008 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4010 MmLockSectionSegment(Segment
);
4012 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4013 while (!IsListEmpty(RegionListHead
))
4015 CurrentEntry
= RemoveHeadList(RegionListHead
);
4016 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4017 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4020 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4022 Status
= MmFreeMemoryArea(AddressSpace
,
4029 Status
= MmFreeMemoryArea(AddressSpace
,
4034 MmUnlockSectionSegment(Segment
);
4035 ObDereferenceObject(Section
);
4036 return(STATUS_SUCCESS
);
4043 MmUnmapViewOfSection(PEPROCESS Process
,
4047 PMEMORY_AREA MemoryArea
;
4048 PMMSUPPORT AddressSpace
;
4049 PROS_SECTION_OBJECT Section
;
4052 PVOID ImageBaseAddress
= 0;
4054 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4055 Process
, BaseAddress
);
4059 AddressSpace
= &Process
->Vm
;
4061 MmLockAddressSpace(AddressSpace
);
4062 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4064 if (MemoryArea
== NULL
||
4065 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4066 MemoryArea
->DeleteInProgress
)
4068 MmUnlockAddressSpace(AddressSpace
);
4069 return STATUS_NOT_MAPPED_VIEW
;
4072 MemoryArea
->DeleteInProgress
= TRUE
;
4074 while (MemoryArea
->PageOpCount
)
4076 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4080 Offset
-= PAGE_SIZE
;
4081 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4082 MemoryArea
->Data
.SectionData
.Segment
,
4083 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4086 MmUnlockAddressSpace(AddressSpace
);
4087 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4088 if (Status
!= STATUS_SUCCESS
)
4090 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4091 KeBugCheck(MEMORY_MANAGEMENT
);
4093 MmLockAddressSpace(AddressSpace
);
4094 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4096 if (MemoryArea
== NULL
||
4097 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4099 MmUnlockAddressSpace(AddressSpace
);
4100 return STATUS_NOT_MAPPED_VIEW
;
4107 Section
= MemoryArea
->Data
.SectionData
.Section
;
4109 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4113 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4114 PMM_SECTION_SEGMENT SectionSegments
;
4115 PMM_SECTION_SEGMENT Segment
;
4117 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4118 ImageSectionObject
= Section
->ImageSection
;
4119 SectionSegments
= ImageSectionObject
->Segments
;
4120 NrSegments
= ImageSectionObject
->NrSegments
;
4122 /* Search for the current segment within the section segments
4123 * and calculate the image base address */
4124 for (i
= 0; i
< NrSegments
; i
++)
4126 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4128 if (Segment
== &SectionSegments
[i
])
4130 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4135 if (i
>= NrSegments
)
4137 KeBugCheck(MEMORY_MANAGEMENT
);
4140 for (i
= 0; i
< NrSegments
; i
++)
4142 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4144 PVOID SBaseAddress
= (PVOID
)
4145 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4147 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4153 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4156 MmUnlockAddressSpace(AddressSpace
);
4158 /* Notify debugger */
4159 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4161 return(STATUS_SUCCESS
);
4164 /**********************************************************************
4166 * NtUnmapViewOfSection
4181 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4185 KPROCESSOR_MODE PreviousMode
;
4188 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4189 ProcessHandle
, BaseAddress
);
4191 PreviousMode
= ExGetPreviousMode();
4193 DPRINT("Referencing process\n");
4194 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4195 PROCESS_VM_OPERATION
,
4198 (PVOID
*)(PVOID
)&Process
,
4200 if (!NT_SUCCESS(Status
))
4202 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4206 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4208 ObDereferenceObject(Process
);
4215 * Queries the information of a section object.
4217 * @param SectionHandle
4218 * Handle to the section object. It must be opened with SECTION_QUERY
4220 * @param SectionInformationClass
4221 * Index to a certain information structure. Can be either
4222 * SectionBasicInformation or SectionImageInformation. The latter
4223 * is valid only for sections that were created with the SEC_IMAGE
4225 * @param SectionInformation
4226 * Caller supplies storage for resulting information.
4228 * Size of the supplied storage.
4229 * @param ResultLength
4237 NtQuerySection(IN HANDLE SectionHandle
,
4238 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4239 OUT PVOID SectionInformation
,
4240 IN SIZE_T SectionInformationLength
,
4241 OUT PSIZE_T ResultLength OPTIONAL
)
4243 PROS_SECTION_OBJECT Section
;
4244 KPROCESSOR_MODE PreviousMode
;
4248 PreviousMode
= ExGetPreviousMode();
4250 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4252 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4254 SectionInformationLength
,
4259 if(!NT_SUCCESS(Status
))
4261 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4265 Status
= ObReferenceObjectByHandle(SectionHandle
,
4267 MmSectionObjectType
,
4269 (PVOID
*)(PVOID
)&Section
,
4271 if (NT_SUCCESS(Status
))
4273 switch (SectionInformationClass
)
4275 case SectionBasicInformation
:
4277 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4281 Sbi
->Attributes
= Section
->AllocationAttributes
;
4282 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4284 Sbi
->BaseAddress
= 0;
4285 Sbi
->Size
.QuadPart
= 0;
4289 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4290 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4293 if (ResultLength
!= NULL
)
4295 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4297 Status
= STATUS_SUCCESS
;
4299 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4301 Status
= _SEH2_GetExceptionCode();
4308 case SectionImageInformation
:
4310 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4314 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4315 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4317 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4318 ImageSectionObject
= Section
->ImageSection
;
4320 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4321 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4322 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4323 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4324 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4325 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4326 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4327 Sii
->Machine
= ImageSectionObject
->Machine
;
4328 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4331 if (ResultLength
!= NULL
)
4333 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4335 Status
= STATUS_SUCCESS
;
4337 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4339 Status
= _SEH2_GetExceptionCode();
4347 ObDereferenceObject(Section
);
4355 * Extends size of file backed section.
4357 * @param SectionHandle
4358 * Handle to the section object. It must be opened with
4359 * SECTION_EXTEND_SIZE access.
4360 * @param NewMaximumSize
4361 * New maximum size of the section in bytes.
4365 * @todo Move the actual code to internal function MmExtendSection.
4369 NtExtendSection(IN HANDLE SectionHandle
,
4370 IN PLARGE_INTEGER NewMaximumSize
)
4372 LARGE_INTEGER SafeNewMaximumSize
;
4373 PROS_SECTION_OBJECT Section
;
4374 KPROCESSOR_MODE PreviousMode
;
4377 PreviousMode
= ExGetPreviousMode();
4379 if(PreviousMode
!= KernelMode
)
4383 /* make a copy on the stack */
4384 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4385 NewMaximumSize
= &SafeNewMaximumSize
;
4387 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4389 /* Return the exception code */
4390 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4395 Status
= ObReferenceObjectByHandle(SectionHandle
,
4396 SECTION_EXTEND_SIZE
,
4397 MmSectionObjectType
,
4401 if (!NT_SUCCESS(Status
))
4406 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4408 ObDereferenceObject(Section
);
4409 return STATUS_INVALID_PARAMETER
;
4413 * - Acquire file extneding resource.
4414 * - Check if we're not resizing the section below it's actual size!
4415 * - Extend segments if needed.
4416 * - Set file information (FileAllocationInformation) to the new size.
4417 * - Release file extending resource.
4420 ObDereferenceObject(Section
);
4422 return STATUS_NOT_IMPLEMENTED
;
4425 /**********************************************************************
4427 * MmMapViewOfSection
4430 * Maps a view of a section into the virtual address space of a
4435 * Pointer to the section object.
4438 * Pointer to the process.
4441 * Desired base address (or NULL) on entry;
4442 * Actual base address of the view on exit.
4445 * Number of high order address bits that must be zero.
4448 * Size in bytes of the initially committed section of
4452 * Offset in bytes from the beginning of the section
4453 * to the beginning of the view.
4456 * Desired length of map (or zero to map all) on entry
4457 * Actual length mapped on exit.
4459 * InheritDisposition
4460 * Specified how the view is to be shared with
4464 * Type of allocation for the pages.
4467 * Protection for the committed region of the view.
4475 MmMapViewOfSection(IN PVOID SectionObject
,
4476 IN PEPROCESS Process
,
4477 IN OUT PVOID
*BaseAddress
,
4478 IN ULONG_PTR ZeroBits
,
4479 IN SIZE_T CommitSize
,
4480 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4481 IN OUT PSIZE_T ViewSize
,
4482 IN SECTION_INHERIT InheritDisposition
,
4483 IN ULONG AllocationType
,
4486 PROS_SECTION_OBJECT Section
;
4487 PMMSUPPORT AddressSpace
;
4489 NTSTATUS Status
= STATUS_SUCCESS
;
4493 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4495 return STATUS_INVALID_PAGE_PROTECTION
;
4499 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4500 AddressSpace
= &Process
->Vm
;
4502 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4504 MmLockAddressSpace(AddressSpace
);
4506 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4510 ULONG_PTR ImageBase
;
4512 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4513 PMM_SECTION_SEGMENT SectionSegments
;
4515 ImageSectionObject
= Section
->ImageSection
;
4516 SectionSegments
= ImageSectionObject
->Segments
;
4517 NrSegments
= ImageSectionObject
->NrSegments
;
4520 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4523 ImageBase
= ImageSectionObject
->ImageBase
;
4527 for (i
= 0; i
< NrSegments
; i
++)
4529 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4531 ULONG_PTR MaxExtent
;
4532 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4533 SectionSegments
[i
].Length
;
4534 ImageSize
= max(ImageSize
, MaxExtent
);
4538 ImageSectionObject
->ImageSize
= ImageSize
;
4540 /* Check there is enough space to map the section at that point. */
4541 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4542 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4544 /* Fail if the user requested a fixed base address. */
4545 if ((*BaseAddress
) != NULL
)
4547 MmUnlockAddressSpace(AddressSpace
);
4548 return(STATUS_UNSUCCESSFUL
);
4550 /* Otherwise find a gap to map the image. */
4551 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4554 MmUnlockAddressSpace(AddressSpace
);
4555 return(STATUS_UNSUCCESSFUL
);
4559 for (i
= 0; i
< NrSegments
; i
++)
4561 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4563 PVOID SBaseAddress
= (PVOID
)
4564 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4565 MmLockSectionSegment(&SectionSegments
[i
]);
4566 Status
= MmMapViewOfSegment(AddressSpace
,
4568 &SectionSegments
[i
],
4570 SectionSegments
[i
].Length
,
4571 SectionSegments
[i
].Protection
,
4574 MmUnlockSectionSegment(&SectionSegments
[i
]);
4575 if (!NT_SUCCESS(Status
))
4577 MmUnlockAddressSpace(AddressSpace
);
4583 *BaseAddress
= (PVOID
)ImageBase
;
4587 /* check for write access */
4588 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4589 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4591 MmUnlockAddressSpace(AddressSpace
);
4592 return STATUS_SECTION_PROTECTION
;
4594 /* check for read access */
4595 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4596 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4598 MmUnlockAddressSpace(AddressSpace
);
4599 return STATUS_SECTION_PROTECTION
;
4601 /* check for execute access */
4602 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4603 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4605 MmUnlockAddressSpace(AddressSpace
);
4606 return STATUS_SECTION_PROTECTION
;
4609 if (ViewSize
== NULL
)
4611 /* Following this pointer would lead to us to the dark side */
4612 /* What to do? Bugcheck? Return status? Do the mambo? */
4613 KeBugCheck(MEMORY_MANAGEMENT
);
4616 if (SectionOffset
== NULL
)
4622 ViewOffset
= SectionOffset
->u
.LowPart
;
4625 if ((ViewOffset
% PAGE_SIZE
) != 0)
4627 MmUnlockAddressSpace(AddressSpace
);
4628 return(STATUS_MAPPED_ALIGNMENT
);
4631 if ((*ViewSize
) == 0)
4633 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4635 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4637 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4640 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4642 MmLockSectionSegment(Section
->Segment
);
4643 Status
= MmMapViewOfSegment(AddressSpace
,
4650 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4651 MmUnlockSectionSegment(Section
->Segment
);
4652 if (!NT_SUCCESS(Status
))
4654 MmUnlockAddressSpace(AddressSpace
);
4659 MmUnlockAddressSpace(AddressSpace
);
4661 return(STATUS_SUCCESS
);
4668 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4669 IN PLARGE_INTEGER NewFileSize
)
4671 /* Check whether an ImageSectionObject exists */
4672 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4674 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4678 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4680 PMM_SECTION_SEGMENT Segment
;
4682 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4685 if (Segment
->ReferenceCount
!= 0)
4687 /* Check size of file */
4688 if (SectionObjectPointer
->SharedCacheMap
)
4690 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4691 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4699 /* Something must gone wrong
4700 * how can we have a Section but no
4702 DPRINT("ERROR: DataSectionObject without reference!\n");
4706 DPRINT("FIXME: didn't check for outstanding write probes\n");
4716 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4726 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4727 IN MMFLUSH_TYPE FlushType
)
4731 case MmFlushForDelete
:
4732 if (SectionObjectPointer
->ImageSectionObject
||
4733 SectionObjectPointer
->DataSectionObject
)
4737 CcRosSetRemoveOnClose(SectionObjectPointer
);
4739 case MmFlushForWrite
:
4749 MmForceSectionClosed (
4750 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4751 IN BOOLEAN DelayClose
)
4762 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4763 OUT PVOID
* MappedBase
,
4764 IN OUT PSIZE_T ViewSize
)
4766 PROS_SECTION_OBJECT Section
;
4767 PMMSUPPORT AddressSpace
;
4770 DPRINT("MmMapViewInSystemSpace() called\n");
4772 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4773 AddressSpace
= MmGetKernelAddressSpace();
4775 MmLockAddressSpace(AddressSpace
);
4778 if ((*ViewSize
) == 0)
4780 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4782 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4784 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4787 MmLockSectionSegment(Section
->Segment
);
4790 Status
= MmMapViewOfSegment(AddressSpace
,
4799 MmUnlockSectionSegment(Section
->Segment
);
4800 MmUnlockAddressSpace(AddressSpace
);
4810 MmMapViewInSessionSpace (
4812 OUT PVOID
*MappedBase
,
4813 IN OUT PSIZE_T ViewSize
4817 return STATUS_NOT_IMPLEMENTED
;
4825 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4827 PMMSUPPORT AddressSpace
;
4830 DPRINT("MmUnmapViewInSystemSpace() called\n");
4832 AddressSpace
= MmGetKernelAddressSpace();
4834 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4844 MmUnmapViewInSessionSpace (
4849 return STATUS_NOT_IMPLEMENTED
;
4852 /**********************************************************************
4857 * Creates a section object.
4860 * SectionObject (OUT)
4861 * Caller supplied storage for the resulting pointer
4862 * to a SECTION_OBJECT instance;
4865 * Specifies the desired access to the section can be a
4867 * STANDARD_RIGHTS_REQUIRED |
4869 * SECTION_MAP_WRITE |
4870 * SECTION_MAP_READ |
4871 * SECTION_MAP_EXECUTE
4873 * ObjectAttributes [OPTIONAL]
4874 * Initialized attributes for the object can be used
4875 * to create a named section;
4878 * Maximizes the size of the memory section. Must be
4879 * non-NULL for a page-file backed section.
4880 * If value specified for a mapped file and the file is
4881 * not large enough, file will be extended.
4883 * SectionPageProtection
4884 * Can be a combination of:
4890 * AllocationAttributes
4891 * Can be a combination of:
4896 * Handle to a file to create a section mapped to a file
4897 * instead of a memory backed section;
4908 MmCreateSection (OUT PVOID
* Section
,
4909 IN ACCESS_MASK DesiredAccess
,
4910 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4911 IN PLARGE_INTEGER MaximumSize
,
4912 IN ULONG SectionPageProtection
,
4913 IN ULONG AllocationAttributes
,
4914 IN HANDLE FileHandle OPTIONAL
,
4915 IN PFILE_OBJECT File OPTIONAL
)
4918 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4921 * Check the protection
4923 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4924 if (Protection
!= PAGE_READONLY
&&
4925 Protection
!= PAGE_READWRITE
&&
4926 Protection
!= PAGE_WRITECOPY
&&
4927 Protection
!= PAGE_EXECUTE
&&
4928 Protection
!= PAGE_EXECUTE_READ
&&
4929 Protection
!= PAGE_EXECUTE_READWRITE
&&
4930 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4932 return STATUS_INVALID_PAGE_PROTECTION
;
4935 if (AllocationAttributes
& SEC_IMAGE
)
4937 return(MmCreateImageSection(SectionObject
,
4941 SectionPageProtection
,
4942 AllocationAttributes
,
4946 if (FileHandle
!= NULL
)
4948 return(MmCreateDataFileSection(SectionObject
,
4952 SectionPageProtection
,
4953 AllocationAttributes
,
4957 return(MmCreatePageFileSection(SectionObject
,
4961 SectionPageProtection
,
4962 AllocationAttributes
));
4967 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
4968 IN PVOID File2MappedAsFile
)
4971 return STATUS_NOT_IMPLEMENTED
;