3 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/mm/section.c
22 * PURPOSE: Implements section objects
24 * PROGRAMMERS: Rex Jolliff
38 * Thomas Weidenmueller
39 * Gunnar Andre' Dalsnes
47 /* INCLUDES *****************************************************************/
51 #include <internal/debug.h>
53 #include <reactos/exeformat.h>
55 /* TYPES *********************************************************************/
59 PSECTION_OBJECT Section
;
60 PMM_SECTION_SEGMENT Segment
;
65 MM_SECTION_PAGEOUT_CONTEXT
;
67 /* GLOBALS *******************************************************************/
69 POBJECT_TYPE EXPORTED MmSectionObjectType
= NULL
;
71 static GENERIC_MAPPING MmpSectionMapping
= {
72 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
73 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
74 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
77 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
78 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
79 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
80 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
81 #define MAX_SHARE_COUNT 0x7FF
82 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
83 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
84 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
86 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
88 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
89 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
92 /* FUNCTIONS *****************************************************************/
94 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
97 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
98 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
99 * RETURNS: Status of the wait.
102 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
104 LARGE_INTEGER Timeout
;
105 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
107 Timeout
.QuadPart
= -100000000LL; // 10 sec
110 Timeout
.QuadPart
= -100000000; // 10 sec
113 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
118 * FUNCTION: Sets the page op completion event and releases the page op.
119 * ARGUMENTS: PMM_PAGEOP.
120 * RETURNS: In shorter time than it takes you to even read this
121 * description, so don't even think about geting a mug of coffee.
124 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
126 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
127 MmReleasePageOp(PageOp
);
132 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
133 * ARGUMENTS: PFILE_OBJECT to wait for.
134 * RETURNS: Status of the wait.
137 MmspWaitForFileLock(PFILE_OBJECT File
)
139 return KeWaitForSingleObject(&File
->Lock
, 0, KernelMode
, FALSE
, NULL
);
144 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
147 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
149 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
151 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
153 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
161 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
163 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
165 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
166 PMM_SECTION_SEGMENT SectionSegments
;
170 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
171 NrSegments
= ImageSectionObject
->NrSegments
;
172 SectionSegments
= ImageSectionObject
->Segments
;
173 for (i
= 0; i
< NrSegments
; i
++)
175 if (SectionSegments
[i
].ReferenceCount
!= 0)
177 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
178 SectionSegments
[i
].ReferenceCount
);
181 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
183 ExFreePool(ImageSectionObject
->Segments
);
184 ExFreePool(ImageSectionObject
);
185 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
187 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
189 PMM_SECTION_SEGMENT Segment
;
191 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
194 if (Segment
->ReferenceCount
!= 0)
196 DPRINT1("Data segment still referenced\n");
199 MmFreePageTablesSectionSegment(Segment
);
201 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
207 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
209 ExAcquireFastMutex(&Segment
->Lock
);
214 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
216 ExReleaseFastMutex(&Segment
->Lock
);
221 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
225 PSECTION_PAGE_TABLE Table
;
226 ULONG DirectoryOffset
;
229 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
231 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
235 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
236 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
240 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
241 ExAllocatePoolWithTag(PagedPool
, sizeof(SECTION_PAGE_TABLE
),
242 TAG_SECTION_PAGE_TABLE
);
247 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
248 DPRINT("Table %x\n", Table
);
251 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
252 Table
->Entry
[TableOffset
] = Entry
;
258 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
261 PSECTION_PAGE_TABLE Table
;
263 ULONG DirectoryOffset
;
266 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
268 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
270 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
274 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
275 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
276 DPRINT("Table %x\n", Table
);
282 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
283 Entry
= Table
->Entry
[TableOffset
];
289 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
294 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
297 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
300 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
302 DPRINT1("Maximum share count reached\n");
305 if (IS_SWAP_FROM_SSE(Entry
))
309 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
310 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
315 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section
,
316 PMM_SECTION_SEGMENT Segment
,
322 BOOLEAN IsDirectMapped
= FALSE
;
324 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
327 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
330 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
332 DPRINT1("Zero share count for unshare\n");
335 if (IS_SWAP_FROM_SSE(Entry
))
339 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
341 * If we reducing the share count of this entry to zero then set the entry
342 * to zero and tell the cache the page is no longer mapped.
344 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
346 PFILE_OBJECT FileObject
;
348 SWAPENTRY SavedSwapEntry
;
350 BOOLEAN IsImageSection
;
353 FileOffset
= Offset
+ Segment
->FileOffset
;
355 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
357 Page
= PFN_FROM_SSE(Entry
);
358 FileObject
= Section
->FileObject
;
359 if (FileObject
!= NULL
&&
360 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
363 if ((FileOffset
% PAGE_SIZE
) == 0 &&
364 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
367 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
368 IsDirectMapped
= TRUE
;
369 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
370 if (!NT_SUCCESS(Status
))
372 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
378 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
379 if (SavedSwapEntry
== 0)
382 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
383 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
387 * Try to page out this page and set the swap entry
388 * within the section segment. There exist no rmap entry
389 * for this page. The pager thread can't page out a
390 * page without a rmap entry.
392 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
396 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
399 MmReleasePageMemoryConsumer(MC_USER
, Page
);
405 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
406 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
414 * We hold all locks. Nobody can do something with the current
415 * process and the current segment (also not within an other process).
418 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
419 if (!NT_SUCCESS(Status
))
421 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
425 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
426 MmSetSavedSwapEntryPage(Page
, 0);
428 MmReleasePageMemoryConsumer(MC_USER
, Page
);
432 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
439 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
441 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
444 BOOL
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
447 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
450 PCACHE_SEGMENT CacheSeg
;
451 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
452 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
455 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
464 MiReadPage(PMEMORY_AREA MemoryArea
,
468 * FUNCTION: Read a page for a section backed memory area.
470 * MemoryArea - Memory area to read the page for.
471 * Offset - Offset of the page to read.
472 * Page - Variable that receives a page contains the read data.
479 PCACHE_SEGMENT CacheSeg
;
480 PFILE_OBJECT FileObject
;
484 BOOLEAN IsImageSection
;
487 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
488 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
489 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
490 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
491 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
495 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
498 * If the file system is letting us go directly to the cache and the
499 * memory area was mapped at an offset in the file which is page aligned
500 * then get the related cache segment.
502 if ((FileOffset
% PAGE_SIZE
) == 0 &&
503 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
504 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
508 * Get the related cache segment; we use a lower level interface than
509 * filesystems do because it is safe for us to use an offset with a
510 * alignment less than the file system block size.
512 Status
= CcRosGetCacheSegment(Bcb
,
518 if (!NT_SUCCESS(Status
))
525 * If the cache segment isn't up to date then call the file
526 * system to read in the data.
528 Status
= ReadCacheSegment(CacheSeg
);
529 if (!NT_SUCCESS(Status
))
531 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
536 * Retrieve the page from the cache segment that we actually want.
538 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
539 FileOffset
- BaseOffset
).QuadPart
>> PAGE_SHIFT
;
541 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
546 ULONG CacheSegOffset
;
548 * Allocate a page, this is rather complicated by the possibility
549 * we might have to move other things out of memory
551 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
552 if (!NT_SUCCESS(Status
))
556 Status
= CcRosGetCacheSegment(Bcb
,
562 if (!NT_SUCCESS(Status
))
569 * If the cache segment isn't up to date then call the file
570 * system to read in the data.
572 Status
= ReadCacheSegment(CacheSeg
);
573 if (!NT_SUCCESS(Status
))
575 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
579 PageAddr
= MmCreateHyperspaceMapping(*Page
);
580 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
581 Length
= RawLength
- SegOffset
;
582 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
584 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
586 else if (CacheSegOffset
>= PAGE_SIZE
)
588 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
592 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
593 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
594 Status
= CcRosGetCacheSegment(Bcb
,
595 FileOffset
+ CacheSegOffset
,
600 if (!NT_SUCCESS(Status
))
602 MmDeleteHyperspaceMapping(PageAddr
);
608 * If the cache segment isn't up to date then call the file
609 * system to read in the data.
611 Status
= ReadCacheSegment(CacheSeg
);
612 if (!NT_SUCCESS(Status
))
614 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
615 MmDeleteHyperspaceMapping(PageAddr
);
619 if (Length
< PAGE_SIZE
)
621 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
625 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
628 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
629 MmDeleteHyperspaceMapping(PageAddr
);
631 return(STATUS_SUCCESS
);
636 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
637 MEMORY_AREA
* MemoryArea
,
645 PSECTION_OBJECT Section
;
646 PMM_SECTION_SEGMENT Segment
;
655 * There is a window between taking the page fault and locking the
656 * address space when another thread could load the page so we check
659 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
663 MmLockPage(MmGetPfnForProcess(AddressSpace
->Process
, Address
));
665 return(STATUS_SUCCESS
);
668 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
669 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
670 + MemoryArea
->Data
.SectionData
.ViewOffset
;
672 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
673 Section
= MemoryArea
->Data
.SectionData
.Section
;
674 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
675 &MemoryArea
->Data
.SectionData
.RegionListHead
,
680 MmLockSectionSegment(Segment
);
683 * Check if this page needs to be mapped COW
685 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
686 (Region
->Protect
== PAGE_READWRITE
||
687 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
689 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
693 Attributes
= Region
->Protect
;
697 * Get or create a page operation descriptor
699 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
702 DPRINT1("MmGetPageOp failed\n");
707 * Check if someone else is already handling this fault, if so wait
710 if (PageOp
->Thread
!= PsGetCurrentThread())
712 MmUnlockSectionSegment(Segment
);
713 MmUnlockAddressSpace(AddressSpace
);
714 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
716 * Check for various strange conditions
718 if (Status
!= STATUS_SUCCESS
)
720 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
723 if (PageOp
->Status
== STATUS_PENDING
)
725 DPRINT1("Woke for page op before completion\n");
728 MmLockAddressSpace(AddressSpace
);
730 * If this wasn't a pagein then restart the operation
732 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
734 MmspCompleteAndReleasePageOp(PageOp
);
735 DPRINT("Address 0x%.8X\n", Address
);
736 return(STATUS_MM_RESTART_OPERATION
);
740 * If the thread handling this fault has failed then we don't retry
742 if (!NT_SUCCESS(PageOp
->Status
))
744 Status
= PageOp
->Status
;
745 MmspCompleteAndReleasePageOp(PageOp
);
746 DPRINT("Address 0x%.8X\n", Address
);
749 MmLockSectionSegment(Segment
);
751 * If the completed fault was for another address space then set the
754 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
756 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
757 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
759 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
762 * The page was a private page in another or in our address space
764 MmUnlockSectionSegment(Segment
);
765 MmspCompleteAndReleasePageOp(PageOp
);
766 return(STATUS_MM_RESTART_OPERATION
);
769 Page
= PFN_FROM_SSE(Entry
);
771 MmSharePageEntrySectionSegment(Segment
, Offset
);
773 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
774 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
776 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
781 if (!NT_SUCCESS(Status
))
783 DbgPrint("Unable to create virtual mapping\n");
786 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
792 MmUnlockSectionSegment(Segment
);
793 PageOp
->Status
= STATUS_SUCCESS
;
794 MmspCompleteAndReleasePageOp(PageOp
);
795 DPRINT("Address 0x%.8X\n", Address
);
796 return(STATUS_SUCCESS
);
799 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
803 * Must be private page we have swapped out.
810 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
812 DPRINT1("Found a swaped out private page in a pagefile section.\n");
816 MmUnlockSectionSegment(Segment
);
817 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
819 MmUnlockAddressSpace(AddressSpace
);
820 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
821 if (!NT_SUCCESS(Status
))
826 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
827 if (!NT_SUCCESS(Status
))
829 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
832 MmLockAddressSpace(AddressSpace
);
833 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
838 if (!NT_SUCCESS(Status
))
840 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
846 * Store the swap entry for later use.
848 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
851 * Add the page to the process's working set
853 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
856 * Finish the operation
862 PageOp
->Status
= STATUS_SUCCESS
;
863 MmspCompleteAndReleasePageOp(PageOp
);
864 DPRINT("Address 0x%.8X\n", Address
);
865 return(STATUS_SUCCESS
);
869 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
871 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
873 MmUnlockSectionSegment(Segment
);
875 * Just map the desired physical page
877 Page
= Offset
>> PAGE_SHIFT
;
878 Status
= MmCreateVirtualMappingUnsafe(AddressSpace
->Process
,
883 if (!NT_SUCCESS(Status
))
885 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
890 * Don't add an rmap entry since the page mapped could be for
895 MmLockPageUnsafe(Page
);
899 * Cleanup and release locks
901 PageOp
->Status
= STATUS_SUCCESS
;
902 MmspCompleteAndReleasePageOp(PageOp
);
903 DPRINT("Address 0x%.8X\n", Address
);
904 return(STATUS_SUCCESS
);
908 * Map anonymous memory for BSS sections
910 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
912 MmUnlockSectionSegment(Segment
);
913 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
914 if (!NT_SUCCESS(Status
))
916 MmUnlockAddressSpace(AddressSpace
);
917 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
918 MmLockAddressSpace(AddressSpace
);
920 if (!NT_SUCCESS(Status
))
924 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
929 if (!NT_SUCCESS(Status
))
931 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
935 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
942 * Cleanup and release locks
944 PageOp
->Status
= STATUS_SUCCESS
;
945 MmspCompleteAndReleasePageOp(PageOp
);
946 DPRINT("Address 0x%.8X\n", Address
);
947 return(STATUS_SUCCESS
);
951 * Get the entry corresponding to the offset within the section
953 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
958 * If the entry is zero (and it can't change because we have
959 * locked the segment) then we need to load the page.
963 * Release all our locks and read in the page from disk
965 MmUnlockSectionSegment(Segment
);
966 MmUnlockAddressSpace(AddressSpace
);
968 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
969 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
971 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
972 if (!NT_SUCCESS(Status
))
974 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
979 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
980 if (!NT_SUCCESS(Status
))
982 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
985 if (!NT_SUCCESS(Status
))
988 * FIXME: What do we know in this case?
991 * Cleanup and release locks
993 MmLockAddressSpace(AddressSpace
);
994 PageOp
->Status
= Status
;
995 MmspCompleteAndReleasePageOp(PageOp
);
996 DPRINT("Address 0x%.8X\n", Address
);
1000 * Relock the address space and segment
1002 MmLockAddressSpace(AddressSpace
);
1003 MmLockSectionSegment(Segment
);
1006 * Check the entry. No one should change the status of a page
1007 * that has a pending page-in.
1009 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1010 if (Entry
!= Entry1
)
1012 DbgPrint("Someone changed ppte entry while we slept\n");
1017 * Mark the offset within the section as having valid, in-memory
1020 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1021 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1022 MmUnlockSectionSegment(Segment
);
1024 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1029 if (!NT_SUCCESS(Status
))
1031 DbgPrint("Unable to create virtual mapping\n");
1034 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1040 PageOp
->Status
= STATUS_SUCCESS
;
1041 MmspCompleteAndReleasePageOp(PageOp
);
1042 DPRINT("Address 0x%.8X\n", Address
);
1043 return(STATUS_SUCCESS
);
1045 else if (IS_SWAP_FROM_SSE(Entry
))
1047 SWAPENTRY SwapEntry
;
1049 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1052 * Release all our locks and read in the page from disk
1054 MmUnlockSectionSegment(Segment
);
1056 MmUnlockAddressSpace(AddressSpace
);
1058 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1059 if (!NT_SUCCESS(Status
))
1064 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1065 if (!NT_SUCCESS(Status
))
1071 * Relock the address space and segment
1073 MmLockAddressSpace(AddressSpace
);
1074 MmLockSectionSegment(Segment
);
1077 * Check the entry. No one should change the status of a page
1078 * that has a pending page-in.
1080 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1081 if (Entry
!= Entry1
)
1083 DbgPrint("Someone changed ppte entry while we slept\n");
1088 * Mark the offset within the section as having valid, in-memory
1091 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1092 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1093 MmUnlockSectionSegment(Segment
);
1096 * Save the swap entry.
1098 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1099 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1104 if (!NT_SUCCESS(Status
))
1106 DbgPrint("Unable to create virtual mapping\n");
1109 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1114 PageOp
->Status
= STATUS_SUCCESS
;
1115 MmspCompleteAndReleasePageOp(PageOp
);
1116 DPRINT("Address 0x%.8X\n", Address
);
1117 return(STATUS_SUCCESS
);
1122 * If the section offset is already in-memory and valid then just
1123 * take another reference to the page
1126 Page
= PFN_FROM_SSE(Entry
);
1128 MmSharePageEntrySectionSegment(Segment
, Offset
);
1129 MmUnlockSectionSegment(Segment
);
1131 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1136 if (!NT_SUCCESS(Status
))
1138 DbgPrint("Unable to create virtual mapping\n");
1141 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1146 PageOp
->Status
= STATUS_SUCCESS
;
1147 MmspCompleteAndReleasePageOp(PageOp
);
1148 DPRINT("Address 0x%.8X\n", Address
);
1149 return(STATUS_SUCCESS
);
1155 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1156 MEMORY_AREA
* MemoryArea
,
1160 PMM_SECTION_SEGMENT Segment
;
1161 PSECTION_OBJECT Section
;
1172 * Check if the page has been paged out or has already been set readwrite
1174 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1175 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1177 DPRINT("Address 0x%.8X\n", Address
);
1178 return(STATUS_SUCCESS
);
1182 * Find the offset of the page
1184 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1185 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1186 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1188 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1189 Section
= MemoryArea
->Data
.SectionData
.Section
;
1190 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1191 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1196 MmLockSectionSegment(Segment
);
1198 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1199 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1201 MmUnlockSectionSegment(Segment
);
1204 * Check if we are doing COW
1206 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1207 (Region
->Protect
== PAGE_READWRITE
||
1208 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1210 DPRINT("Address 0x%.8X\n", Address
);
1211 return(STATUS_UNSUCCESSFUL
);
1214 if (IS_SWAP_FROM_SSE(Entry
) ||
1215 PFN_FROM_SSE(Entry
) != OldPage
)
1217 /* This is a private page. We must only change the page protection. */
1218 MmSetPageProtect(AddressSpace
->Process
, PAddress
, Region
->Protect
);
1219 return(STATUS_SUCCESS
);
1223 * Get or create a pageop
1225 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1226 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1229 DPRINT1("MmGetPageOp failed\n");
1234 * Wait for any other operations to complete
1236 if (PageOp
->Thread
!= PsGetCurrentThread())
1238 MmUnlockAddressSpace(AddressSpace
);
1239 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1241 * Check for various strange conditions
1243 if (Status
== STATUS_TIMEOUT
)
1245 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1248 if (PageOp
->Status
== STATUS_PENDING
)
1250 DPRINT1("Woke for page op before completion\n");
1254 * Restart the operation
1256 MmLockAddressSpace(AddressSpace
);
1257 MmspCompleteAndReleasePageOp(PageOp
);
1258 DPRINT("Address 0x%.8X\n", Address
);
1259 return(STATUS_MM_RESTART_OPERATION
);
1263 * Release locks now we have the pageop
1265 MmUnlockAddressSpace(AddressSpace
);
1270 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1271 if (!NT_SUCCESS(Status
))
1279 MiCopyFromUserPage(NewPage
, PAddress
);
1282 * Delete the old entry.
1284 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1287 * Set the PTE to point to the new page
1289 MmLockAddressSpace(AddressSpace
);
1290 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1295 if (!NT_SUCCESS(Status
))
1297 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1301 MmInsertRmap(NewPage
, AddressSpace
->Process
, PAddress
);
1302 if (!NT_SUCCESS(Status
))
1304 DbgPrint("Unable to create virtual mapping\n");
1309 MmLockPage(NewPage
);
1310 MmUnlockPage(OldPage
);
1314 * Unshare the old page.
1316 MmDeleteRmap(OldPage
, AddressSpace
->Process
, PAddress
);
1317 MmLockSectionSegment(Segment
);
1318 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1319 MmUnlockSectionSegment(Segment
);
1321 PageOp
->Status
= STATUS_SUCCESS
;
1322 MmspCompleteAndReleasePageOp(PageOp
);
1323 DPRINT("Address 0x%.8X\n", Address
);
1324 return(STATUS_SUCCESS
);
1328 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1330 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1334 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1335 MmDeleteVirtualMapping(Process
,
1342 PageOutContext
->WasDirty
= TRUE
;
1344 if (!PageOutContext
->Private
)
1346 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1347 PageOutContext
->Segment
,
1348 PageOutContext
->Offset
,
1349 PageOutContext
->WasDirty
,
1354 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1357 DPRINT("PhysicalAddress %I64x, Address %x\n", Page
, Address
);
1362 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1363 MEMORY_AREA
* MemoryArea
,
1368 MM_SECTION_PAGEOUT_CONTEXT Context
;
1369 SWAPENTRY SwapEntry
;
1373 PFILE_OBJECT FileObject
;
1375 BOOLEAN DirectMapped
;
1376 BOOLEAN IsImageSection
;
1378 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1381 * Get the segment and section.
1383 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1384 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1386 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1387 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1388 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1390 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1392 FileObject
= Context
.Section
->FileObject
;
1393 DirectMapped
= FALSE
;
1394 if (FileObject
!= NULL
&&
1395 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1397 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1400 * If the file system is letting us go directly to the cache and the
1401 * memory area was mapped at an offset in the file which is page aligned
1402 * then note this is a direct mapped page.
1404 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1405 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1407 DirectMapped
= TRUE
;
1413 * This should never happen since mappings of physical memory are never
1414 * placed in the rmap lists.
1416 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1418 DPRINT1("Trying to page out from physical memory section address 0x%X "
1419 "process %d\n", Address
,
1420 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1425 * Get the section segment entry and the physical address.
1427 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1428 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1430 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1431 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1434 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1435 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1438 * Prepare the context structure for the rmap delete call.
1440 Context
.WasDirty
= FALSE
;
1441 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1442 IS_SWAP_FROM_SSE(Entry
) ||
1443 PFN_FROM_SSE(Entry
) != Page
)
1445 Context
.Private
= TRUE
;
1449 Context
.Private
= FALSE
;
1453 * Take an additional reference to the page or the cache segment.
1455 if (DirectMapped
&& !Context
.Private
)
1457 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1459 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1465 MmReferencePage(Page
);
1468 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1471 * If this wasn't a private page then we should have reduced the entry to
1472 * zero by deleting all the rmaps.
1474 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1476 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1477 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1484 * If the page wasn't dirty then we can just free it as for a readonly page.
1485 * Since we unmapped all the mappings above we know it will not suddenly
1487 * If the page is from a pagefile section and has no swap entry,
1488 * we can't free the page at this point.
1490 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1491 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1493 if (Context
.Private
)
1495 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1496 Context
.WasDirty
? "dirty" : "clean", Address
);
1499 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1501 MmSetSavedSwapEntryPage(Page
, 0);
1502 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1503 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1504 PageOp
->Status
= STATUS_SUCCESS
;
1505 MmspCompleteAndReleasePageOp(PageOp
);
1506 return(STATUS_SUCCESS
);
1509 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1511 if (Context
.Private
)
1513 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1514 Context
.WasDirty
? "dirty" : "clean", Address
);
1517 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1519 MmSetSavedSwapEntryPage(Page
, 0);
1522 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1524 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1525 PageOp
->Status
= STATUS_SUCCESS
;
1526 MmspCompleteAndReleasePageOp(PageOp
);
1527 return(STATUS_SUCCESS
);
1530 else if (!Context
.Private
&& DirectMapped
)
1534 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1538 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1539 if (!NT_SUCCESS(Status
))
1541 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1544 PageOp
->Status
= STATUS_SUCCESS
;
1545 MmspCompleteAndReleasePageOp(PageOp
);
1546 return(STATUS_SUCCESS
);
1548 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1552 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1556 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1557 PageOp
->Status
= STATUS_SUCCESS
;
1558 MmspCompleteAndReleasePageOp(PageOp
);
1559 return(STATUS_SUCCESS
);
1561 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1563 MmSetSavedSwapEntryPage(Page
, 0);
1564 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1567 if (!NT_SUCCESS(Status
))
1571 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1572 PageOp
->Status
= STATUS_SUCCESS
;
1573 MmspCompleteAndReleasePageOp(PageOp
);
1574 return(STATUS_SUCCESS
);
1578 * If necessary, allocate an entry in the paging file for this page
1582 SwapEntry
= MmAllocSwapPage();
1585 MmShowOutOfSpaceMessagePagingFile();
1588 * For private pages restore the old mappings.
1590 if (Context
.Private
)
1592 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1594 MemoryArea
->Attributes
,
1597 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1599 AddressSpace
->Process
,
1605 * For non-private pages if the page wasn't direct mapped then
1606 * set it back into the section segment entry so we don't loose
1607 * our copy. Otherwise it will be handled by the cache manager.
1609 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1611 MemoryArea
->Attributes
,
1614 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1616 AddressSpace
->Process
,
1618 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1619 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1621 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1622 MmspCompleteAndReleasePageOp(PageOp
);
1623 return(STATUS_PAGEFILE_QUOTA
);
1628 * Write the page to the pagefile
1630 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1631 if (!NT_SUCCESS(Status
))
1633 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1636 * As above: undo our actions.
1637 * FIXME: Also free the swap page.
1639 if (Context
.Private
)
1641 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1643 MemoryArea
->Attributes
,
1646 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1648 AddressSpace
->Process
,
1653 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1655 MemoryArea
->Attributes
,
1658 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1660 AddressSpace
->Process
,
1662 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1663 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1665 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1666 MmspCompleteAndReleasePageOp(PageOp
);
1667 return(STATUS_UNSUCCESSFUL
);
1671 * Otherwise we have succeeded.
1673 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1674 MmSetSavedSwapEntryPage(Page
, 0);
1675 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1676 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1678 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1682 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1685 if (Context
.Private
)
1687 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1690 if (!NT_SUCCESS(Status
))
1697 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1698 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1701 PageOp
->Status
= STATUS_SUCCESS
;
1702 MmspCompleteAndReleasePageOp(PageOp
);
1703 return(STATUS_SUCCESS
);
1708 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1709 PMEMORY_AREA MemoryArea
,
1714 PSECTION_OBJECT Section
;
1715 PMM_SECTION_SEGMENT Segment
;
1717 SWAPENTRY SwapEntry
;
1721 PFILE_OBJECT FileObject
;
1723 BOOLEAN DirectMapped
;
1724 BOOLEAN IsImageSection
;
1726 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1728 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1729 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1732 * Get the segment and section.
1734 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1735 Section
= MemoryArea
->Data
.SectionData
.Section
;
1736 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1738 FileObject
= Section
->FileObject
;
1739 DirectMapped
= FALSE
;
1740 if (FileObject
!= NULL
&&
1741 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1743 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1746 * If the file system is letting us go directly to the cache and the
1747 * memory area was mapped at an offset in the file which is page aligned
1748 * then note this is a direct mapped page.
1750 if ((Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
% PAGE_SIZE
) == 0 &&
1751 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1753 DirectMapped
= TRUE
;
1758 * This should never happen since mappings of physical memory are never
1759 * placed in the rmap lists.
1761 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1763 DPRINT1("Trying to write back page from physical memory mapped at %X "
1764 "process %d\n", Address
,
1765 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1770 * Get the section segment entry and the physical address.
1772 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1773 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1775 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1776 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1779 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1780 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1783 * Check for a private (COWed) page.
1785 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1786 IS_SWAP_FROM_SSE(Entry
) ||
1787 PFN_FROM_SSE(Entry
) != Page
)
1797 * Speculatively set all mappings of the page to clean.
1799 MmSetCleanAllRmaps(Page
);
1802 * If this page was direct mapped from the cache then the cache manager
1803 * will take care of writing it back to disk.
1805 if (DirectMapped
&& !Private
)
1807 ASSERT(SwapEntry
== 0);
1808 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1809 PageOp
->Status
= STATUS_SUCCESS
;
1810 MmspCompleteAndReleasePageOp(PageOp
);
1811 return(STATUS_SUCCESS
);
1815 * If necessary, allocate an entry in the paging file for this page
1819 SwapEntry
= MmAllocSwapPage();
1822 MmSetDirtyAllRmaps(Page
);
1823 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1824 MmspCompleteAndReleasePageOp(PageOp
);
1825 return(STATUS_PAGEFILE_QUOTA
);
1827 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1831 * Write the page to the pagefile
1833 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1834 if (!NT_SUCCESS(Status
))
1836 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1838 MmSetDirtyAllRmaps(Page
);
1839 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1840 MmspCompleteAndReleasePageOp(PageOp
);
1841 return(STATUS_UNSUCCESSFUL
);
1845 * Otherwise we have succeeded.
1847 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1848 PageOp
->Status
= STATUS_SUCCESS
;
1849 MmspCompleteAndReleasePageOp(PageOp
);
1850 return(STATUS_SUCCESS
);
1854 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1862 PMEMORY_AREA MemoryArea
;
1863 PMM_SECTION_SEGMENT Segment
;
1867 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1868 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1870 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1871 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1876 if (OldProtect
!= NewProtect
)
1878 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1880 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1881 ULONG Protect
= NewProtect
;
1884 * If we doing COW for this segment then check if the page is
1887 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1893 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1894 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1895 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1896 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1898 Protect
= PAGE_READONLY
;
1899 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1900 IS_SWAP_FROM_SSE(Entry
) ||
1901 PFN_FROM_SSE(Entry
) != Page
)
1903 Protect
= NewProtect
;
1907 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1909 MmSetPageProtect(AddressSpace
->Process
, Address
,
1918 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1919 PMEMORY_AREA MemoryArea
,
1927 ULONG_PTR MaxLength
;
1929 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
1930 if (Length
> MaxLength
)
1933 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1934 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1936 *OldProtect
= Region
->Protect
;
1937 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
1938 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1939 BaseAddress
, Length
, Region
->Type
, Protect
,
1940 MmAlterViewAttributes
);
1946 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
1948 PMEMORY_BASIC_INFORMATION Info
,
1949 PULONG ResultLength
)
1952 PVOID RegionBaseAddress
;
1953 PSECTION_OBJECT Section
;
1954 PMM_SECTION_SEGMENT Segment
;
1956 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
1957 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1958 Address
, &RegionBaseAddress
);
1961 return STATUS_UNSUCCESSFUL
;
1964 Section
= MemoryArea
->Data
.SectionData
.Section
;
1965 if (Section
->AllocationAttributes
& SEC_IMAGE
)
1967 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1968 Info
->AllocationBase
= (PBYTE
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
1969 Info
->Type
= MEM_IMAGE
;
1973 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
1974 Info
->Type
= MEM_MAPPED
;
1976 Info
->BaseAddress
= RegionBaseAddress
;
1977 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1978 Info
->RegionSize
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
-
1979 (ULONG_PTR
)MemoryArea
->StartingAddress
);
1980 Info
->State
= MEM_COMMIT
;
1981 Info
->Protect
= Region
->Protect
;
1983 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
1984 return(STATUS_SUCCESS
);
1989 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
1994 ULONG SavedSwapEntry
;
1999 Length
= PAGE_ROUND_UP(Segment
->Length
);
2000 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2002 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2005 if (IS_SWAP_FROM_SSE(Entry
))
2007 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2011 Page
= PFN_FROM_SSE(Entry
);
2012 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2013 if (SavedSwapEntry
!= 0)
2015 MmSetSavedSwapEntryPage(Page
, 0);
2016 MmFreeSwapPage(SavedSwapEntry
);
2018 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2020 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2026 MmpDeleteSection(PVOID ObjectBody
)
2028 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
2030 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2031 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2036 PMM_SECTION_SEGMENT SectionSegments
;
2039 * NOTE: Section->ImageSection can be NULL for short time
2040 * during the section creating. If we fail for some reason
2041 * until the image section is properly initialized we shouldn't
2042 * process further here.
2044 if (Section
->ImageSection
== NULL
)
2047 SectionSegments
= Section
->ImageSection
->Segments
;
2048 NrSegments
= Section
->ImageSection
->NrSegments
;
2050 for (i
= 0; i
< NrSegments
; i
++)
2052 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2054 MmLockSectionSegment(&SectionSegments
[i
]);
2056 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2057 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2061 MmpFreePageFileSegment(&SectionSegments
[i
]);
2063 MmUnlockSectionSegment(&SectionSegments
[i
]);
2070 * NOTE: Section->Segment can be NULL for short time
2071 * during the section creating.
2073 if (Section
->Segment
== NULL
)
2076 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2078 MmpFreePageFileSegment(Section
->Segment
);
2079 MmFreePageTablesSectionSegment(Section
->Segment
);
2080 ExFreePool(Section
->Segment
);
2081 Section
->Segment
= NULL
;
2085 InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2088 if (Section
->FileObject
!= NULL
)
2090 CcRosDereferenceCache(Section
->FileObject
);
2091 ObDereferenceObject(Section
->FileObject
);
2092 Section
->FileObject
= NULL
;
2097 MmpCloseSection(PVOID ObjectBody
,
2100 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2101 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2107 MmCreatePhysicalMemorySection(VOID
)
2109 PSECTION_OBJECT PhysSection
;
2111 OBJECT_ATTRIBUTES Obj
;
2112 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2113 LARGE_INTEGER SectionSize
;
2116 * Create the section mapping physical memory
2118 SectionSize
.QuadPart
= 0xFFFFFFFF;
2119 InitializeObjectAttributes(&Obj
,
2124 Status
= MmCreateSection(&PhysSection
,
2128 PAGE_EXECUTE_READWRITE
,
2132 if (!NT_SUCCESS(Status
))
2134 DbgPrint("Failed to create PhysicalMemory section\n");
2137 Status
= ObInsertObject(PhysSection
,
2143 if (!NT_SUCCESS(Status
))
2145 ObDereferenceObject(PhysSection
);
2147 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2148 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2150 return(STATUS_SUCCESS
);
2156 MmInitSectionImplementation(VOID
)
2158 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2159 UNICODE_STRING Name
;
2161 DPRINT("Creating Section Object Type\n");
2163 /* Initialize the Section object type */
2164 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2165 RtlInitUnicodeString(&Name
, L
"Section");
2166 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2167 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(SECTION_OBJECT
);
2168 ObjectTypeInitializer
.PoolType
= PagedPool
;
2169 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2170 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2171 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2172 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2173 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &MmSectionObjectType
);
2175 return(STATUS_SUCCESS
);
2180 MmCreatePageFileSection(PSECTION_OBJECT
*SectionObject
,
2181 ACCESS_MASK DesiredAccess
,
2182 POBJECT_ATTRIBUTES ObjectAttributes
,
2183 PLARGE_INTEGER UMaximumSize
,
2184 ULONG SectionPageProtection
,
2185 ULONG AllocationAttributes
)
2187 * Create a section which is backed by the pagefile
2190 LARGE_INTEGER MaximumSize
;
2191 PSECTION_OBJECT Section
;
2192 PMM_SECTION_SEGMENT Segment
;
2195 if (UMaximumSize
== NULL
)
2197 return(STATUS_UNSUCCESSFUL
);
2199 MaximumSize
= *UMaximumSize
;
2202 * Create the section
2204 Status
= ObCreateObject(ExGetPreviousMode(),
2205 MmSectionObjectType
,
2207 ExGetPreviousMode(),
2209 sizeof(SECTION_OBJECT
),
2212 (PVOID
*)(PVOID
)&Section
);
2213 if (!NT_SUCCESS(Status
))
2221 Section
->SectionPageProtection
= SectionPageProtection
;
2222 Section
->AllocationAttributes
= AllocationAttributes
;
2223 Section
->Segment
= NULL
;
2224 Section
->FileObject
= NULL
;
2225 Section
->MaximumSize
= MaximumSize
;
2226 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2227 TAG_MM_SECTION_SEGMENT
);
2228 if (Segment
== NULL
)
2230 ObDereferenceObject(Section
);
2231 return(STATUS_NO_MEMORY
);
2233 Section
->Segment
= Segment
;
2234 Segment
->ReferenceCount
= 1;
2235 ExInitializeFastMutex(&Segment
->Lock
);
2236 Segment
->FileOffset
= 0;
2237 Segment
->Protection
= SectionPageProtection
;
2238 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2239 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2240 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2241 Segment
->WriteCopy
= FALSE
;
2242 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2243 Segment
->VirtualAddress
= 0;
2244 Segment
->Characteristics
= 0;
2245 *SectionObject
= Section
;
2246 return(STATUS_SUCCESS
);
2252 MmCreateDataFileSection(PSECTION_OBJECT
*SectionObject
,
2253 ACCESS_MASK DesiredAccess
,
2254 POBJECT_ATTRIBUTES ObjectAttributes
,
2255 PLARGE_INTEGER UMaximumSize
,
2256 ULONG SectionPageProtection
,
2257 ULONG AllocationAttributes
,
2260 * Create a section backed by a data file
2263 PSECTION_OBJECT Section
;
2265 LARGE_INTEGER MaximumSize
;
2266 PFILE_OBJECT FileObject
;
2267 PMM_SECTION_SEGMENT Segment
;
2269 IO_STATUS_BLOCK Iosb
;
2270 LARGE_INTEGER Offset
;
2272 FILE_STANDARD_INFORMATION FileInfo
;
2275 * Create the section
2277 Status
= ObCreateObject(ExGetPreviousMode(),
2278 MmSectionObjectType
,
2280 ExGetPreviousMode(),
2282 sizeof(SECTION_OBJECT
),
2285 (PVOID
*)(PVOID
)&Section
);
2286 if (!NT_SUCCESS(Status
))
2293 Section
->SectionPageProtection
= SectionPageProtection
;
2294 Section
->AllocationAttributes
= AllocationAttributes
;
2295 Section
->Segment
= NULL
;
2298 * Check file access required
2300 if (SectionPageProtection
& PAGE_READWRITE
||
2301 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2303 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2307 FileAccess
= FILE_READ_DATA
;
2311 * Reference the file handle
2313 Status
= ObReferenceObjectByHandle(FileHandle
,
2317 (PVOID
*)(PVOID
)&FileObject
,
2319 if (!NT_SUCCESS(Status
))
2321 ObDereferenceObject(Section
);
2326 * FIXME: This is propably not entirely correct. We can't look into
2327 * the standard FCB header because it might not be initialized yet
2328 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2329 * standard file information is filled on first request).
2331 Status
= IoQueryFileInformation(FileObject
,
2332 FileStandardInformation
,
2333 sizeof(FILE_STANDARD_INFORMATION
),
2336 if (!NT_SUCCESS(Status
))
2338 ObDereferenceObject(Section
);
2339 ObDereferenceObject(FileObject
);
2344 * FIXME: Revise this once a locking order for file size changes is
2347 if (UMaximumSize
!= NULL
)
2349 MaximumSize
= *UMaximumSize
;
2353 MaximumSize
= FileInfo
.EndOfFile
;
2354 /* Mapping zero-sized files isn't allowed. */
2355 if (MaximumSize
.QuadPart
== 0)
2357 ObDereferenceObject(Section
);
2358 ObDereferenceObject(FileObject
);
2359 return STATUS_FILE_INVALID
;
2363 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2365 Status
= IoSetInformation(FileObject
,
2366 FileAllocationInformation
,
2367 sizeof(LARGE_INTEGER
),
2369 if (!NT_SUCCESS(Status
))
2371 ObDereferenceObject(Section
);
2372 ObDereferenceObject(FileObject
);
2373 return(STATUS_SECTION_NOT_EXTENDED
);
2377 if (FileObject
->SectionObjectPointer
== NULL
||
2378 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2381 * Read a bit so caching is initiated for the file object.
2382 * This is only needed because MiReadPage currently cannot
2383 * handle non-cached streams.
2385 Offset
.QuadPart
= 0;
2386 Status
= ZwReadFile(FileHandle
,
2395 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2397 ObDereferenceObject(Section
);
2398 ObDereferenceObject(FileObject
);
2401 if (FileObject
->SectionObjectPointer
== NULL
||
2402 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2404 /* FIXME: handle this situation */
2405 ObDereferenceObject(Section
);
2406 ObDereferenceObject(FileObject
);
2407 return STATUS_INVALID_PARAMETER
;
2414 Status
= MmspWaitForFileLock(FileObject
);
2415 if (Status
!= STATUS_SUCCESS
)
2417 ObDereferenceObject(Section
);
2418 ObDereferenceObject(FileObject
);
2423 * If this file hasn't been mapped as a data file before then allocate a
2424 * section segment to describe the data file mapping
2426 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2428 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2429 TAG_MM_SECTION_SEGMENT
);
2430 if (Segment
== NULL
)
2432 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2433 ObDereferenceObject(Section
);
2434 ObDereferenceObject(FileObject
);
2435 return(STATUS_NO_MEMORY
);
2437 Section
->Segment
= Segment
;
2438 Segment
->ReferenceCount
= 1;
2439 ExInitializeFastMutex(&Segment
->Lock
);
2441 * Set the lock before assigning the segment to the file object
2443 ExAcquireFastMutex(&Segment
->Lock
);
2444 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2446 Segment
->FileOffset
= 0;
2447 Segment
->Protection
= SectionPageProtection
;
2448 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2449 Segment
->Characteristics
= 0;
2450 Segment
->WriteCopy
= FALSE
;
2451 if (AllocationAttributes
& SEC_RESERVE
)
2453 Segment
->Length
= Segment
->RawLength
= 0;
2457 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2458 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2460 Segment
->VirtualAddress
= 0;
2461 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2466 * If the file is already mapped as a data file then we may need
2470 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2472 Section
->Segment
= Segment
;
2473 InterlockedIncrementUL(&Segment
->ReferenceCount
);
2474 MmLockSectionSegment(Segment
);
2476 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2477 !(AllocationAttributes
& SEC_RESERVE
))
2479 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2480 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2483 MmUnlockSectionSegment(Segment
);
2484 Section
->FileObject
= FileObject
;
2485 Section
->MaximumSize
= MaximumSize
;
2486 CcRosReferenceCache(FileObject
);
2487 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2488 *SectionObject
= Section
;
2489 return(STATUS_SUCCESS
);
2493 TODO: not that great (declaring loaders statically, having to declare all of
2494 them, having to keep them extern, etc.), will fix in the future
2496 extern NTSTATUS NTAPI PeFmtCreateSection
2498 IN CONST VOID
* FileHeader
,
2499 IN SIZE_T FileHeaderSize
,
2501 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2503 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2504 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2507 extern NTSTATUS NTAPI ElfFmtCreateSection
2509 IN CONST VOID
* FileHeader
,
2510 IN SIZE_T FileHeaderSize
,
2512 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2514 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2515 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2518 /* TODO: this is a standard DDK/PSDK macro */
2519 #ifndef RTL_NUMBER_OF
2520 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2523 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2532 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2534 SIZE_T SizeOfSegments
;
2535 PMM_SECTION_SEGMENT Segments
;
2537 /* TODO: check for integer overflow */
2538 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2540 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2542 TAG_MM_SECTION_SEGMENT
);
2545 RtlZeroMemory(Segments
, SizeOfSegments
);
2553 ExeFmtpReadFile(IN PVOID File
,
2554 IN PLARGE_INTEGER Offset
,
2557 OUT PVOID
* AllocBase
,
2558 OUT PULONG ReadSize
)
2561 LARGE_INTEGER FileOffset
;
2563 ULONG OffsetAdjustment
;
2568 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2572 KEBUGCHECK(STATUS_INVALID_PARAMETER_4
);
2575 FileOffset
= *Offset
;
2577 /* Negative/special offset: it cannot be used in this context */
2578 if(FileOffset
.u
.HighPart
< 0)
2580 KEBUGCHECK(STATUS_INVALID_PARAMETER_5
);
2583 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2584 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2585 FileOffset
.u
.LowPart
= AdjustOffset
;
2587 BufferSize
= Length
+ OffsetAdjustment
;
2588 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2591 * It's ok to use paged pool, because this is a temporary buffer only used in
2592 * the loading of executables. The assumption is that MmCreateSection is
2593 * always called at low IRQLs and that these buffers don't survive a brief
2594 * initialization phase
2596 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2598 TAG('M', 'm', 'X', 'r'));
2603 Status
= MmspPageRead(File
,
2610 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2611 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2612 * to initialize internal state is even worse. Our cache manager is in need of
2616 IO_STATUS_BLOCK Iosb
;
2618 Status
= ZwReadFile(File
,
2628 if(NT_SUCCESS(Status
))
2630 UsedSize
= Iosb
.Information
;
2635 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2637 Status
= STATUS_IN_PAGE_ERROR
;
2638 ASSERT(!NT_SUCCESS(Status
));
2641 if(NT_SUCCESS(Status
))
2643 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2644 *AllocBase
= Buffer
;
2645 *ReadSize
= UsedSize
- OffsetAdjustment
;
2656 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2657 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2658 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2663 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2667 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2669 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2670 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2677 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2681 MmspAssertSegmentsSorted(ImageSectionObject
);
2683 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2685 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2689 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2690 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2691 ImageSectionObject
->Segments
[i
- 1].Length
));
2699 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2703 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2705 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2706 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2714 MmspCompareSegments(const void * x
,
2717 PMM_SECTION_SEGMENT Segment1
= (PMM_SECTION_SEGMENT
)x
;
2718 PMM_SECTION_SEGMENT Segment2
= (PMM_SECTION_SEGMENT
)y
;
2721 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2722 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2726 * Ensures an image section's segments are sorted in memory
2731 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2734 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2736 MmspAssertSegmentsSorted(ImageSectionObject
);
2740 qsort(ImageSectionObject
->Segments
,
2741 ImageSectionObject
->NrSegments
,
2742 sizeof(ImageSectionObject
->Segments
[0]),
2743 MmspCompareSegments
);
2749 * Ensures an image section's segments don't overlap in memory and don't have
2750 * gaps and don't have a null size. We let them map to overlapping file regions,
2751 * though - that's not necessarily an error
2756 MmspCheckSegmentBounds
2758 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2764 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2766 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2770 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2772 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2774 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2782 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2783 * page could be OK (Windows seems to be OK with them), and larger gaps
2784 * could lead to image sections spanning several discontiguous regions
2785 * (NtMapViewOfSection could then refuse to map them, and they could
2786 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2788 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2789 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2790 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2801 * Merges and pads an image section's segments until they all are page-aligned
2802 * and have a size that is a multiple of the page size
2807 MmspPageAlignSegments
2809 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2815 BOOLEAN Initialized
;
2817 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2819 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2823 Initialized
= FALSE
;
2826 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2828 PMM_SECTION_SEGMENT EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2831 * The first segment requires special handling
2835 ULONG_PTR VirtualAddress
;
2836 ULONG_PTR VirtualOffset
;
2838 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2840 /* Round down the virtual address to the nearest page */
2841 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2843 /* Round up the virtual size to the nearest page */
2844 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2845 EffectiveSegment
->VirtualAddress
;
2847 /* Adjust the raw address and size */
2848 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2850 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
2856 * Garbage in, garbage out: unaligned base addresses make the file
2857 * offset point in curious and odd places, but that's what we were
2860 EffectiveSegment
->FileOffset
-= VirtualOffset
;
2861 EffectiveSegment
->RawLength
+= VirtualOffset
;
2865 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
2866 ULONG_PTR EndOfEffectiveSegment
;
2868 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
2869 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
2872 * The current segment begins exactly where the current effective
2873 * segment ended, therefore beginning a new effective segment
2875 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
2878 ASSERT(LastSegment
<= i
);
2879 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
2881 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2884 * Copy the current segment. If necessary, the effective segment
2885 * will be expanded later
2887 *EffectiveSegment
= *Segment
;
2890 * Page-align the virtual size. We know for sure the virtual address
2893 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
2894 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
2897 * The current segment is still part of the current effective segment:
2898 * extend the effective segment to reflect this
2900 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
2902 static const ULONG FlagsToProtection
[16] =
2910 PAGE_EXECUTE_READWRITE
,
2911 PAGE_EXECUTE_READWRITE
,
2916 PAGE_EXECUTE_WRITECOPY
,
2917 PAGE_EXECUTE_WRITECOPY
,
2918 PAGE_EXECUTE_WRITECOPY
,
2919 PAGE_EXECUTE_WRITECOPY
2922 unsigned ProtectionFlags
;
2925 * Extend the file size
2928 /* Unaligned segments must be contiguous within the file */
2929 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
2930 EffectiveSegment
->RawLength
))
2935 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
2938 * Extend the virtual size
2940 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) > EndOfEffectiveSegment
);
2942 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
2943 EffectiveSegment
->VirtualAddress
;
2946 * Merge the protection
2948 EffectiveSegment
->Protection
|= Segment
->Protection
;
2950 /* Clean up redundance */
2951 ProtectionFlags
= 0;
2953 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
2954 ProtectionFlags
|= 1 << 0;
2956 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
2957 ProtectionFlags
|= 1 << 1;
2959 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
2960 ProtectionFlags
|= 1 << 2;
2962 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2963 ProtectionFlags
|= 1 << 3;
2965 ASSERT(ProtectionFlags
< 16);
2966 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
2968 /* If a segment was required to be shared and cannot, fail */
2969 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
2970 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2976 * We assume no holes between segments at this point
2989 ExeFmtpCreateImageSection(HANDLE FileHandle
,
2990 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2992 LARGE_INTEGER Offset
;
2994 PVOID FileHeaderBuffer
;
2995 ULONG FileHeaderSize
;
2997 ULONG OldNrSegments
;
3002 * Read the beginning of the file (2 pages). Should be enough to contain
3003 * all (or most) of the headers
3005 Offset
.QuadPart
= 0;
3007 /* FIXME: use FileObject instead of FileHandle */
3008 Status
= ExeFmtpReadFile (FileHandle
,
3015 if (!NT_SUCCESS(Status
))
3018 if (FileHeaderSize
== 0)
3020 ExFreePool(FileHeaderBuffer
);
3021 return STATUS_UNSUCCESSFUL
;
3025 * Look for a loader that can handle this executable
3027 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3029 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3032 /* FIXME: use FileObject instead of FileHandle */
3033 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3039 ExeFmtpAllocateSegments
);
3041 if (!NT_SUCCESS(Status
))
3043 if (ImageSectionObject
->Segments
)
3045 ExFreePool(ImageSectionObject
->Segments
);
3046 ImageSectionObject
->Segments
= NULL
;
3050 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3054 ExFreePool(FileHeaderBuffer
);
3057 * No loader handled the format
3059 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3061 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3062 ASSERT(!NT_SUCCESS(Status
));
3065 if (!NT_SUCCESS(Status
))
3068 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3073 /* FIXME? are these values platform-dependent? */
3074 if(ImageSectionObject
->StackReserve
== 0)
3075 ImageSectionObject
->StackReserve
= 0x40000;
3077 if(ImageSectionObject
->StackCommit
== 0)
3078 ImageSectionObject
->StackCommit
= 0x1000;
3080 if(ImageSectionObject
->ImageBase
== 0)
3082 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3083 ImageSectionObject
->ImageBase
= 0x10000000;
3085 ImageSectionObject
->ImageBase
= 0x00400000;
3089 * And now the fun part: fixing the segments
3092 /* Sort them by virtual address */
3093 MmspSortSegments(ImageSectionObject
, Flags
);
3095 /* Ensure they don't overlap in memory */
3096 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3097 return STATUS_INVALID_IMAGE_FORMAT
;
3099 /* Ensure they are aligned */
3100 OldNrSegments
= ImageSectionObject
->NrSegments
;
3102 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3103 return STATUS_INVALID_IMAGE_FORMAT
;
3105 /* Trim them if the alignment phase merged some of them */
3106 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3108 PMM_SECTION_SEGMENT Segments
;
3109 SIZE_T SizeOfSegments
;
3111 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3113 Segments
= ExAllocatePoolWithTag(PagedPool
,
3115 TAG_MM_SECTION_SEGMENT
);
3117 if (Segments
== NULL
)
3118 return STATUS_INSUFFICIENT_RESOURCES
;
3120 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3121 ExFreePool(ImageSectionObject
->Segments
);
3122 ImageSectionObject
->Segments
= Segments
;
3125 /* And finish their initialization */
3126 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3128 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3129 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3131 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3132 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3135 ASSERT(NT_SUCCESS(Status
));
3140 MmCreateImageSection(PSECTION_OBJECT
*SectionObject
,
3141 ACCESS_MASK DesiredAccess
,
3142 POBJECT_ATTRIBUTES ObjectAttributes
,
3143 PLARGE_INTEGER UMaximumSize
,
3144 ULONG SectionPageProtection
,
3145 ULONG AllocationAttributes
,
3148 PSECTION_OBJECT Section
;
3150 PFILE_OBJECT FileObject
;
3151 PMM_SECTION_SEGMENT SectionSegments
;
3152 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3154 ULONG FileAccess
= 0;
3157 * Specifying a maximum size is meaningless for an image section
3159 if (UMaximumSize
!= NULL
)
3161 return(STATUS_INVALID_PARAMETER_4
);
3165 * Check file access required
3167 if (SectionPageProtection
& PAGE_READWRITE
||
3168 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3170 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3174 FileAccess
= FILE_READ_DATA
;
3178 * Reference the file handle
3180 Status
= ObReferenceObjectByHandle(FileHandle
,
3184 (PVOID
*)(PVOID
)&FileObject
,
3187 if (!NT_SUCCESS(Status
))
3193 * Create the section
3195 Status
= ObCreateObject (ExGetPreviousMode(),
3196 MmSectionObjectType
,
3198 ExGetPreviousMode(),
3200 sizeof(SECTION_OBJECT
),
3203 (PVOID
*)(PVOID
)&Section
);
3204 if (!NT_SUCCESS(Status
))
3206 ObDereferenceObject(FileObject
);
3213 Section
->SectionPageProtection
= SectionPageProtection
;
3214 Section
->AllocationAttributes
= AllocationAttributes
;
3217 * Initialized caching for this file object if previously caching
3218 * was initialized for the same on disk file
3220 Status
= CcTryToInitializeFileCache(FileObject
);
3222 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3224 NTSTATUS StatusExeFmt
;
3226 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3227 if (ImageSectionObject
== NULL
)
3229 ObDereferenceObject(FileObject
);
3230 ObDereferenceObject(Section
);
3231 return(STATUS_NO_MEMORY
);
3234 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3236 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3238 if (!NT_SUCCESS(StatusExeFmt
))
3240 if(ImageSectionObject
->Segments
!= NULL
)
3241 ExFreePool(ImageSectionObject
->Segments
);
3243 ExFreePool(ImageSectionObject
);
3244 ObDereferenceObject(Section
);
3245 ObDereferenceObject(FileObject
);
3246 return(StatusExeFmt
);
3249 Section
->ImageSection
= ImageSectionObject
;
3250 ASSERT(ImageSectionObject
->Segments
);
3255 Status
= MmspWaitForFileLock(FileObject
);
3256 if (!NT_SUCCESS(Status
))
3258 ExFreePool(ImageSectionObject
->Segments
);
3259 ExFreePool(ImageSectionObject
);
3260 ObDereferenceObject(Section
);
3261 ObDereferenceObject(FileObject
);
3265 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3266 ImageSectionObject
, NULL
))
3269 * An other thread has initialized the some image in the background
3271 ExFreePool(ImageSectionObject
->Segments
);
3272 ExFreePool(ImageSectionObject
);
3273 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3274 Section
->ImageSection
= ImageSectionObject
;
3275 SectionSegments
= ImageSectionObject
->Segments
;
3277 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3279 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3283 Status
= StatusExeFmt
;
3290 Status
= MmspWaitForFileLock(FileObject
);
3291 if (Status
!= STATUS_SUCCESS
)
3293 ObDereferenceObject(Section
);
3294 ObDereferenceObject(FileObject
);
3298 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3299 Section
->ImageSection
= ImageSectionObject
;
3300 SectionSegments
= ImageSectionObject
->Segments
;
3303 * Otherwise just reference all the section segments
3305 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3307 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3310 Status
= STATUS_SUCCESS
;
3312 Section
->FileObject
= FileObject
;
3313 CcRosReferenceCache(FileObject
);
3314 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
3315 *SectionObject
= Section
;
3323 NtCreateSection (OUT PHANDLE SectionHandle
,
3324 IN ACCESS_MASK DesiredAccess
,
3325 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3326 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3327 IN ULONG SectionPageProtection OPTIONAL
,
3328 IN ULONG AllocationAttributes
,
3329 IN HANDLE FileHandle OPTIONAL
)
3331 LARGE_INTEGER SafeMaximumSize
;
3332 PSECTION_OBJECT SectionObject
;
3333 KPROCESSOR_MODE PreviousMode
;
3334 NTSTATUS Status
= STATUS_SUCCESS
;
3336 PreviousMode
= ExGetPreviousMode();
3338 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3342 /* make a copy on the stack */
3343 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3344 MaximumSize
= &SafeMaximumSize
;
3348 Status
= _SEH_GetExceptionCode();
3352 if(!NT_SUCCESS(Status
))
3359 * Check the protection
3361 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
3362 SectionPageProtection
)
3364 return(STATUS_INVALID_PAGE_PROTECTION
);
3367 Status
= MmCreateSection(&SectionObject
,
3371 SectionPageProtection
,
3372 AllocationAttributes
,
3376 if (NT_SUCCESS(Status
))
3378 Status
= ObInsertObject ((PVOID
)SectionObject
,
3384 ObDereferenceObject(SectionObject
);
3391 /**********************************************************************
3409 NtOpenSection(PHANDLE SectionHandle
,
3410 ACCESS_MASK DesiredAccess
,
3411 POBJECT_ATTRIBUTES ObjectAttributes
)
3414 KPROCESSOR_MODE PreviousMode
;
3415 NTSTATUS Status
= STATUS_SUCCESS
;
3417 PreviousMode
= ExGetPreviousMode();
3419 if(PreviousMode
!= KernelMode
)
3423 ProbeForWriteHandle(SectionHandle
);
3427 Status
= _SEH_GetExceptionCode();
3431 if(!NT_SUCCESS(Status
))
3437 Status
= ObOpenObjectByName(ObjectAttributes
,
3438 MmSectionObjectType
,
3445 if(NT_SUCCESS(Status
))
3449 *SectionHandle
= hSection
;
3453 Status
= _SEH_GetExceptionCode();
3462 MmMapViewOfSegment(PEPROCESS Process
,
3463 PMADDRESS_SPACE AddressSpace
,
3464 PSECTION_OBJECT Section
,
3465 PMM_SECTION_SEGMENT Segment
,
3474 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3476 BoundaryAddressMultiple
.QuadPart
= 0;
3478 Status
= MmCreateMemoryArea(Process
,
3480 MEMORY_AREA_SECTION_VIEW
,
3487 BoundaryAddressMultiple
);
3488 if (!NT_SUCCESS(Status
))
3490 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3491 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3496 ObReferenceObjectByPointer((PVOID
)Section
,
3499 ExGetPreviousMode());
3500 MArea
->Data
.SectionData
.Segment
= Segment
;
3501 MArea
->Data
.SectionData
.Section
= Section
;
3502 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3503 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3504 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3505 ViewSize
, 0, Protect
);
3507 return(STATUS_SUCCESS
);
3511 /**********************************************************************
3513 * NtMapViewOfSection
3516 * Maps a view of a section into the virtual address space of a
3521 * Handle of the section.
3524 * Handle of the process.
3527 * Desired base address (or NULL) on entry;
3528 * Actual base address of the view on exit.
3531 * Number of high order address bits that must be zero.
3534 * Size in bytes of the initially committed section of
3538 * Offset in bytes from the beginning of the section
3539 * to the beginning of the view.
3542 * Desired length of map (or zero to map all) on entry
3543 * Actual length mapped on exit.
3545 * InheritDisposition
3546 * Specified how the view is to be shared with
3550 * Type of allocation for the pages.
3553 * Protection for the committed region of the view.
3561 NtMapViewOfSection(IN HANDLE SectionHandle
,
3562 IN HANDLE ProcessHandle
,
3563 IN OUT PVOID
* BaseAddress OPTIONAL
,
3564 IN ULONG ZeroBits OPTIONAL
,
3565 IN ULONG CommitSize
,
3566 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3567 IN OUT PULONG ViewSize
,
3568 IN SECTION_INHERIT InheritDisposition
,
3569 IN ULONG AllocationType OPTIONAL
,
3572 PVOID SafeBaseAddress
;
3573 LARGE_INTEGER SafeSectionOffset
;
3575 PSECTION_OBJECT Section
;
3577 KPROCESSOR_MODE PreviousMode
;
3578 PMADDRESS_SPACE AddressSpace
;
3579 NTSTATUS Status
= STATUS_SUCCESS
;
3581 PreviousMode
= ExGetPreviousMode();
3583 if(PreviousMode
!= KernelMode
)
3585 SafeBaseAddress
= NULL
;
3586 SafeSectionOffset
.QuadPart
= 0;
3591 if(BaseAddress
!= NULL
)
3593 ProbeForWritePointer(BaseAddress
);
3594 SafeBaseAddress
= *BaseAddress
;
3596 if(SectionOffset
!= NULL
)
3598 ProbeForWriteLargeInteger(SectionOffset
);
3599 SafeSectionOffset
= *SectionOffset
;
3601 ProbeForWriteUlong(ViewSize
);
3602 SafeViewSize
= *ViewSize
;
3606 Status
= _SEH_GetExceptionCode();
3610 if(!NT_SUCCESS(Status
))
3617 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3618 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3619 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3622 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3623 PROCESS_VM_OPERATION
,
3626 (PVOID
*)(PVOID
)&Process
,
3628 if (!NT_SUCCESS(Status
))
3633 AddressSpace
= &Process
->AddressSpace
;
3635 Status
= ObReferenceObjectByHandle(SectionHandle
,
3637 MmSectionObjectType
,
3639 (PVOID
*)(PVOID
)&Section
,
3641 if (!(NT_SUCCESS(Status
)))
3643 DPRINT("ObReference failed rc=%x\n",Status
);
3644 ObDereferenceObject(Process
);
3648 Status
= MmMapViewOfSection(Section
,
3650 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3653 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3654 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3659 ObDereferenceObject(Section
);
3660 ObDereferenceObject(Process
);
3662 if(NT_SUCCESS(Status
))
3664 /* copy parameters back to the caller */
3667 if(BaseAddress
!= NULL
)
3669 *BaseAddress
= SafeBaseAddress
;
3671 if(SectionOffset
!= NULL
)
3673 *SectionOffset
= SafeSectionOffset
;
3675 if(ViewSize
!= NULL
)
3677 *ViewSize
= SafeViewSize
;
3682 Status
= _SEH_GetExceptionCode();
3691 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3692 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3695 PFILE_OBJECT FileObject
;
3698 SWAPENTRY SavedSwapEntry
;
3701 PSECTION_OBJECT Section
;
3702 PMM_SECTION_SEGMENT Segment
;
3703 PMADDRESS_SPACE AddressSpace
;
3705 AddressSpace
= (PMADDRESS_SPACE
)Context
;
3707 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3709 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3710 MemoryArea
->Data
.SectionData
.ViewOffset
;
3712 Section
= MemoryArea
->Data
.SectionData
.Section
;
3713 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3715 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3719 MmUnlockSectionSegment(Segment
);
3720 MmUnlockAddressSpace(AddressSpace
);
3722 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3723 if (Status
!= STATUS_SUCCESS
)
3725 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3729 MmLockAddressSpace(AddressSpace
);
3730 MmLockSectionSegment(Segment
);
3731 MmspCompleteAndReleasePageOp(PageOp
);
3732 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3735 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3738 * For a dirty, datafile, non-private page mark it as dirty in the
3741 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3743 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3745 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3746 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3747 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3748 ASSERT(SwapEntry
== 0);
3757 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3759 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3762 MmFreeSwapPage(SwapEntry
);
3766 if (IS_SWAP_FROM_SSE(Entry
) ||
3767 Page
!= PFN_FROM_SSE(Entry
))
3772 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3774 DPRINT1("Found a private page in a pagefile section.\n");
3778 * Just dereference private pages
3780 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3781 if (SavedSwapEntry
!= 0)
3783 MmFreeSwapPage(SavedSwapEntry
);
3784 MmSetSavedSwapEntryPage(Page
, 0);
3786 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3787 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3791 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3792 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3798 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3802 PMEMORY_AREA MemoryArea
;
3803 PSECTION_OBJECT Section
;
3804 PMM_SECTION_SEGMENT Segment
;
3805 PLIST_ENTRY CurrentEntry
;
3806 PMM_REGION CurrentRegion
;
3807 PLIST_ENTRY RegionListHead
;
3809 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3811 if (MemoryArea
== NULL
)
3813 return(STATUS_UNSUCCESSFUL
);
3816 MemoryArea
->DeleteInProgress
= TRUE
;
3817 Section
= MemoryArea
->Data
.SectionData
.Section
;
3818 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3820 MmLockSectionSegment(Segment
);
3822 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3823 while (!IsListEmpty(RegionListHead
))
3825 CurrentEntry
= RemoveHeadList(RegionListHead
);
3826 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3827 ExFreePool(CurrentRegion
);
3830 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3832 Status
= MmFreeMemoryArea(AddressSpace
,
3839 Status
= MmFreeMemoryArea(AddressSpace
,
3844 MmUnlockSectionSegment(Segment
);
3845 ObDereferenceObject(Section
);
3846 return(STATUS_SUCCESS
);
3853 MmUnmapViewOfSection(PEPROCESS Process
,
3857 PMEMORY_AREA MemoryArea
;
3858 PMADDRESS_SPACE AddressSpace
;
3859 PSECTION_OBJECT Section
;
3861 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3862 Process
, BaseAddress
);
3866 AddressSpace
= &Process
->AddressSpace
;
3867 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3869 if (MemoryArea
== NULL
||
3870 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
3871 MemoryArea
->DeleteInProgress
)
3873 return STATUS_NOT_MAPPED_VIEW
;
3876 Section
= MemoryArea
->Data
.SectionData
.Section
;
3878 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3882 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3883 PMM_SECTION_SEGMENT SectionSegments
;
3884 PVOID ImageBaseAddress
= 0;
3885 PMM_SECTION_SEGMENT Segment
;
3887 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3888 ImageSectionObject
= Section
->ImageSection
;
3889 SectionSegments
= ImageSectionObject
->Segments
;
3890 NrSegments
= ImageSectionObject
->NrSegments
;
3892 /* Search for the current segment within the section segments
3893 * and calculate the image base address */
3894 for (i
= 0; i
< NrSegments
; i
++)
3896 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3898 if (Segment
== &SectionSegments
[i
])
3900 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3905 if (i
>= NrSegments
)
3910 for (i
= 0; i
< NrSegments
; i
++)
3912 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3914 PVOID SBaseAddress
= (PVOID
)
3915 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3917 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
3923 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
3925 return(STATUS_SUCCESS
);
3928 /**********************************************************************
3930 * NtUnmapViewOfSection
3945 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3949 KPROCESSOR_MODE PreviousMode
;
3952 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3953 ProcessHandle
, BaseAddress
);
3955 PreviousMode
= ExGetPreviousMode();
3957 DPRINT("Referencing process\n");
3958 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3959 PROCESS_VM_OPERATION
,
3962 (PVOID
*)(PVOID
)&Process
,
3964 if (!NT_SUCCESS(Status
))
3966 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3970 MmLockAddressSpace(&Process
->AddressSpace
);
3971 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3972 MmUnlockAddressSpace(&Process
->AddressSpace
);
3974 ObDereferenceObject(Process
);
3981 * Queries the information of a section object.
3983 * @param SectionHandle
3984 * Handle to the section object. It must be opened with SECTION_QUERY
3986 * @param SectionInformationClass
3987 * Index to a certain information structure. Can be either
3988 * SectionBasicInformation or SectionImageInformation. The latter
3989 * is valid only for sections that were created with the SEC_IMAGE
3991 * @param SectionInformation
3992 * Caller supplies storage for resulting information.
3994 * Size of the supplied storage.
3995 * @param ResultLength
4003 NtQuerySection(IN HANDLE SectionHandle
,
4004 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4005 OUT PVOID SectionInformation
,
4006 IN ULONG SectionInformationLength
,
4007 OUT PULONG ResultLength OPTIONAL
)
4009 PSECTION_OBJECT Section
;
4010 KPROCESSOR_MODE PreviousMode
;
4011 NTSTATUS Status
= STATUS_SUCCESS
;
4013 PreviousMode
= ExGetPreviousMode();
4015 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4017 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4019 SectionInformationLength
,
4023 if(!NT_SUCCESS(Status
))
4025 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4029 Status
= ObReferenceObjectByHandle(SectionHandle
,
4031 MmSectionObjectType
,
4033 (PVOID
*)(PVOID
)&Section
,
4035 if (NT_SUCCESS(Status
))
4037 switch (SectionInformationClass
)
4039 case SectionBasicInformation
:
4041 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4045 Sbi
->Attributes
= Section
->AllocationAttributes
;
4046 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4048 Sbi
->BaseAddress
= 0;
4049 Sbi
->Size
.QuadPart
= 0;
4053 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4054 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4057 if (ResultLength
!= NULL
)
4059 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4061 Status
= STATUS_SUCCESS
;
4065 Status
= _SEH_GetExceptionCode();
4072 case SectionImageInformation
:
4074 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4078 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4079 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4081 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4082 ImageSectionObject
= Section
->ImageSection
;
4084 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4085 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4086 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4087 Sii
->SubsystemType
= ImageSectionObject
->Subsystem
;
4088 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4089 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4090 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4091 Sii
->Machine
= ImageSectionObject
->Machine
;
4092 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4095 if (ResultLength
!= NULL
)
4097 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4099 Status
= STATUS_SUCCESS
;
4103 Status
= _SEH_GetExceptionCode();
4111 ObDereferenceObject(Section
);
4119 * Extends size of file backed section.
4121 * @param SectionHandle
4122 * Handle to the section object. It must be opened with
4123 * SECTION_EXTEND_SIZE access.
4124 * @param NewMaximumSize
4125 * New maximum size of the section in bytes.
4129 * @todo Move the actual code to internal function MmExtendSection.
4133 NtExtendSection(IN HANDLE SectionHandle
,
4134 IN PLARGE_INTEGER NewMaximumSize
)
4136 LARGE_INTEGER SafeNewMaximumSize
;
4137 PSECTION_OBJECT Section
;
4138 KPROCESSOR_MODE PreviousMode
;
4139 NTSTATUS Status
= STATUS_SUCCESS
;
4141 PreviousMode
= ExGetPreviousMode();
4143 if(PreviousMode
!= KernelMode
)
4147 /* make a copy on the stack */
4148 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4149 NewMaximumSize
= &SafeNewMaximumSize
;
4153 Status
= _SEH_GetExceptionCode();
4157 if(!NT_SUCCESS(Status
))
4163 Status
= ObReferenceObjectByHandle(SectionHandle
,
4164 SECTION_EXTEND_SIZE
,
4165 MmSectionObjectType
,
4169 if (!NT_SUCCESS(Status
))
4174 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4176 ObfDereferenceObject(Section
);
4177 return STATUS_INVALID_PARAMETER
;
4181 * - Acquire file extneding resource.
4182 * - Check if we're not resizing the section below it's actual size!
4183 * - Extend segments if needed.
4184 * - Set file information (FileAllocationInformation) to the new size.
4185 * - Release file extending resource.
4188 ObDereferenceObject(Section
);
4190 return STATUS_NOT_IMPLEMENTED
;
4194 /**********************************************************************
4196 * MmAllocateSection@4
4206 * Code taken from ntoskrnl/mm/special.c.
4211 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4217 PMADDRESS_SPACE AddressSpace
;
4218 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4220 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4222 BoundaryAddressMultiple
.QuadPart
= 0;
4224 AddressSpace
= MmGetKernelAddressSpace();
4225 Result
= BaseAddress
;
4226 MmLockAddressSpace(AddressSpace
);
4227 Status
= MmCreateMemoryArea (NULL
,
4236 BoundaryAddressMultiple
);
4237 MmUnlockAddressSpace(AddressSpace
);
4239 if (!NT_SUCCESS(Status
))
4243 DPRINT("Result %p\n",Result
);
4244 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
4248 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
4249 if (!NT_SUCCESS(Status
))
4251 DbgPrint("Unable to allocate page\n");
4254 Status
= MmCreateVirtualMapping (NULL
,
4255 (PVOID
)((ULONG_PTR
)Result
+ (i
* PAGE_SIZE
)),
4259 if (!NT_SUCCESS(Status
))
4261 DbgPrint("Unable to create virtual mapping\n");
4265 return ((PVOID
)Result
);
4269 /**********************************************************************
4271 * MmMapViewOfSection
4274 * Maps a view of a section into the virtual address space of a
4279 * Pointer to the section object.
4282 * Pointer to the process.
4285 * Desired base address (or NULL) on entry;
4286 * Actual base address of the view on exit.
4289 * Number of high order address bits that must be zero.
4292 * Size in bytes of the initially committed section of
4296 * Offset in bytes from the beginning of the section
4297 * to the beginning of the view.
4300 * Desired length of map (or zero to map all) on entry
4301 * Actual length mapped on exit.
4303 * InheritDisposition
4304 * Specified how the view is to be shared with
4308 * Type of allocation for the pages.
4311 * Protection for the committed region of the view.
4319 MmMapViewOfSection(IN PVOID SectionObject
,
4320 IN PEPROCESS Process
,
4321 IN OUT PVOID
*BaseAddress
,
4323 IN ULONG CommitSize
,
4324 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4325 IN OUT PULONG ViewSize
,
4326 IN SECTION_INHERIT InheritDisposition
,
4327 IN ULONG AllocationType
,
4330 PSECTION_OBJECT Section
;
4331 PMADDRESS_SPACE AddressSpace
;
4333 NTSTATUS Status
= STATUS_SUCCESS
;
4337 Section
= (PSECTION_OBJECT
)SectionObject
;
4338 AddressSpace
= &Process
->AddressSpace
;
4340 MmLockAddressSpace(AddressSpace
);
4342 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4346 ULONG_PTR ImageBase
;
4348 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4349 PMM_SECTION_SEGMENT SectionSegments
;
4351 ImageSectionObject
= Section
->ImageSection
;
4352 SectionSegments
= ImageSectionObject
->Segments
;
4353 NrSegments
= ImageSectionObject
->NrSegments
;
4356 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4359 ImageBase
= ImageSectionObject
->ImageBase
;
4363 for (i
= 0; i
< NrSegments
; i
++)
4365 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4367 ULONG_PTR MaxExtent
;
4368 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4369 SectionSegments
[i
].Length
;
4370 ImageSize
= max(ImageSize
, MaxExtent
);
4374 /* Check there is enough space to map the section at that point. */
4375 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4376 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4378 /* Fail if the user requested a fixed base address. */
4379 if ((*BaseAddress
) != NULL
)
4381 MmUnlockAddressSpace(AddressSpace
);
4382 return(STATUS_UNSUCCESSFUL
);
4384 /* Otherwise find a gap to map the image. */
4385 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4388 MmUnlockAddressSpace(AddressSpace
);
4389 return(STATUS_UNSUCCESSFUL
);
4393 for (i
= 0; i
< NrSegments
; i
++)
4395 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4397 PVOID SBaseAddress
= (PVOID
)
4398 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4399 MmLockSectionSegment(&SectionSegments
[i
]);
4400 Status
= MmMapViewOfSegment(Process
,
4403 &SectionSegments
[i
],
4405 SectionSegments
[i
].Length
,
4406 SectionSegments
[i
].Protection
,
4409 MmUnlockSectionSegment(&SectionSegments
[i
]);
4410 if (!NT_SUCCESS(Status
))
4412 MmUnlockAddressSpace(AddressSpace
);
4418 *BaseAddress
= (PVOID
)ImageBase
;
4422 if (ViewSize
== NULL
)
4424 /* Following this pointer would lead to us to the dark side */
4425 /* What to do? Bugcheck? Return status? Do the mambo? */
4426 KEBUGCHECK(MEMORY_MANAGEMENT
);
4429 if (SectionOffset
== NULL
)
4435 ViewOffset
= SectionOffset
->u
.LowPart
;
4438 if ((ViewOffset
% PAGE_SIZE
) != 0)
4440 MmUnlockAddressSpace(AddressSpace
);
4441 return(STATUS_MAPPED_ALIGNMENT
);
4444 if ((*ViewSize
) == 0)
4446 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4448 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4450 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4453 MmLockSectionSegment(Section
->Segment
);
4454 Status
= MmMapViewOfSegment(Process
,
4462 (AllocationType
& MEM_TOP_DOWN
));
4463 MmUnlockSectionSegment(Section
->Segment
);
4464 if (!NT_SUCCESS(Status
))
4466 MmUnlockAddressSpace(AddressSpace
);
4471 MmUnlockAddressSpace(AddressSpace
);
4473 return(STATUS_SUCCESS
);
4480 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4481 IN PLARGE_INTEGER NewFileSize
)
4492 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
4502 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4503 IN MMFLUSH_TYPE FlushType
)
4507 case MmFlushForDelete
:
4508 if (SectionObjectPointer
->ImageSectionObject
||
4509 SectionObjectPointer
->DataSectionObject
)
4513 CcRosSetRemoveOnClose(SectionObjectPointer
);
4515 case MmFlushForWrite
:
4525 MmForceSectionClosed (
4526 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4527 IN BOOLEAN DelayClose
)
4538 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4539 OUT PVOID
* MappedBase
,
4540 IN OUT PULONG ViewSize
)
4542 PSECTION_OBJECT Section
;
4543 PMADDRESS_SPACE AddressSpace
;
4546 DPRINT("MmMapViewInSystemSpace() called\n");
4548 Section
= (PSECTION_OBJECT
)SectionObject
;
4549 AddressSpace
= MmGetKernelAddressSpace();
4551 MmLockAddressSpace(AddressSpace
);
4554 if ((*ViewSize
) == 0)
4556 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4558 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4560 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4563 MmLockSectionSegment(Section
->Segment
);
4566 Status
= MmMapViewOfSegment(NULL
,
4576 MmUnlockSectionSegment(Section
->Segment
);
4577 MmUnlockAddressSpace(AddressSpace
);
4587 MmMapViewInSessionSpace (
4589 OUT PVOID
*MappedBase
,
4590 IN OUT PSIZE_T ViewSize
4594 return STATUS_NOT_IMPLEMENTED
;
4602 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4604 PMADDRESS_SPACE AddressSpace
;
4607 DPRINT("MmUnmapViewInSystemSpace() called\n");
4609 AddressSpace
= MmGetKernelAddressSpace();
4611 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4621 MmUnmapViewInSessionSpace (
4626 return STATUS_NOT_IMPLEMENTED
;
4633 MmSetBankedSection (DWORD Unknown0
,
4641 return (STATUS_NOT_IMPLEMENTED
);
4645 /**********************************************************************
4650 * Creates a section object.
4653 * SectionObject (OUT)
4654 * Caller supplied storage for the resulting pointer
4655 * to a SECTION_OBJECT instance;
4658 * Specifies the desired access to the section can be a
4660 * STANDARD_RIGHTS_REQUIRED |
4662 * SECTION_MAP_WRITE |
4663 * SECTION_MAP_READ |
4664 * SECTION_MAP_EXECUTE
4666 * ObjectAttributes [OPTIONAL]
4667 * Initialized attributes for the object can be used
4668 * to create a named section;
4671 * Maximizes the size of the memory section. Must be
4672 * non-NULL for a page-file backed section.
4673 * If value specified for a mapped file and the file is
4674 * not large enough, file will be extended.
4676 * SectionPageProtection
4677 * Can be a combination of:
4683 * AllocationAttributes
4684 * Can be a combination of:
4689 * Handle to a file to create a section mapped to a file
4690 * instead of a memory backed section;
4701 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4702 IN ACCESS_MASK DesiredAccess
,
4703 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4704 IN PLARGE_INTEGER MaximumSize
,
4705 IN ULONG SectionPageProtection
,
4706 IN ULONG AllocationAttributes
,
4707 IN HANDLE FileHandle OPTIONAL
,
4708 IN PFILE_OBJECT File OPTIONAL
)
4710 if (AllocationAttributes
& SEC_IMAGE
)
4712 return(MmCreateImageSection(SectionObject
,
4716 SectionPageProtection
,
4717 AllocationAttributes
,
4721 if (FileHandle
!= NULL
)
4723 return(MmCreateDataFileSection(SectionObject
,
4727 SectionPageProtection
,
4728 AllocationAttributes
,
4732 return(MmCreatePageFileSection(SectionObject
,
4736 SectionPageProtection
,
4737 AllocationAttributes
));