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
]);
160 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
162 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
164 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
165 PMM_SECTION_SEGMENT SectionSegments
;
169 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
170 NrSegments
= ImageSectionObject
->NrSegments
;
171 SectionSegments
= ImageSectionObject
->Segments
;
172 for (i
= 0; i
< NrSegments
; i
++)
174 if (SectionSegments
[i
].ReferenceCount
!= 0)
176 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
177 SectionSegments
[i
].ReferenceCount
);
180 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
182 ExFreePool(ImageSectionObject
->Segments
);
183 ExFreePool(ImageSectionObject
);
184 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
186 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
188 PMM_SECTION_SEGMENT Segment
;
190 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
193 if (Segment
->ReferenceCount
!= 0)
195 DPRINT1("Data segment still referenced\n");
198 MmFreePageTablesSectionSegment(Segment
);
200 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
205 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
207 ExAcquireFastMutex(&Segment
->Lock
);
211 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
213 ExReleaseFastMutex(&Segment
->Lock
);
217 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
221 PSECTION_PAGE_TABLE Table
;
222 ULONG DirectoryOffset
;
225 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
227 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
231 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
232 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
236 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
237 ExAllocatePoolWithTag(PagedPool
, sizeof(SECTION_PAGE_TABLE
),
238 TAG_SECTION_PAGE_TABLE
);
243 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
244 DPRINT("Table %x\n", Table
);
247 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
248 Table
->Entry
[TableOffset
] = Entry
;
253 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
256 PSECTION_PAGE_TABLE Table
;
258 ULONG DirectoryOffset
;
261 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
263 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
265 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
269 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
270 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
271 DPRINT("Table %x\n", Table
);
277 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
278 Entry
= Table
->Entry
[TableOffset
];
283 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
288 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
291 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
294 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
296 DPRINT1("Maximum share count reached\n");
299 if (IS_SWAP_FROM_SSE(Entry
))
303 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
304 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
308 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section
,
309 PMM_SECTION_SEGMENT Segment
,
315 BOOLEAN IsDirectMapped
= FALSE
;
317 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
320 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
323 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
325 DPRINT1("Zero share count for unshare\n");
328 if (IS_SWAP_FROM_SSE(Entry
))
332 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
334 * If we reducing the share count of this entry to zero then set the entry
335 * to zero and tell the cache the page is no longer mapped.
337 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
339 PFILE_OBJECT FileObject
;
341 SWAPENTRY SavedSwapEntry
;
343 BOOLEAN IsImageSection
;
346 FileOffset
= Offset
+ Segment
->FileOffset
;
348 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
350 Page
= PFN_FROM_SSE(Entry
);
351 FileObject
= Section
->FileObject
;
352 if (FileObject
!= NULL
&&
353 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
356 if ((FileOffset
% PAGE_SIZE
) == 0 &&
357 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
360 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
361 IsDirectMapped
= TRUE
;
362 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
363 if (!NT_SUCCESS(Status
))
365 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
371 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
372 if (SavedSwapEntry
== 0)
375 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
376 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
380 * Try to page out this page and set the swap entry
381 * within the section segment. There exist no rmap entry
382 * for this page. The pager thread can't page out a
383 * page without a rmap entry.
385 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
389 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
392 MmReleasePageMemoryConsumer(MC_USER
, Page
);
398 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
399 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
407 * We hold all locks. Nobody can do something with the current
408 * process and the current segment (also not within an other process).
411 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
412 if (!NT_SUCCESS(Status
))
414 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
418 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
419 MmSetSavedSwapEntryPage(Page
, 0);
421 MmReleasePageMemoryConsumer(MC_USER
, Page
);
425 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
432 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
434 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
437 BOOL
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
440 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
443 PCACHE_SEGMENT CacheSeg
;
444 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
445 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
448 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
456 MiReadPage(PMEMORY_AREA MemoryArea
,
460 * FUNCTION: Read a page for a section backed memory area.
462 * MemoryArea - Memory area to read the page for.
463 * Offset - Offset of the page to read.
464 * Page - Variable that receives a page contains the read data.
471 PCACHE_SEGMENT CacheSeg
;
472 PFILE_OBJECT FileObject
;
476 BOOLEAN IsImageSection
;
479 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
480 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
481 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
482 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
483 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
487 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
490 * If the file system is letting us go directly to the cache and the
491 * memory area was mapped at an offset in the file which is page aligned
492 * then get the related cache segment.
494 if ((FileOffset
% PAGE_SIZE
) == 0 &&
495 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
496 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
500 * Get the related cache segment; we use a lower level interface than
501 * filesystems do because it is safe for us to use an offset with a
502 * alignment less than the file system block size.
504 Status
= CcRosGetCacheSegment(Bcb
,
510 if (!NT_SUCCESS(Status
))
517 * If the cache segment isn't up to date then call the file
518 * system to read in the data.
520 Status
= ReadCacheSegment(CacheSeg
);
521 if (!NT_SUCCESS(Status
))
523 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
528 * Retrieve the page from the cache segment that we actually want.
530 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
531 FileOffset
- BaseOffset
).QuadPart
>> PAGE_SHIFT
;
533 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
538 ULONG CacheSegOffset
;
540 * Allocate a page, this is rather complicated by the possibility
541 * we might have to move other things out of memory
543 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
544 if (!NT_SUCCESS(Status
))
548 Status
= CcRosGetCacheSegment(Bcb
,
554 if (!NT_SUCCESS(Status
))
561 * If the cache segment isn't up to date then call the file
562 * system to read in the data.
564 Status
= ReadCacheSegment(CacheSeg
);
565 if (!NT_SUCCESS(Status
))
567 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
571 PageAddr
= MmCreateHyperspaceMapping(*Page
);
572 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
573 Length
= RawLength
- SegOffset
;
574 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
576 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
578 else if (CacheSegOffset
>= PAGE_SIZE
)
580 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
584 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
585 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
586 Status
= CcRosGetCacheSegment(Bcb
,
587 FileOffset
+ CacheSegOffset
,
592 if (!NT_SUCCESS(Status
))
594 MmDeleteHyperspaceMapping(PageAddr
);
600 * If the cache segment isn't up to date then call the file
601 * system to read in the data.
603 Status
= ReadCacheSegment(CacheSeg
);
604 if (!NT_SUCCESS(Status
))
606 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
607 MmDeleteHyperspaceMapping(PageAddr
);
611 if (Length
< PAGE_SIZE
)
613 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
617 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
620 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
621 MmDeleteHyperspaceMapping(PageAddr
);
623 return(STATUS_SUCCESS
);
627 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
628 MEMORY_AREA
* MemoryArea
,
636 PSECTION_OBJECT Section
;
637 PMM_SECTION_SEGMENT Segment
;
646 * There is a window between taking the page fault and locking the
647 * address space when another thread could load the page so we check
650 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
654 MmLockPage(MmGetPfnForProcess(AddressSpace
->Process
, Address
));
656 return(STATUS_SUCCESS
);
659 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
660 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
661 + MemoryArea
->Data
.SectionData
.ViewOffset
;
663 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
664 Section
= MemoryArea
->Data
.SectionData
.Section
;
665 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
666 &MemoryArea
->Data
.SectionData
.RegionListHead
,
671 MmLockSectionSegment(Segment
);
674 * Check if this page needs to be mapped COW
676 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
677 (Region
->Protect
== PAGE_READWRITE
||
678 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
680 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
684 Attributes
= Region
->Protect
;
688 * Get or create a page operation descriptor
690 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
693 DPRINT1("MmGetPageOp failed\n");
698 * Check if someone else is already handling this fault, if so wait
701 if (PageOp
->Thread
!= PsGetCurrentThread())
703 MmUnlockSectionSegment(Segment
);
704 MmUnlockAddressSpace(AddressSpace
);
705 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
707 * Check for various strange conditions
709 if (Status
!= STATUS_SUCCESS
)
711 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
714 if (PageOp
->Status
== STATUS_PENDING
)
716 DPRINT1("Woke for page op before completion\n");
719 MmLockAddressSpace(AddressSpace
);
721 * If this wasn't a pagein then restart the operation
723 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
725 MmspCompleteAndReleasePageOp(PageOp
);
726 DPRINT("Address 0x%.8X\n", Address
);
727 return(STATUS_MM_RESTART_OPERATION
);
731 * If the thread handling this fault has failed then we don't retry
733 if (!NT_SUCCESS(PageOp
->Status
))
735 Status
= PageOp
->Status
;
736 MmspCompleteAndReleasePageOp(PageOp
);
737 DPRINT("Address 0x%.8X\n", Address
);
740 MmLockSectionSegment(Segment
);
742 * If the completed fault was for another address space then set the
745 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
747 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
748 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
750 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
753 * The page was a private page in another or in our address space
755 MmUnlockSectionSegment(Segment
);
756 MmspCompleteAndReleasePageOp(PageOp
);
757 return(STATUS_MM_RESTART_OPERATION
);
760 Page
= PFN_FROM_SSE(Entry
);
762 MmSharePageEntrySectionSegment(Segment
, Offset
);
764 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
765 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
767 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
772 if (!NT_SUCCESS(Status
))
774 DbgPrint("Unable to create virtual mapping\n");
777 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
783 MmUnlockSectionSegment(Segment
);
784 PageOp
->Status
= STATUS_SUCCESS
;
785 MmspCompleteAndReleasePageOp(PageOp
);
786 DPRINT("Address 0x%.8X\n", Address
);
787 return(STATUS_SUCCESS
);
790 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
794 * Must be private page we have swapped out.
801 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
803 DPRINT1("Found a swaped out private page in a pagefile section.\n");
807 MmUnlockSectionSegment(Segment
);
808 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
810 MmUnlockAddressSpace(AddressSpace
);
811 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
812 if (!NT_SUCCESS(Status
))
817 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
818 if (!NT_SUCCESS(Status
))
820 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
823 MmLockAddressSpace(AddressSpace
);
824 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
829 if (!NT_SUCCESS(Status
))
831 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
837 * Store the swap entry for later use.
839 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
842 * Add the page to the process's working set
844 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
847 * Finish the operation
853 PageOp
->Status
= STATUS_SUCCESS
;
854 MmspCompleteAndReleasePageOp(PageOp
);
855 DPRINT("Address 0x%.8X\n", Address
);
856 return(STATUS_SUCCESS
);
860 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
862 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
864 MmUnlockSectionSegment(Segment
);
866 * Just map the desired physical page
868 Page
= Offset
>> PAGE_SHIFT
;
869 Status
= MmCreateVirtualMappingUnsafe(AddressSpace
->Process
,
874 if (!NT_SUCCESS(Status
))
876 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
881 * Don't add an rmap entry since the page mapped could be for
886 MmLockPageUnsafe(Page
);
890 * Cleanup and release locks
892 PageOp
->Status
= STATUS_SUCCESS
;
893 MmspCompleteAndReleasePageOp(PageOp
);
894 DPRINT("Address 0x%.8X\n", Address
);
895 return(STATUS_SUCCESS
);
899 * Map anonymous memory for BSS sections
901 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
903 MmUnlockSectionSegment(Segment
);
904 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
905 if (!NT_SUCCESS(Status
))
907 MmUnlockAddressSpace(AddressSpace
);
908 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
909 MmLockAddressSpace(AddressSpace
);
911 if (!NT_SUCCESS(Status
))
915 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
920 if (!NT_SUCCESS(Status
))
922 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
926 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
933 * Cleanup and release locks
935 PageOp
->Status
= STATUS_SUCCESS
;
936 MmspCompleteAndReleasePageOp(PageOp
);
937 DPRINT("Address 0x%.8X\n", Address
);
938 return(STATUS_SUCCESS
);
942 * Get the entry corresponding to the offset within the section
944 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
949 * If the entry is zero (and it can't change because we have
950 * locked the segment) then we need to load the page.
954 * Release all our locks and read in the page from disk
956 MmUnlockSectionSegment(Segment
);
957 MmUnlockAddressSpace(AddressSpace
);
959 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
960 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
962 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
963 if (!NT_SUCCESS(Status
))
965 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
970 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
971 if (!NT_SUCCESS(Status
))
973 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
976 if (!NT_SUCCESS(Status
))
979 * FIXME: What do we know in this case?
982 * Cleanup and release locks
984 MmLockAddressSpace(AddressSpace
);
985 PageOp
->Status
= Status
;
986 MmspCompleteAndReleasePageOp(PageOp
);
987 DPRINT("Address 0x%.8X\n", Address
);
991 * Relock the address space and segment
993 MmLockAddressSpace(AddressSpace
);
994 MmLockSectionSegment(Segment
);
997 * Check the entry. No one should change the status of a page
998 * that has a pending page-in.
1000 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1001 if (Entry
!= Entry1
)
1003 DbgPrint("Someone changed ppte entry while we slept\n");
1008 * Mark the offset within the section as having valid, in-memory
1011 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1012 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1013 MmUnlockSectionSegment(Segment
);
1015 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1020 if (!NT_SUCCESS(Status
))
1022 DbgPrint("Unable to create virtual mapping\n");
1025 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1031 PageOp
->Status
= STATUS_SUCCESS
;
1032 MmspCompleteAndReleasePageOp(PageOp
);
1033 DPRINT("Address 0x%.8X\n", Address
);
1034 return(STATUS_SUCCESS
);
1036 else if (IS_SWAP_FROM_SSE(Entry
))
1038 SWAPENTRY SwapEntry
;
1040 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1043 * Release all our locks and read in the page from disk
1045 MmUnlockSectionSegment(Segment
);
1047 MmUnlockAddressSpace(AddressSpace
);
1049 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1050 if (!NT_SUCCESS(Status
))
1055 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1056 if (!NT_SUCCESS(Status
))
1062 * Relock the address space and segment
1064 MmLockAddressSpace(AddressSpace
);
1065 MmLockSectionSegment(Segment
);
1068 * Check the entry. No one should change the status of a page
1069 * that has a pending page-in.
1071 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1072 if (Entry
!= Entry1
)
1074 DbgPrint("Someone changed ppte entry while we slept\n");
1079 * Mark the offset within the section as having valid, in-memory
1082 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1083 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1084 MmUnlockSectionSegment(Segment
);
1087 * Save the swap entry.
1089 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1090 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1095 if (!NT_SUCCESS(Status
))
1097 DbgPrint("Unable to create virtual mapping\n");
1100 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1105 PageOp
->Status
= STATUS_SUCCESS
;
1106 MmspCompleteAndReleasePageOp(PageOp
);
1107 DPRINT("Address 0x%.8X\n", Address
);
1108 return(STATUS_SUCCESS
);
1113 * If the section offset is already in-memory and valid then just
1114 * take another reference to the page
1117 Page
= PFN_FROM_SSE(Entry
);
1119 MmSharePageEntrySectionSegment(Segment
, Offset
);
1120 MmUnlockSectionSegment(Segment
);
1122 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1127 if (!NT_SUCCESS(Status
))
1129 DbgPrint("Unable to create virtual mapping\n");
1132 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1137 PageOp
->Status
= STATUS_SUCCESS
;
1138 MmspCompleteAndReleasePageOp(PageOp
);
1139 DPRINT("Address 0x%.8X\n", Address
);
1140 return(STATUS_SUCCESS
);
1145 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1146 MEMORY_AREA
* MemoryArea
,
1150 PMM_SECTION_SEGMENT Segment
;
1151 PSECTION_OBJECT Section
;
1162 * Check if the page has been paged out or has already been set readwrite
1164 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1165 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1167 DPRINT("Address 0x%.8X\n", Address
);
1168 return(STATUS_SUCCESS
);
1172 * Find the offset of the page
1174 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1175 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1176 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1178 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1179 Section
= MemoryArea
->Data
.SectionData
.Section
;
1180 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1181 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1186 MmLockSectionSegment(Segment
);
1188 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1189 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1191 MmUnlockSectionSegment(Segment
);
1194 * Check if we are doing COW
1196 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1197 (Region
->Protect
== PAGE_READWRITE
||
1198 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1200 DPRINT("Address 0x%.8X\n", Address
);
1201 return(STATUS_UNSUCCESSFUL
);
1204 if (IS_SWAP_FROM_SSE(Entry
) ||
1205 PFN_FROM_SSE(Entry
) != OldPage
)
1207 /* This is a private page. We must only change the page protection. */
1208 MmSetPageProtect(AddressSpace
->Process
, PAddress
, Region
->Protect
);
1209 return(STATUS_SUCCESS
);
1213 * Get or create a pageop
1215 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1216 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1219 DPRINT1("MmGetPageOp failed\n");
1224 * Wait for any other operations to complete
1226 if (PageOp
->Thread
!= PsGetCurrentThread())
1228 MmUnlockAddressSpace(AddressSpace
);
1229 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1231 * Check for various strange conditions
1233 if (Status
== STATUS_TIMEOUT
)
1235 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1238 if (PageOp
->Status
== STATUS_PENDING
)
1240 DPRINT1("Woke for page op before completion\n");
1244 * Restart the operation
1246 MmLockAddressSpace(AddressSpace
);
1247 MmspCompleteAndReleasePageOp(PageOp
);
1248 DPRINT("Address 0x%.8X\n", Address
);
1249 return(STATUS_MM_RESTART_OPERATION
);
1253 * Release locks now we have the pageop
1255 MmUnlockAddressSpace(AddressSpace
);
1260 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1261 if (!NT_SUCCESS(Status
))
1269 MiCopyFromUserPage(NewPage
, PAddress
);
1272 * Delete the old entry.
1274 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1277 * Set the PTE to point to the new page
1279 MmLockAddressSpace(AddressSpace
);
1280 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1285 if (!NT_SUCCESS(Status
))
1287 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1291 MmInsertRmap(NewPage
, AddressSpace
->Process
, PAddress
);
1292 if (!NT_SUCCESS(Status
))
1294 DbgPrint("Unable to create virtual mapping\n");
1299 MmLockPage(NewPage
);
1300 MmUnlockPage(OldPage
);
1304 * Unshare the old page.
1306 MmDeleteRmap(OldPage
, AddressSpace
->Process
, PAddress
);
1307 MmLockSectionSegment(Segment
);
1308 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1309 MmUnlockSectionSegment(Segment
);
1311 PageOp
->Status
= STATUS_SUCCESS
;
1312 MmspCompleteAndReleasePageOp(PageOp
);
1313 DPRINT("Address 0x%.8X\n", Address
);
1314 return(STATUS_SUCCESS
);
1318 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1320 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1324 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1325 MmDeleteVirtualMapping(Process
,
1332 PageOutContext
->WasDirty
= TRUE
;
1334 if (!PageOutContext
->Private
)
1336 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1337 PageOutContext
->Segment
,
1338 PageOutContext
->Offset
,
1339 PageOutContext
->WasDirty
,
1344 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1347 DPRINT("PhysicalAddress %I64x, Address %x\n", Page
, Address
);
1351 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1352 MEMORY_AREA
* MemoryArea
,
1357 MM_SECTION_PAGEOUT_CONTEXT Context
;
1358 SWAPENTRY SwapEntry
;
1362 PFILE_OBJECT FileObject
;
1364 BOOLEAN DirectMapped
;
1365 BOOLEAN IsImageSection
;
1367 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1370 * Get the segment and section.
1372 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1373 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1375 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1376 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1377 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1379 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1381 FileObject
= Context
.Section
->FileObject
;
1382 DirectMapped
= FALSE
;
1383 if (FileObject
!= NULL
&&
1384 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1386 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1389 * If the file system is letting us go directly to the cache and the
1390 * memory area was mapped at an offset in the file which is page aligned
1391 * then note this is a direct mapped page.
1393 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1394 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1396 DirectMapped
= TRUE
;
1402 * This should never happen since mappings of physical memory are never
1403 * placed in the rmap lists.
1405 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1407 DPRINT1("Trying to page out from physical memory section address 0x%X "
1408 "process %d\n", Address
,
1409 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1414 * Get the section segment entry and the physical address.
1416 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1417 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1419 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1420 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1423 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1424 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1427 * Prepare the context structure for the rmap delete call.
1429 Context
.WasDirty
= FALSE
;
1430 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1431 IS_SWAP_FROM_SSE(Entry
) ||
1432 PFN_FROM_SSE(Entry
) != Page
)
1434 Context
.Private
= TRUE
;
1438 Context
.Private
= FALSE
;
1442 * Take an additional reference to the page or the cache segment.
1444 if (DirectMapped
&& !Context
.Private
)
1446 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1448 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1454 MmReferencePage(Page
);
1457 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1460 * If this wasn't a private page then we should have reduced the entry to
1461 * zero by deleting all the rmaps.
1463 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1465 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1466 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1473 * If the page wasn't dirty then we can just free it as for a readonly page.
1474 * Since we unmapped all the mappings above we know it will not suddenly
1476 * If the page is from a pagefile section and has no swap entry,
1477 * we can't free the page at this point.
1479 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1480 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1482 if (Context
.Private
)
1484 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1485 Context
.WasDirty
? "dirty" : "clean", Address
);
1488 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1490 MmSetSavedSwapEntryPage(Page
, 0);
1491 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1492 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1493 PageOp
->Status
= STATUS_SUCCESS
;
1494 MmspCompleteAndReleasePageOp(PageOp
);
1495 return(STATUS_SUCCESS
);
1498 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1500 if (Context
.Private
)
1502 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1503 Context
.WasDirty
? "dirty" : "clean", Address
);
1506 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1508 MmSetSavedSwapEntryPage(Page
, 0);
1511 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1513 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1514 PageOp
->Status
= STATUS_SUCCESS
;
1515 MmspCompleteAndReleasePageOp(PageOp
);
1516 return(STATUS_SUCCESS
);
1519 else if (!Context
.Private
&& DirectMapped
)
1523 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1527 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1528 if (!NT_SUCCESS(Status
))
1530 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1533 PageOp
->Status
= STATUS_SUCCESS
;
1534 MmspCompleteAndReleasePageOp(PageOp
);
1535 return(STATUS_SUCCESS
);
1537 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1541 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1545 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1546 PageOp
->Status
= STATUS_SUCCESS
;
1547 MmspCompleteAndReleasePageOp(PageOp
);
1548 return(STATUS_SUCCESS
);
1550 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1552 MmSetSavedSwapEntryPage(Page
, 0);
1553 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1556 if (!NT_SUCCESS(Status
))
1560 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1561 PageOp
->Status
= STATUS_SUCCESS
;
1562 MmspCompleteAndReleasePageOp(PageOp
);
1563 return(STATUS_SUCCESS
);
1567 * If necessary, allocate an entry in the paging file for this page
1571 SwapEntry
= MmAllocSwapPage();
1574 MmShowOutOfSpaceMessagePagingFile();
1577 * For private pages restore the old mappings.
1579 if (Context
.Private
)
1581 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1583 MemoryArea
->Attributes
,
1586 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1588 AddressSpace
->Process
,
1594 * For non-private pages if the page wasn't direct mapped then
1595 * set it back into the section segment entry so we don't loose
1596 * our copy. Otherwise it will be handled by the cache manager.
1598 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1600 MemoryArea
->Attributes
,
1603 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1605 AddressSpace
->Process
,
1607 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1608 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1610 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1611 MmspCompleteAndReleasePageOp(PageOp
);
1612 return(STATUS_PAGEFILE_QUOTA
);
1617 * Write the page to the pagefile
1619 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1620 if (!NT_SUCCESS(Status
))
1622 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1625 * As above: undo our actions.
1626 * FIXME: Also free the swap page.
1628 if (Context
.Private
)
1630 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1632 MemoryArea
->Attributes
,
1635 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1637 AddressSpace
->Process
,
1642 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1644 MemoryArea
->Attributes
,
1647 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1649 AddressSpace
->Process
,
1651 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1652 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1654 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1655 MmspCompleteAndReleasePageOp(PageOp
);
1656 return(STATUS_UNSUCCESSFUL
);
1660 * Otherwise we have succeeded.
1662 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1663 MmSetSavedSwapEntryPage(Page
, 0);
1664 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1665 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1667 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1671 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1674 if (Context
.Private
)
1676 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1679 if (!NT_SUCCESS(Status
))
1686 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1687 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1690 PageOp
->Status
= STATUS_SUCCESS
;
1691 MmspCompleteAndReleasePageOp(PageOp
);
1692 return(STATUS_SUCCESS
);
1696 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1697 PMEMORY_AREA MemoryArea
,
1702 PSECTION_OBJECT Section
;
1703 PMM_SECTION_SEGMENT Segment
;
1705 SWAPENTRY SwapEntry
;
1709 PFILE_OBJECT FileObject
;
1711 BOOLEAN DirectMapped
;
1712 BOOLEAN IsImageSection
;
1714 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1716 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1717 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1720 * Get the segment and section.
1722 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1723 Section
= MemoryArea
->Data
.SectionData
.Section
;
1724 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1726 FileObject
= Section
->FileObject
;
1727 DirectMapped
= FALSE
;
1728 if (FileObject
!= NULL
&&
1729 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1731 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1734 * If the file system is letting us go directly to the cache and the
1735 * memory area was mapped at an offset in the file which is page aligned
1736 * then note this is a direct mapped page.
1738 if ((Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
% PAGE_SIZE
) == 0 &&
1739 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1741 DirectMapped
= TRUE
;
1746 * This should never happen since mappings of physical memory are never
1747 * placed in the rmap lists.
1749 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1751 DPRINT1("Trying to write back page from physical memory mapped at %X "
1752 "process %d\n", Address
,
1753 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1758 * Get the section segment entry and the physical address.
1760 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1761 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1763 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1764 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1767 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1768 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1771 * Check for a private (COWed) page.
1773 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1774 IS_SWAP_FROM_SSE(Entry
) ||
1775 PFN_FROM_SSE(Entry
) != Page
)
1785 * Speculatively set all mappings of the page to clean.
1787 MmSetCleanAllRmaps(Page
);
1790 * If this page was direct mapped from the cache then the cache manager
1791 * will take care of writing it back to disk.
1793 if (DirectMapped
&& !Private
)
1795 ASSERT(SwapEntry
== 0);
1796 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1797 PageOp
->Status
= STATUS_SUCCESS
;
1798 MmspCompleteAndReleasePageOp(PageOp
);
1799 return(STATUS_SUCCESS
);
1803 * If necessary, allocate an entry in the paging file for this page
1807 SwapEntry
= MmAllocSwapPage();
1810 MmSetDirtyAllRmaps(Page
);
1811 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1812 MmspCompleteAndReleasePageOp(PageOp
);
1813 return(STATUS_PAGEFILE_QUOTA
);
1815 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1819 * Write the page to the pagefile
1821 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1822 if (!NT_SUCCESS(Status
))
1824 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1826 MmSetDirtyAllRmaps(Page
);
1827 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1828 MmspCompleteAndReleasePageOp(PageOp
);
1829 return(STATUS_UNSUCCESSFUL
);
1833 * Otherwise we have succeeded.
1835 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1836 PageOp
->Status
= STATUS_SUCCESS
;
1837 MmspCompleteAndReleasePageOp(PageOp
);
1838 return(STATUS_SUCCESS
);
1842 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1850 PMEMORY_AREA MemoryArea
;
1851 PMM_SECTION_SEGMENT Segment
;
1855 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1856 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1858 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1859 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1864 if (OldProtect
!= NewProtect
)
1866 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1868 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1869 ULONG Protect
= NewProtect
;
1872 * If we doing COW for this segment then check if the page is
1875 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1881 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1882 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1883 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1884 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1886 Protect
= PAGE_READONLY
;
1887 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1888 IS_SWAP_FROM_SSE(Entry
) ||
1889 PFN_FROM_SSE(Entry
) != Page
)
1891 Protect
= NewProtect
;
1895 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1897 MmSetPageProtect(AddressSpace
->Process
, Address
,
1905 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1906 PMEMORY_AREA MemoryArea
,
1914 ULONG_PTR MaxLength
;
1916 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
1917 if (Length
> MaxLength
)
1920 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1921 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1923 *OldProtect
= Region
->Protect
;
1924 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
1925 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1926 BaseAddress
, Length
, Region
->Type
, Protect
,
1927 MmAlterViewAttributes
);
1933 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
1935 PMEMORY_BASIC_INFORMATION Info
,
1936 PULONG ResultLength
)
1939 PVOID RegionBaseAddress
;
1940 PSECTION_OBJECT Section
;
1941 PMM_SECTION_SEGMENT Segment
;
1943 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
1944 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1945 Address
, &RegionBaseAddress
);
1948 return STATUS_UNSUCCESSFUL
;
1951 Section
= MemoryArea
->Data
.SectionData
.Section
;
1952 if (Section
->AllocationAttributes
& SEC_IMAGE
)
1954 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1955 Info
->AllocationBase
= (PBYTE
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
1956 Info
->Type
= MEM_IMAGE
;
1960 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
1961 Info
->Type
= MEM_MAPPED
;
1963 Info
->BaseAddress
= RegionBaseAddress
;
1964 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1965 Info
->RegionSize
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
-
1966 (ULONG_PTR
)MemoryArea
->StartingAddress
);
1967 Info
->State
= MEM_COMMIT
;
1968 Info
->Protect
= Region
->Protect
;
1970 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
1971 return(STATUS_SUCCESS
);
1975 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
1980 ULONG SavedSwapEntry
;
1985 Length
= PAGE_ROUND_UP(Segment
->Length
);
1986 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
1988 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1991 if (IS_SWAP_FROM_SSE(Entry
))
1993 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
1997 Page
= PFN_FROM_SSE(Entry
);
1998 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
1999 if (SavedSwapEntry
!= 0)
2001 MmSetSavedSwapEntryPage(Page
, 0);
2002 MmFreeSwapPage(SavedSwapEntry
);
2004 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2006 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2012 MmpDeleteSection(PVOID ObjectBody
)
2014 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
2016 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2017 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2022 PMM_SECTION_SEGMENT SectionSegments
;
2025 * NOTE: Section->ImageSection can be NULL for short time
2026 * during the section creating. If we fail for some reason
2027 * until the image section is properly initialized we shouldn't
2028 * process further here.
2030 if (Section
->ImageSection
== NULL
)
2033 SectionSegments
= Section
->ImageSection
->Segments
;
2034 NrSegments
= Section
->ImageSection
->NrSegments
;
2036 for (i
= 0; i
< NrSegments
; i
++)
2038 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2040 MmLockSectionSegment(&SectionSegments
[i
]);
2042 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2043 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2047 MmpFreePageFileSegment(&SectionSegments
[i
]);
2049 MmUnlockSectionSegment(&SectionSegments
[i
]);
2056 * NOTE: Section->Segment can be NULL for short time
2057 * during the section creating.
2059 if (Section
->Segment
== NULL
)
2062 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2064 MmpFreePageFileSegment(Section
->Segment
);
2065 MmFreePageTablesSectionSegment(Section
->Segment
);
2066 ExFreePool(Section
->Segment
);
2067 Section
->Segment
= NULL
;
2071 InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2074 if (Section
->FileObject
!= NULL
)
2076 CcRosDereferenceCache(Section
->FileObject
);
2077 ObDereferenceObject(Section
->FileObject
);
2078 Section
->FileObject
= NULL
;
2083 MmpCloseSection(PVOID ObjectBody
,
2086 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2087 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2090 NTSTATUS INIT_FUNCTION
2091 MmCreatePhysicalMemorySection(VOID
)
2093 PSECTION_OBJECT PhysSection
;
2095 OBJECT_ATTRIBUTES Obj
;
2096 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2097 LARGE_INTEGER SectionSize
;
2100 * Create the section mapping physical memory
2102 SectionSize
.QuadPart
= 0xFFFFFFFF;
2103 InitializeObjectAttributes(&Obj
,
2108 Status
= MmCreateSection(&PhysSection
,
2112 PAGE_EXECUTE_READWRITE
,
2116 if (!NT_SUCCESS(Status
))
2118 DbgPrint("Failed to create PhysicalMemory section\n");
2121 Status
= ObInsertObject(PhysSection
,
2127 if (!NT_SUCCESS(Status
))
2129 ObDereferenceObject(PhysSection
);
2131 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2132 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2134 return(STATUS_SUCCESS
);
2137 NTSTATUS INIT_FUNCTION
2138 MmInitSectionImplementation(VOID
)
2140 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2141 UNICODE_STRING Name
;
2143 DPRINT("Creating Section Object Type\n");
2145 /* Initialize the Section object type */
2146 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2147 RtlInitUnicodeString(&Name
, L
"Section");
2148 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2149 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(SECTION_OBJECT
);
2150 ObjectTypeInitializer
.PoolType
= PagedPool
;
2151 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2152 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2153 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2154 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2155 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &MmSectionObjectType
);
2157 return(STATUS_SUCCESS
);
2161 MmCreatePageFileSection(PSECTION_OBJECT
*SectionObject
,
2162 ACCESS_MASK DesiredAccess
,
2163 POBJECT_ATTRIBUTES ObjectAttributes
,
2164 PLARGE_INTEGER UMaximumSize
,
2165 ULONG SectionPageProtection
,
2166 ULONG AllocationAttributes
)
2168 * Create a section which is backed by the pagefile
2171 LARGE_INTEGER MaximumSize
;
2172 PSECTION_OBJECT Section
;
2173 PMM_SECTION_SEGMENT Segment
;
2176 if (UMaximumSize
== NULL
)
2178 return(STATUS_UNSUCCESSFUL
);
2180 MaximumSize
= *UMaximumSize
;
2183 * Create the section
2185 Status
= ObCreateObject(ExGetPreviousMode(),
2186 MmSectionObjectType
,
2188 ExGetPreviousMode(),
2190 sizeof(SECTION_OBJECT
),
2193 (PVOID
*)(PVOID
)&Section
);
2194 if (!NT_SUCCESS(Status
))
2202 Section
->SectionPageProtection
= SectionPageProtection
;
2203 Section
->AllocationAttributes
= AllocationAttributes
;
2204 Section
->Segment
= NULL
;
2205 Section
->FileObject
= NULL
;
2206 Section
->MaximumSize
= MaximumSize
;
2207 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2208 TAG_MM_SECTION_SEGMENT
);
2209 if (Segment
== NULL
)
2211 ObDereferenceObject(Section
);
2212 return(STATUS_NO_MEMORY
);
2214 Section
->Segment
= Segment
;
2215 Segment
->ReferenceCount
= 1;
2216 ExInitializeFastMutex(&Segment
->Lock
);
2217 Segment
->FileOffset
= 0;
2218 Segment
->Protection
= SectionPageProtection
;
2219 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2220 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2221 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2222 Segment
->WriteCopy
= FALSE
;
2223 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2224 Segment
->VirtualAddress
= 0;
2225 Segment
->Characteristics
= 0;
2226 *SectionObject
= Section
;
2227 return(STATUS_SUCCESS
);
2232 MmCreateDataFileSection(PSECTION_OBJECT
*SectionObject
,
2233 ACCESS_MASK DesiredAccess
,
2234 POBJECT_ATTRIBUTES ObjectAttributes
,
2235 PLARGE_INTEGER UMaximumSize
,
2236 ULONG SectionPageProtection
,
2237 ULONG AllocationAttributes
,
2240 * Create a section backed by a data file
2243 PSECTION_OBJECT Section
;
2245 LARGE_INTEGER MaximumSize
;
2246 PFILE_OBJECT FileObject
;
2247 PMM_SECTION_SEGMENT Segment
;
2249 IO_STATUS_BLOCK Iosb
;
2250 LARGE_INTEGER Offset
;
2252 FILE_STANDARD_INFORMATION FileInfo
;
2255 * Create the section
2257 Status
= ObCreateObject(ExGetPreviousMode(),
2258 MmSectionObjectType
,
2260 ExGetPreviousMode(),
2262 sizeof(SECTION_OBJECT
),
2265 (PVOID
*)(PVOID
)&Section
);
2266 if (!NT_SUCCESS(Status
))
2273 Section
->SectionPageProtection
= SectionPageProtection
;
2274 Section
->AllocationAttributes
= AllocationAttributes
;
2275 Section
->Segment
= NULL
;
2278 * Check file access required
2280 if (SectionPageProtection
& PAGE_READWRITE
||
2281 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2283 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2287 FileAccess
= FILE_READ_DATA
;
2291 * Reference the file handle
2293 Status
= ObReferenceObjectByHandle(FileHandle
,
2297 (PVOID
*)(PVOID
)&FileObject
,
2299 if (!NT_SUCCESS(Status
))
2301 ObDereferenceObject(Section
);
2306 * FIXME: This is propably not entirely correct. We can't look into
2307 * the standard FCB header because it might not be initialized yet
2308 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2309 * standard file information is filled on first request).
2311 Status
= NtQueryInformationFile(FileHandle
,
2314 sizeof(FILE_STANDARD_INFORMATION
),
2315 FileStandardInformation
);
2316 if (!NT_SUCCESS(Status
))
2318 ObDereferenceObject(Section
);
2319 ObDereferenceObject(FileObject
);
2324 * FIXME: Revise this once a locking order for file size changes is
2327 if (UMaximumSize
!= NULL
)
2329 MaximumSize
= *UMaximumSize
;
2333 MaximumSize
= FileInfo
.EndOfFile
;
2334 /* Mapping zero-sized files isn't allowed. */
2335 if (MaximumSize
.QuadPart
== 0)
2337 ObDereferenceObject(Section
);
2338 ObDereferenceObject(FileObject
);
2339 return STATUS_FILE_INVALID
;
2343 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2345 Status
= NtSetInformationFile(FileHandle
,
2348 sizeof(LARGE_INTEGER
),
2349 FileAllocationInformation
);
2350 if (!NT_SUCCESS(Status
))
2352 ObDereferenceObject(Section
);
2353 ObDereferenceObject(FileObject
);
2354 return(STATUS_SECTION_NOT_EXTENDED
);
2358 if (FileObject
->SectionObjectPointer
== NULL
||
2359 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2362 * Read a bit so caching is initiated for the file object.
2363 * This is only needed because MiReadPage currently cannot
2364 * handle non-cached streams.
2366 Offset
.QuadPart
= 0;
2367 Status
= ZwReadFile(FileHandle
,
2376 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2378 ObDereferenceObject(Section
);
2379 ObDereferenceObject(FileObject
);
2382 if (FileObject
->SectionObjectPointer
== NULL
||
2383 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2385 /* FIXME: handle this situation */
2386 ObDereferenceObject(Section
);
2387 ObDereferenceObject(FileObject
);
2388 return STATUS_INVALID_PARAMETER
;
2395 Status
= MmspWaitForFileLock(FileObject
);
2396 if (Status
!= STATUS_SUCCESS
)
2398 ObDereferenceObject(Section
);
2399 ObDereferenceObject(FileObject
);
2404 * If this file hasn't been mapped as a data file before then allocate a
2405 * section segment to describe the data file mapping
2407 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2409 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2410 TAG_MM_SECTION_SEGMENT
);
2411 if (Segment
== NULL
)
2413 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2414 ObDereferenceObject(Section
);
2415 ObDereferenceObject(FileObject
);
2416 return(STATUS_NO_MEMORY
);
2418 Section
->Segment
= Segment
;
2419 Segment
->ReferenceCount
= 1;
2420 ExInitializeFastMutex(&Segment
->Lock
);
2422 * Set the lock before assigning the segment to the file object
2424 ExAcquireFastMutex(&Segment
->Lock
);
2425 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2427 Segment
->FileOffset
= 0;
2428 Segment
->Protection
= SectionPageProtection
;
2429 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2430 Segment
->Characteristics
= 0;
2431 Segment
->WriteCopy
= FALSE
;
2432 if (AllocationAttributes
& SEC_RESERVE
)
2434 Segment
->Length
= Segment
->RawLength
= 0;
2438 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2439 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2441 Segment
->VirtualAddress
= 0;
2442 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2447 * If the file is already mapped as a data file then we may need
2451 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2453 Section
->Segment
= Segment
;
2454 InterlockedIncrementUL(&Segment
->ReferenceCount
);
2455 MmLockSectionSegment(Segment
);
2457 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2458 !(AllocationAttributes
& SEC_RESERVE
))
2460 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2461 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2464 MmUnlockSectionSegment(Segment
);
2465 Section
->FileObject
= FileObject
;
2466 Section
->MaximumSize
= MaximumSize
;
2467 CcRosReferenceCache(FileObject
);
2468 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2469 *SectionObject
= Section
;
2470 return(STATUS_SUCCESS
);
2474 TODO: not that great (declaring loaders statically, having to declare all of
2475 them, having to keep them extern, etc.), will fix in the future
2477 extern NTSTATUS NTAPI PeFmtCreateSection
2479 IN CONST VOID
* FileHeader
,
2480 IN SIZE_T FileHeaderSize
,
2482 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2484 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2485 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2488 extern NTSTATUS NTAPI ElfFmtCreateSection
2490 IN CONST VOID
* FileHeader
,
2491 IN SIZE_T FileHeaderSize
,
2493 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2495 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2496 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2499 /* TODO: this is a standard DDK/PSDK macro */
2500 #ifndef RTL_NUMBER_OF
2501 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2504 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2513 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2515 SIZE_T SizeOfSegments
;
2516 PMM_SECTION_SEGMENT Segments
;
2518 /* TODO: check for integer overflow */
2519 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2521 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2523 TAG_MM_SECTION_SEGMENT
);
2526 RtlZeroMemory(Segments
, SizeOfSegments
);
2534 ExeFmtpReadFile(IN PVOID File
,
2535 IN PLARGE_INTEGER Offset
,
2538 OUT PVOID
* AllocBase
,
2539 OUT PULONG ReadSize
)
2542 LARGE_INTEGER FileOffset
;
2544 ULONG OffsetAdjustment
;
2549 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2553 KEBUGCHECK(STATUS_INVALID_PARAMETER_4
);
2556 FileOffset
= *Offset
;
2558 /* Negative/special offset: it cannot be used in this context */
2559 if(FileOffset
.u
.HighPart
< 0)
2561 KEBUGCHECK(STATUS_INVALID_PARAMETER_5
);
2564 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2565 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2566 FileOffset
.u
.LowPart
= AdjustOffset
;
2568 BufferSize
= Length
+ OffsetAdjustment
;
2569 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2572 * It's ok to use paged pool, because this is a temporary buffer only used in
2573 * the loading of executables. The assumption is that MmCreateSection is
2574 * always called at low IRQLs and that these buffers don't survive a brief
2575 * initialization phase
2577 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2579 TAG('M', 'm', 'X', 'r'));
2584 Status
= MmspPageRead(File
,
2591 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2592 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2593 * to initialize internal state is even worse. Our cache manager is in need of
2597 IO_STATUS_BLOCK Iosb
;
2599 Status
= ZwReadFile(File
,
2609 if(NT_SUCCESS(Status
))
2611 UsedSize
= Iosb
.Information
;
2616 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2618 Status
= STATUS_IN_PAGE_ERROR
;
2619 ASSERT(!NT_SUCCESS(Status
));
2622 if(NT_SUCCESS(Status
))
2624 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2625 *AllocBase
= Buffer
;
2626 *ReadSize
= UsedSize
- OffsetAdjustment
;
2637 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2638 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2639 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2644 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2648 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2650 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2651 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2658 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2662 MmspAssertSegmentsSorted(ImageSectionObject
);
2664 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2666 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2670 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2671 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2672 ImageSectionObject
->Segments
[i
- 1].Length
));
2680 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2684 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2686 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2687 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2695 MmspCompareSegments(const void * x
,
2698 PMM_SECTION_SEGMENT Segment1
= (PMM_SECTION_SEGMENT
)x
;
2699 PMM_SECTION_SEGMENT Segment2
= (PMM_SECTION_SEGMENT
)y
;
2702 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2703 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2707 * Ensures an image section's segments are sorted in memory
2712 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2715 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2717 MmspAssertSegmentsSorted(ImageSectionObject
);
2721 qsort(ImageSectionObject
->Segments
,
2722 ImageSectionObject
->NrSegments
,
2723 sizeof(ImageSectionObject
->Segments
[0]),
2724 MmspCompareSegments
);
2730 * Ensures an image section's segments don't overlap in memory and don't have
2731 * gaps and don't have a null size. We let them map to overlapping file regions,
2732 * though - that's not necessarily an error
2737 MmspCheckSegmentBounds
2739 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2745 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2747 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2751 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2753 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2755 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2763 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2764 * page could be OK (Windows seems to be OK with them), and larger gaps
2765 * could lead to image sections spanning several discontiguous regions
2766 * (NtMapViewOfSection could then refuse to map them, and they could
2767 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2769 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2770 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2771 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2782 * Merges and pads an image section's segments until they all are page-aligned
2783 * and have a size that is a multiple of the page size
2788 MmspPageAlignSegments
2790 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2796 BOOLEAN Initialized
;
2798 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2800 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2804 Initialized
= FALSE
;
2807 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2809 PMM_SECTION_SEGMENT EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2812 * The first segment requires special handling
2816 ULONG_PTR VirtualAddress
;
2817 ULONG_PTR VirtualOffset
;
2819 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2821 /* Round down the virtual address to the nearest page */
2822 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2824 /* Round up the virtual size to the nearest page */
2825 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2826 EffectiveSegment
->VirtualAddress
;
2828 /* Adjust the raw address and size */
2829 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2831 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
2837 * Garbage in, garbage out: unaligned base addresses make the file
2838 * offset point in curious and odd places, but that's what we were
2841 EffectiveSegment
->FileOffset
-= VirtualOffset
;
2842 EffectiveSegment
->RawLength
+= VirtualOffset
;
2846 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
2847 ULONG_PTR EndOfEffectiveSegment
;
2849 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
2850 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
2853 * The current segment begins exactly where the current effective
2854 * segment ended, therefore beginning a new effective segment
2856 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
2859 ASSERT(LastSegment
<= i
);
2860 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
2862 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2865 * Copy the current segment. If necessary, the effective segment
2866 * will be expanded later
2868 *EffectiveSegment
= *Segment
;
2871 * Page-align the virtual size. We know for sure the virtual address
2874 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
2875 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
2878 * The current segment is still part of the current effective segment:
2879 * extend the effective segment to reflect this
2881 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
2883 static const ULONG FlagsToProtection
[16] =
2891 PAGE_EXECUTE_READWRITE
,
2892 PAGE_EXECUTE_READWRITE
,
2897 PAGE_EXECUTE_WRITECOPY
,
2898 PAGE_EXECUTE_WRITECOPY
,
2899 PAGE_EXECUTE_WRITECOPY
,
2900 PAGE_EXECUTE_WRITECOPY
2903 unsigned ProtectionFlags
;
2906 * Extend the file size
2909 /* Unaligned segments must be contiguous within the file */
2910 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
2911 EffectiveSegment
->RawLength
))
2916 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
2919 * Extend the virtual size
2921 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) > EndOfEffectiveSegment
);
2923 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
2924 EffectiveSegment
->VirtualAddress
;
2927 * Merge the protection
2929 EffectiveSegment
->Protection
|= Segment
->Protection
;
2931 /* Clean up redundance */
2932 ProtectionFlags
= 0;
2934 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
2935 ProtectionFlags
|= 1 << 0;
2937 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
2938 ProtectionFlags
|= 1 << 1;
2940 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
2941 ProtectionFlags
|= 1 << 2;
2943 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2944 ProtectionFlags
|= 1 << 3;
2946 ASSERT(ProtectionFlags
< 16);
2947 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
2949 /* If a segment was required to be shared and cannot, fail */
2950 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
2951 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2957 * We assume no holes between segments at this point
2970 ExeFmtpCreateImageSection(HANDLE FileHandle
,
2971 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2973 LARGE_INTEGER Offset
;
2975 PVOID FileHeaderBuffer
;
2976 ULONG FileHeaderSize
;
2978 ULONG OldNrSegments
;
2983 * Read the beginning of the file (2 pages). Should be enough to contain
2984 * all (or most) of the headers
2986 Offset
.QuadPart
= 0;
2988 /* FIXME: use FileObject instead of FileHandle */
2989 Status
= ExeFmtpReadFile (FileHandle
,
2996 if (!NT_SUCCESS(Status
))
2999 if (FileHeaderSize
== 0)
3001 ExFreePool(FileHeaderBuffer
);
3002 return STATUS_UNSUCCESSFUL
;
3006 * Look for a loader that can handle this executable
3008 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3010 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3013 /* FIXME: use FileObject instead of FileHandle */
3014 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3020 ExeFmtpAllocateSegments
);
3022 if (!NT_SUCCESS(Status
))
3024 if (ImageSectionObject
->Segments
)
3026 ExFreePool(ImageSectionObject
->Segments
);
3027 ImageSectionObject
->Segments
= NULL
;
3031 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3035 ExFreePool(FileHeaderBuffer
);
3038 * No loader handled the format
3040 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3042 Status
= STATUS_INVALID_IMAGE_FORMAT
;
3043 ASSERT(!NT_SUCCESS(Status
));
3046 if (!NT_SUCCESS(Status
))
3049 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3054 /* FIXME? are these values platform-dependent? */
3055 if(ImageSectionObject
->StackReserve
== 0)
3056 ImageSectionObject
->StackReserve
= 0x40000;
3058 if(ImageSectionObject
->StackCommit
== 0)
3059 ImageSectionObject
->StackCommit
= 0x1000;
3061 if(ImageSectionObject
->ImageBase
== 0)
3063 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3064 ImageSectionObject
->ImageBase
= 0x10000000;
3066 ImageSectionObject
->ImageBase
= 0x00400000;
3070 * And now the fun part: fixing the segments
3073 /* Sort them by virtual address */
3074 MmspSortSegments(ImageSectionObject
, Flags
);
3076 /* Ensure they don't overlap in memory */
3077 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3078 return STATUS_INVALID_IMAGE_FORMAT
;
3080 /* Ensure they are aligned */
3081 OldNrSegments
= ImageSectionObject
->NrSegments
;
3083 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3084 return STATUS_INVALID_IMAGE_FORMAT
;
3086 /* Trim them if the alignment phase merged some of them */
3087 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3089 PMM_SECTION_SEGMENT Segments
;
3090 SIZE_T SizeOfSegments
;
3092 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3094 Segments
= ExAllocatePoolWithTag(PagedPool
,
3096 TAG_MM_SECTION_SEGMENT
);
3098 if (Segments
== NULL
)
3099 return STATUS_INSUFFICIENT_RESOURCES
;
3101 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3102 ExFreePool(ImageSectionObject
->Segments
);
3103 ImageSectionObject
->Segments
= Segments
;
3106 /* And finish their initialization */
3107 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3109 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3110 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3112 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3113 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3116 ASSERT(NT_SUCCESS(Status
));
3121 MmCreateImageSection(PSECTION_OBJECT
*SectionObject
,
3122 ACCESS_MASK DesiredAccess
,
3123 POBJECT_ATTRIBUTES ObjectAttributes
,
3124 PLARGE_INTEGER UMaximumSize
,
3125 ULONG SectionPageProtection
,
3126 ULONG AllocationAttributes
,
3129 PSECTION_OBJECT Section
;
3131 PFILE_OBJECT FileObject
;
3132 PMM_SECTION_SEGMENT SectionSegments
;
3133 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3135 ULONG FileAccess
= 0;
3138 * Specifying a maximum size is meaningless for an image section
3140 if (UMaximumSize
!= NULL
)
3142 return(STATUS_INVALID_PARAMETER_4
);
3146 * Check file access required
3148 if (SectionPageProtection
& PAGE_READWRITE
||
3149 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3151 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3155 FileAccess
= FILE_READ_DATA
;
3159 * Reference the file handle
3161 Status
= ObReferenceObjectByHandle(FileHandle
,
3165 (PVOID
*)(PVOID
)&FileObject
,
3168 if (!NT_SUCCESS(Status
))
3174 * Create the section
3176 Status
= ObCreateObject (ExGetPreviousMode(),
3177 MmSectionObjectType
,
3179 ExGetPreviousMode(),
3181 sizeof(SECTION_OBJECT
),
3184 (PVOID
*)(PVOID
)&Section
);
3185 if (!NT_SUCCESS(Status
))
3187 ObDereferenceObject(FileObject
);
3194 Section
->SectionPageProtection
= SectionPageProtection
;
3195 Section
->AllocationAttributes
= AllocationAttributes
;
3198 * Initialized caching for this file object if previously caching
3199 * was initialized for the same on disk file
3201 Status
= CcTryToInitializeFileCache(FileObject
);
3203 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3205 NTSTATUS StatusExeFmt
;
3207 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3208 if (ImageSectionObject
== NULL
)
3210 ObDereferenceObject(FileObject
);
3211 ObDereferenceObject(Section
);
3212 return(STATUS_NO_MEMORY
);
3215 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3217 if (!NT_SUCCESS(StatusExeFmt
))
3219 if(ImageSectionObject
->Segments
!= NULL
)
3220 ExFreePool(ImageSectionObject
->Segments
);
3222 ExFreePool(ImageSectionObject
);
3223 ObDereferenceObject(Section
);
3224 ObDereferenceObject(FileObject
);
3225 return(StatusExeFmt
);
3228 Section
->ImageSection
= ImageSectionObject
;
3229 ASSERT(ImageSectionObject
->Segments
);
3234 Status
= MmspWaitForFileLock(FileObject
);
3235 if (!NT_SUCCESS(Status
))
3237 ExFreePool(ImageSectionObject
->Segments
);
3238 ExFreePool(ImageSectionObject
);
3239 ObDereferenceObject(Section
);
3240 ObDereferenceObject(FileObject
);
3244 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3245 ImageSectionObject
, NULL
))
3248 * An other thread has initialized the some image in the background
3250 ExFreePool(ImageSectionObject
->Segments
);
3251 ExFreePool(ImageSectionObject
);
3252 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3253 Section
->ImageSection
= ImageSectionObject
;
3254 SectionSegments
= ImageSectionObject
->Segments
;
3256 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3258 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3262 Status
= StatusExeFmt
;
3269 Status
= MmspWaitForFileLock(FileObject
);
3270 if (Status
!= STATUS_SUCCESS
)
3272 ObDereferenceObject(Section
);
3273 ObDereferenceObject(FileObject
);
3277 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3278 Section
->ImageSection
= ImageSectionObject
;
3279 SectionSegments
= ImageSectionObject
->Segments
;
3282 * Otherwise just reference all the section segments
3284 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3286 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3289 Status
= STATUS_SUCCESS
;
3291 Section
->FileObject
= FileObject
;
3292 CcRosReferenceCache(FileObject
);
3293 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
3294 *SectionObject
= Section
;
3302 NtCreateSection (OUT PHANDLE SectionHandle
,
3303 IN ACCESS_MASK DesiredAccess
,
3304 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3305 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3306 IN ULONG SectionPageProtection OPTIONAL
,
3307 IN ULONG AllocationAttributes
,
3308 IN HANDLE FileHandle OPTIONAL
)
3310 LARGE_INTEGER SafeMaximumSize
;
3311 PSECTION_OBJECT SectionObject
;
3312 KPROCESSOR_MODE PreviousMode
;
3313 NTSTATUS Status
= STATUS_SUCCESS
;
3315 PreviousMode
= ExGetPreviousMode();
3317 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3321 ProbeForRead(MaximumSize
,
3322 sizeof(LARGE_INTEGER
),
3324 /* make a copy on the stack */
3325 SafeMaximumSize
= *MaximumSize
;
3326 MaximumSize
= &SafeMaximumSize
;
3330 Status
= _SEH_GetExceptionCode();
3334 if(!NT_SUCCESS(Status
))
3341 * Check the protection
3343 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
3344 SectionPageProtection
)
3346 return(STATUS_INVALID_PAGE_PROTECTION
);
3349 Status
= MmCreateSection(&SectionObject
,
3353 SectionPageProtection
,
3354 AllocationAttributes
,
3358 if (NT_SUCCESS(Status
))
3360 Status
= ObInsertObject ((PVOID
)SectionObject
,
3366 ObDereferenceObject(SectionObject
);
3373 /**********************************************************************
3391 NtOpenSection(PHANDLE SectionHandle
,
3392 ACCESS_MASK DesiredAccess
,
3393 POBJECT_ATTRIBUTES ObjectAttributes
)
3396 KPROCESSOR_MODE PreviousMode
;
3397 NTSTATUS Status
= STATUS_SUCCESS
;
3399 PreviousMode
= ExGetPreviousMode();
3401 if(PreviousMode
!= KernelMode
)
3405 ProbeForWrite(SectionHandle
,
3411 Status
= _SEH_GetExceptionCode();
3415 if(!NT_SUCCESS(Status
))
3421 Status
= ObOpenObjectByName(ObjectAttributes
,
3422 MmSectionObjectType
,
3429 if(NT_SUCCESS(Status
))
3433 *SectionHandle
= hSection
;
3437 Status
= _SEH_GetExceptionCode();
3446 MmMapViewOfSegment(PEPROCESS Process
,
3447 PMADDRESS_SPACE AddressSpace
,
3448 PSECTION_OBJECT Section
,
3449 PMM_SECTION_SEGMENT Segment
,
3458 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3460 BoundaryAddressMultiple
.QuadPart
= 0;
3462 Status
= MmCreateMemoryArea(Process
,
3464 MEMORY_AREA_SECTION_VIEW
,
3471 BoundaryAddressMultiple
);
3472 if (!NT_SUCCESS(Status
))
3474 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3475 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3480 ObReferenceObjectByPointer((PVOID
)Section
,
3483 ExGetPreviousMode());
3484 MArea
->Data
.SectionData
.Segment
= Segment
;
3485 MArea
->Data
.SectionData
.Section
= Section
;
3486 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3487 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3488 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3489 ViewSize
, 0, Protect
);
3491 return(STATUS_SUCCESS
);
3495 /**********************************************************************
3497 * NtMapViewOfSection
3500 * Maps a view of a section into the virtual address space of a
3505 * Handle of the section.
3508 * Handle of the process.
3511 * Desired base address (or NULL) on entry;
3512 * Actual base address of the view on exit.
3515 * Number of high order address bits that must be zero.
3518 * Size in bytes of the initially committed section of
3522 * Offset in bytes from the beginning of the section
3523 * to the beginning of the view.
3526 * Desired length of map (or zero to map all) on entry
3527 * Actual length mapped on exit.
3529 * InheritDisposition
3530 * Specified how the view is to be shared with
3534 * Type of allocation for the pages.
3537 * Protection for the committed region of the view.
3545 NtMapViewOfSection(IN HANDLE SectionHandle
,
3546 IN HANDLE ProcessHandle
,
3547 IN OUT PVOID
* BaseAddress OPTIONAL
,
3548 IN ULONG ZeroBits OPTIONAL
,
3549 IN ULONG CommitSize
,
3550 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3551 IN OUT PULONG ViewSize
,
3552 IN SECTION_INHERIT InheritDisposition
,
3553 IN ULONG AllocationType OPTIONAL
,
3556 PVOID SafeBaseAddress
;
3557 LARGE_INTEGER SafeSectionOffset
;
3559 PSECTION_OBJECT Section
;
3561 KPROCESSOR_MODE PreviousMode
;
3562 PMADDRESS_SPACE AddressSpace
;
3563 NTSTATUS Status
= STATUS_SUCCESS
;
3565 PreviousMode
= ExGetPreviousMode();
3567 if(PreviousMode
!= KernelMode
)
3569 SafeBaseAddress
= NULL
;
3570 SafeSectionOffset
.QuadPart
= 0;
3575 if(BaseAddress
!= NULL
)
3577 ProbeForWrite(BaseAddress
,
3580 SafeBaseAddress
= *BaseAddress
;
3582 if(SectionOffset
!= NULL
)
3584 ProbeForWrite(SectionOffset
,
3585 sizeof(LARGE_INTEGER
),
3587 SafeSectionOffset
= *SectionOffset
;
3589 ProbeForWrite(ViewSize
,
3592 SafeViewSize
= *ViewSize
;
3596 Status
= _SEH_GetExceptionCode();
3600 if(!NT_SUCCESS(Status
))
3607 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3608 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3609 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3612 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3613 PROCESS_VM_OPERATION
,
3616 (PVOID
*)(PVOID
)&Process
,
3618 if (!NT_SUCCESS(Status
))
3623 AddressSpace
= &Process
->AddressSpace
;
3625 Status
= ObReferenceObjectByHandle(SectionHandle
,
3627 MmSectionObjectType
,
3629 (PVOID
*)(PVOID
)&Section
,
3631 if (!(NT_SUCCESS(Status
)))
3633 DPRINT("ObReference failed rc=%x\n",Status
);
3634 ObDereferenceObject(Process
);
3638 Status
= MmMapViewOfSection(Section
,
3640 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3643 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3644 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3649 ObDereferenceObject(Section
);
3650 ObDereferenceObject(Process
);
3652 if(NT_SUCCESS(Status
))
3654 /* copy parameters back to the caller */
3657 if(BaseAddress
!= NULL
)
3659 *BaseAddress
= SafeBaseAddress
;
3661 if(SectionOffset
!= NULL
)
3663 *SectionOffset
= SafeSectionOffset
;
3665 if(ViewSize
!= NULL
)
3667 *ViewSize
= SafeViewSize
;
3672 Status
= _SEH_GetExceptionCode();
3681 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3682 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3685 PFILE_OBJECT FileObject
;
3688 SWAPENTRY SavedSwapEntry
;
3691 PSECTION_OBJECT Section
;
3692 PMM_SECTION_SEGMENT Segment
;
3693 PMADDRESS_SPACE AddressSpace
;
3695 AddressSpace
= (PMADDRESS_SPACE
)Context
;
3697 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3699 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3700 MemoryArea
->Data
.SectionData
.ViewOffset
;
3702 Section
= MemoryArea
->Data
.SectionData
.Section
;
3703 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3705 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3709 MmUnlockSectionSegment(Segment
);
3710 MmUnlockAddressSpace(AddressSpace
);
3712 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3713 if (Status
!= STATUS_SUCCESS
)
3715 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3719 MmLockAddressSpace(AddressSpace
);
3720 MmLockSectionSegment(Segment
);
3721 MmspCompleteAndReleasePageOp(PageOp
);
3722 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3725 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3728 * For a dirty, datafile, non-private page mark it as dirty in the
3731 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3733 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3735 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3736 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3737 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3738 ASSERT(SwapEntry
== 0);
3747 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3749 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3752 MmFreeSwapPage(SwapEntry
);
3756 if (IS_SWAP_FROM_SSE(Entry
) ||
3757 Page
!= PFN_FROM_SSE(Entry
))
3762 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3764 DPRINT1("Found a private page in a pagefile section.\n");
3768 * Just dereference private pages
3770 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3771 if (SavedSwapEntry
!= 0)
3773 MmFreeSwapPage(SavedSwapEntry
);
3774 MmSetSavedSwapEntryPage(Page
, 0);
3776 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3777 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3781 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3782 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3788 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3792 PMEMORY_AREA MemoryArea
;
3793 PSECTION_OBJECT Section
;
3794 PMM_SECTION_SEGMENT Segment
;
3795 PLIST_ENTRY CurrentEntry
;
3796 PMM_REGION CurrentRegion
;
3797 PLIST_ENTRY RegionListHead
;
3799 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3801 if (MemoryArea
== NULL
)
3803 return(STATUS_UNSUCCESSFUL
);
3806 MemoryArea
->DeleteInProgress
= TRUE
;
3807 Section
= MemoryArea
->Data
.SectionData
.Section
;
3808 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3810 MmLockSectionSegment(Segment
);
3812 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3813 while (!IsListEmpty(RegionListHead
))
3815 CurrentEntry
= RemoveHeadList(RegionListHead
);
3816 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3817 ExFreePool(CurrentRegion
);
3820 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3822 Status
= MmFreeMemoryArea(AddressSpace
,
3829 Status
= MmFreeMemoryArea(AddressSpace
,
3834 MmUnlockSectionSegment(Segment
);
3835 ObDereferenceObject(Section
);
3836 return(STATUS_SUCCESS
);
3843 MmUnmapViewOfSection(PEPROCESS Process
,
3847 PMEMORY_AREA MemoryArea
;
3848 PMADDRESS_SPACE AddressSpace
;
3849 PSECTION_OBJECT Section
;
3851 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3852 Process
, BaseAddress
);
3856 AddressSpace
= &Process
->AddressSpace
;
3857 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3859 if (MemoryArea
== NULL
||
3860 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
3861 MemoryArea
->DeleteInProgress
)
3863 return STATUS_NOT_MAPPED_VIEW
;
3866 Section
= MemoryArea
->Data
.SectionData
.Section
;
3868 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3872 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3873 PMM_SECTION_SEGMENT SectionSegments
;
3874 PVOID ImageBaseAddress
= 0;
3875 PMM_SECTION_SEGMENT Segment
;
3877 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3878 ImageSectionObject
= Section
->ImageSection
;
3879 SectionSegments
= ImageSectionObject
->Segments
;
3880 NrSegments
= ImageSectionObject
->NrSegments
;
3882 /* Search for the current segment within the section segments
3883 * and calculate the image base address */
3884 for (i
= 0; i
< NrSegments
; i
++)
3886 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3888 if (Segment
== &SectionSegments
[i
])
3890 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3895 if (i
>= NrSegments
)
3900 for (i
= 0; i
< NrSegments
; i
++)
3902 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3904 PVOID SBaseAddress
= (PVOID
)
3905 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3907 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
3913 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
3915 return(STATUS_SUCCESS
);
3918 /**********************************************************************
3920 * NtUnmapViewOfSection
3935 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3939 KPROCESSOR_MODE PreviousMode
;
3942 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3943 ProcessHandle
, BaseAddress
);
3945 PreviousMode
= ExGetPreviousMode();
3947 DPRINT("Referencing process\n");
3948 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3949 PROCESS_VM_OPERATION
,
3952 (PVOID
*)(PVOID
)&Process
,
3954 if (!NT_SUCCESS(Status
))
3956 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3960 MmLockAddressSpace(&Process
->AddressSpace
);
3961 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3962 MmUnlockAddressSpace(&Process
->AddressSpace
);
3964 ObDereferenceObject(Process
);
3971 * Queries the information of a section object.
3973 * @param SectionHandle
3974 * Handle to the section object. It must be opened with SECTION_QUERY
3976 * @param SectionInformationClass
3977 * Index to a certain information structure. Can be either
3978 * SectionBasicInformation or SectionImageInformation. The latter
3979 * is valid only for sections that were created with the SEC_IMAGE
3981 * @param SectionInformation
3982 * Caller supplies storage for resulting information.
3984 * Size of the supplied storage.
3985 * @param ResultLength
3993 NtQuerySection(IN HANDLE SectionHandle
,
3994 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
3995 OUT PVOID SectionInformation
,
3996 IN ULONG SectionInformationLength
,
3997 OUT PULONG ResultLength OPTIONAL
)
3999 PSECTION_OBJECT Section
;
4000 KPROCESSOR_MODE PreviousMode
;
4001 NTSTATUS Status
= STATUS_SUCCESS
;
4003 PreviousMode
= ExGetPreviousMode();
4005 DefaultQueryInfoBufferCheck(SectionInformationClass
,
4008 SectionInformationLength
,
4013 if(!NT_SUCCESS(Status
))
4015 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4019 Status
= ObReferenceObjectByHandle(SectionHandle
,
4021 MmSectionObjectType
,
4023 (PVOID
*)(PVOID
)&Section
,
4025 if (NT_SUCCESS(Status
))
4027 switch (SectionInformationClass
)
4029 case SectionBasicInformation
:
4031 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4035 Sbi
->Attributes
= Section
->AllocationAttributes
;
4036 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4038 Sbi
->BaseAddress
= 0;
4039 Sbi
->Size
.QuadPart
= 0;
4043 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4044 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4047 if (ResultLength
!= NULL
)
4049 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4051 Status
= STATUS_SUCCESS
;
4055 Status
= _SEH_GetExceptionCode();
4062 case SectionImageInformation
:
4064 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4068 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4069 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4071 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4072 ImageSectionObject
= Section
->ImageSection
;
4074 Sii
->EntryPoint
= ImageSectionObject
->EntryPoint
;
4075 Sii
->StackReserve
= ImageSectionObject
->StackReserve
;
4076 Sii
->StackCommit
= ImageSectionObject
->StackCommit
;
4077 Sii
->Subsystem
= ImageSectionObject
->Subsystem
;
4078 Sii
->MinorSubsystemVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4079 Sii
->MajorSubsystemVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4080 Sii
->Characteristics
= ImageSectionObject
->ImageCharacteristics
;
4081 Sii
->ImageNumber
= ImageSectionObject
->Machine
;
4082 Sii
->Executable
= ImageSectionObject
->Executable
;
4085 if (ResultLength
!= NULL
)
4087 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4089 Status
= STATUS_SUCCESS
;
4093 Status
= _SEH_GetExceptionCode();
4101 ObDereferenceObject(Section
);
4109 * Extends size of file backed section.
4111 * @param SectionHandle
4112 * Handle to the section object. It must be opened with
4113 * SECTION_EXTEND_SIZE access.
4114 * @param NewMaximumSize
4115 * New maximum size of the section in bytes.
4119 * @todo Move the actual code to internal function MmExtendSection.
4123 NtExtendSection(IN HANDLE SectionHandle
,
4124 IN PLARGE_INTEGER NewMaximumSize
)
4126 LARGE_INTEGER SafeNewMaximumSize
;
4127 PSECTION_OBJECT Section
;
4128 KPROCESSOR_MODE PreviousMode
;
4129 NTSTATUS Status
= STATUS_SUCCESS
;
4131 PreviousMode
= ExGetPreviousMode();
4133 if(PreviousMode
!= KernelMode
)
4137 ProbeForRead(NewMaximumSize
,
4138 sizeof(LARGE_INTEGER
),
4140 /* make a copy on the stack */
4141 SafeNewMaximumSize
= *NewMaximumSize
;
4142 NewMaximumSize
= &SafeNewMaximumSize
;
4146 Status
= _SEH_GetExceptionCode();
4150 if(!NT_SUCCESS(Status
))
4156 Status
= ObReferenceObjectByHandle(SectionHandle
,
4157 SECTION_EXTEND_SIZE
,
4158 MmSectionObjectType
,
4162 if (!NT_SUCCESS(Status
))
4167 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4169 ObfDereferenceObject(Section
);
4170 return STATUS_INVALID_PARAMETER
;
4174 * - Acquire file extneding resource.
4175 * - Check if we're not resizing the section below it's actual size!
4176 * - Extend segments if needed.
4177 * - Set file information (FileAllocationInformation) to the new size.
4178 * - Release file extending resource.
4181 ObDereferenceObject(Section
);
4183 return STATUS_NOT_IMPLEMENTED
;
4187 /**********************************************************************
4189 * MmAllocateSection@4
4199 * Code taken from ntoskrnl/mm/special.c.
4204 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4210 PMADDRESS_SPACE AddressSpace
;
4211 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4213 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4215 BoundaryAddressMultiple
.QuadPart
= 0;
4217 AddressSpace
= MmGetKernelAddressSpace();
4218 Result
= BaseAddress
;
4219 MmLockAddressSpace(AddressSpace
);
4220 Status
= MmCreateMemoryArea (NULL
,
4229 BoundaryAddressMultiple
);
4230 MmUnlockAddressSpace(AddressSpace
);
4232 if (!NT_SUCCESS(Status
))
4236 DPRINT("Result %p\n",Result
);
4237 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
4241 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
4242 if (!NT_SUCCESS(Status
))
4244 DbgPrint("Unable to allocate page\n");
4247 Status
= MmCreateVirtualMapping (NULL
,
4248 (PVOID
)((ULONG_PTR
)Result
+ (i
* PAGE_SIZE
)),
4252 if (!NT_SUCCESS(Status
))
4254 DbgPrint("Unable to create virtual mapping\n");
4258 return ((PVOID
)Result
);
4262 /**********************************************************************
4264 * MmMapViewOfSection
4267 * Maps a view of a section into the virtual address space of a
4272 * Pointer to the section object.
4275 * Pointer to the process.
4278 * Desired base address (or NULL) on entry;
4279 * Actual base address of the view on exit.
4282 * Number of high order address bits that must be zero.
4285 * Size in bytes of the initially committed section of
4289 * Offset in bytes from the beginning of the section
4290 * to the beginning of the view.
4293 * Desired length of map (or zero to map all) on entry
4294 * Actual length mapped on exit.
4296 * InheritDisposition
4297 * Specified how the view is to be shared with
4301 * Type of allocation for the pages.
4304 * Protection for the committed region of the view.
4312 MmMapViewOfSection(IN PVOID SectionObject
,
4313 IN PEPROCESS Process
,
4314 IN OUT PVOID
*BaseAddress
,
4316 IN ULONG CommitSize
,
4317 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4318 IN OUT PULONG ViewSize
,
4319 IN SECTION_INHERIT InheritDisposition
,
4320 IN ULONG AllocationType
,
4323 PSECTION_OBJECT Section
;
4324 PMADDRESS_SPACE AddressSpace
;
4326 NTSTATUS Status
= STATUS_SUCCESS
;
4330 Section
= (PSECTION_OBJECT
)SectionObject
;
4331 AddressSpace
= &Process
->AddressSpace
;
4333 MmLockAddressSpace(AddressSpace
);
4335 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4339 ULONG_PTR ImageBase
;
4341 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4342 PMM_SECTION_SEGMENT SectionSegments
;
4344 ImageSectionObject
= Section
->ImageSection
;
4345 SectionSegments
= ImageSectionObject
->Segments
;
4346 NrSegments
= ImageSectionObject
->NrSegments
;
4349 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4352 ImageBase
= ImageSectionObject
->ImageBase
;
4356 for (i
= 0; i
< NrSegments
; i
++)
4358 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4360 ULONG_PTR MaxExtent
;
4361 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4362 SectionSegments
[i
].Length
;
4363 ImageSize
= max(ImageSize
, MaxExtent
);
4367 /* Check there is enough space to map the section at that point. */
4368 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4369 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4371 /* Fail if the user requested a fixed base address. */
4372 if ((*BaseAddress
) != NULL
)
4374 MmUnlockAddressSpace(AddressSpace
);
4375 return(STATUS_UNSUCCESSFUL
);
4377 /* Otherwise find a gap to map the image. */
4378 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4381 MmUnlockAddressSpace(AddressSpace
);
4382 return(STATUS_UNSUCCESSFUL
);
4386 for (i
= 0; i
< NrSegments
; i
++)
4388 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4390 PVOID SBaseAddress
= (PVOID
)
4391 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4392 MmLockSectionSegment(&SectionSegments
[i
]);
4393 Status
= MmMapViewOfSegment(Process
,
4396 &SectionSegments
[i
],
4398 SectionSegments
[i
].Length
,
4399 SectionSegments
[i
].Protection
,
4402 MmUnlockSectionSegment(&SectionSegments
[i
]);
4403 if (!NT_SUCCESS(Status
))
4405 MmUnlockAddressSpace(AddressSpace
);
4411 *BaseAddress
= (PVOID
)ImageBase
;
4415 if (ViewSize
== NULL
)
4417 /* Following this pointer would lead to us to the dark side */
4418 /* What to do? Bugcheck? Return status? Do the mambo? */
4419 KEBUGCHECK(MEMORY_MANAGEMENT
);
4422 if (SectionOffset
== NULL
)
4428 ViewOffset
= SectionOffset
->u
.LowPart
;
4431 if ((ViewOffset
% PAGE_SIZE
) != 0)
4433 MmUnlockAddressSpace(AddressSpace
);
4434 return(STATUS_MAPPED_ALIGNMENT
);
4437 if ((*ViewSize
) == 0)
4439 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4441 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4443 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4446 MmLockSectionSegment(Section
->Segment
);
4447 Status
= MmMapViewOfSegment(Process
,
4455 (AllocationType
& MEM_TOP_DOWN
));
4456 MmUnlockSectionSegment(Section
->Segment
);
4457 if (!NT_SUCCESS(Status
))
4459 MmUnlockAddressSpace(AddressSpace
);
4464 MmUnlockAddressSpace(AddressSpace
);
4466 return(STATUS_SUCCESS
);
4473 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4474 IN PLARGE_INTEGER NewFileSize
)
4485 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
4495 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4496 IN MMFLUSH_TYPE FlushType
)
4500 case MmFlushForDelete
:
4501 if (SectionObjectPointer
->ImageSectionObject
||
4502 SectionObjectPointer
->DataSectionObject
)
4506 CcRosSetRemoveOnClose(SectionObjectPointer
);
4508 case MmFlushForWrite
:
4518 MmForceSectionClosed (
4519 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4520 IN BOOLEAN DelayClose
)
4531 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4532 OUT PVOID
* MappedBase
,
4533 IN OUT PULONG ViewSize
)
4535 PSECTION_OBJECT Section
;
4536 PMADDRESS_SPACE AddressSpace
;
4539 DPRINT("MmMapViewInSystemSpace() called\n");
4541 Section
= (PSECTION_OBJECT
)SectionObject
;
4542 AddressSpace
= MmGetKernelAddressSpace();
4544 MmLockAddressSpace(AddressSpace
);
4547 if ((*ViewSize
) == 0)
4549 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4551 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4553 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4556 MmLockSectionSegment(Section
->Segment
);
4559 Status
= MmMapViewOfSegment(NULL
,
4569 MmUnlockSectionSegment(Section
->Segment
);
4570 MmUnlockAddressSpace(AddressSpace
);
4580 MmMapViewInSessionSpace (
4582 OUT PVOID
*MappedBase
,
4583 IN OUT PSIZE_T ViewSize
4587 return STATUS_NOT_IMPLEMENTED
;
4595 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4597 PMADDRESS_SPACE AddressSpace
;
4600 DPRINT("MmUnmapViewInSystemSpace() called\n");
4602 AddressSpace
= MmGetKernelAddressSpace();
4604 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4614 MmUnmapViewInSessionSpace (
4619 return STATUS_NOT_IMPLEMENTED
;
4626 MmSetBankedSection (DWORD Unknown0
,
4634 return (STATUS_NOT_IMPLEMENTED
);
4638 /**********************************************************************
4643 * Creates a section object.
4646 * SectionObject (OUT)
4647 * Caller supplied storage for the resulting pointer
4648 * to a SECTION_OBJECT instance;
4651 * Specifies the desired access to the section can be a
4653 * STANDARD_RIGHTS_REQUIRED |
4655 * SECTION_MAP_WRITE |
4656 * SECTION_MAP_READ |
4657 * SECTION_MAP_EXECUTE
4659 * ObjectAttributes [OPTIONAL]
4660 * Initialized attributes for the object can be used
4661 * to create a named section;
4664 * Maximizes the size of the memory section. Must be
4665 * non-NULL for a page-file backed section.
4666 * If value specified for a mapped file and the file is
4667 * not large enough, file will be extended.
4669 * SectionPageProtection
4670 * Can be a combination of:
4676 * AllocationAttributes
4677 * Can be a combination of:
4682 * Handle to a file to create a section mapped to a file
4683 * instead of a memory backed section;
4694 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4695 IN ACCESS_MASK DesiredAccess
,
4696 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4697 IN PLARGE_INTEGER MaximumSize
,
4698 IN ULONG SectionPageProtection
,
4699 IN ULONG AllocationAttributes
,
4700 IN HANDLE FileHandle OPTIONAL
,
4701 IN PFILE_OBJECT File OPTIONAL
)
4703 if (AllocationAttributes
& SEC_IMAGE
)
4705 return(MmCreateImageSection(SectionObject
,
4709 SectionPageProtection
,
4710 AllocationAttributes
,
4714 if (FileHandle
!= NULL
)
4716 return(MmCreateDataFileSection(SectionObject
,
4720 SectionPageProtection
,
4721 AllocationAttributes
,
4725 return(MmCreatePageFileSection(SectionObject
,
4729 SectionPageProtection
,
4730 AllocationAttributes
));