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 PMM_SECTION_SEGMENT EffectiveSegment
;
2968 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2970 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2975 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2977 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2980 * The first segment requires special handling
2984 ULONG_PTR VirtualAddress
;
2985 ULONG_PTR VirtualOffset
;
2987 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2989 /* Round down the virtual address to the nearest page */
2990 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2992 /* Round up the virtual size to the nearest page */
2993 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2994 EffectiveSegment
->VirtualAddress
;
2996 /* Adjust the raw address and size */
2997 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2999 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3005 * Garbage in, garbage out: unaligned base addresses make the file
3006 * offset point in curious and odd places, but that's what we were
3009 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3010 EffectiveSegment
->RawLength
+= VirtualOffset
;
3014 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3015 ULONG_PTR EndOfEffectiveSegment
;
3017 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3018 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3021 * The current segment begins exactly where the current effective
3022 * segment ended, therefore beginning a new effective segment
3024 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3027 ASSERT(LastSegment
<= i
);
3028 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3030 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3032 if (LastSegment
!= i
)
3035 * Copy the current segment. If necessary, the effective segment
3036 * will be expanded later
3038 *EffectiveSegment
= *Segment
;
3042 * Page-align the virtual size. We know for sure the virtual address
3045 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3046 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3049 * The current segment is still part of the current effective segment:
3050 * extend the effective segment to reflect this
3052 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3054 static const ULONG FlagsToProtection
[16] =
3062 PAGE_EXECUTE_READWRITE
,
3063 PAGE_EXECUTE_READWRITE
,
3068 PAGE_EXECUTE_WRITECOPY
,
3069 PAGE_EXECUTE_WRITECOPY
,
3070 PAGE_EXECUTE_WRITECOPY
,
3071 PAGE_EXECUTE_WRITECOPY
3074 unsigned ProtectionFlags
;
3077 * Extend the file size
3080 /* Unaligned segments must be contiguous within the file */
3081 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3082 EffectiveSegment
->RawLength
))
3087 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3090 * Extend the virtual size
3092 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3094 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3095 EffectiveSegment
->VirtualAddress
;
3098 * Merge the protection
3100 EffectiveSegment
->Protection
|= Segment
->Protection
;
3102 /* Clean up redundance */
3103 ProtectionFlags
= 0;
3105 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3106 ProtectionFlags
|= 1 << 0;
3108 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3109 ProtectionFlags
|= 1 << 1;
3111 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3112 ProtectionFlags
|= 1 << 2;
3114 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3115 ProtectionFlags
|= 1 << 3;
3117 ASSERT(ProtectionFlags
< 16);
3118 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3120 /* If a segment was required to be shared and cannot, fail */
3121 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3122 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3128 * We assume no holes between segments at this point
3132 KeBugCheck(MEMORY_MANAGEMENT
);
3136 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3142 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3143 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3145 LARGE_INTEGER Offset
;
3147 PVOID FileHeaderBuffer
;
3148 ULONG FileHeaderSize
;
3150 ULONG OldNrSegments
;
3155 * Read the beginning of the file (2 pages). Should be enough to contain
3156 * all (or most) of the headers
3158 Offset
.QuadPart
= 0;
3160 /* FIXME: use FileObject instead of FileHandle */
3161 Status
= ExeFmtpReadFile (FileHandle
,
3168 if (!NT_SUCCESS(Status
))
3171 if (FileHeaderSize
== 0)
3173 ExFreePool(FileHeaderBuffer
);
3174 return STATUS_UNSUCCESSFUL
;
3178 * Look for a loader that can handle this executable
3180 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3182 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3185 /* FIXME: use FileObject instead of FileHandle */
3186 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3192 ExeFmtpAllocateSegments
);
3194 if (!NT_SUCCESS(Status
))
3196 if (ImageSectionObject
->Segments
)
3198 ExFreePool(ImageSectionObject
->Segments
);
3199 ImageSectionObject
->Segments
= NULL
;
3203 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3207 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3210 * No loader handled the format
3212 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3214 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3215 ASSERT(!NT_SUCCESS(Status
));
3218 if (!NT_SUCCESS(Status
))
3221 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3226 /* FIXME? are these values platform-dependent? */
3227 if(ImageSectionObject
->StackReserve
== 0)
3228 ImageSectionObject
->StackReserve
= 0x40000;
3230 if(ImageSectionObject
->StackCommit
== 0)
3231 ImageSectionObject
->StackCommit
= 0x1000;
3233 if(ImageSectionObject
->ImageBase
== 0)
3235 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3236 ImageSectionObject
->ImageBase
= 0x10000000;
3238 ImageSectionObject
->ImageBase
= 0x00400000;
3242 * And now the fun part: fixing the segments
3245 /* Sort them by virtual address */
3246 MmspSortSegments(ImageSectionObject
, Flags
);
3248 /* Ensure they don't overlap in memory */
3249 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3250 return STATUS_INVALID_IMAGE_FORMAT
;
3252 /* Ensure they are aligned */
3253 OldNrSegments
= ImageSectionObject
->NrSegments
;
3255 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3256 return STATUS_INVALID_IMAGE_FORMAT
;
3258 /* Trim them if the alignment phase merged some of them */
3259 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3261 PMM_SECTION_SEGMENT Segments
;
3262 SIZE_T SizeOfSegments
;
3264 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3266 Segments
= ExAllocatePoolWithTag(PagedPool
,
3268 TAG_MM_SECTION_SEGMENT
);
3270 if (Segments
== NULL
)
3271 return STATUS_INSUFFICIENT_RESOURCES
;
3273 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3274 ExFreePool(ImageSectionObject
->Segments
);
3275 ImageSectionObject
->Segments
= Segments
;
3278 /* And finish their initialization */
3279 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3281 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3282 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3284 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3285 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3288 ASSERT(NT_SUCCESS(Status
));
3293 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3294 ACCESS_MASK DesiredAccess
,
3295 POBJECT_ATTRIBUTES ObjectAttributes
,
3296 PLARGE_INTEGER UMaximumSize
,
3297 ULONG SectionPageProtection
,
3298 ULONG AllocationAttributes
,
3301 PROS_SECTION_OBJECT Section
;
3303 PFILE_OBJECT FileObject
;
3304 PMM_SECTION_SEGMENT SectionSegments
;
3305 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3307 ULONG FileAccess
= 0;
3310 * Specifying a maximum size is meaningless for an image section
3312 if (UMaximumSize
!= NULL
)
3314 return(STATUS_INVALID_PARAMETER_4
);
3318 * Check file access required
3320 if (SectionPageProtection
& PAGE_READWRITE
||
3321 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3323 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3327 FileAccess
= FILE_READ_DATA
;
3331 * Reference the file handle
3333 Status
= ObReferenceObjectByHandle(FileHandle
,
3336 ExGetPreviousMode(),
3337 (PVOID
*)(PVOID
)&FileObject
,
3340 if (!NT_SUCCESS(Status
))
3346 * Create the section
3348 Status
= ObCreateObject (ExGetPreviousMode(),
3349 MmSectionObjectType
,
3351 ExGetPreviousMode(),
3353 sizeof(ROS_SECTION_OBJECT
),
3356 (PVOID
*)(PVOID
)&Section
);
3357 if (!NT_SUCCESS(Status
))
3359 ObDereferenceObject(FileObject
);
3366 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3367 Section
->SectionPageProtection
= SectionPageProtection
;
3368 Section
->AllocationAttributes
= AllocationAttributes
;
3371 * Initialized caching for this file object if previously caching
3372 * was initialized for the same on disk file
3374 Status
= CcTryToInitializeFileCache(FileObject
);
3376 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3378 NTSTATUS StatusExeFmt
;
3380 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3381 if (ImageSectionObject
== NULL
)
3383 ObDereferenceObject(FileObject
);
3384 ObDereferenceObject(Section
);
3385 return(STATUS_NO_MEMORY
);
3388 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3390 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3392 if (!NT_SUCCESS(StatusExeFmt
))
3394 if(ImageSectionObject
->Segments
!= NULL
)
3395 ExFreePool(ImageSectionObject
->Segments
);
3397 ExFreePool(ImageSectionObject
);
3398 ObDereferenceObject(Section
);
3399 ObDereferenceObject(FileObject
);
3400 return(StatusExeFmt
);
3403 Section
->ImageSection
= ImageSectionObject
;
3404 ASSERT(ImageSectionObject
->Segments
);
3409 Status
= MmspWaitForFileLock(FileObject
);
3410 if (!NT_SUCCESS(Status
))
3412 ExFreePool(ImageSectionObject
->Segments
);
3413 ExFreePool(ImageSectionObject
);
3414 ObDereferenceObject(Section
);
3415 ObDereferenceObject(FileObject
);
3419 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3420 ImageSectionObject
, NULL
))
3423 * An other thread has initialized the same image in the background
3425 ExFreePool(ImageSectionObject
->Segments
);
3426 ExFreePool(ImageSectionObject
);
3427 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3428 Section
->ImageSection
= ImageSectionObject
;
3429 SectionSegments
= ImageSectionObject
->Segments
;
3431 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3433 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3437 Status
= StatusExeFmt
;
3444 Status
= MmspWaitForFileLock(FileObject
);
3445 if (Status
!= STATUS_SUCCESS
)
3447 ObDereferenceObject(Section
);
3448 ObDereferenceObject(FileObject
);
3452 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3453 Section
->ImageSection
= ImageSectionObject
;
3454 SectionSegments
= ImageSectionObject
->Segments
;
3457 * Otherwise just reference all the section segments
3459 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3461 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3464 Status
= STATUS_SUCCESS
;
3466 Section
->FileObject
= FileObject
;
3467 CcRosReferenceCache(FileObject
);
3468 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3469 *SectionObject
= Section
;
3477 NtCreateSection (OUT PHANDLE SectionHandle
,
3478 IN ACCESS_MASK DesiredAccess
,
3479 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3480 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3481 IN ULONG SectionPageProtection OPTIONAL
,
3482 IN ULONG AllocationAttributes
,
3483 IN HANDLE FileHandle OPTIONAL
)
3485 LARGE_INTEGER SafeMaximumSize
;
3486 PVOID SectionObject
;
3487 KPROCESSOR_MODE PreviousMode
;
3490 PreviousMode
= ExGetPreviousMode();
3492 if(PreviousMode
!= KernelMode
)
3496 if (MaximumSize
!= NULL
)
3498 /* make a copy on the stack */
3499 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3500 MaximumSize
= &SafeMaximumSize
;
3502 ProbeForWriteHandle(SectionHandle
);
3504 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3506 /* Return the exception code */
3507 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3512 Status
= MmCreateSection(&SectionObject
,
3516 SectionPageProtection
,
3517 AllocationAttributes
,
3520 if (NT_SUCCESS(Status
))
3522 Status
= ObInsertObject ((PVOID
)SectionObject
,
3534 /**********************************************************************
3552 NtOpenSection(PHANDLE SectionHandle
,
3553 ACCESS_MASK DesiredAccess
,
3554 POBJECT_ATTRIBUTES ObjectAttributes
)
3557 KPROCESSOR_MODE PreviousMode
;
3560 PreviousMode
= ExGetPreviousMode();
3562 if(PreviousMode
!= KernelMode
)
3566 ProbeForWriteHandle(SectionHandle
);
3568 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3570 /* Return the exception code */
3571 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3576 Status
= ObOpenObjectByName(ObjectAttributes
,
3577 MmSectionObjectType
,
3584 if(NT_SUCCESS(Status
))
3588 *SectionHandle
= hSection
;
3590 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3592 Status
= _SEH2_GetExceptionCode();
3601 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3602 PROS_SECTION_OBJECT Section
,
3603 PMM_SECTION_SEGMENT Segment
,
3608 ULONG AllocationType
)
3612 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3614 BoundaryAddressMultiple
.QuadPart
= 0;
3616 Status
= MmCreateMemoryArea(AddressSpace
,
3617 MEMORY_AREA_SECTION_VIEW
,
3624 BoundaryAddressMultiple
);
3625 if (!NT_SUCCESS(Status
))
3627 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3628 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3632 ObReferenceObject((PVOID
)Section
);
3634 MArea
->Data
.SectionData
.Segment
= Segment
;
3635 MArea
->Data
.SectionData
.Section
= Section
;
3636 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3637 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3638 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3639 ViewSize
, 0, Protect
);
3641 return(STATUS_SUCCESS
);
3645 /**********************************************************************
3647 * NtMapViewOfSection
3650 * Maps a view of a section into the virtual address space of a
3655 * Handle of the section.
3658 * Handle of the process.
3661 * Desired base address (or NULL) on entry;
3662 * Actual base address of the view on exit.
3665 * Number of high order address bits that must be zero.
3668 * Size in bytes of the initially committed section of
3672 * Offset in bytes from the beginning of the section
3673 * to the beginning of the view.
3676 * Desired length of map (or zero to map all) on entry
3677 * Actual length mapped on exit.
3679 * InheritDisposition
3680 * Specified how the view is to be shared with
3684 * Type of allocation for the pages.
3687 * Protection for the committed region of the view.
3695 NtMapViewOfSection(IN HANDLE SectionHandle
,
3696 IN HANDLE ProcessHandle
,
3697 IN OUT PVOID
* BaseAddress OPTIONAL
,
3698 IN ULONG_PTR ZeroBits OPTIONAL
,
3699 IN SIZE_T CommitSize
,
3700 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3701 IN OUT PSIZE_T ViewSize
,
3702 IN SECTION_INHERIT InheritDisposition
,
3703 IN ULONG AllocationType OPTIONAL
,
3706 PVOID SafeBaseAddress
;
3707 LARGE_INTEGER SafeSectionOffset
;
3708 SIZE_T SafeViewSize
;
3709 PROS_SECTION_OBJECT Section
;
3711 KPROCESSOR_MODE PreviousMode
;
3714 ACCESS_MASK DesiredAccess
;
3717 * Check the protection
3719 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3721 return STATUS_INVALID_PARAMETER_10
;
3724 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3725 if (tmpProtect
!= PAGE_NOACCESS
&&
3726 tmpProtect
!= PAGE_READONLY
&&
3727 tmpProtect
!= PAGE_READWRITE
&&
3728 tmpProtect
!= PAGE_WRITECOPY
&&
3729 tmpProtect
!= PAGE_EXECUTE
&&
3730 tmpProtect
!= PAGE_EXECUTE_READ
&&
3731 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3732 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3734 return STATUS_INVALID_PAGE_PROTECTION
;
3737 PreviousMode
= ExGetPreviousMode();
3739 if(PreviousMode
!= KernelMode
)
3741 SafeBaseAddress
= NULL
;
3742 SafeSectionOffset
.QuadPart
= 0;
3747 if(BaseAddress
!= NULL
)
3749 ProbeForWritePointer(BaseAddress
);
3750 SafeBaseAddress
= *BaseAddress
;
3752 if(SectionOffset
!= NULL
)
3754 ProbeForWriteLargeInteger(SectionOffset
);
3755 SafeSectionOffset
= *SectionOffset
;
3757 ProbeForWriteSize_t(ViewSize
);
3758 SafeViewSize
= *ViewSize
;
3760 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3762 /* Return the exception code */
3763 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3769 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3770 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3771 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3774 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3776 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3777 PROCESS_VM_OPERATION
,
3780 (PVOID
*)(PVOID
)&Process
,
3782 if (!NT_SUCCESS(Status
))
3787 /* Convert NT Protection Attr to Access Mask */
3788 if (Protect
== PAGE_READONLY
)
3790 DesiredAccess
= SECTION_MAP_READ
;
3792 else if (Protect
== PAGE_READWRITE
)
3794 DesiredAccess
= SECTION_MAP_WRITE
;
3796 else if (Protect
== PAGE_WRITECOPY
)
3798 DesiredAccess
= SECTION_QUERY
;
3800 /* FIXME: Handle other Protection Attributes. For now keep previous behavior */
3803 DesiredAccess
= SECTION_MAP_READ
;
3806 Status
= ObReferenceObjectByHandle(SectionHandle
,
3808 MmSectionObjectType
,
3810 (PVOID
*)(PVOID
)&Section
,
3812 if (!(NT_SUCCESS(Status
)))
3814 DPRINT("ObReference failed rc=%x\n",Status
);
3815 ObDereferenceObject(Process
);
3819 Status
= MmMapViewOfSection(Section
,
3821 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3824 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3825 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3830 /* Check if this is an image for the current process */
3831 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3832 (Process
== PsGetCurrentProcess()) &&
3833 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3835 /* Notify the debugger */
3836 DbgkMapViewOfSection(Section
,
3838 SafeSectionOffset
.LowPart
,
3842 ObDereferenceObject(Section
);
3843 ObDereferenceObject(Process
);
3845 if(NT_SUCCESS(Status
))
3847 /* copy parameters back to the caller */
3850 if(BaseAddress
!= NULL
)
3852 *BaseAddress
= SafeBaseAddress
;
3854 if(SectionOffset
!= NULL
)
3856 *SectionOffset
= SafeSectionOffset
;
3858 if(ViewSize
!= NULL
)
3860 *ViewSize
= SafeViewSize
;
3863 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3865 Status
= _SEH2_GetExceptionCode();
3874 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3875 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3878 PFILE_OBJECT FileObject
;
3881 SWAPENTRY SavedSwapEntry
;
3884 PROS_SECTION_OBJECT Section
;
3885 PMM_SECTION_SEGMENT Segment
;
3886 PMMSUPPORT AddressSpace
;
3889 AddressSpace
= (PMMSUPPORT
)Context
;
3890 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3892 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3894 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3895 MemoryArea
->Data
.SectionData
.ViewOffset
;
3897 Section
= MemoryArea
->Data
.SectionData
.Section
;
3898 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3900 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3904 MmUnlockSectionSegment(Segment
);
3905 MmUnlockAddressSpace(AddressSpace
);
3907 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3908 if (Status
!= STATUS_SUCCESS
)
3910 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3911 KeBugCheck(MEMORY_MANAGEMENT
);
3914 MmLockAddressSpace(AddressSpace
);
3915 MmLockSectionSegment(Segment
);
3916 MmspCompleteAndReleasePageOp(PageOp
);
3917 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3920 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3923 * For a dirty, datafile, non-private page mark it as dirty in the
3926 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3928 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3930 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3931 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3932 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3933 ASSERT(SwapEntry
== 0);
3942 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3944 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3945 KeBugCheck(MEMORY_MANAGEMENT
);
3947 MmFreeSwapPage(SwapEntry
);
3951 if (IS_SWAP_FROM_SSE(Entry
) ||
3952 Page
!= PFN_FROM_SSE(Entry
))
3957 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3959 DPRINT1("Found a private page in a pagefile section.\n");
3960 KeBugCheck(MEMORY_MANAGEMENT
);
3963 * Just dereference private pages
3965 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3966 if (SavedSwapEntry
!= 0)
3968 MmFreeSwapPage(SavedSwapEntry
);
3969 MmSetSavedSwapEntryPage(Page
, 0);
3971 MmDeleteRmap(Page
, Process
, Address
);
3972 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3976 MmDeleteRmap(Page
, Process
, Address
);
3977 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3983 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
3987 PMEMORY_AREA MemoryArea
;
3988 PROS_SECTION_OBJECT Section
;
3989 PMM_SECTION_SEGMENT Segment
;
3990 PLIST_ENTRY CurrentEntry
;
3991 PMM_REGION CurrentRegion
;
3992 PLIST_ENTRY RegionListHead
;
3994 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3996 if (MemoryArea
== NULL
)
3998 return(STATUS_UNSUCCESSFUL
);
4001 MemoryArea
->DeleteInProgress
= TRUE
;
4002 Section
= MemoryArea
->Data
.SectionData
.Section
;
4003 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4005 MmLockSectionSegment(Segment
);
4007 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4008 while (!IsListEmpty(RegionListHead
))
4010 CurrentEntry
= RemoveHeadList(RegionListHead
);
4011 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4012 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4015 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4017 Status
= MmFreeMemoryArea(AddressSpace
,
4024 Status
= MmFreeMemoryArea(AddressSpace
,
4029 MmUnlockSectionSegment(Segment
);
4030 ObDereferenceObject(Section
);
4038 MmUnmapViewOfSection(PEPROCESS Process
,
4042 PMEMORY_AREA MemoryArea
;
4043 PMMSUPPORT AddressSpace
;
4044 PROS_SECTION_OBJECT Section
;
4047 PVOID ImageBaseAddress
= 0;
4049 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4050 Process
, BaseAddress
);
4054 AddressSpace
= &Process
->Vm
;
4056 MmLockAddressSpace(AddressSpace
);
4057 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4059 if (MemoryArea
== NULL
||
4060 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4061 MemoryArea
->DeleteInProgress
)
4063 MmUnlockAddressSpace(AddressSpace
);
4064 return STATUS_NOT_MAPPED_VIEW
;
4067 MemoryArea
->DeleteInProgress
= TRUE
;
4069 while (MemoryArea
->PageOpCount
)
4071 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4075 Offset
-= PAGE_SIZE
;
4076 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4077 MemoryArea
->Data
.SectionData
.Segment
,
4078 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4081 MmUnlockAddressSpace(AddressSpace
);
4082 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4083 if (Status
!= STATUS_SUCCESS
)
4085 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4086 KeBugCheck(MEMORY_MANAGEMENT
);
4088 MmLockAddressSpace(AddressSpace
);
4089 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4091 if (MemoryArea
== NULL
||
4092 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4094 MmUnlockAddressSpace(AddressSpace
);
4095 return STATUS_NOT_MAPPED_VIEW
;
4102 Section
= MemoryArea
->Data
.SectionData
.Section
;
4104 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4108 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4109 PMM_SECTION_SEGMENT SectionSegments
;
4110 PMM_SECTION_SEGMENT Segment
;
4112 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4113 ImageSectionObject
= Section
->ImageSection
;
4114 SectionSegments
= ImageSectionObject
->Segments
;
4115 NrSegments
= ImageSectionObject
->NrSegments
;
4117 /* Search for the current segment within the section segments
4118 * and calculate the image base address */
4119 for (i
= 0; i
< NrSegments
; i
++)
4121 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4123 if (Segment
== &SectionSegments
[i
])
4125 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4130 if (i
>= NrSegments
)
4132 KeBugCheck(MEMORY_MANAGEMENT
);
4135 for (i
= 0; i
< NrSegments
; i
++)
4137 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4139 PVOID SBaseAddress
= (PVOID
)
4140 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4142 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4148 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4151 MmUnlockAddressSpace(AddressSpace
);
4153 /* Notify debugger */
4154 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4156 return(STATUS_SUCCESS
);
4159 /**********************************************************************
4161 * NtUnmapViewOfSection
4176 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4180 KPROCESSOR_MODE PreviousMode
;
4183 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4184 ProcessHandle
, BaseAddress
);
4186 PreviousMode
= ExGetPreviousMode();
4188 DPRINT("Referencing process\n");
4189 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4190 PROCESS_VM_OPERATION
,
4193 (PVOID
*)(PVOID
)&Process
,
4195 if (!NT_SUCCESS(Status
))
4197 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4201 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4203 ObDereferenceObject(Process
);
4210 * Queries the information of a section object.
4212 * @param SectionHandle
4213 * Handle to the section object. It must be opened with SECTION_QUERY
4215 * @param SectionInformationClass
4216 * Index to a certain information structure. Can be either
4217 * SectionBasicInformation or SectionImageInformation. The latter
4218 * is valid only for sections that were created with the SEC_IMAGE
4220 * @param SectionInformation
4221 * Caller supplies storage for resulting information.
4223 * Size of the supplied storage.
4224 * @param ResultLength
4232 NtQuerySection(IN HANDLE SectionHandle
,
4233 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4234 OUT PVOID SectionInformation
,
4235 IN SIZE_T SectionInformationLength
,
4236 OUT PSIZE_T ResultLength OPTIONAL
)
4238 PROS_SECTION_OBJECT Section
;
4239 KPROCESSOR_MODE PreviousMode
;
4243 PreviousMode
= ExGetPreviousMode();
4245 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4247 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4249 SectionInformationLength
,
4254 if(!NT_SUCCESS(Status
))
4256 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4260 Status
= ObReferenceObjectByHandle(SectionHandle
,
4262 MmSectionObjectType
,
4264 (PVOID
*)(PVOID
)&Section
,
4266 if (NT_SUCCESS(Status
))
4268 switch (SectionInformationClass
)
4270 case SectionBasicInformation
:
4272 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4276 Sbi
->Attributes
= Section
->AllocationAttributes
;
4277 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4279 Sbi
->BaseAddress
= 0;
4280 Sbi
->Size
.QuadPart
= 0;
4284 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4285 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4288 if (ResultLength
!= NULL
)
4290 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4292 Status
= STATUS_SUCCESS
;
4294 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4296 Status
= _SEH2_GetExceptionCode();
4303 case SectionImageInformation
:
4305 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4309 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4310 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4312 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4313 ImageSectionObject
= Section
->ImageSection
;
4315 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4316 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4317 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4318 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4319 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4320 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4321 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4322 Sii
->Machine
= ImageSectionObject
->Machine
;
4323 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4326 if (ResultLength
!= NULL
)
4328 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4330 Status
= STATUS_SUCCESS
;
4332 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4334 Status
= _SEH2_GetExceptionCode();
4342 ObDereferenceObject(Section
);
4350 * Extends size of file backed section.
4352 * @param SectionHandle
4353 * Handle to the section object. It must be opened with
4354 * SECTION_EXTEND_SIZE access.
4355 * @param NewMaximumSize
4356 * New maximum size of the section in bytes.
4360 * @todo Move the actual code to internal function MmExtendSection.
4364 NtExtendSection(IN HANDLE SectionHandle
,
4365 IN PLARGE_INTEGER NewMaximumSize
)
4367 LARGE_INTEGER SafeNewMaximumSize
;
4368 PROS_SECTION_OBJECT Section
;
4369 KPROCESSOR_MODE PreviousMode
;
4372 PreviousMode
= ExGetPreviousMode();
4374 if(PreviousMode
!= KernelMode
)
4378 /* make a copy on the stack */
4379 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4380 NewMaximumSize
= &SafeNewMaximumSize
;
4382 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4384 /* Return the exception code */
4385 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4390 Status
= ObReferenceObjectByHandle(SectionHandle
,
4391 SECTION_EXTEND_SIZE
,
4392 MmSectionObjectType
,
4396 if (!NT_SUCCESS(Status
))
4401 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4403 ObDereferenceObject(Section
);
4404 return STATUS_INVALID_PARAMETER
;
4408 * - Acquire file extneding resource.
4409 * - Check if we're not resizing the section below it's actual size!
4410 * - Extend segments if needed.
4411 * - Set file information (FileAllocationInformation) to the new size.
4412 * - Release file extending resource.
4415 ObDereferenceObject(Section
);
4417 return STATUS_NOT_IMPLEMENTED
;
4420 /**********************************************************************
4422 * MmMapViewOfSection
4425 * Maps a view of a section into the virtual address space of a
4430 * Pointer to the section object.
4433 * Pointer to the process.
4436 * Desired base address (or NULL) on entry;
4437 * Actual base address of the view on exit.
4440 * Number of high order address bits that must be zero.
4443 * Size in bytes of the initially committed section of
4447 * Offset in bytes from the beginning of the section
4448 * to the beginning of the view.
4451 * Desired length of map (or zero to map all) on entry
4452 * Actual length mapped on exit.
4454 * InheritDisposition
4455 * Specified how the view is to be shared with
4459 * Type of allocation for the pages.
4462 * Protection for the committed region of the view.
4470 MmMapViewOfSection(IN PVOID SectionObject
,
4471 IN PEPROCESS Process
,
4472 IN OUT PVOID
*BaseAddress
,
4473 IN ULONG_PTR ZeroBits
,
4474 IN SIZE_T CommitSize
,
4475 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4476 IN OUT PSIZE_T ViewSize
,
4477 IN SECTION_INHERIT InheritDisposition
,
4478 IN ULONG AllocationType
,
4481 PROS_SECTION_OBJECT Section
;
4482 PMMSUPPORT AddressSpace
;
4484 NTSTATUS Status
= STATUS_SUCCESS
;
4488 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4490 return STATUS_INVALID_PAGE_PROTECTION
;
4494 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4495 AddressSpace
= &Process
->Vm
;
4497 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4499 MmLockAddressSpace(AddressSpace
);
4501 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4505 ULONG_PTR ImageBase
;
4507 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4508 PMM_SECTION_SEGMENT SectionSegments
;
4510 ImageSectionObject
= Section
->ImageSection
;
4511 SectionSegments
= ImageSectionObject
->Segments
;
4512 NrSegments
= ImageSectionObject
->NrSegments
;
4515 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4518 ImageBase
= ImageSectionObject
->ImageBase
;
4522 for (i
= 0; i
< NrSegments
; i
++)
4524 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4526 ULONG_PTR MaxExtent
;
4527 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4528 SectionSegments
[i
].Length
;
4529 ImageSize
= max(ImageSize
, MaxExtent
);
4533 ImageSectionObject
->ImageSize
= ImageSize
;
4535 /* Check there is enough space to map the section at that point. */
4536 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4537 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4539 /* Fail if the user requested a fixed base address. */
4540 if ((*BaseAddress
) != NULL
)
4542 MmUnlockAddressSpace(AddressSpace
);
4543 return(STATUS_UNSUCCESSFUL
);
4545 /* Otherwise find a gap to map the image. */
4546 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4549 MmUnlockAddressSpace(AddressSpace
);
4550 return(STATUS_UNSUCCESSFUL
);
4554 for (i
= 0; i
< NrSegments
; i
++)
4556 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4558 PVOID SBaseAddress
= (PVOID
)
4559 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4560 MmLockSectionSegment(&SectionSegments
[i
]);
4561 Status
= MmMapViewOfSegment(AddressSpace
,
4563 &SectionSegments
[i
],
4565 SectionSegments
[i
].Length
,
4566 SectionSegments
[i
].Protection
,
4569 MmUnlockSectionSegment(&SectionSegments
[i
]);
4570 if (!NT_SUCCESS(Status
))
4572 MmUnlockAddressSpace(AddressSpace
);
4578 *BaseAddress
= (PVOID
)ImageBase
;
4582 /* check for write access */
4583 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4584 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4586 MmUnlockAddressSpace(AddressSpace
);
4587 return STATUS_SECTION_PROTECTION
;
4589 /* check for read access */
4590 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4591 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4593 MmUnlockAddressSpace(AddressSpace
);
4594 return STATUS_SECTION_PROTECTION
;
4596 /* check for execute access */
4597 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4598 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4600 MmUnlockAddressSpace(AddressSpace
);
4601 return STATUS_SECTION_PROTECTION
;
4604 if (ViewSize
== NULL
)
4606 /* Following this pointer would lead to us to the dark side */
4607 /* What to do? Bugcheck? Return status? Do the mambo? */
4608 KeBugCheck(MEMORY_MANAGEMENT
);
4611 if (SectionOffset
== NULL
)
4617 ViewOffset
= SectionOffset
->u
.LowPart
;
4620 if ((ViewOffset
% PAGE_SIZE
) != 0)
4622 MmUnlockAddressSpace(AddressSpace
);
4623 return(STATUS_MAPPED_ALIGNMENT
);
4626 if ((*ViewSize
) == 0)
4628 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4630 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4632 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4635 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4637 MmLockSectionSegment(Section
->Segment
);
4638 Status
= MmMapViewOfSegment(AddressSpace
,
4645 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4646 MmUnlockSectionSegment(Section
->Segment
);
4647 if (!NT_SUCCESS(Status
))
4649 MmUnlockAddressSpace(AddressSpace
);
4654 MmUnlockAddressSpace(AddressSpace
);
4656 return(STATUS_SUCCESS
);
4663 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4664 IN PLARGE_INTEGER NewFileSize
)
4666 /* Check whether an ImageSectionObject exists */
4667 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4669 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4673 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4675 PMM_SECTION_SEGMENT Segment
;
4677 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4680 if (Segment
->ReferenceCount
!= 0)
4682 /* Check size of file */
4683 if (SectionObjectPointer
->SharedCacheMap
)
4685 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4686 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4694 /* Something must gone wrong
4695 * how can we have a Section but no
4697 DPRINT("ERROR: DataSectionObject without reference!\n");
4701 DPRINT("FIXME: didn't check for outstanding write probes\n");
4711 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4721 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4722 IN MMFLUSH_TYPE FlushType
)
4726 case MmFlushForDelete
:
4727 if (SectionObjectPointer
->ImageSectionObject
||
4728 SectionObjectPointer
->DataSectionObject
)
4732 CcRosSetRemoveOnClose(SectionObjectPointer
);
4734 case MmFlushForWrite
:
4744 MmForceSectionClosed (
4745 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4746 IN BOOLEAN DelayClose
)
4757 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4758 OUT PVOID
* MappedBase
,
4759 IN OUT PSIZE_T ViewSize
)
4761 PROS_SECTION_OBJECT Section
;
4762 PMMSUPPORT AddressSpace
;
4765 DPRINT("MmMapViewInSystemSpace() called\n");
4767 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4768 AddressSpace
= MmGetKernelAddressSpace();
4770 MmLockAddressSpace(AddressSpace
);
4773 if ((*ViewSize
) == 0)
4775 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4777 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4779 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4782 MmLockSectionSegment(Section
->Segment
);
4785 Status
= MmMapViewOfSegment(AddressSpace
,
4794 MmUnlockSectionSegment(Section
->Segment
);
4795 MmUnlockAddressSpace(AddressSpace
);
4805 MmMapViewInSessionSpace (
4807 OUT PVOID
*MappedBase
,
4808 IN OUT PSIZE_T ViewSize
4812 return STATUS_NOT_IMPLEMENTED
;
4820 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4822 PMMSUPPORT AddressSpace
;
4825 DPRINT("MmUnmapViewInSystemSpace() called\n");
4827 AddressSpace
= MmGetKernelAddressSpace();
4829 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4839 MmUnmapViewInSessionSpace (
4844 return STATUS_NOT_IMPLEMENTED
;
4847 /**********************************************************************
4852 * Creates a section object.
4855 * SectionObject (OUT)
4856 * Caller supplied storage for the resulting pointer
4857 * to a SECTION_OBJECT instance;
4860 * Specifies the desired access to the section can be a
4862 * STANDARD_RIGHTS_REQUIRED |
4864 * SECTION_MAP_WRITE |
4865 * SECTION_MAP_READ |
4866 * SECTION_MAP_EXECUTE
4868 * ObjectAttributes [OPTIONAL]
4869 * Initialized attributes for the object can be used
4870 * to create a named section;
4873 * Maximizes the size of the memory section. Must be
4874 * non-NULL for a page-file backed section.
4875 * If value specified for a mapped file and the file is
4876 * not large enough, file will be extended.
4878 * SectionPageProtection
4879 * Can be a combination of:
4885 * AllocationAttributes
4886 * Can be a combination of:
4891 * Handle to a file to create a section mapped to a file
4892 * instead of a memory backed section;
4903 MmCreateSection (OUT PVOID
* Section
,
4904 IN ACCESS_MASK DesiredAccess
,
4905 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4906 IN PLARGE_INTEGER MaximumSize
,
4907 IN ULONG SectionPageProtection
,
4908 IN ULONG AllocationAttributes
,
4909 IN HANDLE FileHandle OPTIONAL
,
4910 IN PFILE_OBJECT File OPTIONAL
)
4913 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4916 * Check the protection
4918 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4919 if (Protection
!= PAGE_READONLY
&&
4920 Protection
!= PAGE_READWRITE
&&
4921 Protection
!= PAGE_WRITECOPY
&&
4922 Protection
!= PAGE_EXECUTE
&&
4923 Protection
!= PAGE_EXECUTE_READ
&&
4924 Protection
!= PAGE_EXECUTE_READWRITE
&&
4925 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4927 return STATUS_INVALID_PAGE_PROTECTION
;
4930 if (AllocationAttributes
& SEC_IMAGE
)
4932 return(MmCreateImageSection(SectionObject
,
4936 SectionPageProtection
,
4937 AllocationAttributes
,
4941 if (FileHandle
!= NULL
)
4943 return(MmCreateDataFileSection(SectionObject
,
4947 SectionPageProtection
,
4948 AllocationAttributes
,
4952 return(MmCreatePageFileSection(SectionObject
,
4956 SectionPageProtection
,
4957 AllocationAttributes
));
4962 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
4963 IN PVOID File2MappedAsFile
)
4966 return STATUS_NOT_IMPLEMENTED
;