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
= IoQueryFileInformation(FileObject
,
2312 FileStandardInformation
,
2313 sizeof(FILE_STANDARD_INFORMATION
),
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
= IoSetInformation(FileObject
,
2346 FileAllocationInformation
,
2347 sizeof(LARGE_INTEGER
),
2349 if (!NT_SUCCESS(Status
))
2351 ObDereferenceObject(Section
);
2352 ObDereferenceObject(FileObject
);
2353 return(STATUS_SECTION_NOT_EXTENDED
);
2357 if (FileObject
->SectionObjectPointer
== NULL
||
2358 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2361 * Read a bit so caching is initiated for the file object.
2362 * This is only needed because MiReadPage currently cannot
2363 * handle non-cached streams.
2365 Offset
.QuadPart
= 0;
2366 Status
= ZwReadFile(FileHandle
,
2375 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2377 ObDereferenceObject(Section
);
2378 ObDereferenceObject(FileObject
);
2381 if (FileObject
->SectionObjectPointer
== NULL
||
2382 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2384 /* FIXME: handle this situation */
2385 ObDereferenceObject(Section
);
2386 ObDereferenceObject(FileObject
);
2387 return STATUS_INVALID_PARAMETER
;
2394 Status
= MmspWaitForFileLock(FileObject
);
2395 if (Status
!= STATUS_SUCCESS
)
2397 ObDereferenceObject(Section
);
2398 ObDereferenceObject(FileObject
);
2403 * If this file hasn't been mapped as a data file before then allocate a
2404 * section segment to describe the data file mapping
2406 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2408 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2409 TAG_MM_SECTION_SEGMENT
);
2410 if (Segment
== NULL
)
2412 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2413 ObDereferenceObject(Section
);
2414 ObDereferenceObject(FileObject
);
2415 return(STATUS_NO_MEMORY
);
2417 Section
->Segment
= Segment
;
2418 Segment
->ReferenceCount
= 1;
2419 ExInitializeFastMutex(&Segment
->Lock
);
2421 * Set the lock before assigning the segment to the file object
2423 ExAcquireFastMutex(&Segment
->Lock
);
2424 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2426 Segment
->FileOffset
= 0;
2427 Segment
->Protection
= SectionPageProtection
;
2428 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2429 Segment
->Characteristics
= 0;
2430 Segment
->WriteCopy
= FALSE
;
2431 if (AllocationAttributes
& SEC_RESERVE
)
2433 Segment
->Length
= Segment
->RawLength
= 0;
2437 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2438 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2440 Segment
->VirtualAddress
= 0;
2441 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2446 * If the file is already mapped as a data file then we may need
2450 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2452 Section
->Segment
= Segment
;
2453 InterlockedIncrementUL(&Segment
->ReferenceCount
);
2454 MmLockSectionSegment(Segment
);
2456 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2457 !(AllocationAttributes
& SEC_RESERVE
))
2459 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2460 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2463 MmUnlockSectionSegment(Segment
);
2464 Section
->FileObject
= FileObject
;
2465 Section
->MaximumSize
= MaximumSize
;
2466 CcRosReferenceCache(FileObject
);
2467 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2468 *SectionObject
= Section
;
2469 return(STATUS_SUCCESS
);
2473 TODO: not that great (declaring loaders statically, having to declare all of
2474 them, having to keep them extern, etc.), will fix in the future
2476 extern NTSTATUS NTAPI PeFmtCreateSection
2478 IN CONST VOID
* FileHeader
,
2479 IN SIZE_T FileHeaderSize
,
2481 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2483 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2484 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2487 extern NTSTATUS NTAPI ElfFmtCreateSection
2489 IN CONST VOID
* FileHeader
,
2490 IN SIZE_T FileHeaderSize
,
2492 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2494 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2495 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2498 /* TODO: this is a standard DDK/PSDK macro */
2499 #ifndef RTL_NUMBER_OF
2500 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2503 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2512 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2514 SIZE_T SizeOfSegments
;
2515 PMM_SECTION_SEGMENT Segments
;
2517 /* TODO: check for integer overflow */
2518 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2520 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2522 TAG_MM_SECTION_SEGMENT
);
2525 RtlZeroMemory(Segments
, SizeOfSegments
);
2533 ExeFmtpReadFile(IN PVOID File
,
2534 IN PLARGE_INTEGER Offset
,
2537 OUT PVOID
* AllocBase
,
2538 OUT PULONG ReadSize
)
2541 LARGE_INTEGER FileOffset
;
2543 ULONG OffsetAdjustment
;
2548 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2552 KEBUGCHECK(STATUS_INVALID_PARAMETER_4
);
2555 FileOffset
= *Offset
;
2557 /* Negative/special offset: it cannot be used in this context */
2558 if(FileOffset
.u
.HighPart
< 0)
2560 KEBUGCHECK(STATUS_INVALID_PARAMETER_5
);
2563 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2564 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2565 FileOffset
.u
.LowPart
= AdjustOffset
;
2567 BufferSize
= Length
+ OffsetAdjustment
;
2568 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2571 * It's ok to use paged pool, because this is a temporary buffer only used in
2572 * the loading of executables. The assumption is that MmCreateSection is
2573 * always called at low IRQLs and that these buffers don't survive a brief
2574 * initialization phase
2576 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2578 TAG('M', 'm', 'X', 'r'));
2583 Status
= MmspPageRead(File
,
2590 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2591 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2592 * to initialize internal state is even worse. Our cache manager is in need of
2596 IO_STATUS_BLOCK Iosb
;
2598 Status
= ZwReadFile(File
,
2608 if(NT_SUCCESS(Status
))
2610 UsedSize
= Iosb
.Information
;
2615 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2617 Status
= STATUS_IN_PAGE_ERROR
;
2618 ASSERT(!NT_SUCCESS(Status
));
2621 if(NT_SUCCESS(Status
))
2623 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2624 *AllocBase
= Buffer
;
2625 *ReadSize
= UsedSize
- OffsetAdjustment
;
2636 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2637 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2638 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2643 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2647 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2649 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2650 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2657 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2661 MmspAssertSegmentsSorted(ImageSectionObject
);
2663 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2665 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2669 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2670 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2671 ImageSectionObject
->Segments
[i
- 1].Length
));
2679 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2683 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2685 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2686 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2694 MmspCompareSegments(const void * x
,
2697 PMM_SECTION_SEGMENT Segment1
= (PMM_SECTION_SEGMENT
)x
;
2698 PMM_SECTION_SEGMENT Segment2
= (PMM_SECTION_SEGMENT
)y
;
2701 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2702 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2706 * Ensures an image section's segments are sorted in memory
2711 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2714 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2716 MmspAssertSegmentsSorted(ImageSectionObject
);
2720 qsort(ImageSectionObject
->Segments
,
2721 ImageSectionObject
->NrSegments
,
2722 sizeof(ImageSectionObject
->Segments
[0]),
2723 MmspCompareSegments
);
2729 * Ensures an image section's segments don't overlap in memory and don't have
2730 * gaps and don't have a null size. We let them map to overlapping file regions,
2731 * though - that's not necessarily an error
2736 MmspCheckSegmentBounds
2738 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2744 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2746 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2750 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2752 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2754 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2762 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2763 * page could be OK (Windows seems to be OK with them), and larger gaps
2764 * could lead to image sections spanning several discontiguous regions
2765 * (NtMapViewOfSection could then refuse to map them, and they could
2766 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2768 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2769 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2770 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2781 * Merges and pads an image section's segments until they all are page-aligned
2782 * and have a size that is a multiple of the page size
2787 MmspPageAlignSegments
2789 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2795 BOOLEAN Initialized
;
2797 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2799 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2803 Initialized
= FALSE
;
2806 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2808 PMM_SECTION_SEGMENT EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2811 * The first segment requires special handling
2815 ULONG_PTR VirtualAddress
;
2816 ULONG_PTR VirtualOffset
;
2818 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2820 /* Round down the virtual address to the nearest page */
2821 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2823 /* Round up the virtual size to the nearest page */
2824 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2825 EffectiveSegment
->VirtualAddress
;
2827 /* Adjust the raw address and size */
2828 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2830 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
2836 * Garbage in, garbage out: unaligned base addresses make the file
2837 * offset point in curious and odd places, but that's what we were
2840 EffectiveSegment
->FileOffset
-= VirtualOffset
;
2841 EffectiveSegment
->RawLength
+= VirtualOffset
;
2845 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
2846 ULONG_PTR EndOfEffectiveSegment
;
2848 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
2849 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
2852 * The current segment begins exactly where the current effective
2853 * segment ended, therefore beginning a new effective segment
2855 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
2858 ASSERT(LastSegment
<= i
);
2859 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
2861 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2864 * Copy the current segment. If necessary, the effective segment
2865 * will be expanded later
2867 *EffectiveSegment
= *Segment
;
2870 * Page-align the virtual size. We know for sure the virtual address
2873 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
2874 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
2877 * The current segment is still part of the current effective segment:
2878 * extend the effective segment to reflect this
2880 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
2882 static const ULONG FlagsToProtection
[16] =
2890 PAGE_EXECUTE_READWRITE
,
2891 PAGE_EXECUTE_READWRITE
,
2896 PAGE_EXECUTE_WRITECOPY
,
2897 PAGE_EXECUTE_WRITECOPY
,
2898 PAGE_EXECUTE_WRITECOPY
,
2899 PAGE_EXECUTE_WRITECOPY
2902 unsigned ProtectionFlags
;
2905 * Extend the file size
2908 /* Unaligned segments must be contiguous within the file */
2909 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
2910 EffectiveSegment
->RawLength
))
2915 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
2918 * Extend the virtual size
2920 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) > EndOfEffectiveSegment
);
2922 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
2923 EffectiveSegment
->VirtualAddress
;
2926 * Merge the protection
2928 EffectiveSegment
->Protection
|= Segment
->Protection
;
2930 /* Clean up redundance */
2931 ProtectionFlags
= 0;
2933 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
2934 ProtectionFlags
|= 1 << 0;
2936 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
2937 ProtectionFlags
|= 1 << 1;
2939 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
2940 ProtectionFlags
|= 1 << 2;
2942 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2943 ProtectionFlags
|= 1 << 3;
2945 ASSERT(ProtectionFlags
< 16);
2946 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
2948 /* If a segment was required to be shared and cannot, fail */
2949 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
2950 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2956 * We assume no holes between segments at this point
2969 ExeFmtpCreateImageSection(HANDLE FileHandle
,
2970 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2972 LARGE_INTEGER Offset
;
2974 PVOID FileHeaderBuffer
;
2975 ULONG FileHeaderSize
;
2977 ULONG OldNrSegments
;
2982 * Read the beginning of the file (2 pages). Should be enough to contain
2983 * all (or most) of the headers
2985 Offset
.QuadPart
= 0;
2987 /* FIXME: use FileObject instead of FileHandle */
2988 Status
= ExeFmtpReadFile (FileHandle
,
2995 if (!NT_SUCCESS(Status
))
2998 if (FileHeaderSize
== 0)
3000 ExFreePool(FileHeaderBuffer
);
3001 return STATUS_UNSUCCESSFUL
;
3005 * Look for a loader that can handle this executable
3007 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3009 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3012 /* FIXME: use FileObject instead of FileHandle */
3013 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3019 ExeFmtpAllocateSegments
);
3021 if (!NT_SUCCESS(Status
))
3023 if (ImageSectionObject
->Segments
)
3025 ExFreePool(ImageSectionObject
->Segments
);
3026 ImageSectionObject
->Segments
= NULL
;
3030 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3034 ExFreePool(FileHeaderBuffer
);
3037 * No loader handled the format
3039 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3041 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3042 ASSERT(!NT_SUCCESS(Status
));
3045 if (!NT_SUCCESS(Status
))
3048 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3053 /* FIXME? are these values platform-dependent? */
3054 if(ImageSectionObject
->StackReserve
== 0)
3055 ImageSectionObject
->StackReserve
= 0x40000;
3057 if(ImageSectionObject
->StackCommit
== 0)
3058 ImageSectionObject
->StackCommit
= 0x1000;
3060 if(ImageSectionObject
->ImageBase
== 0)
3062 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3063 ImageSectionObject
->ImageBase
= 0x10000000;
3065 ImageSectionObject
->ImageBase
= 0x00400000;
3069 * And now the fun part: fixing the segments
3072 /* Sort them by virtual address */
3073 MmspSortSegments(ImageSectionObject
, Flags
);
3075 /* Ensure they don't overlap in memory */
3076 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3077 return STATUS_INVALID_IMAGE_FORMAT
;
3079 /* Ensure they are aligned */
3080 OldNrSegments
= ImageSectionObject
->NrSegments
;
3082 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3083 return STATUS_INVALID_IMAGE_FORMAT
;
3085 /* Trim them if the alignment phase merged some of them */
3086 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3088 PMM_SECTION_SEGMENT Segments
;
3089 SIZE_T SizeOfSegments
;
3091 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3093 Segments
= ExAllocatePoolWithTag(PagedPool
,
3095 TAG_MM_SECTION_SEGMENT
);
3097 if (Segments
== NULL
)
3098 return STATUS_INSUFFICIENT_RESOURCES
;
3100 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3101 ExFreePool(ImageSectionObject
->Segments
);
3102 ImageSectionObject
->Segments
= Segments
;
3105 /* And finish their initialization */
3106 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3108 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3109 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3111 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3112 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3115 ASSERT(NT_SUCCESS(Status
));
3120 MmCreateImageSection(PSECTION_OBJECT
*SectionObject
,
3121 ACCESS_MASK DesiredAccess
,
3122 POBJECT_ATTRIBUTES ObjectAttributes
,
3123 PLARGE_INTEGER UMaximumSize
,
3124 ULONG SectionPageProtection
,
3125 ULONG AllocationAttributes
,
3128 PSECTION_OBJECT Section
;
3130 PFILE_OBJECT FileObject
;
3131 PMM_SECTION_SEGMENT SectionSegments
;
3132 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3134 ULONG FileAccess
= 0;
3137 * Specifying a maximum size is meaningless for an image section
3139 if (UMaximumSize
!= NULL
)
3141 return(STATUS_INVALID_PARAMETER_4
);
3145 * Check file access required
3147 if (SectionPageProtection
& PAGE_READWRITE
||
3148 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3150 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3154 FileAccess
= FILE_READ_DATA
;
3158 * Reference the file handle
3160 Status
= ObReferenceObjectByHandle(FileHandle
,
3164 (PVOID
*)(PVOID
)&FileObject
,
3167 if (!NT_SUCCESS(Status
))
3173 * Create the section
3175 Status
= ObCreateObject (ExGetPreviousMode(),
3176 MmSectionObjectType
,
3178 ExGetPreviousMode(),
3180 sizeof(SECTION_OBJECT
),
3183 (PVOID
*)(PVOID
)&Section
);
3184 if (!NT_SUCCESS(Status
))
3186 ObDereferenceObject(FileObject
);
3193 Section
->SectionPageProtection
= SectionPageProtection
;
3194 Section
->AllocationAttributes
= AllocationAttributes
;
3197 * Initialized caching for this file object if previously caching
3198 * was initialized for the same on disk file
3200 Status
= CcTryToInitializeFileCache(FileObject
);
3202 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3204 NTSTATUS StatusExeFmt
;
3206 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3207 if (ImageSectionObject
== NULL
)
3209 ObDereferenceObject(FileObject
);
3210 ObDereferenceObject(Section
);
3211 return(STATUS_NO_MEMORY
);
3214 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3216 if (!NT_SUCCESS(StatusExeFmt
))
3218 if(ImageSectionObject
->Segments
!= NULL
)
3219 ExFreePool(ImageSectionObject
->Segments
);
3221 ExFreePool(ImageSectionObject
);
3222 ObDereferenceObject(Section
);
3223 ObDereferenceObject(FileObject
);
3224 return(StatusExeFmt
);
3227 Section
->ImageSection
= ImageSectionObject
;
3228 ASSERT(ImageSectionObject
->Segments
);
3233 Status
= MmspWaitForFileLock(FileObject
);
3234 if (!NT_SUCCESS(Status
))
3236 ExFreePool(ImageSectionObject
->Segments
);
3237 ExFreePool(ImageSectionObject
);
3238 ObDereferenceObject(Section
);
3239 ObDereferenceObject(FileObject
);
3243 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3244 ImageSectionObject
, NULL
))
3247 * An other thread has initialized the some image in the background
3249 ExFreePool(ImageSectionObject
->Segments
);
3250 ExFreePool(ImageSectionObject
);
3251 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3252 Section
->ImageSection
= ImageSectionObject
;
3253 SectionSegments
= ImageSectionObject
->Segments
;
3255 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3257 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3261 Status
= StatusExeFmt
;
3268 Status
= MmspWaitForFileLock(FileObject
);
3269 if (Status
!= STATUS_SUCCESS
)
3271 ObDereferenceObject(Section
);
3272 ObDereferenceObject(FileObject
);
3276 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3277 Section
->ImageSection
= ImageSectionObject
;
3278 SectionSegments
= ImageSectionObject
->Segments
;
3281 * Otherwise just reference all the section segments
3283 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3285 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3288 Status
= STATUS_SUCCESS
;
3290 Section
->FileObject
= FileObject
;
3291 CcRosReferenceCache(FileObject
);
3292 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
3293 *SectionObject
= Section
;
3301 NtCreateSection (OUT PHANDLE SectionHandle
,
3302 IN ACCESS_MASK DesiredAccess
,
3303 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3304 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3305 IN ULONG SectionPageProtection OPTIONAL
,
3306 IN ULONG AllocationAttributes
,
3307 IN HANDLE FileHandle OPTIONAL
)
3309 LARGE_INTEGER SafeMaximumSize
;
3310 PSECTION_OBJECT SectionObject
;
3311 KPROCESSOR_MODE PreviousMode
;
3312 NTSTATUS Status
= STATUS_SUCCESS
;
3314 PreviousMode
= ExGetPreviousMode();
3316 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3320 ProbeForRead(MaximumSize
,
3321 sizeof(LARGE_INTEGER
),
3323 /* make a copy on the stack */
3324 SafeMaximumSize
= *MaximumSize
;
3325 MaximumSize
= &SafeMaximumSize
;
3329 Status
= _SEH_GetExceptionCode();
3333 if(!NT_SUCCESS(Status
))
3340 * Check the protection
3342 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
3343 SectionPageProtection
)
3345 return(STATUS_INVALID_PAGE_PROTECTION
);
3348 Status
= MmCreateSection(&SectionObject
,
3352 SectionPageProtection
,
3353 AllocationAttributes
,
3357 if (NT_SUCCESS(Status
))
3359 Status
= ObInsertObject ((PVOID
)SectionObject
,
3365 ObDereferenceObject(SectionObject
);
3372 /**********************************************************************
3390 NtOpenSection(PHANDLE SectionHandle
,
3391 ACCESS_MASK DesiredAccess
,
3392 POBJECT_ATTRIBUTES ObjectAttributes
)
3395 KPROCESSOR_MODE PreviousMode
;
3396 NTSTATUS Status
= STATUS_SUCCESS
;
3398 PreviousMode
= ExGetPreviousMode();
3400 if(PreviousMode
!= KernelMode
)
3404 ProbeForWrite(SectionHandle
,
3410 Status
= _SEH_GetExceptionCode();
3414 if(!NT_SUCCESS(Status
))
3420 Status
= ObOpenObjectByName(ObjectAttributes
,
3421 MmSectionObjectType
,
3428 if(NT_SUCCESS(Status
))
3432 *SectionHandle
= hSection
;
3436 Status
= _SEH_GetExceptionCode();
3445 MmMapViewOfSegment(PEPROCESS Process
,
3446 PMADDRESS_SPACE AddressSpace
,
3447 PSECTION_OBJECT Section
,
3448 PMM_SECTION_SEGMENT Segment
,
3457 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3459 BoundaryAddressMultiple
.QuadPart
= 0;
3461 Status
= MmCreateMemoryArea(Process
,
3463 MEMORY_AREA_SECTION_VIEW
,
3470 BoundaryAddressMultiple
);
3471 if (!NT_SUCCESS(Status
))
3473 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3474 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3479 ObReferenceObjectByPointer((PVOID
)Section
,
3482 ExGetPreviousMode());
3483 MArea
->Data
.SectionData
.Segment
= Segment
;
3484 MArea
->Data
.SectionData
.Section
= Section
;
3485 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3486 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3487 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3488 ViewSize
, 0, Protect
);
3490 return(STATUS_SUCCESS
);
3494 /**********************************************************************
3496 * NtMapViewOfSection
3499 * Maps a view of a section into the virtual address space of a
3504 * Handle of the section.
3507 * Handle of the process.
3510 * Desired base address (or NULL) on entry;
3511 * Actual base address of the view on exit.
3514 * Number of high order address bits that must be zero.
3517 * Size in bytes of the initially committed section of
3521 * Offset in bytes from the beginning of the section
3522 * to the beginning of the view.
3525 * Desired length of map (or zero to map all) on entry
3526 * Actual length mapped on exit.
3528 * InheritDisposition
3529 * Specified how the view is to be shared with
3533 * Type of allocation for the pages.
3536 * Protection for the committed region of the view.
3544 NtMapViewOfSection(IN HANDLE SectionHandle
,
3545 IN HANDLE ProcessHandle
,
3546 IN OUT PVOID
* BaseAddress OPTIONAL
,
3547 IN ULONG ZeroBits OPTIONAL
,
3548 IN ULONG CommitSize
,
3549 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3550 IN OUT PULONG ViewSize
,
3551 IN SECTION_INHERIT InheritDisposition
,
3552 IN ULONG AllocationType OPTIONAL
,
3555 PVOID SafeBaseAddress
;
3556 LARGE_INTEGER SafeSectionOffset
;
3558 PSECTION_OBJECT Section
;
3560 KPROCESSOR_MODE PreviousMode
;
3561 PMADDRESS_SPACE AddressSpace
;
3562 NTSTATUS Status
= STATUS_SUCCESS
;
3564 PreviousMode
= ExGetPreviousMode();
3566 if(PreviousMode
!= KernelMode
)
3568 SafeBaseAddress
= NULL
;
3569 SafeSectionOffset
.QuadPart
= 0;
3574 if(BaseAddress
!= NULL
)
3576 ProbeForWrite(BaseAddress
,
3579 SafeBaseAddress
= *BaseAddress
;
3581 if(SectionOffset
!= NULL
)
3583 ProbeForWrite(SectionOffset
,
3584 sizeof(LARGE_INTEGER
),
3586 SafeSectionOffset
= *SectionOffset
;
3588 ProbeForWrite(ViewSize
,
3591 SafeViewSize
= *ViewSize
;
3595 Status
= _SEH_GetExceptionCode();
3599 if(!NT_SUCCESS(Status
))
3606 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3607 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3608 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3611 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3612 PROCESS_VM_OPERATION
,
3615 (PVOID
*)(PVOID
)&Process
,
3617 if (!NT_SUCCESS(Status
))
3622 AddressSpace
= &Process
->AddressSpace
;
3624 Status
= ObReferenceObjectByHandle(SectionHandle
,
3626 MmSectionObjectType
,
3628 (PVOID
*)(PVOID
)&Section
,
3630 if (!(NT_SUCCESS(Status
)))
3632 DPRINT("ObReference failed rc=%x\n",Status
);
3633 ObDereferenceObject(Process
);
3637 Status
= MmMapViewOfSection(Section
,
3639 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3642 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3643 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3648 ObDereferenceObject(Section
);
3649 ObDereferenceObject(Process
);
3651 if(NT_SUCCESS(Status
))
3653 /* copy parameters back to the caller */
3656 if(BaseAddress
!= NULL
)
3658 *BaseAddress
= SafeBaseAddress
;
3660 if(SectionOffset
!= NULL
)
3662 *SectionOffset
= SafeSectionOffset
;
3664 if(ViewSize
!= NULL
)
3666 *ViewSize
= SafeViewSize
;
3671 Status
= _SEH_GetExceptionCode();
3680 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3681 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3684 PFILE_OBJECT FileObject
;
3687 SWAPENTRY SavedSwapEntry
;
3690 PSECTION_OBJECT Section
;
3691 PMM_SECTION_SEGMENT Segment
;
3692 PMADDRESS_SPACE AddressSpace
;
3694 AddressSpace
= (PMADDRESS_SPACE
)Context
;
3696 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3698 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3699 MemoryArea
->Data
.SectionData
.ViewOffset
;
3701 Section
= MemoryArea
->Data
.SectionData
.Section
;
3702 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3704 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3708 MmUnlockSectionSegment(Segment
);
3709 MmUnlockAddressSpace(AddressSpace
);
3711 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3712 if (Status
!= STATUS_SUCCESS
)
3714 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3718 MmLockAddressSpace(AddressSpace
);
3719 MmLockSectionSegment(Segment
);
3720 MmspCompleteAndReleasePageOp(PageOp
);
3721 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3724 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3727 * For a dirty, datafile, non-private page mark it as dirty in the
3730 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3732 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3734 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3735 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3736 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3737 ASSERT(SwapEntry
== 0);
3746 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3748 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3751 MmFreeSwapPage(SwapEntry
);
3755 if (IS_SWAP_FROM_SSE(Entry
) ||
3756 Page
!= PFN_FROM_SSE(Entry
))
3761 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3763 DPRINT1("Found a private page in a pagefile section.\n");
3767 * Just dereference private pages
3769 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3770 if (SavedSwapEntry
!= 0)
3772 MmFreeSwapPage(SavedSwapEntry
);
3773 MmSetSavedSwapEntryPage(Page
, 0);
3775 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3776 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3780 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3781 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3787 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3791 PMEMORY_AREA MemoryArea
;
3792 PSECTION_OBJECT Section
;
3793 PMM_SECTION_SEGMENT Segment
;
3794 PLIST_ENTRY CurrentEntry
;
3795 PMM_REGION CurrentRegion
;
3796 PLIST_ENTRY RegionListHead
;
3798 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3800 if (MemoryArea
== NULL
)
3802 return(STATUS_UNSUCCESSFUL
);
3805 MemoryArea
->DeleteInProgress
= TRUE
;
3806 Section
= MemoryArea
->Data
.SectionData
.Section
;
3807 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3809 MmLockSectionSegment(Segment
);
3811 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3812 while (!IsListEmpty(RegionListHead
))
3814 CurrentEntry
= RemoveHeadList(RegionListHead
);
3815 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3816 ExFreePool(CurrentRegion
);
3819 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3821 Status
= MmFreeMemoryArea(AddressSpace
,
3828 Status
= MmFreeMemoryArea(AddressSpace
,
3833 MmUnlockSectionSegment(Segment
);
3834 ObDereferenceObject(Section
);
3835 return(STATUS_SUCCESS
);
3842 MmUnmapViewOfSection(PEPROCESS Process
,
3846 PMEMORY_AREA MemoryArea
;
3847 PMADDRESS_SPACE AddressSpace
;
3848 PSECTION_OBJECT Section
;
3850 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3851 Process
, BaseAddress
);
3855 AddressSpace
= &Process
->AddressSpace
;
3856 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3858 if (MemoryArea
== NULL
||
3859 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
3860 MemoryArea
->DeleteInProgress
)
3862 return STATUS_NOT_MAPPED_VIEW
;
3865 Section
= MemoryArea
->Data
.SectionData
.Section
;
3867 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3871 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3872 PMM_SECTION_SEGMENT SectionSegments
;
3873 PVOID ImageBaseAddress
= 0;
3874 PMM_SECTION_SEGMENT Segment
;
3876 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3877 ImageSectionObject
= Section
->ImageSection
;
3878 SectionSegments
= ImageSectionObject
->Segments
;
3879 NrSegments
= ImageSectionObject
->NrSegments
;
3881 /* Search for the current segment within the section segments
3882 * and calculate the image base address */
3883 for (i
= 0; i
< NrSegments
; i
++)
3885 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3887 if (Segment
== &SectionSegments
[i
])
3889 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3894 if (i
>= NrSegments
)
3899 for (i
= 0; i
< NrSegments
; i
++)
3901 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3903 PVOID SBaseAddress
= (PVOID
)
3904 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3906 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
3912 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
3914 return(STATUS_SUCCESS
);
3917 /**********************************************************************
3919 * NtUnmapViewOfSection
3934 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3938 KPROCESSOR_MODE PreviousMode
;
3941 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3942 ProcessHandle
, BaseAddress
);
3944 PreviousMode
= ExGetPreviousMode();
3946 DPRINT("Referencing process\n");
3947 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3948 PROCESS_VM_OPERATION
,
3951 (PVOID
*)(PVOID
)&Process
,
3953 if (!NT_SUCCESS(Status
))
3955 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3959 MmLockAddressSpace(&Process
->AddressSpace
);
3960 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3961 MmUnlockAddressSpace(&Process
->AddressSpace
);
3963 ObDereferenceObject(Process
);
3970 * Queries the information of a section object.
3972 * @param SectionHandle
3973 * Handle to the section object. It must be opened with SECTION_QUERY
3975 * @param SectionInformationClass
3976 * Index to a certain information structure. Can be either
3977 * SectionBasicInformation or SectionImageInformation. The latter
3978 * is valid only for sections that were created with the SEC_IMAGE
3980 * @param SectionInformation
3981 * Caller supplies storage for resulting information.
3983 * Size of the supplied storage.
3984 * @param ResultLength
3992 NtQuerySection(IN HANDLE SectionHandle
,
3993 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
3994 OUT PVOID SectionInformation
,
3995 IN ULONG SectionInformationLength
,
3996 OUT PULONG ResultLength OPTIONAL
)
3998 PSECTION_OBJECT Section
;
3999 KPROCESSOR_MODE PreviousMode
;
4000 NTSTATUS Status
= STATUS_SUCCESS
;
4002 PreviousMode
= ExGetPreviousMode();
4004 DefaultQueryInfoBufferCheck(SectionInformationClass
,
4007 SectionInformationLength
,
4012 if(!NT_SUCCESS(Status
))
4014 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4018 Status
= ObReferenceObjectByHandle(SectionHandle
,
4020 MmSectionObjectType
,
4022 (PVOID
*)(PVOID
)&Section
,
4024 if (NT_SUCCESS(Status
))
4026 switch (SectionInformationClass
)
4028 case SectionBasicInformation
:
4030 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4034 Sbi
->Attributes
= Section
->AllocationAttributes
;
4035 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4037 Sbi
->BaseAddress
= 0;
4038 Sbi
->Size
.QuadPart
= 0;
4042 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4043 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4046 if (ResultLength
!= NULL
)
4048 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4050 Status
= STATUS_SUCCESS
;
4054 Status
= _SEH_GetExceptionCode();
4061 case SectionImageInformation
:
4063 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4067 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4068 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4070 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4071 ImageSectionObject
= Section
->ImageSection
;
4073 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4074 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4075 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4076 Sii
->SubsystemType
= ImageSectionObject
->Subsystem
;
4077 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4078 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4079 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4080 Sii
->Machine
= ImageSectionObject
->Machine
;
4081 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4084 if (ResultLength
!= NULL
)
4086 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4088 Status
= STATUS_SUCCESS
;
4092 Status
= _SEH_GetExceptionCode();
4100 ObDereferenceObject(Section
);
4108 * Extends size of file backed section.
4110 * @param SectionHandle
4111 * Handle to the section object. It must be opened with
4112 * SECTION_EXTEND_SIZE access.
4113 * @param NewMaximumSize
4114 * New maximum size of the section in bytes.
4118 * @todo Move the actual code to internal function MmExtendSection.
4122 NtExtendSection(IN HANDLE SectionHandle
,
4123 IN PLARGE_INTEGER NewMaximumSize
)
4125 LARGE_INTEGER SafeNewMaximumSize
;
4126 PSECTION_OBJECT Section
;
4127 KPROCESSOR_MODE PreviousMode
;
4128 NTSTATUS Status
= STATUS_SUCCESS
;
4130 PreviousMode
= ExGetPreviousMode();
4132 if(PreviousMode
!= KernelMode
)
4136 ProbeForRead(NewMaximumSize
,
4137 sizeof(LARGE_INTEGER
),
4139 /* make a copy on the stack */
4140 SafeNewMaximumSize
= *NewMaximumSize
;
4141 NewMaximumSize
= &SafeNewMaximumSize
;
4145 Status
= _SEH_GetExceptionCode();
4149 if(!NT_SUCCESS(Status
))
4155 Status
= ObReferenceObjectByHandle(SectionHandle
,
4156 SECTION_EXTEND_SIZE
,
4157 MmSectionObjectType
,
4161 if (!NT_SUCCESS(Status
))
4166 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4168 ObfDereferenceObject(Section
);
4169 return STATUS_INVALID_PARAMETER
;
4173 * - Acquire file extneding resource.
4174 * - Check if we're not resizing the section below it's actual size!
4175 * - Extend segments if needed.
4176 * - Set file information (FileAllocationInformation) to the new size.
4177 * - Release file extending resource.
4180 ObDereferenceObject(Section
);
4182 return STATUS_NOT_IMPLEMENTED
;
4186 /**********************************************************************
4188 * MmAllocateSection@4
4198 * Code taken from ntoskrnl/mm/special.c.
4203 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4209 PMADDRESS_SPACE AddressSpace
;
4210 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4212 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4214 BoundaryAddressMultiple
.QuadPart
= 0;
4216 AddressSpace
= MmGetKernelAddressSpace();
4217 Result
= BaseAddress
;
4218 MmLockAddressSpace(AddressSpace
);
4219 Status
= MmCreateMemoryArea (NULL
,
4228 BoundaryAddressMultiple
);
4229 MmUnlockAddressSpace(AddressSpace
);
4231 if (!NT_SUCCESS(Status
))
4235 DPRINT("Result %p\n",Result
);
4236 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
4240 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
4241 if (!NT_SUCCESS(Status
))
4243 DbgPrint("Unable to allocate page\n");
4246 Status
= MmCreateVirtualMapping (NULL
,
4247 (PVOID
)((ULONG_PTR
)Result
+ (i
* PAGE_SIZE
)),
4251 if (!NT_SUCCESS(Status
))
4253 DbgPrint("Unable to create virtual mapping\n");
4257 return ((PVOID
)Result
);
4261 /**********************************************************************
4263 * MmMapViewOfSection
4266 * Maps a view of a section into the virtual address space of a
4271 * Pointer to the section object.
4274 * Pointer to the process.
4277 * Desired base address (or NULL) on entry;
4278 * Actual base address of the view on exit.
4281 * Number of high order address bits that must be zero.
4284 * Size in bytes of the initially committed section of
4288 * Offset in bytes from the beginning of the section
4289 * to the beginning of the view.
4292 * Desired length of map (or zero to map all) on entry
4293 * Actual length mapped on exit.
4295 * InheritDisposition
4296 * Specified how the view is to be shared with
4300 * Type of allocation for the pages.
4303 * Protection for the committed region of the view.
4311 MmMapViewOfSection(IN PVOID SectionObject
,
4312 IN PEPROCESS Process
,
4313 IN OUT PVOID
*BaseAddress
,
4315 IN ULONG CommitSize
,
4316 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4317 IN OUT PULONG ViewSize
,
4318 IN SECTION_INHERIT InheritDisposition
,
4319 IN ULONG AllocationType
,
4322 PSECTION_OBJECT Section
;
4323 PMADDRESS_SPACE AddressSpace
;
4325 NTSTATUS Status
= STATUS_SUCCESS
;
4329 Section
= (PSECTION_OBJECT
)SectionObject
;
4330 AddressSpace
= &Process
->AddressSpace
;
4332 MmLockAddressSpace(AddressSpace
);
4334 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4338 ULONG_PTR ImageBase
;
4340 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4341 PMM_SECTION_SEGMENT SectionSegments
;
4343 ImageSectionObject
= Section
->ImageSection
;
4344 SectionSegments
= ImageSectionObject
->Segments
;
4345 NrSegments
= ImageSectionObject
->NrSegments
;
4348 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4351 ImageBase
= ImageSectionObject
->ImageBase
;
4355 for (i
= 0; i
< NrSegments
; i
++)
4357 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4359 ULONG_PTR MaxExtent
;
4360 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4361 SectionSegments
[i
].Length
;
4362 ImageSize
= max(ImageSize
, MaxExtent
);
4366 /* Check there is enough space to map the section at that point. */
4367 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4368 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4370 /* Fail if the user requested a fixed base address. */
4371 if ((*BaseAddress
) != NULL
)
4373 MmUnlockAddressSpace(AddressSpace
);
4374 return(STATUS_UNSUCCESSFUL
);
4376 /* Otherwise find a gap to map the image. */
4377 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4380 MmUnlockAddressSpace(AddressSpace
);
4381 return(STATUS_UNSUCCESSFUL
);
4385 for (i
= 0; i
< NrSegments
; i
++)
4387 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4389 PVOID SBaseAddress
= (PVOID
)
4390 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4391 MmLockSectionSegment(&SectionSegments
[i
]);
4392 Status
= MmMapViewOfSegment(Process
,
4395 &SectionSegments
[i
],
4397 SectionSegments
[i
].Length
,
4398 SectionSegments
[i
].Protection
,
4401 MmUnlockSectionSegment(&SectionSegments
[i
]);
4402 if (!NT_SUCCESS(Status
))
4404 MmUnlockAddressSpace(AddressSpace
);
4410 *BaseAddress
= (PVOID
)ImageBase
;
4414 if (ViewSize
== NULL
)
4416 /* Following this pointer would lead to us to the dark side */
4417 /* What to do? Bugcheck? Return status? Do the mambo? */
4418 KEBUGCHECK(MEMORY_MANAGEMENT
);
4421 if (SectionOffset
== NULL
)
4427 ViewOffset
= SectionOffset
->u
.LowPart
;
4430 if ((ViewOffset
% PAGE_SIZE
) != 0)
4432 MmUnlockAddressSpace(AddressSpace
);
4433 return(STATUS_MAPPED_ALIGNMENT
);
4436 if ((*ViewSize
) == 0)
4438 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4440 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4442 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4445 MmLockSectionSegment(Section
->Segment
);
4446 Status
= MmMapViewOfSegment(Process
,
4454 (AllocationType
& MEM_TOP_DOWN
));
4455 MmUnlockSectionSegment(Section
->Segment
);
4456 if (!NT_SUCCESS(Status
))
4458 MmUnlockAddressSpace(AddressSpace
);
4463 MmUnlockAddressSpace(AddressSpace
);
4465 return(STATUS_SUCCESS
);
4472 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4473 IN PLARGE_INTEGER NewFileSize
)
4484 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
4494 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4495 IN MMFLUSH_TYPE FlushType
)
4499 case MmFlushForDelete
:
4500 if (SectionObjectPointer
->ImageSectionObject
||
4501 SectionObjectPointer
->DataSectionObject
)
4505 CcRosSetRemoveOnClose(SectionObjectPointer
);
4507 case MmFlushForWrite
:
4517 MmForceSectionClosed (
4518 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4519 IN BOOLEAN DelayClose
)
4530 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4531 OUT PVOID
* MappedBase
,
4532 IN OUT PULONG ViewSize
)
4534 PSECTION_OBJECT Section
;
4535 PMADDRESS_SPACE AddressSpace
;
4538 DPRINT("MmMapViewInSystemSpace() called\n");
4540 Section
= (PSECTION_OBJECT
)SectionObject
;
4541 AddressSpace
= MmGetKernelAddressSpace();
4543 MmLockAddressSpace(AddressSpace
);
4546 if ((*ViewSize
) == 0)
4548 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4550 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4552 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4555 MmLockSectionSegment(Section
->Segment
);
4558 Status
= MmMapViewOfSegment(NULL
,
4568 MmUnlockSectionSegment(Section
->Segment
);
4569 MmUnlockAddressSpace(AddressSpace
);
4579 MmMapViewInSessionSpace (
4581 OUT PVOID
*MappedBase
,
4582 IN OUT PSIZE_T ViewSize
4586 return STATUS_NOT_IMPLEMENTED
;
4594 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4596 PMADDRESS_SPACE AddressSpace
;
4599 DPRINT("MmUnmapViewInSystemSpace() called\n");
4601 AddressSpace
= MmGetKernelAddressSpace();
4603 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4613 MmUnmapViewInSessionSpace (
4618 return STATUS_NOT_IMPLEMENTED
;
4625 MmSetBankedSection (DWORD Unknown0
,
4633 return (STATUS_NOT_IMPLEMENTED
);
4637 /**********************************************************************
4642 * Creates a section object.
4645 * SectionObject (OUT)
4646 * Caller supplied storage for the resulting pointer
4647 * to a SECTION_OBJECT instance;
4650 * Specifies the desired access to the section can be a
4652 * STANDARD_RIGHTS_REQUIRED |
4654 * SECTION_MAP_WRITE |
4655 * SECTION_MAP_READ |
4656 * SECTION_MAP_EXECUTE
4658 * ObjectAttributes [OPTIONAL]
4659 * Initialized attributes for the object can be used
4660 * to create a named section;
4663 * Maximizes the size of the memory section. Must be
4664 * non-NULL for a page-file backed section.
4665 * If value specified for a mapped file and the file is
4666 * not large enough, file will be extended.
4668 * SectionPageProtection
4669 * Can be a combination of:
4675 * AllocationAttributes
4676 * Can be a combination of:
4681 * Handle to a file to create a section mapped to a file
4682 * instead of a memory backed section;
4693 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4694 IN ACCESS_MASK DesiredAccess
,
4695 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4696 IN PLARGE_INTEGER MaximumSize
,
4697 IN ULONG SectionPageProtection
,
4698 IN ULONG AllocationAttributes
,
4699 IN HANDLE FileHandle OPTIONAL
,
4700 IN PFILE_OBJECT File OPTIONAL
)
4702 if (AllocationAttributes
& SEC_IMAGE
)
4704 return(MmCreateImageSection(SectionObject
,
4708 SectionPageProtection
,
4709 AllocationAttributes
,
4713 if (FileHandle
!= NULL
)
4715 return(MmCreateDataFileSection(SectionObject
,
4719 SectionPageProtection
,
4720 AllocationAttributes
,
4724 return(MmCreatePageFileSection(SectionObject
,
4728 SectionPageProtection
,
4729 AllocationAttributes
));