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 ULONG_PTR MmSubsectionBase
;
76 static GENERIC_MAPPING MmpSectionMapping
= {
77 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
78 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
79 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
82 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
83 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
84 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
85 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
86 #define MAX_SHARE_COUNT 0x7FF
87 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
88 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
89 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
91 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
93 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
94 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
97 /* FUNCTIONS *****************************************************************/
101 MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section
)
106 /* Return the file object */
107 return Section
->FileObject
; // Section->ControlArea->FileObject on NT
112 MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section
,
113 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
115 POBJECT_NAME_INFORMATION ObjectNameInfo
;
119 /* Make sure it's an image section */
121 if (!(Section
->AllocationAttributes
& SEC_IMAGE
))
124 return STATUS_SECTION_NOT_IMAGE
;
127 /* Allocate memory for our structure */
128 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
,
131 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
134 Status
= ObQueryNameString(Section
->FileObject
,
138 if (!NT_SUCCESS(Status
))
140 /* Failed, free memory */
141 ExFreePoolWithTag(ObjectNameInfo
, ' mM');
146 *ModuleName
= ObjectNameInfo
;
147 return STATUS_SUCCESS
;
152 MmGetFileNameForAddress(IN PVOID Address
,
153 OUT PUNICODE_STRING ModuleName
)
155 PROS_SECTION_OBJECT Section
;
156 PMEMORY_AREA MemoryArea
;
157 PMMSUPPORT AddressSpace
;
158 POBJECT_NAME_INFORMATION ModuleNameInformation
;
159 NTSTATUS Status
= STATUS_ADDRESS_NOT_ASSOCIATED
;
161 /* Get the MM_AVL_TABLE from EPROCESS */
162 if (Address
>= MmSystemRangeStart
)
164 AddressSpace
= MmGetKernelAddressSpace();
168 AddressSpace
= &PsGetCurrentProcess()->Vm
;
171 /* Lock address space */
172 MmLockAddressSpace(AddressSpace
);
174 /* Locate the memory area for the process by address */
175 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
177 /* Make sure it's a section view type */
178 if ((MemoryArea
!= NULL
) && (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
))
180 /* Get the section pointer to the SECTION_OBJECT */
181 Section
= MemoryArea
->Data
.SectionData
.Section
;
183 /* Unlock address space */
184 MmUnlockAddressSpace(AddressSpace
);
186 /* Get the filename of the section */
187 Status
= MmGetFileNameForSection(Section
,&ModuleNameInformation
);
189 if (NT_SUCCESS(Status
))
191 /* Init modulename */
192 RtlCreateUnicodeString(ModuleName
,
193 ModuleNameInformation
->Name
.Buffer
);
195 /* Free temp taged buffer from MmGetFileNameForSection() */
196 ExFreePoolWithTag(ModuleNameInformation
, ' mM');
197 DPRINT("Found ModuleName %S by address %p\n",
198 ModuleName
->Buffer
,Address
);
203 /* Unlock address space */
204 MmUnlockAddressSpace(AddressSpace
);
210 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
213 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
214 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
215 * RETURNS: Status of the wait.
218 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
220 LARGE_INTEGER Timeout
;
221 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
223 Timeout
.QuadPart
= -100000000LL; // 10 sec
226 Timeout
.QuadPart
= -100000000; // 10 sec
229 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
234 * FUNCTION: Sets the page op completion event and releases the page op.
235 * ARGUMENTS: PMM_PAGEOP.
236 * RETURNS: In shorter time than it takes you to even read this
237 * description, so don't even think about geting a mug of coffee.
240 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
242 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
243 MmReleasePageOp(PageOp
);
248 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
249 * ARGUMENTS: PFILE_OBJECT to wait for.
250 * RETURNS: Status of the wait.
253 MmspWaitForFileLock(PFILE_OBJECT File
)
255 return STATUS_SUCCESS
;
256 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
261 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
264 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
266 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
268 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
270 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
278 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
280 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
282 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
283 PMM_SECTION_SEGMENT SectionSegments
;
287 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
288 NrSegments
= ImageSectionObject
->NrSegments
;
289 SectionSegments
= ImageSectionObject
->Segments
;
290 for (i
= 0; i
< NrSegments
; i
++)
292 if (SectionSegments
[i
].ReferenceCount
!= 0)
294 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
295 SectionSegments
[i
].ReferenceCount
);
296 KeBugCheck(MEMORY_MANAGEMENT
);
298 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
300 ExFreePool(ImageSectionObject
->Segments
);
301 ExFreePool(ImageSectionObject
);
302 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
304 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
306 PMM_SECTION_SEGMENT Segment
;
308 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
311 if (Segment
->ReferenceCount
!= 0)
313 DPRINT1("Data segment still referenced\n");
314 KeBugCheck(MEMORY_MANAGEMENT
);
316 MmFreePageTablesSectionSegment(Segment
);
318 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
324 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
326 ExAcquireFastMutex(&Segment
->Lock
);
331 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
333 ExReleaseFastMutex(&Segment
->Lock
);
338 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
342 PSECTION_PAGE_TABLE Table
;
343 ULONG DirectoryOffset
;
346 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
348 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
352 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
353 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
357 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
358 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
359 TAG_SECTION_PAGE_TABLE
);
362 KeBugCheck(MEMORY_MANAGEMENT
);
364 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
365 DPRINT("Table %x\n", Table
);
368 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
369 Table
->Entry
[TableOffset
] = Entry
;
375 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
378 PSECTION_PAGE_TABLE Table
;
380 ULONG DirectoryOffset
;
383 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
385 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
387 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
391 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
392 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
393 DPRINT("Table %x\n", Table
);
399 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
400 Entry
= Table
->Entry
[TableOffset
];
406 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
411 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
414 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
415 KeBugCheck(MEMORY_MANAGEMENT
);
417 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
419 DPRINT1("Maximum share count reached\n");
420 KeBugCheck(MEMORY_MANAGEMENT
);
422 if (IS_SWAP_FROM_SSE(Entry
))
424 KeBugCheck(MEMORY_MANAGEMENT
);
426 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
427 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
432 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
433 PMM_SECTION_SEGMENT Segment
,
439 BOOLEAN IsDirectMapped
= FALSE
;
441 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
444 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
445 KeBugCheck(MEMORY_MANAGEMENT
);
447 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
449 DPRINT1("Zero share count for unshare\n");
450 KeBugCheck(MEMORY_MANAGEMENT
);
452 if (IS_SWAP_FROM_SSE(Entry
))
454 KeBugCheck(MEMORY_MANAGEMENT
);
456 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
458 * If we reducing the share count of this entry to zero then set the entry
459 * to zero and tell the cache the page is no longer mapped.
461 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
463 PFILE_OBJECT FileObject
;
465 SWAPENTRY SavedSwapEntry
;
467 BOOLEAN IsImageSection
;
470 FileOffset
= Offset
+ Segment
->FileOffset
;
472 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
474 Page
= PFN_FROM_SSE(Entry
);
475 FileObject
= Section
->FileObject
;
476 if (FileObject
!= NULL
&&
477 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
480 if ((FileOffset
% PAGE_SIZE
) == 0 &&
481 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
484 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
485 IsDirectMapped
= TRUE
;
486 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
487 if (!NT_SUCCESS(Status
))
489 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
490 KeBugCheck(MEMORY_MANAGEMENT
);
495 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
496 if (SavedSwapEntry
== 0)
499 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
500 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
504 * Try to page out this page and set the swap entry
505 * within the section segment. There exist no rmap entry
506 * for this page. The pager thread can't page out a
507 * page without a rmap entry.
509 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
513 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
516 MmReleasePageMemoryConsumer(MC_USER
, Page
);
522 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
523 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
531 * We hold all locks. Nobody can do something with the current
532 * process and the current segment (also not within an other process).
535 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
536 if (!NT_SUCCESS(Status
))
538 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
539 KeBugCheck(MEMORY_MANAGEMENT
);
542 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
543 MmSetSavedSwapEntryPage(Page
, 0);
545 MmReleasePageMemoryConsumer(MC_USER
, Page
);
549 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
550 KeBugCheck(MEMORY_MANAGEMENT
);
556 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
558 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
561 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
564 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
567 PCACHE_SEGMENT CacheSeg
;
568 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
569 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
572 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
581 MiCopyFromUserPage(PFN_TYPE DestPage
, PVOID SourceAddress
)
587 Process
= PsGetCurrentProcess();
588 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
589 if (TempAddress
== NULL
)
591 return(STATUS_NO_MEMORY
);
593 memcpy(TempAddress
, SourceAddress
, PAGE_SIZE
);
594 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
595 return(STATUS_SUCCESS
);
600 MiReadPage(PMEMORY_AREA MemoryArea
,
604 * FUNCTION: Read a page for a section backed memory area.
606 * MemoryArea - Memory area to read the page for.
607 * Offset - Offset of the page to read.
608 * Page - Variable that receives a page contains the read data.
615 PCACHE_SEGMENT CacheSeg
;
616 PFILE_OBJECT FileObject
;
620 BOOLEAN IsImageSection
;
623 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
624 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
625 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
626 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
627 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
631 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
634 * If the file system is letting us go directly to the cache and the
635 * memory area was mapped at an offset in the file which is page aligned
636 * then get the related cache segment.
638 if ((FileOffset
% PAGE_SIZE
) == 0 &&
639 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
640 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
644 * Get the related cache segment; we use a lower level interface than
645 * filesystems do because it is safe for us to use an offset with a
646 * alignment less than the file system block size.
648 Status
= CcRosGetCacheSegment(Bcb
,
654 if (!NT_SUCCESS(Status
))
661 * If the cache segment isn't up to date then call the file
662 * system to read in the data.
664 Status
= ReadCacheSegment(CacheSeg
);
665 if (!NT_SUCCESS(Status
))
667 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
672 * Retrieve the page from the cache segment that we actually want.
674 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
675 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
677 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
684 ULONG CacheSegOffset
;
687 * Allocate a page, this is rather complicated by the possibility
688 * we might have to move other things out of memory
690 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
691 if (!NT_SUCCESS(Status
))
695 Status
= CcRosGetCacheSegment(Bcb
,
701 if (!NT_SUCCESS(Status
))
708 * If the cache segment isn't up to date then call the file
709 * system to read in the data.
711 Status
= ReadCacheSegment(CacheSeg
);
712 if (!NT_SUCCESS(Status
))
714 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
719 Process
= PsGetCurrentProcess();
720 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
721 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
722 Length
= RawLength
- SegOffset
;
723 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
725 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
727 else if (CacheSegOffset
>= PAGE_SIZE
)
729 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
733 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
734 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
735 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
736 Status
= CcRosGetCacheSegment(Bcb
,
737 FileOffset
+ CacheSegOffset
,
742 if (!NT_SUCCESS(Status
))
749 * If the cache segment isn't up to date then call the file
750 * system to read in the data.
752 Status
= ReadCacheSegment(CacheSeg
);
753 if (!NT_SUCCESS(Status
))
755 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
759 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
760 if (Length
< PAGE_SIZE
)
762 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
766 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
769 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
770 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
772 return(STATUS_SUCCESS
);
777 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
778 MEMORY_AREA
* MemoryArea
,
786 PROS_SECTION_OBJECT Section
;
787 PMM_SECTION_SEGMENT Segment
;
793 BOOLEAN HasSwapEntry
;
794 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
797 * There is a window between taking the page fault and locking the
798 * address space when another thread could load the page so we check
801 if (MmIsPagePresent(Process
, Address
))
803 return(STATUS_SUCCESS
);
806 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
807 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
808 + MemoryArea
->Data
.SectionData
.ViewOffset
;
810 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
811 Section
= MemoryArea
->Data
.SectionData
.Section
;
812 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
813 &MemoryArea
->Data
.SectionData
.RegionListHead
,
818 MmLockSectionSegment(Segment
);
821 * Check if this page needs to be mapped COW
823 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
824 (Region
->Protect
== PAGE_READWRITE
||
825 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
827 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
831 Attributes
= Region
->Protect
;
835 * Get or create a page operation descriptor
837 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
840 DPRINT1("MmGetPageOp failed\n");
841 KeBugCheck(MEMORY_MANAGEMENT
);
845 * Check if someone else is already handling this fault, if so wait
848 if (PageOp
->Thread
!= PsGetCurrentThread())
850 MmUnlockSectionSegment(Segment
);
851 MmUnlockAddressSpace(AddressSpace
);
852 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
854 * Check for various strange conditions
856 if (Status
!= STATUS_SUCCESS
)
858 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
859 KeBugCheck(MEMORY_MANAGEMENT
);
861 if (PageOp
->Status
== STATUS_PENDING
)
863 DPRINT1("Woke for page op before completion\n");
864 KeBugCheck(MEMORY_MANAGEMENT
);
866 MmLockAddressSpace(AddressSpace
);
868 * If this wasn't a pagein then restart the operation
870 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
872 MmspCompleteAndReleasePageOp(PageOp
);
873 DPRINT("Address 0x%.8X\n", Address
);
874 return(STATUS_MM_RESTART_OPERATION
);
878 * If the thread handling this fault has failed then we don't retry
880 if (!NT_SUCCESS(PageOp
->Status
))
882 Status
= PageOp
->Status
;
883 MmspCompleteAndReleasePageOp(PageOp
);
884 DPRINT("Address 0x%.8X\n", Address
);
887 MmLockSectionSegment(Segment
);
889 * If the completed fault was for another address space then set the
892 if (!MmIsPagePresent(Process
, Address
))
894 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
895 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
897 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
900 * The page was a private page in another or in our address space
902 MmUnlockSectionSegment(Segment
);
903 MmspCompleteAndReleasePageOp(PageOp
);
904 return(STATUS_MM_RESTART_OPERATION
);
907 Page
= PFN_FROM_SSE(Entry
);
909 MmSharePageEntrySectionSegment(Segment
, Offset
);
911 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
912 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
914 Status
= MmCreateVirtualMapping(Process
,
919 if (!NT_SUCCESS(Status
))
921 DPRINT1("Unable to create virtual mapping\n");
922 KeBugCheck(MEMORY_MANAGEMENT
);
924 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
926 MmUnlockSectionSegment(Segment
);
927 PageOp
->Status
= STATUS_SUCCESS
;
928 MmspCompleteAndReleasePageOp(PageOp
);
929 DPRINT("Address 0x%.8X\n", Address
);
930 return(STATUS_SUCCESS
);
933 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
937 * Must be private page we have swapped out.
944 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
946 DPRINT1("Found a swaped out private page in a pagefile section.\n");
947 KeBugCheck(MEMORY_MANAGEMENT
);
950 MmUnlockSectionSegment(Segment
);
951 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
953 MmUnlockAddressSpace(AddressSpace
);
954 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
955 if (!NT_SUCCESS(Status
))
957 KeBugCheck(MEMORY_MANAGEMENT
);
960 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
961 if (!NT_SUCCESS(Status
))
963 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
964 KeBugCheck(MEMORY_MANAGEMENT
);
966 MmLockAddressSpace(AddressSpace
);
967 Status
= MmCreateVirtualMapping(Process
,
972 if (!NT_SUCCESS(Status
))
974 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
975 KeBugCheck(MEMORY_MANAGEMENT
);
980 * Store the swap entry for later use.
982 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
985 * Add the page to the process's working set
987 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
990 * Finish the operation
992 PageOp
->Status
= STATUS_SUCCESS
;
993 MmspCompleteAndReleasePageOp(PageOp
);
994 DPRINT("Address 0x%.8X\n", Address
);
995 return(STATUS_SUCCESS
);
999 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1001 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1003 MmUnlockSectionSegment(Segment
);
1005 * Just map the desired physical page
1007 Page
= Offset
>> PAGE_SHIFT
;
1008 Status
= MmCreateVirtualMappingUnsafe(Process
,
1013 if (!NT_SUCCESS(Status
))
1015 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1016 KeBugCheck(MEMORY_MANAGEMENT
);
1021 * Cleanup and release locks
1023 PageOp
->Status
= STATUS_SUCCESS
;
1024 MmspCompleteAndReleasePageOp(PageOp
);
1025 DPRINT("Address 0x%.8X\n", Address
);
1026 return(STATUS_SUCCESS
);
1030 * Map anonymous memory for BSS sections
1032 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1034 MmUnlockSectionSegment(Segment
);
1035 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1036 if (!NT_SUCCESS(Status
))
1038 MmUnlockAddressSpace(AddressSpace
);
1039 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1040 MmLockAddressSpace(AddressSpace
);
1042 if (!NT_SUCCESS(Status
))
1044 KeBugCheck(MEMORY_MANAGEMENT
);
1046 Status
= MmCreateVirtualMapping(Process
,
1051 if (!NT_SUCCESS(Status
))
1053 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1054 KeBugCheck(MEMORY_MANAGEMENT
);
1057 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1060 * Cleanup and release locks
1062 PageOp
->Status
= STATUS_SUCCESS
;
1063 MmspCompleteAndReleasePageOp(PageOp
);
1064 DPRINT("Address 0x%.8X\n", Address
);
1065 return(STATUS_SUCCESS
);
1069 * Get the entry corresponding to the offset within the section
1071 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1076 * If the entry is zero (and it can't change because we have
1077 * locked the segment) then we need to load the page.
1081 * Release all our locks and read in the page from disk
1083 MmUnlockSectionSegment(Segment
);
1084 MmUnlockAddressSpace(AddressSpace
);
1086 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1087 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1089 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1090 if (!NT_SUCCESS(Status
))
1092 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1097 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1098 if (!NT_SUCCESS(Status
))
1100 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1103 if (!NT_SUCCESS(Status
))
1106 * FIXME: What do we know in this case?
1109 * Cleanup and release locks
1111 MmLockAddressSpace(AddressSpace
);
1112 PageOp
->Status
= Status
;
1113 MmspCompleteAndReleasePageOp(PageOp
);
1114 DPRINT("Address 0x%.8X\n", Address
);
1118 * Relock the address space and segment
1120 MmLockAddressSpace(AddressSpace
);
1121 MmLockSectionSegment(Segment
);
1124 * Check the entry. No one should change the status of a page
1125 * that has a pending page-in.
1127 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1128 if (Entry
!= Entry1
)
1130 DPRINT1("Someone changed ppte entry while we slept\n");
1131 KeBugCheck(MEMORY_MANAGEMENT
);
1135 * Mark the offset within the section as having valid, in-memory
1138 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1139 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1140 MmUnlockSectionSegment(Segment
);
1142 Status
= MmCreateVirtualMapping(Process
,
1147 if (!NT_SUCCESS(Status
))
1149 DPRINT1("Unable to create virtual mapping\n");
1150 KeBugCheck(MEMORY_MANAGEMENT
);
1152 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1154 PageOp
->Status
= STATUS_SUCCESS
;
1155 MmspCompleteAndReleasePageOp(PageOp
);
1156 DPRINT("Address 0x%.8X\n", Address
);
1157 return(STATUS_SUCCESS
);
1159 else if (IS_SWAP_FROM_SSE(Entry
))
1161 SWAPENTRY SwapEntry
;
1163 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1166 * Release all our locks and read in the page from disk
1168 MmUnlockSectionSegment(Segment
);
1170 MmUnlockAddressSpace(AddressSpace
);
1172 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1173 if (!NT_SUCCESS(Status
))
1175 KeBugCheck(MEMORY_MANAGEMENT
);
1178 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1179 if (!NT_SUCCESS(Status
))
1181 KeBugCheck(MEMORY_MANAGEMENT
);
1185 * Relock the address space and segment
1187 MmLockAddressSpace(AddressSpace
);
1188 MmLockSectionSegment(Segment
);
1191 * Check the entry. No one should change the status of a page
1192 * that has a pending page-in.
1194 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1195 if (Entry
!= Entry1
)
1197 DPRINT1("Someone changed ppte entry while we slept\n");
1198 KeBugCheck(MEMORY_MANAGEMENT
);
1202 * Mark the offset within the section as having valid, in-memory
1205 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1206 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1207 MmUnlockSectionSegment(Segment
);
1210 * Save the swap entry.
1212 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1213 Status
= MmCreateVirtualMapping(Process
,
1218 if (!NT_SUCCESS(Status
))
1220 DPRINT1("Unable to create virtual mapping\n");
1221 KeBugCheck(MEMORY_MANAGEMENT
);
1223 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1224 PageOp
->Status
= STATUS_SUCCESS
;
1225 MmspCompleteAndReleasePageOp(PageOp
);
1226 DPRINT("Address 0x%.8X\n", Address
);
1227 return(STATUS_SUCCESS
);
1232 * If the section offset is already in-memory and valid then just
1233 * take another reference to the page
1236 Page
= PFN_FROM_SSE(Entry
);
1238 MmSharePageEntrySectionSegment(Segment
, Offset
);
1239 MmUnlockSectionSegment(Segment
);
1241 Status
= MmCreateVirtualMapping(Process
,
1246 if (!NT_SUCCESS(Status
))
1248 DPRINT1("Unable to create virtual mapping\n");
1249 KeBugCheck(MEMORY_MANAGEMENT
);
1251 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1252 PageOp
->Status
= STATUS_SUCCESS
;
1253 MmspCompleteAndReleasePageOp(PageOp
);
1254 DPRINT("Address 0x%.8X\n", Address
);
1255 return(STATUS_SUCCESS
);
1261 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1262 MEMORY_AREA
* MemoryArea
,
1266 PMM_SECTION_SEGMENT Segment
;
1267 PROS_SECTION_OBJECT Section
;
1276 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1278 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1281 * Check if the page has been paged out or has already been set readwrite
1283 if (!MmIsPagePresent(Process
, Address
) ||
1284 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1286 DPRINT("Address 0x%.8X\n", Address
);
1287 return(STATUS_SUCCESS
);
1291 * Find the offset of the page
1293 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1294 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1295 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1297 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1298 Section
= MemoryArea
->Data
.SectionData
.Section
;
1299 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1300 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1305 MmLockSectionSegment(Segment
);
1307 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1308 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1310 MmUnlockSectionSegment(Segment
);
1313 * Check if we are doing COW
1315 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1316 (Region
->Protect
== PAGE_READWRITE
||
1317 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1319 DPRINT("Address 0x%.8X\n", Address
);
1320 return(STATUS_ACCESS_VIOLATION
);
1323 if (IS_SWAP_FROM_SSE(Entry
) ||
1324 PFN_FROM_SSE(Entry
) != OldPage
)
1326 /* This is a private page. We must only change the page protection. */
1327 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1328 return(STATUS_SUCCESS
);
1332 * Get or create a pageop
1334 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1335 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1338 DPRINT1("MmGetPageOp failed\n");
1339 KeBugCheck(MEMORY_MANAGEMENT
);
1343 * Wait for any other operations to complete
1345 if (PageOp
->Thread
!= PsGetCurrentThread())
1347 MmUnlockAddressSpace(AddressSpace
);
1348 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1350 * Check for various strange conditions
1352 if (Status
== STATUS_TIMEOUT
)
1354 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1355 KeBugCheck(MEMORY_MANAGEMENT
);
1357 if (PageOp
->Status
== STATUS_PENDING
)
1359 DPRINT1("Woke for page op before completion\n");
1360 KeBugCheck(MEMORY_MANAGEMENT
);
1363 * Restart the operation
1365 MmLockAddressSpace(AddressSpace
);
1366 MmspCompleteAndReleasePageOp(PageOp
);
1367 DPRINT("Address 0x%.8X\n", Address
);
1368 return(STATUS_MM_RESTART_OPERATION
);
1372 * Release locks now we have the pageop
1374 MmUnlockAddressSpace(AddressSpace
);
1379 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1380 if (!NT_SUCCESS(Status
))
1382 KeBugCheck(MEMORY_MANAGEMENT
);
1388 MiCopyFromUserPage(NewPage
, PAddress
);
1390 MmLockAddressSpace(AddressSpace
);
1392 * Delete the old entry.
1394 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1397 * Set the PTE to point to the new page
1399 Status
= MmCreateVirtualMapping(Process
,
1404 if (!NT_SUCCESS(Status
))
1406 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1407 KeBugCheck(MEMORY_MANAGEMENT
);
1410 if (!NT_SUCCESS(Status
))
1412 DPRINT1("Unable to create virtual mapping\n");
1413 KeBugCheck(MEMORY_MANAGEMENT
);
1417 * Unshare the old page.
1419 MmDeleteRmap(OldPage
, Process
, PAddress
);
1420 MmInsertRmap(NewPage
, Process
, PAddress
);
1421 MmLockSectionSegment(Segment
);
1422 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1423 MmUnlockSectionSegment(Segment
);
1425 PageOp
->Status
= STATUS_SUCCESS
;
1426 MmspCompleteAndReleasePageOp(PageOp
);
1427 DPRINT("Address 0x%.8X\n", Address
);
1428 return(STATUS_SUCCESS
);
1432 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1434 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1438 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1441 MmLockAddressSpace(&Process
->Vm
);
1444 MmDeleteVirtualMapping(Process
,
1451 PageOutContext
->WasDirty
= TRUE
;
1453 if (!PageOutContext
->Private
)
1455 MmLockSectionSegment(PageOutContext
->Segment
);
1456 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1457 PageOutContext
->Segment
,
1458 PageOutContext
->Offset
,
1459 PageOutContext
->WasDirty
,
1461 MmUnlockSectionSegment(PageOutContext
->Segment
);
1465 MmUnlockAddressSpace(&Process
->Vm
);
1468 if (PageOutContext
->Private
)
1470 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1473 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1478 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1479 MEMORY_AREA
* MemoryArea
,
1484 MM_SECTION_PAGEOUT_CONTEXT Context
;
1485 SWAPENTRY SwapEntry
;
1489 PFILE_OBJECT FileObject
;
1491 BOOLEAN DirectMapped
;
1492 BOOLEAN IsImageSection
;
1493 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1496 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1499 * Get the segment and section.
1501 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1502 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1504 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1505 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1506 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1508 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1510 FileObject
= Context
.Section
->FileObject
;
1511 DirectMapped
= FALSE
;
1512 if (FileObject
!= NULL
&&
1513 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1515 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1518 * If the file system is letting us go directly to the cache and the
1519 * memory area was mapped at an offset in the file which is page aligned
1520 * then note this is a direct mapped page.
1522 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1523 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1525 DirectMapped
= TRUE
;
1531 * This should never happen since mappings of physical memory are never
1532 * placed in the rmap lists.
1534 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1536 DPRINT1("Trying to page out from physical memory section address 0x%X "
1537 "process %d\n", Address
,
1538 Process
? Process
->UniqueProcessId
: 0);
1539 KeBugCheck(MEMORY_MANAGEMENT
);
1543 * Get the section segment entry and the physical address.
1545 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1546 if (!MmIsPagePresent(Process
, Address
))
1548 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1549 Process
? Process
->UniqueProcessId
: 0, Address
);
1550 KeBugCheck(MEMORY_MANAGEMENT
);
1552 Page
= MmGetPfnForProcess(Process
, Address
);
1553 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1556 * Prepare the context structure for the rmap delete call.
1558 Context
.WasDirty
= FALSE
;
1559 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1560 IS_SWAP_FROM_SSE(Entry
) ||
1561 PFN_FROM_SSE(Entry
) != Page
)
1563 Context
.Private
= TRUE
;
1567 Context
.Private
= FALSE
;
1571 * Take an additional reference to the page or the cache segment.
1573 if (DirectMapped
&& !Context
.Private
)
1575 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1577 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1578 KeBugCheck(MEMORY_MANAGEMENT
);
1583 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1584 MmReferencePage(Page
);
1585 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1588 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1591 * If this wasn't a private page then we should have reduced the entry to
1592 * zero by deleting all the rmaps.
1594 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1596 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1597 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1599 KeBugCheck(MEMORY_MANAGEMENT
);
1604 * If the page wasn't dirty then we can just free it as for a readonly page.
1605 * Since we unmapped all the mappings above we know it will not suddenly
1607 * If the page is from a pagefile section and has no swap entry,
1608 * we can't free the page at this point.
1610 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1611 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1613 if (Context
.Private
)
1615 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1616 Context
.WasDirty
? "dirty" : "clean", Address
);
1617 KeBugCheck(MEMORY_MANAGEMENT
);
1619 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1621 MmSetSavedSwapEntryPage(Page
, 0);
1622 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1623 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1624 PageOp
->Status
= STATUS_SUCCESS
;
1625 MmspCompleteAndReleasePageOp(PageOp
);
1626 return(STATUS_SUCCESS
);
1629 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1631 if (Context
.Private
)
1633 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1634 Context
.WasDirty
? "dirty" : "clean", Address
);
1635 KeBugCheck(MEMORY_MANAGEMENT
);
1637 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1639 MmSetSavedSwapEntryPage(Page
, 0);
1642 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1644 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1645 PageOp
->Status
= STATUS_SUCCESS
;
1646 MmspCompleteAndReleasePageOp(PageOp
);
1647 return(STATUS_SUCCESS
);
1650 else if (!Context
.Private
&& DirectMapped
)
1654 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1656 KeBugCheck(MEMORY_MANAGEMENT
);
1658 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1659 if (!NT_SUCCESS(Status
))
1661 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1662 KeBugCheck(MEMORY_MANAGEMENT
);
1664 PageOp
->Status
= STATUS_SUCCESS
;
1665 MmspCompleteAndReleasePageOp(PageOp
);
1666 return(STATUS_SUCCESS
);
1668 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1672 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1674 KeBugCheck(MEMORY_MANAGEMENT
);
1676 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1677 PageOp
->Status
= STATUS_SUCCESS
;
1678 MmspCompleteAndReleasePageOp(PageOp
);
1679 return(STATUS_SUCCESS
);
1681 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1683 MmSetSavedSwapEntryPage(Page
, 0);
1684 MmLockAddressSpace(AddressSpace
);
1685 Status
= MmCreatePageFileMapping(Process
,
1688 MmUnlockAddressSpace(AddressSpace
);
1689 if (!NT_SUCCESS(Status
))
1691 KeBugCheck(MEMORY_MANAGEMENT
);
1693 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1694 PageOp
->Status
= STATUS_SUCCESS
;
1695 MmspCompleteAndReleasePageOp(PageOp
);
1696 return(STATUS_SUCCESS
);
1700 * If necessary, allocate an entry in the paging file for this page
1704 SwapEntry
= MmAllocSwapPage();
1707 MmShowOutOfSpaceMessagePagingFile();
1708 MmLockAddressSpace(AddressSpace
);
1710 * For private pages restore the old mappings.
1712 if (Context
.Private
)
1714 Status
= MmCreateVirtualMapping(Process
,
1716 MemoryArea
->Protect
,
1719 MmSetDirtyPage(Process
, Address
);
1727 * For non-private pages if the page wasn't direct mapped then
1728 * set it back into the section segment entry so we don't loose
1729 * our copy. Otherwise it will be handled by the cache manager.
1731 Status
= MmCreateVirtualMapping(Process
,
1733 MemoryArea
->Protect
,
1736 MmSetDirtyPage(Process
, Address
);
1740 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1741 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1743 MmUnlockAddressSpace(AddressSpace
);
1744 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1745 MmspCompleteAndReleasePageOp(PageOp
);
1746 return(STATUS_PAGEFILE_QUOTA
);
1751 * Write the page to the pagefile
1753 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1754 if (!NT_SUCCESS(Status
))
1756 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1759 * As above: undo our actions.
1760 * FIXME: Also free the swap page.
1762 MmLockAddressSpace(AddressSpace
);
1763 if (Context
.Private
)
1765 Status
= MmCreateVirtualMapping(Process
,
1767 MemoryArea
->Protect
,
1770 MmSetDirtyPage(Process
, Address
);
1777 Status
= MmCreateVirtualMapping(Process
,
1779 MemoryArea
->Protect
,
1782 MmSetDirtyPage(Process
, Address
);
1786 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1787 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1789 MmUnlockAddressSpace(AddressSpace
);
1790 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1791 MmspCompleteAndReleasePageOp(PageOp
);
1792 return(STATUS_UNSUCCESSFUL
);
1796 * Otherwise we have succeeded.
1798 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1799 MmSetSavedSwapEntryPage(Page
, 0);
1800 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1801 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1803 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1807 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1810 if (Context
.Private
)
1812 MmLockAddressSpace(AddressSpace
);
1813 Status
= MmCreatePageFileMapping(Process
,
1816 MmUnlockAddressSpace(AddressSpace
);
1817 if (!NT_SUCCESS(Status
))
1819 KeBugCheck(MEMORY_MANAGEMENT
);
1824 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1825 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1828 PageOp
->Status
= STATUS_SUCCESS
;
1829 MmspCompleteAndReleasePageOp(PageOp
);
1830 return(STATUS_SUCCESS
);
1835 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
1836 PMEMORY_AREA MemoryArea
,
1841 PROS_SECTION_OBJECT Section
;
1842 PMM_SECTION_SEGMENT Segment
;
1844 SWAPENTRY SwapEntry
;
1848 PFILE_OBJECT FileObject
;
1850 BOOLEAN DirectMapped
;
1851 BOOLEAN IsImageSection
;
1852 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1854 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1856 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1857 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1860 * Get the segment and section.
1862 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1863 Section
= MemoryArea
->Data
.SectionData
.Section
;
1864 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1866 FileObject
= Section
->FileObject
;
1867 DirectMapped
= FALSE
;
1868 if (FileObject
!= NULL
&&
1869 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1871 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1874 * If the file system is letting us go directly to the cache and the
1875 * memory area was mapped at an offset in the file which is page aligned
1876 * then note this is a direct mapped page.
1878 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1879 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1881 DirectMapped
= TRUE
;
1886 * This should never happen since mappings of physical memory are never
1887 * placed in the rmap lists.
1889 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1891 DPRINT1("Trying to write back page from physical memory mapped at %X "
1892 "process %d\n", Address
,
1893 Process
? Process
->UniqueProcessId
: 0);
1894 KeBugCheck(MEMORY_MANAGEMENT
);
1898 * Get the section segment entry and the physical address.
1900 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1901 if (!MmIsPagePresent(Process
, Address
))
1903 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1904 Process
? Process
->UniqueProcessId
: 0, Address
);
1905 KeBugCheck(MEMORY_MANAGEMENT
);
1907 Page
= MmGetPfnForProcess(Process
, Address
);
1908 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1911 * Check for a private (COWed) page.
1913 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1914 IS_SWAP_FROM_SSE(Entry
) ||
1915 PFN_FROM_SSE(Entry
) != Page
)
1925 * Speculatively set all mappings of the page to clean.
1927 MmSetCleanAllRmaps(Page
);
1930 * If this page was direct mapped from the cache then the cache manager
1931 * will take care of writing it back to disk.
1933 if (DirectMapped
&& !Private
)
1935 ASSERT(SwapEntry
== 0);
1936 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1937 PageOp
->Status
= STATUS_SUCCESS
;
1938 MmspCompleteAndReleasePageOp(PageOp
);
1939 return(STATUS_SUCCESS
);
1943 * If necessary, allocate an entry in the paging file for this page
1947 SwapEntry
= MmAllocSwapPage();
1950 MmSetDirtyAllRmaps(Page
);
1951 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1952 MmspCompleteAndReleasePageOp(PageOp
);
1953 return(STATUS_PAGEFILE_QUOTA
);
1955 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1959 * Write the page to the pagefile
1961 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1962 if (!NT_SUCCESS(Status
))
1964 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1966 MmSetDirtyAllRmaps(Page
);
1967 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1968 MmspCompleteAndReleasePageOp(PageOp
);
1969 return(STATUS_UNSUCCESSFUL
);
1973 * Otherwise we have succeeded.
1975 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1976 PageOp
->Status
= STATUS_SUCCESS
;
1977 MmspCompleteAndReleasePageOp(PageOp
);
1978 return(STATUS_SUCCESS
);
1982 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
1990 PMEMORY_AREA MemoryArea
;
1991 PMM_SECTION_SEGMENT Segment
;
1992 BOOLEAN DoCOW
= FALSE
;
1994 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1996 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1997 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1999 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
2000 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2005 if (OldProtect
!= NewProtect
)
2007 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2009 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2010 ULONG Protect
= NewProtect
;
2013 * If we doing COW for this segment then check if the page is
2016 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2022 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2023 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2024 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2025 Page
= MmGetPfnForProcess(Process
, Address
);
2027 Protect
= PAGE_READONLY
;
2028 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2029 IS_SWAP_FROM_SSE(Entry
) ||
2030 PFN_FROM_SSE(Entry
) != Page
)
2032 Protect
= NewProtect
;
2036 if (MmIsPagePresent(Process
, Address
))
2038 MmSetPageProtect(Process
, Address
,
2047 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2048 PMEMORY_AREA MemoryArea
,
2056 ULONG_PTR MaxLength
;
2058 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2059 if (Length
> MaxLength
)
2062 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2063 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2065 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2066 Region
->Protect
!= Protect
)
2068 return STATUS_INVALID_PAGE_PROTECTION
;
2071 *OldProtect
= Region
->Protect
;
2072 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2073 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2074 BaseAddress
, Length
, Region
->Type
, Protect
,
2075 MmAlterViewAttributes
);
2081 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2083 PMEMORY_BASIC_INFORMATION Info
,
2084 PULONG ResultLength
)
2087 PVOID RegionBaseAddress
;
2088 PROS_SECTION_OBJECT Section
;
2089 PMM_SECTION_SEGMENT Segment
;
2091 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2092 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2093 Address
, &RegionBaseAddress
);
2096 return STATUS_UNSUCCESSFUL
;
2099 Section
= MemoryArea
->Data
.SectionData
.Section
;
2100 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2102 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2103 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2104 Info
->Type
= MEM_IMAGE
;
2108 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2109 Info
->Type
= MEM_MAPPED
;
2111 Info
->BaseAddress
= RegionBaseAddress
;
2112 Info
->AllocationProtect
= MemoryArea
->Protect
;
2113 Info
->RegionSize
= Region
->Length
;
2114 Info
->State
= MEM_COMMIT
;
2115 Info
->Protect
= Region
->Protect
;
2117 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2118 return(STATUS_SUCCESS
);
2123 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2128 ULONG SavedSwapEntry
;
2133 Length
= PAGE_ROUND_UP(Segment
->Length
);
2134 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2136 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2139 if (IS_SWAP_FROM_SSE(Entry
))
2141 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2145 Page
= PFN_FROM_SSE(Entry
);
2146 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2147 if (SavedSwapEntry
!= 0)
2149 MmSetSavedSwapEntryPage(Page
, 0);
2150 MmFreeSwapPage(SavedSwapEntry
);
2152 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2154 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2160 MmpDeleteSection(PVOID ObjectBody
)
2162 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2164 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2165 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2170 PMM_SECTION_SEGMENT SectionSegments
;
2173 * NOTE: Section->ImageSection can be NULL for short time
2174 * during the section creating. If we fail for some reason
2175 * until the image section is properly initialized we shouldn't
2176 * process further here.
2178 if (Section
->ImageSection
== NULL
)
2181 SectionSegments
= Section
->ImageSection
->Segments
;
2182 NrSegments
= Section
->ImageSection
->NrSegments
;
2184 for (i
= 0; i
< NrSegments
; i
++)
2186 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2188 MmLockSectionSegment(&SectionSegments
[i
]);
2190 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2191 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2195 MmpFreePageFileSegment(&SectionSegments
[i
]);
2197 MmUnlockSectionSegment(&SectionSegments
[i
]);
2204 * NOTE: Section->Segment can be NULL for short time
2205 * during the section creating.
2207 if (Section
->Segment
== NULL
)
2210 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2212 MmpFreePageFileSegment(Section
->Segment
);
2213 MmFreePageTablesSectionSegment(Section
->Segment
);
2214 ExFreePool(Section
->Segment
);
2215 Section
->Segment
= NULL
;
2219 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2222 if (Section
->FileObject
!= NULL
)
2224 CcRosDereferenceCache(Section
->FileObject
);
2225 ObDereferenceObject(Section
->FileObject
);
2226 Section
->FileObject
= NULL
;
2231 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2233 IN ACCESS_MASK GrantedAccess
,
2234 IN ULONG ProcessHandleCount
,
2235 IN ULONG SystemHandleCount
)
2237 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2238 Object
, ProcessHandleCount
);
2244 MmCreatePhysicalMemorySection(VOID
)
2246 PROS_SECTION_OBJECT PhysSection
;
2248 OBJECT_ATTRIBUTES Obj
;
2249 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2250 LARGE_INTEGER SectionSize
;
2254 * Create the section mapping physical memory
2256 SectionSize
.QuadPart
= 0xFFFFFFFF;
2257 InitializeObjectAttributes(&Obj
,
2262 Status
= MmCreateSection((PVOID
)&PhysSection
,
2266 PAGE_EXECUTE_READWRITE
,
2270 if (!NT_SUCCESS(Status
))
2272 DPRINT1("Failed to create PhysicalMemory section\n");
2273 KeBugCheck(MEMORY_MANAGEMENT
);
2275 Status
= ObInsertObject(PhysSection
,
2281 if (!NT_SUCCESS(Status
))
2283 ObDereferenceObject(PhysSection
);
2285 ObCloseHandle(Handle
, KernelMode
);
2286 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2287 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2289 return(STATUS_SUCCESS
);
2295 MmInitSectionImplementation(VOID
)
2297 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2298 UNICODE_STRING Name
;
2300 DPRINT("Creating Section Object Type\n");
2302 /* Initialize the Section object type */
2303 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2304 RtlInitUnicodeString(&Name
, L
"Section");
2305 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2306 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2307 ObjectTypeInitializer
.PoolType
= PagedPool
;
2308 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2309 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2310 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2311 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2312 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2313 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2315 MmCreatePhysicalMemorySection();
2317 return(STATUS_SUCCESS
);
2322 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2323 ACCESS_MASK DesiredAccess
,
2324 POBJECT_ATTRIBUTES ObjectAttributes
,
2325 PLARGE_INTEGER UMaximumSize
,
2326 ULONG SectionPageProtection
,
2327 ULONG AllocationAttributes
)
2329 * Create a section which is backed by the pagefile
2332 LARGE_INTEGER MaximumSize
;
2333 PROS_SECTION_OBJECT Section
;
2334 PMM_SECTION_SEGMENT Segment
;
2337 if (UMaximumSize
== NULL
)
2339 return(STATUS_UNSUCCESSFUL
);
2341 MaximumSize
= *UMaximumSize
;
2344 * Create the section
2346 Status
= ObCreateObject(ExGetPreviousMode(),
2347 MmSectionObjectType
,
2349 ExGetPreviousMode(),
2351 sizeof(ROS_SECTION_OBJECT
),
2354 (PVOID
*)(PVOID
)&Section
);
2355 if (!NT_SUCCESS(Status
))
2363 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2364 Section
->SectionPageProtection
= SectionPageProtection
;
2365 Section
->AllocationAttributes
= AllocationAttributes
;
2366 Section
->MaximumSize
= MaximumSize
;
2367 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2368 TAG_MM_SECTION_SEGMENT
);
2369 if (Segment
== NULL
)
2371 ObDereferenceObject(Section
);
2372 return(STATUS_NO_MEMORY
);
2374 Section
->Segment
= Segment
;
2375 Segment
->ReferenceCount
= 1;
2376 ExInitializeFastMutex(&Segment
->Lock
);
2377 Segment
->FileOffset
= 0;
2378 Segment
->Protection
= SectionPageProtection
;
2379 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2380 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2381 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2382 Segment
->WriteCopy
= FALSE
;
2383 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2384 Segment
->VirtualAddress
= 0;
2385 Segment
->Characteristics
= 0;
2386 *SectionObject
= Section
;
2387 return(STATUS_SUCCESS
);
2393 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2394 ACCESS_MASK DesiredAccess
,
2395 POBJECT_ATTRIBUTES ObjectAttributes
,
2396 PLARGE_INTEGER UMaximumSize
,
2397 ULONG SectionPageProtection
,
2398 ULONG AllocationAttributes
,
2401 * Create a section backed by a data file
2404 PROS_SECTION_OBJECT Section
;
2406 LARGE_INTEGER MaximumSize
;
2407 PFILE_OBJECT FileObject
;
2408 PMM_SECTION_SEGMENT Segment
;
2410 IO_STATUS_BLOCK Iosb
;
2411 LARGE_INTEGER Offset
;
2413 FILE_STANDARD_INFORMATION FileInfo
;
2417 * Create the section
2419 Status
= ObCreateObject(ExGetPreviousMode(),
2420 MmSectionObjectType
,
2422 ExGetPreviousMode(),
2424 sizeof(ROS_SECTION_OBJECT
),
2427 (PVOID
*)(PVOID
)&Section
);
2428 if (!NT_SUCCESS(Status
))
2435 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2436 Section
->SectionPageProtection
= SectionPageProtection
;
2437 Section
->AllocationAttributes
= AllocationAttributes
;
2440 * Check file access required
2442 if (SectionPageProtection
& PAGE_READWRITE
||
2443 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2445 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2449 FileAccess
= FILE_READ_DATA
;
2453 * Reference the file handle
2455 Status
= ObReferenceObjectByHandle(FileHandle
,
2458 ExGetPreviousMode(),
2459 (PVOID
*)(PVOID
)&FileObject
,
2461 if (!NT_SUCCESS(Status
))
2463 ObDereferenceObject(Section
);
2468 * FIXME: This is propably not entirely correct. We can't look into
2469 * the standard FCB header because it might not be initialized yet
2470 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2471 * standard file information is filled on first request).
2473 Status
= IoQueryFileInformation(FileObject
,
2474 FileStandardInformation
,
2475 sizeof(FILE_STANDARD_INFORMATION
),
2478 Iosb
.Information
= Length
;
2479 if (!NT_SUCCESS(Status
))
2481 ObDereferenceObject(Section
);
2482 ObDereferenceObject(FileObject
);
2487 * FIXME: Revise this once a locking order for file size changes is
2490 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2492 MaximumSize
= *UMaximumSize
;
2496 MaximumSize
= FileInfo
.EndOfFile
;
2497 /* Mapping zero-sized files isn't allowed. */
2498 if (MaximumSize
.QuadPart
== 0)
2500 ObDereferenceObject(Section
);
2501 ObDereferenceObject(FileObject
);
2502 return STATUS_FILE_INVALID
;
2506 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2508 Status
= IoSetInformation(FileObject
,
2509 FileAllocationInformation
,
2510 sizeof(LARGE_INTEGER
),
2512 if (!NT_SUCCESS(Status
))
2514 ObDereferenceObject(Section
);
2515 ObDereferenceObject(FileObject
);
2516 return(STATUS_SECTION_NOT_EXTENDED
);
2520 if (FileObject
->SectionObjectPointer
== NULL
||
2521 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2524 * Read a bit so caching is initiated for the file object.
2525 * This is only needed because MiReadPage currently cannot
2526 * handle non-cached streams.
2528 Offset
.QuadPart
= 0;
2529 Status
= ZwReadFile(FileHandle
,
2538 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2540 ObDereferenceObject(Section
);
2541 ObDereferenceObject(FileObject
);
2544 if (FileObject
->SectionObjectPointer
== NULL
||
2545 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2547 /* FIXME: handle this situation */
2548 ObDereferenceObject(Section
);
2549 ObDereferenceObject(FileObject
);
2550 return STATUS_INVALID_PARAMETER
;
2557 Status
= MmspWaitForFileLock(FileObject
);
2558 if (Status
!= STATUS_SUCCESS
)
2560 ObDereferenceObject(Section
);
2561 ObDereferenceObject(FileObject
);
2566 * If this file hasn't been mapped as a data file before then allocate a
2567 * section segment to describe the data file mapping
2569 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2571 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2572 TAG_MM_SECTION_SEGMENT
);
2573 if (Segment
== NULL
)
2575 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2576 ObDereferenceObject(Section
);
2577 ObDereferenceObject(FileObject
);
2578 return(STATUS_NO_MEMORY
);
2580 Section
->Segment
= Segment
;
2581 Segment
->ReferenceCount
= 1;
2582 ExInitializeFastMutex(&Segment
->Lock
);
2584 * Set the lock before assigning the segment to the file object
2586 ExAcquireFastMutex(&Segment
->Lock
);
2587 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2589 Segment
->FileOffset
= 0;
2590 Segment
->Protection
= SectionPageProtection
;
2591 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2592 Segment
->Characteristics
= 0;
2593 Segment
->WriteCopy
= FALSE
;
2594 if (AllocationAttributes
& SEC_RESERVE
)
2596 Segment
->Length
= Segment
->RawLength
= 0;
2600 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2601 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2603 Segment
->VirtualAddress
= 0;
2604 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2609 * If the file is already mapped as a data file then we may need
2613 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2615 Section
->Segment
= Segment
;
2616 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2617 MmLockSectionSegment(Segment
);
2619 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2620 !(AllocationAttributes
& SEC_RESERVE
))
2622 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2623 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2626 MmUnlockSectionSegment(Segment
);
2627 Section
->FileObject
= FileObject
;
2628 Section
->MaximumSize
= MaximumSize
;
2629 CcRosReferenceCache(FileObject
);
2630 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2631 *SectionObject
= Section
;
2632 return(STATUS_SUCCESS
);
2636 TODO: not that great (declaring loaders statically, having to declare all of
2637 them, having to keep them extern, etc.), will fix in the future
2639 extern NTSTATUS NTAPI PeFmtCreateSection
2641 IN CONST VOID
* FileHeader
,
2642 IN SIZE_T FileHeaderSize
,
2644 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2646 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2647 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2650 extern NTSTATUS NTAPI ElfFmtCreateSection
2652 IN CONST VOID
* FileHeader
,
2653 IN SIZE_T FileHeaderSize
,
2655 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2657 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2658 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2661 /* TODO: this is a standard DDK/PSDK macro */
2662 #ifndef RTL_NUMBER_OF
2663 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2666 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2677 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2679 SIZE_T SizeOfSegments
;
2680 PMM_SECTION_SEGMENT Segments
;
2682 /* TODO: check for integer overflow */
2683 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2685 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2687 TAG_MM_SECTION_SEGMENT
);
2690 RtlZeroMemory(Segments
, SizeOfSegments
);
2698 ExeFmtpReadFile(IN PVOID File
,
2699 IN PLARGE_INTEGER Offset
,
2702 OUT PVOID
* AllocBase
,
2703 OUT PULONG ReadSize
)
2706 LARGE_INTEGER FileOffset
;
2708 ULONG OffsetAdjustment
;
2713 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2717 KeBugCheck(MEMORY_MANAGEMENT
);
2720 FileOffset
= *Offset
;
2722 /* Negative/special offset: it cannot be used in this context */
2723 if(FileOffset
.u
.HighPart
< 0)
2725 KeBugCheck(MEMORY_MANAGEMENT
);
2728 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2729 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2730 FileOffset
.u
.LowPart
= AdjustOffset
;
2732 BufferSize
= Length
+ OffsetAdjustment
;
2733 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2736 * It's ok to use paged pool, because this is a temporary buffer only used in
2737 * the loading of executables. The assumption is that MmCreateSection is
2738 * always called at low IRQLs and that these buffers don't survive a brief
2739 * initialization phase
2741 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2746 KeBugCheck(MEMORY_MANAGEMENT
);
2752 Status
= MmspPageRead(File
,
2759 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2760 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2761 * to initialize internal state is even worse. Our cache manager is in need of
2765 IO_STATUS_BLOCK Iosb
;
2767 Status
= ZwReadFile(File
,
2777 if(NT_SUCCESS(Status
))
2779 UsedSize
= Iosb
.Information
;
2784 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2786 Status
= STATUS_IN_PAGE_ERROR
;
2787 ASSERT(!NT_SUCCESS(Status
));
2790 if(NT_SUCCESS(Status
))
2792 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2793 *AllocBase
= Buffer
;
2794 *ReadSize
= UsedSize
- OffsetAdjustment
;
2798 ExFreePoolWithTag(Buffer
, 'rXmM');
2805 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2806 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2807 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2812 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2816 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2818 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2819 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2826 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2830 MmspAssertSegmentsSorted(ImageSectionObject
);
2832 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2834 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2838 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2839 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2840 ImageSectionObject
->Segments
[i
- 1].Length
));
2848 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2852 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2854 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2855 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2863 MmspCompareSegments(const void * x
,
2866 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2867 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2870 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2871 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2875 * Ensures an image section's segments are sorted in memory
2880 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2883 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2885 MmspAssertSegmentsSorted(ImageSectionObject
);
2889 qsort(ImageSectionObject
->Segments
,
2890 ImageSectionObject
->NrSegments
,
2891 sizeof(ImageSectionObject
->Segments
[0]),
2892 MmspCompareSegments
);
2898 * Ensures an image section's segments don't overlap in memory and don't have
2899 * gaps and don't have a null size. We let them map to overlapping file regions,
2900 * though - that's not necessarily an error
2905 MmspCheckSegmentBounds
2907 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2913 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2915 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2919 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2921 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2923 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2931 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2932 * page could be OK (Windows seems to be OK with them), and larger gaps
2933 * could lead to image sections spanning several discontiguous regions
2934 * (NtMapViewOfSection could then refuse to map them, and they could
2935 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2937 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2938 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2939 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2950 * Merges and pads an image section's segments until they all are page-aligned
2951 * and have a size that is a multiple of the page size
2956 MmspPageAlignSegments
2958 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2964 BOOLEAN Initialized
;
2965 PMM_SECTION_SEGMENT EffectiveSegment
;
2967 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2969 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2973 Initialized
= FALSE
;
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
;
3712 PMMSUPPORT AddressSpace
;
3715 ACCESS_MASK DesiredAccess
;
3718 * Check the protection
3720 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3722 return STATUS_INVALID_PARAMETER_10
;
3725 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3726 if (tmpProtect
!= PAGE_NOACCESS
&&
3727 tmpProtect
!= PAGE_READONLY
&&
3728 tmpProtect
!= PAGE_READWRITE
&&
3729 tmpProtect
!= PAGE_WRITECOPY
&&
3730 tmpProtect
!= PAGE_EXECUTE
&&
3731 tmpProtect
!= PAGE_EXECUTE_READ
&&
3732 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3733 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3735 return STATUS_INVALID_PAGE_PROTECTION
;
3738 PreviousMode
= ExGetPreviousMode();
3740 if(PreviousMode
!= KernelMode
)
3742 SafeBaseAddress
= NULL
;
3743 SafeSectionOffset
.QuadPart
= 0;
3748 if(BaseAddress
!= NULL
)
3750 ProbeForWritePointer(BaseAddress
);
3751 SafeBaseAddress
= *BaseAddress
;
3753 if(SectionOffset
!= NULL
)
3755 ProbeForWriteLargeInteger(SectionOffset
);
3756 SafeSectionOffset
= *SectionOffset
;
3758 ProbeForWriteSize_t(ViewSize
);
3759 SafeViewSize
= *ViewSize
;
3761 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3763 /* Return the exception code */
3764 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3770 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3771 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3772 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3775 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3777 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3778 PROCESS_VM_OPERATION
,
3781 (PVOID
*)(PVOID
)&Process
,
3783 if (!NT_SUCCESS(Status
))
3788 AddressSpace
= &Process
->Vm
;
3790 /* Convert NT Protection Attr to Access Mask */
3791 if (Protect
== PAGE_READONLY
)
3793 DesiredAccess
= SECTION_MAP_READ
;
3795 else if (Protect
== PAGE_READWRITE
)
3797 DesiredAccess
= SECTION_MAP_WRITE
;
3799 else if (Protect
== PAGE_WRITECOPY
)
3801 DesiredAccess
= SECTION_QUERY
;
3803 /* FIXME: Handle other Protection Attributes. For now keep previous behavior */
3806 DesiredAccess
= SECTION_MAP_READ
;
3809 Status
= ObReferenceObjectByHandle(SectionHandle
,
3811 MmSectionObjectType
,
3813 (PVOID
*)(PVOID
)&Section
,
3815 if (!(NT_SUCCESS(Status
)))
3817 DPRINT("ObReference failed rc=%x\n",Status
);
3818 ObDereferenceObject(Process
);
3822 Status
= MmMapViewOfSection(Section
,
3824 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3827 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3828 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3833 /* Check if this is an image for the current process */
3834 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3835 (Process
== PsGetCurrentProcess()) &&
3836 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3838 /* Notify the debugger */
3839 DbgkMapViewOfSection(Section
,
3841 SafeSectionOffset
.LowPart
,
3845 ObDereferenceObject(Section
);
3846 ObDereferenceObject(Process
);
3848 if(NT_SUCCESS(Status
))
3850 /* copy parameters back to the caller */
3853 if(BaseAddress
!= NULL
)
3855 *BaseAddress
= SafeBaseAddress
;
3857 if(SectionOffset
!= NULL
)
3859 *SectionOffset
= SafeSectionOffset
;
3861 if(ViewSize
!= NULL
)
3863 *ViewSize
= SafeViewSize
;
3866 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3868 Status
= _SEH2_GetExceptionCode();
3877 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3878 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3881 PFILE_OBJECT FileObject
;
3884 SWAPENTRY SavedSwapEntry
;
3887 PROS_SECTION_OBJECT Section
;
3888 PMM_SECTION_SEGMENT Segment
;
3889 PMMSUPPORT AddressSpace
;
3892 AddressSpace
= (PMMSUPPORT
)Context
;
3893 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3895 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3897 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3898 MemoryArea
->Data
.SectionData
.ViewOffset
;
3900 Section
= MemoryArea
->Data
.SectionData
.Section
;
3901 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3903 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3907 MmUnlockSectionSegment(Segment
);
3908 MmUnlockAddressSpace(AddressSpace
);
3910 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3911 if (Status
!= STATUS_SUCCESS
)
3913 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3914 KeBugCheck(MEMORY_MANAGEMENT
);
3917 MmLockAddressSpace(AddressSpace
);
3918 MmLockSectionSegment(Segment
);
3919 MmspCompleteAndReleasePageOp(PageOp
);
3920 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3923 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3926 * For a dirty, datafile, non-private page mark it as dirty in the
3929 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3931 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3933 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3934 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3935 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3936 ASSERT(SwapEntry
== 0);
3945 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3947 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3948 KeBugCheck(MEMORY_MANAGEMENT
);
3950 MmFreeSwapPage(SwapEntry
);
3954 if (IS_SWAP_FROM_SSE(Entry
) ||
3955 Page
!= PFN_FROM_SSE(Entry
))
3960 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3962 DPRINT1("Found a private page in a pagefile section.\n");
3963 KeBugCheck(MEMORY_MANAGEMENT
);
3966 * Just dereference private pages
3968 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3969 if (SavedSwapEntry
!= 0)
3971 MmFreeSwapPage(SavedSwapEntry
);
3972 MmSetSavedSwapEntryPage(Page
, 0);
3974 MmDeleteRmap(Page
, Process
, Address
);
3975 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3979 MmDeleteRmap(Page
, Process
, Address
);
3980 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3986 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
3990 PMEMORY_AREA MemoryArea
;
3991 PROS_SECTION_OBJECT Section
;
3992 PMM_SECTION_SEGMENT Segment
;
3993 PLIST_ENTRY CurrentEntry
;
3994 PMM_REGION CurrentRegion
;
3995 PLIST_ENTRY RegionListHead
;
3997 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3999 if (MemoryArea
== NULL
)
4001 return(STATUS_UNSUCCESSFUL
);
4004 MemoryArea
->DeleteInProgress
= TRUE
;
4005 Section
= MemoryArea
->Data
.SectionData
.Section
;
4006 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4008 MmLockSectionSegment(Segment
);
4010 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4011 while (!IsListEmpty(RegionListHead
))
4013 CurrentEntry
= RemoveHeadList(RegionListHead
);
4014 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4015 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4018 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4020 Status
= MmFreeMemoryArea(AddressSpace
,
4027 Status
= MmFreeMemoryArea(AddressSpace
,
4032 MmUnlockSectionSegment(Segment
);
4033 ObDereferenceObject(Section
);
4034 return(STATUS_SUCCESS
);
4041 MmUnmapViewOfSection(PEPROCESS Process
,
4045 PMEMORY_AREA MemoryArea
;
4046 PMMSUPPORT AddressSpace
;
4047 PROS_SECTION_OBJECT Section
;
4050 PVOID ImageBaseAddress
= 0;
4052 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4053 Process
, BaseAddress
);
4057 AddressSpace
= &Process
->Vm
;
4059 MmLockAddressSpace(AddressSpace
);
4060 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4062 if (MemoryArea
== NULL
||
4063 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4064 MemoryArea
->DeleteInProgress
)
4066 MmUnlockAddressSpace(AddressSpace
);
4067 return STATUS_NOT_MAPPED_VIEW
;
4070 MemoryArea
->DeleteInProgress
= TRUE
;
4072 while (MemoryArea
->PageOpCount
)
4074 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4078 Offset
-= PAGE_SIZE
;
4079 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4080 MemoryArea
->Data
.SectionData
.Segment
,
4081 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4084 MmUnlockAddressSpace(AddressSpace
);
4085 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4086 if (Status
!= STATUS_SUCCESS
)
4088 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4089 KeBugCheck(MEMORY_MANAGEMENT
);
4091 MmLockAddressSpace(AddressSpace
);
4092 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4094 if (MemoryArea
== NULL
||
4095 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4097 MmUnlockAddressSpace(AddressSpace
);
4098 return STATUS_NOT_MAPPED_VIEW
;
4105 Section
= MemoryArea
->Data
.SectionData
.Section
;
4107 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4111 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4112 PMM_SECTION_SEGMENT SectionSegments
;
4113 PMM_SECTION_SEGMENT Segment
;
4115 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4116 ImageSectionObject
= Section
->ImageSection
;
4117 SectionSegments
= ImageSectionObject
->Segments
;
4118 NrSegments
= ImageSectionObject
->NrSegments
;
4120 /* Search for the current segment within the section segments
4121 * and calculate the image base address */
4122 for (i
= 0; i
< NrSegments
; i
++)
4124 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4126 if (Segment
== &SectionSegments
[i
])
4128 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4133 if (i
>= NrSegments
)
4135 KeBugCheck(MEMORY_MANAGEMENT
);
4138 for (i
= 0; i
< NrSegments
; i
++)
4140 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4142 PVOID SBaseAddress
= (PVOID
)
4143 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4145 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4151 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4154 MmUnlockAddressSpace(AddressSpace
);
4156 /* Notify debugger */
4157 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4159 return(STATUS_SUCCESS
);
4162 /**********************************************************************
4164 * NtUnmapViewOfSection
4179 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4183 KPROCESSOR_MODE PreviousMode
;
4186 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4187 ProcessHandle
, BaseAddress
);
4189 PreviousMode
= ExGetPreviousMode();
4191 DPRINT("Referencing process\n");
4192 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4193 PROCESS_VM_OPERATION
,
4196 (PVOID
*)(PVOID
)&Process
,
4198 if (!NT_SUCCESS(Status
))
4200 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4204 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4206 ObDereferenceObject(Process
);
4213 * Queries the information of a section object.
4215 * @param SectionHandle
4216 * Handle to the section object. It must be opened with SECTION_QUERY
4218 * @param SectionInformationClass
4219 * Index to a certain information structure. Can be either
4220 * SectionBasicInformation or SectionImageInformation. The latter
4221 * is valid only for sections that were created with the SEC_IMAGE
4223 * @param SectionInformation
4224 * Caller supplies storage for resulting information.
4226 * Size of the supplied storage.
4227 * @param ResultLength
4235 NtQuerySection(IN HANDLE SectionHandle
,
4236 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4237 OUT PVOID SectionInformation
,
4238 IN SIZE_T SectionInformationLength
,
4239 OUT PSIZE_T ResultLength OPTIONAL
)
4241 PROS_SECTION_OBJECT Section
;
4242 KPROCESSOR_MODE PreviousMode
;
4246 PreviousMode
= ExGetPreviousMode();
4248 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4250 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4252 SectionInformationLength
,
4257 if(!NT_SUCCESS(Status
))
4259 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4263 Status
= ObReferenceObjectByHandle(SectionHandle
,
4265 MmSectionObjectType
,
4267 (PVOID
*)(PVOID
)&Section
,
4269 if (NT_SUCCESS(Status
))
4271 switch (SectionInformationClass
)
4273 case SectionBasicInformation
:
4275 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4279 Sbi
->Attributes
= Section
->AllocationAttributes
;
4280 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4282 Sbi
->BaseAddress
= 0;
4283 Sbi
->Size
.QuadPart
= 0;
4287 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4288 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4291 if (ResultLength
!= NULL
)
4293 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4295 Status
= STATUS_SUCCESS
;
4297 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4299 Status
= _SEH2_GetExceptionCode();
4306 case SectionImageInformation
:
4308 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4312 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4313 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4315 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4316 ImageSectionObject
= Section
->ImageSection
;
4318 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4319 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4320 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4321 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4322 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4323 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4324 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4325 Sii
->Machine
= ImageSectionObject
->Machine
;
4326 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4329 if (ResultLength
!= NULL
)
4331 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4333 Status
= STATUS_SUCCESS
;
4335 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4337 Status
= _SEH2_GetExceptionCode();
4345 ObDereferenceObject(Section
);
4353 * Extends size of file backed section.
4355 * @param SectionHandle
4356 * Handle to the section object. It must be opened with
4357 * SECTION_EXTEND_SIZE access.
4358 * @param NewMaximumSize
4359 * New maximum size of the section in bytes.
4363 * @todo Move the actual code to internal function MmExtendSection.
4367 NtExtendSection(IN HANDLE SectionHandle
,
4368 IN PLARGE_INTEGER NewMaximumSize
)
4370 LARGE_INTEGER SafeNewMaximumSize
;
4371 PROS_SECTION_OBJECT Section
;
4372 KPROCESSOR_MODE PreviousMode
;
4375 PreviousMode
= ExGetPreviousMode();
4377 if(PreviousMode
!= KernelMode
)
4381 /* make a copy on the stack */
4382 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4383 NewMaximumSize
= &SafeNewMaximumSize
;
4385 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4387 /* Return the exception code */
4388 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4393 Status
= ObReferenceObjectByHandle(SectionHandle
,
4394 SECTION_EXTEND_SIZE
,
4395 MmSectionObjectType
,
4399 if (!NT_SUCCESS(Status
))
4404 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4406 ObDereferenceObject(Section
);
4407 return STATUS_INVALID_PARAMETER
;
4411 * - Acquire file extneding resource.
4412 * - Check if we're not resizing the section below it's actual size!
4413 * - Extend segments if needed.
4414 * - Set file information (FileAllocationInformation) to the new size.
4415 * - Release file extending resource.
4418 ObDereferenceObject(Section
);
4420 return STATUS_NOT_IMPLEMENTED
;
4423 /**********************************************************************
4425 * MmMapViewOfSection
4428 * Maps a view of a section into the virtual address space of a
4433 * Pointer to the section object.
4436 * Pointer to the process.
4439 * Desired base address (or NULL) on entry;
4440 * Actual base address of the view on exit.
4443 * Number of high order address bits that must be zero.
4446 * Size in bytes of the initially committed section of
4450 * Offset in bytes from the beginning of the section
4451 * to the beginning of the view.
4454 * Desired length of map (or zero to map all) on entry
4455 * Actual length mapped on exit.
4457 * InheritDisposition
4458 * Specified how the view is to be shared with
4462 * Type of allocation for the pages.
4465 * Protection for the committed region of the view.
4473 MmMapViewOfSection(IN PVOID SectionObject
,
4474 IN PEPROCESS Process
,
4475 IN OUT PVOID
*BaseAddress
,
4476 IN ULONG_PTR ZeroBits
,
4477 IN SIZE_T CommitSize
,
4478 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4479 IN OUT PSIZE_T ViewSize
,
4480 IN SECTION_INHERIT InheritDisposition
,
4481 IN ULONG AllocationType
,
4484 PROS_SECTION_OBJECT Section
;
4485 PMMSUPPORT AddressSpace
;
4487 NTSTATUS Status
= STATUS_SUCCESS
;
4491 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4493 return STATUS_INVALID_PAGE_PROTECTION
;
4497 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4498 AddressSpace
= &Process
->Vm
;
4500 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4502 MmLockAddressSpace(AddressSpace
);
4504 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4508 ULONG_PTR ImageBase
;
4510 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4511 PMM_SECTION_SEGMENT SectionSegments
;
4513 ImageSectionObject
= Section
->ImageSection
;
4514 SectionSegments
= ImageSectionObject
->Segments
;
4515 NrSegments
= ImageSectionObject
->NrSegments
;
4518 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4521 ImageBase
= ImageSectionObject
->ImageBase
;
4525 for (i
= 0; i
< NrSegments
; i
++)
4527 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4529 ULONG_PTR MaxExtent
;
4530 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4531 SectionSegments
[i
].Length
;
4532 ImageSize
= max(ImageSize
, MaxExtent
);
4536 ImageSectionObject
->ImageSize
= ImageSize
;
4538 /* Check there is enough space to map the section at that point. */
4539 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4540 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4542 /* Fail if the user requested a fixed base address. */
4543 if ((*BaseAddress
) != NULL
)
4545 MmUnlockAddressSpace(AddressSpace
);
4546 return(STATUS_UNSUCCESSFUL
);
4548 /* Otherwise find a gap to map the image. */
4549 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4552 MmUnlockAddressSpace(AddressSpace
);
4553 return(STATUS_UNSUCCESSFUL
);
4557 for (i
= 0; i
< NrSegments
; i
++)
4559 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4561 PVOID SBaseAddress
= (PVOID
)
4562 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4563 MmLockSectionSegment(&SectionSegments
[i
]);
4564 Status
= MmMapViewOfSegment(AddressSpace
,
4566 &SectionSegments
[i
],
4568 SectionSegments
[i
].Length
,
4569 SectionSegments
[i
].Protection
,
4572 MmUnlockSectionSegment(&SectionSegments
[i
]);
4573 if (!NT_SUCCESS(Status
))
4575 MmUnlockAddressSpace(AddressSpace
);
4581 *BaseAddress
= (PVOID
)ImageBase
;
4585 /* check for write access */
4586 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4587 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4589 MmUnlockAddressSpace(AddressSpace
);
4590 return STATUS_SECTION_PROTECTION
;
4592 /* check for read access */
4593 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4594 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4596 MmUnlockAddressSpace(AddressSpace
);
4597 return STATUS_SECTION_PROTECTION
;
4599 /* check for execute access */
4600 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4601 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4603 MmUnlockAddressSpace(AddressSpace
);
4604 return STATUS_SECTION_PROTECTION
;
4607 if (ViewSize
== NULL
)
4609 /* Following this pointer would lead to us to the dark side */
4610 /* What to do? Bugcheck? Return status? Do the mambo? */
4611 KeBugCheck(MEMORY_MANAGEMENT
);
4614 if (SectionOffset
== NULL
)
4620 ViewOffset
= SectionOffset
->u
.LowPart
;
4623 if ((ViewOffset
% PAGE_SIZE
) != 0)
4625 MmUnlockAddressSpace(AddressSpace
);
4626 return(STATUS_MAPPED_ALIGNMENT
);
4629 if ((*ViewSize
) == 0)
4631 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4633 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4635 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4638 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4640 MmLockSectionSegment(Section
->Segment
);
4641 Status
= MmMapViewOfSegment(AddressSpace
,
4648 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4649 MmUnlockSectionSegment(Section
->Segment
);
4650 if (!NT_SUCCESS(Status
))
4652 MmUnlockAddressSpace(AddressSpace
);
4657 MmUnlockAddressSpace(AddressSpace
);
4659 return(STATUS_SUCCESS
);
4666 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4667 IN PLARGE_INTEGER NewFileSize
)
4669 /* Check whether an ImageSectionObject exists */
4670 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4672 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4676 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4678 PMM_SECTION_SEGMENT Segment
;
4680 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4683 if (Segment
->ReferenceCount
!= 0)
4685 /* Check size of file */
4686 if (SectionObjectPointer
->SharedCacheMap
)
4688 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4689 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4697 /* Something must gone wrong
4698 * how can we have a Section but no
4700 DPRINT("ERROR: DataSectionObject without reference!\n");
4704 DPRINT("FIXME: didn't check for outstanding write probes\n");
4714 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4724 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4725 IN MMFLUSH_TYPE FlushType
)
4729 case MmFlushForDelete
:
4730 if (SectionObjectPointer
->ImageSectionObject
||
4731 SectionObjectPointer
->DataSectionObject
)
4735 CcRosSetRemoveOnClose(SectionObjectPointer
);
4737 case MmFlushForWrite
:
4747 MmForceSectionClosed (
4748 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4749 IN BOOLEAN DelayClose
)
4760 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4761 OUT PVOID
* MappedBase
,
4762 IN OUT PSIZE_T ViewSize
)
4764 PROS_SECTION_OBJECT Section
;
4765 PMMSUPPORT AddressSpace
;
4768 DPRINT("MmMapViewInSystemSpace() called\n");
4770 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4771 AddressSpace
= MmGetKernelAddressSpace();
4773 MmLockAddressSpace(AddressSpace
);
4776 if ((*ViewSize
) == 0)
4778 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4780 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4782 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4785 MmLockSectionSegment(Section
->Segment
);
4788 Status
= MmMapViewOfSegment(AddressSpace
,
4797 MmUnlockSectionSegment(Section
->Segment
);
4798 MmUnlockAddressSpace(AddressSpace
);
4808 MmMapViewInSessionSpace (
4810 OUT PVOID
*MappedBase
,
4811 IN OUT PSIZE_T ViewSize
4815 return STATUS_NOT_IMPLEMENTED
;
4823 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4825 PMMSUPPORT AddressSpace
;
4828 DPRINT("MmUnmapViewInSystemSpace() called\n");
4830 AddressSpace
= MmGetKernelAddressSpace();
4832 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4842 MmUnmapViewInSessionSpace (
4847 return STATUS_NOT_IMPLEMENTED
;
4850 /**********************************************************************
4855 * Creates a section object.
4858 * SectionObject (OUT)
4859 * Caller supplied storage for the resulting pointer
4860 * to a SECTION_OBJECT instance;
4863 * Specifies the desired access to the section can be a
4865 * STANDARD_RIGHTS_REQUIRED |
4867 * SECTION_MAP_WRITE |
4868 * SECTION_MAP_READ |
4869 * SECTION_MAP_EXECUTE
4871 * ObjectAttributes [OPTIONAL]
4872 * Initialized attributes for the object can be used
4873 * to create a named section;
4876 * Maximizes the size of the memory section. Must be
4877 * non-NULL for a page-file backed section.
4878 * If value specified for a mapped file and the file is
4879 * not large enough, file will be extended.
4881 * SectionPageProtection
4882 * Can be a combination of:
4888 * AllocationAttributes
4889 * Can be a combination of:
4894 * Handle to a file to create a section mapped to a file
4895 * instead of a memory backed section;
4906 MmCreateSection (OUT PVOID
* Section
,
4907 IN ACCESS_MASK DesiredAccess
,
4908 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4909 IN PLARGE_INTEGER MaximumSize
,
4910 IN ULONG SectionPageProtection
,
4911 IN ULONG AllocationAttributes
,
4912 IN HANDLE FileHandle OPTIONAL
,
4913 IN PFILE_OBJECT File OPTIONAL
)
4916 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4919 * Check the protection
4921 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4922 if (Protection
!= PAGE_READONLY
&&
4923 Protection
!= PAGE_READWRITE
&&
4924 Protection
!= PAGE_WRITECOPY
&&
4925 Protection
!= PAGE_EXECUTE
&&
4926 Protection
!= PAGE_EXECUTE_READ
&&
4927 Protection
!= PAGE_EXECUTE_READWRITE
&&
4928 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4930 return STATUS_INVALID_PAGE_PROTECTION
;
4933 if (AllocationAttributes
& SEC_IMAGE
)
4935 return(MmCreateImageSection(SectionObject
,
4939 SectionPageProtection
,
4940 AllocationAttributes
,
4944 if (FileHandle
!= NULL
)
4946 return(MmCreateDataFileSection(SectionObject
,
4950 SectionPageProtection
,
4951 AllocationAttributes
,
4955 return(MmCreatePageFileSection(SectionObject
,
4959 SectionPageProtection
,
4960 AllocationAttributes
));
4965 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
4966 IN PVOID File2MappedAsFile
)
4969 return STATUS_NOT_IMPLEMENTED
;