3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/section.c
6 * PURPOSE: Implements section objects
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
17 #include <reactos/exeformat.h>
19 /* TYPES *********************************************************************/
23 PSECTION_OBJECT Section
;
24 PMM_SECTION_SEGMENT Segment
;
29 MM_SECTION_PAGEOUT_CONTEXT
;
31 /* GLOBALS *******************************************************************/
33 POBJECT_TYPE EXPORTED MmSectionObjectType
= NULL
;
35 static GENERIC_MAPPING MmpSectionMapping
= {
36 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
37 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
38 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
41 #define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S')
42 #define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T')
44 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
45 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
46 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
47 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
48 #define MAX_SHARE_COUNT 0x7FF
49 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
50 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
51 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
53 /* FUNCTIONS *****************************************************************/
55 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
58 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
59 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
60 * RETURNS: Status of the wait.
63 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
65 LARGE_INTEGER Timeout
;
66 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
68 Timeout
.QuadPart
= -100000000LL; // 10 sec
71 Timeout
.QuadPart
= -100000000; // 10 sec
74 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
79 * FUNCTION: Sets the page op completion event and releases the page op.
80 * ARGUMENTS: PMM_PAGEOP.
81 * RETURNS: In shorter time than it takes you to even read this
82 * description, so don't even think about geting a mug of coffee.
85 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
87 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
88 MmReleasePageOp(PageOp
);
93 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
94 * ARGUMENTS: PFILE_OBJECT to wait for.
95 * RETURNS: Status of the wait.
98 MmspWaitForFileLock(PFILE_OBJECT File
)
100 return KeWaitForSingleObject(&File
->Lock
, 0, KernelMode
, FALSE
, NULL
);
105 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
108 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
110 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
112 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
114 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
121 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
123 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
125 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
126 PMM_SECTION_SEGMENT SectionSegments
;
130 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
131 NrSegments
= ImageSectionObject
->NrSegments
;
132 SectionSegments
= ImageSectionObject
->Segments
;
133 for (i
= 0; i
< NrSegments
; i
++)
135 if (SectionSegments
[i
].ReferenceCount
!= 0)
137 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
138 SectionSegments
[i
].ReferenceCount
);
141 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
143 ExFreePool(ImageSectionObject
->Segments
);
144 ExFreePool(ImageSectionObject
);
145 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
147 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
149 PMM_SECTION_SEGMENT Segment
;
151 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
154 if (Segment
->ReferenceCount
!= 0)
156 DPRINT1("Data segment still referenced\n");
159 MmFreePageTablesSectionSegment(Segment
);
161 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
166 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
168 ExAcquireFastMutex(&Segment
->Lock
);
172 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
174 ExReleaseFastMutex(&Segment
->Lock
);
178 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
182 PSECTION_PAGE_TABLE Table
;
183 ULONG DirectoryOffset
;
186 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
188 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
192 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
193 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
197 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
198 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
199 TAG_SECTION_PAGE_TABLE
);
204 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
205 DPRINT("Table %x\n", Table
);
208 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
209 Table
->Entry
[TableOffset
] = Entry
;
214 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
217 PSECTION_PAGE_TABLE Table
;
219 ULONG DirectoryOffset
;
222 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
224 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
226 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
230 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
231 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
232 DPRINT("Table %x\n", Table
);
238 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
239 Entry
= Table
->Entry
[TableOffset
];
244 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
249 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
252 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
255 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
257 DPRINT1("Maximum share count reached\n");
260 if (IS_SWAP_FROM_SSE(Entry
))
264 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
265 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
269 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section
,
270 PMM_SECTION_SEGMENT Segment
,
276 BOOLEAN IsDirectMapped
= FALSE
;
278 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
281 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
284 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
286 DPRINT1("Zero share count for unshare\n");
289 if (IS_SWAP_FROM_SSE(Entry
))
293 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
295 * If we reducing the share count of this entry to zero then set the entry
296 * to zero and tell the cache the page is no longer mapped.
298 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
300 PFILE_OBJECT FileObject
;
302 SWAPENTRY SavedSwapEntry
;
304 BOOLEAN IsImageSection
;
307 FileOffset
= Offset
+ Segment
->FileOffset
;
309 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
311 Page
= PFN_FROM_SSE(Entry
);
312 FileObject
= Section
->FileObject
;
313 if (FileObject
!= NULL
&&
314 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
317 if ((FileOffset
% PAGE_SIZE
) == 0 &&
318 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
321 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
322 IsDirectMapped
= TRUE
;
323 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
324 if (!NT_SUCCESS(Status
))
326 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
332 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
333 if (SavedSwapEntry
== 0)
336 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
337 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
341 * Try to page out this page and set the swap entry
342 * within the section segment. There exist no rmap entry
343 * for this page. The pager thread can't page out a
344 * page without a rmap entry.
346 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
350 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
353 MmReleasePageMemoryConsumer(MC_USER
, Page
);
359 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
360 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
368 * We hold all locks. Nobody can do something with the current
369 * process and the current segment (also not within an other process).
372 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
373 if (!NT_SUCCESS(Status
))
375 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
379 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
380 MmSetSavedSwapEntryPage(Page
, 0);
382 MmReleasePageMemoryConsumer(MC_USER
, Page
);
386 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
393 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
395 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
398 BOOL
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
401 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
404 PCACHE_SEGMENT CacheSeg
;
405 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
406 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
409 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
417 MiReadPage(PMEMORY_AREA MemoryArea
,
421 * FUNCTION: Read a page for a section backed memory area.
423 * MemoryArea - Memory area to read the page for.
424 * Offset - Offset of the page to read.
425 * Page - Variable that receives a page contains the read data.
432 PCACHE_SEGMENT CacheSeg
;
433 PFILE_OBJECT FileObject
;
437 BOOLEAN IsImageSection
;
440 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
441 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
442 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
443 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
444 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
448 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
451 * If the file system is letting us go directly to the cache and the
452 * memory area was mapped at an offset in the file which is page aligned
453 * then get the related cache segment.
455 if ((FileOffset
% PAGE_SIZE
) == 0 &&
456 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
457 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
461 * Get the related cache segment; we use a lower level interface than
462 * filesystems do because it is safe for us to use an offset with a
463 * alignment less than the file system block size.
465 Status
= CcRosGetCacheSegment(Bcb
,
471 if (!NT_SUCCESS(Status
))
478 * If the cache segment isn't up to date then call the file
479 * system to read in the data.
481 Status
= ReadCacheSegment(CacheSeg
);
482 if (!NT_SUCCESS(Status
))
484 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
489 * Retrieve the page from the cache segment that we actually want.
491 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
492 FileOffset
- BaseOffset
).QuadPart
>> PAGE_SHIFT
;
494 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
499 ULONG CacheSegOffset
;
501 * Allocate a page, this is rather complicated by the possibility
502 * we might have to move other things out of memory
504 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
505 if (!NT_SUCCESS(Status
))
509 Status
= CcRosGetCacheSegment(Bcb
,
515 if (!NT_SUCCESS(Status
))
522 * If the cache segment isn't up to date then call the file
523 * system to read in the data.
525 Status
= ReadCacheSegment(CacheSeg
);
526 if (!NT_SUCCESS(Status
))
528 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
532 PageAddr
= MmCreateHyperspaceMapping(*Page
);
533 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
534 Length
= RawLength
- SegOffset
;
535 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
537 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
539 else if (CacheSegOffset
>= PAGE_SIZE
)
541 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
545 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
546 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
547 Status
= CcRosGetCacheSegment(Bcb
,
548 FileOffset
+ CacheSegOffset
,
553 if (!NT_SUCCESS(Status
))
555 MmDeleteHyperspaceMapping(PageAddr
);
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
);
568 MmDeleteHyperspaceMapping(PageAddr
);
572 if (Length
< PAGE_SIZE
)
574 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
578 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
581 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
582 MmDeleteHyperspaceMapping(PageAddr
);
584 return(STATUS_SUCCESS
);
588 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
589 MEMORY_AREA
* MemoryArea
,
597 PSECTION_OBJECT Section
;
598 PMM_SECTION_SEGMENT Segment
;
607 * There is a window between taking the page fault and locking the
608 * address space when another thread could load the page so we check
611 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
615 MmLockPage(MmGetPfnForProcess(AddressSpace
->Process
, Address
));
617 return(STATUS_SUCCESS
);
620 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
621 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
623 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
624 Section
= MemoryArea
->Data
.SectionData
.Section
;
625 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
626 &MemoryArea
->Data
.SectionData
.RegionListHead
,
631 MmLockSectionSegment(Segment
);
634 * Check if this page needs to be mapped COW
636 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
637 (Region
->Protect
== PAGE_READWRITE
||
638 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
640 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
644 Attributes
= Region
->Protect
;
648 * Get or create a page operation descriptor
650 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
653 DPRINT1("MmGetPageOp failed\n");
658 * Check if someone else is already handling this fault, if so wait
661 if (PageOp
->Thread
!= PsGetCurrentThread())
663 MmUnlockSectionSegment(Segment
);
664 MmUnlockAddressSpace(AddressSpace
);
665 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
667 * Check for various strange conditions
669 if (Status
!= STATUS_SUCCESS
)
671 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
674 if (PageOp
->Status
== STATUS_PENDING
)
676 DPRINT1("Woke for page op before completion\n");
679 MmLockAddressSpace(AddressSpace
);
681 * If this wasn't a pagein then restart the operation
683 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
685 MmspCompleteAndReleasePageOp(PageOp
);
686 DPRINT("Address 0x%.8X\n", Address
);
687 return(STATUS_MM_RESTART_OPERATION
);
691 * If the thread handling this fault has failed then we don't retry
693 if (!NT_SUCCESS(PageOp
->Status
))
695 Status
= PageOp
->Status
;
696 MmspCompleteAndReleasePageOp(PageOp
);
697 DPRINT("Address 0x%.8X\n", Address
);
700 MmLockSectionSegment(Segment
);
702 * If the completed fault was for another address space then set the
705 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
707 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
708 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
710 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
713 * The page was a private page in another or in our address space
715 MmUnlockSectionSegment(Segment
);
716 MmspCompleteAndReleasePageOp(PageOp
);
717 return(STATUS_MM_RESTART_OPERATION
);
720 Page
= PFN_FROM_SSE(Entry
);
722 MmSharePageEntrySectionSegment(Segment
, Offset
);
724 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
729 if (!NT_SUCCESS(Status
))
731 DbgPrint("Unable to create virtual mapping\n");
734 MmInsertRmap(Page
, MemoryArea
->Process
, (PVOID
)PAddress
);
740 MmUnlockSectionSegment(Segment
);
741 PageOp
->Status
= STATUS_SUCCESS
;
742 MmspCompleteAndReleasePageOp(PageOp
);
743 DPRINT("Address 0x%.8X\n", Address
);
744 return(STATUS_SUCCESS
);
747 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
751 * Must be private page we have swapped out.
758 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
760 DPRINT1("Found a swaped out private page in a pagefile section.\n");
764 MmUnlockSectionSegment(Segment
);
765 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
767 MmUnlockAddressSpace(AddressSpace
);
768 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
769 if (!NT_SUCCESS(Status
))
774 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
775 if (!NT_SUCCESS(Status
))
777 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
780 MmLockAddressSpace(AddressSpace
);
781 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
786 if (!NT_SUCCESS(Status
))
788 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
794 * Store the swap entry for later use.
796 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
799 * Add the page to the process's working set
801 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
804 * Finish the operation
810 PageOp
->Status
= STATUS_SUCCESS
;
811 MmspCompleteAndReleasePageOp(PageOp
);
812 DPRINT("Address 0x%.8X\n", Address
);
813 return(STATUS_SUCCESS
);
817 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
819 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
821 MmUnlockSectionSegment(Segment
);
823 * Just map the desired physical page
825 Page
= (Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
) >> PAGE_SHIFT
;
826 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
831 if (!NT_SUCCESS(Status
))
833 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
838 * Don't add an rmap entry since the page mapped could be for
847 * Cleanup and release locks
849 PageOp
->Status
= STATUS_SUCCESS
;
850 MmspCompleteAndReleasePageOp(PageOp
);
851 DPRINT("Address 0x%.8X\n", Address
);
852 return(STATUS_SUCCESS
);
856 * Map anonymous memory for BSS sections
858 if (Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
)
860 MmUnlockSectionSegment(Segment
);
861 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
862 if (!NT_SUCCESS(Status
))
864 MmUnlockAddressSpace(AddressSpace
);
865 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
866 MmLockAddressSpace(AddressSpace
);
868 if (!NT_SUCCESS(Status
))
872 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
877 if (!NT_SUCCESS(Status
))
879 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
883 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
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 * Get the entry corresponding to the offset within the section
901 Offset
+= MemoryArea
->Data
.SectionData
.ViewOffset
;
902 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
907 * If the entry is zero (and it can't change because we have
908 * locked the segment) then we need to load the page.
912 * Release all our locks and read in the page from disk
914 MmUnlockSectionSegment(Segment
);
915 MmUnlockAddressSpace(AddressSpace
);
917 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
918 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
920 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
921 if (!NT_SUCCESS(Status
))
923 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
928 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
929 if (!NT_SUCCESS(Status
))
931 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
934 if (!NT_SUCCESS(Status
))
937 * FIXME: What do we know in this case?
940 * Cleanup and release locks
942 MmLockAddressSpace(AddressSpace
);
943 PageOp
->Status
= Status
;
944 MmspCompleteAndReleasePageOp(PageOp
);
945 DPRINT("Address 0x%.8X\n", Address
);
949 * Relock the address space and segment
951 MmLockAddressSpace(AddressSpace
);
952 MmLockSectionSegment(Segment
);
955 * Check the entry. No one should change the status of a page
956 * that has a pending page-in.
958 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
961 DbgPrint("Someone changed ppte entry while we slept\n");
966 * Mark the offset within the section as having valid, in-memory
969 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
970 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
971 MmUnlockSectionSegment(Segment
);
973 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
978 if (!NT_SUCCESS(Status
))
980 DbgPrint("Unable to create virtual mapping\n");
983 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
989 PageOp
->Status
= STATUS_SUCCESS
;
990 MmspCompleteAndReleasePageOp(PageOp
);
991 DPRINT("Address 0x%.8X\n", Address
);
992 return(STATUS_SUCCESS
);
994 else if (IS_SWAP_FROM_SSE(Entry
))
998 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1001 * Release all our locks and read in the page from disk
1003 MmUnlockSectionSegment(Segment
);
1005 MmUnlockAddressSpace(AddressSpace
);
1007 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1008 if (!NT_SUCCESS(Status
))
1013 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1014 if (!NT_SUCCESS(Status
))
1020 * Relock the address space and segment
1022 MmLockAddressSpace(AddressSpace
);
1023 MmLockSectionSegment(Segment
);
1026 * Check the entry. No one should change the status of a page
1027 * that has a pending page-in.
1029 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1030 if (Entry
!= Entry1
)
1032 DbgPrint("Someone changed ppte entry while we slept\n");
1037 * Mark the offset within the section as having valid, in-memory
1040 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1041 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1042 MmUnlockSectionSegment(Segment
);
1045 * Save the swap entry.
1047 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1048 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1053 if (!NT_SUCCESS(Status
))
1055 DbgPrint("Unable to create virtual mapping\n");
1058 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1063 PageOp
->Status
= STATUS_SUCCESS
;
1064 MmspCompleteAndReleasePageOp(PageOp
);
1065 DPRINT("Address 0x%.8X\n", Address
);
1066 return(STATUS_SUCCESS
);
1071 * If the section offset is already in-memory and valid then just
1072 * take another reference to the page
1075 Page
= PFN_FROM_SSE(Entry
);
1077 MmSharePageEntrySectionSegment(Segment
, Offset
);
1078 MmUnlockSectionSegment(Segment
);
1080 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1085 if (!NT_SUCCESS(Status
))
1087 DbgPrint("Unable to create virtual mapping\n");
1090 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1095 PageOp
->Status
= STATUS_SUCCESS
;
1096 MmspCompleteAndReleasePageOp(PageOp
);
1097 DPRINT("Address 0x%.8X\n", Address
);
1098 return(STATUS_SUCCESS
);
1103 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1104 MEMORY_AREA
* MemoryArea
,
1108 PMM_SECTION_SEGMENT Segment
;
1109 PSECTION_OBJECT Section
;
1120 * Check if the page has been paged out or has already been set readwrite
1122 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1123 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1125 DPRINT("Address 0x%.8X\n", Address
);
1126 return(STATUS_SUCCESS
);
1130 * Find the offset of the page
1132 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1133 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1135 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1136 Section
= MemoryArea
->Data
.SectionData
.Section
;
1137 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1138 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1143 MmLockSectionSegment(Segment
);
1145 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1146 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1148 MmUnlockSectionSegment(Segment
);
1151 * Check if we are doing COW
1153 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1154 (Region
->Protect
== PAGE_READWRITE
||
1155 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1157 DPRINT("Address 0x%.8X\n", Address
);
1158 return(STATUS_UNSUCCESSFUL
);
1161 if (IS_SWAP_FROM_SSE(Entry
) ||
1162 PFN_FROM_SSE(Entry
) != OldPage
)
1164 /* This is a private page. We must only change the page protection. */
1165 MmSetPageProtect(AddressSpace
->Process
, PAddress
, Region
->Protect
);
1166 return(STATUS_SUCCESS
);
1170 * Get or create a pageop
1172 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1173 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1176 DPRINT1("MmGetPageOp failed\n");
1181 * Wait for any other operations to complete
1183 if (PageOp
->Thread
!= PsGetCurrentThread())
1185 MmUnlockAddressSpace(AddressSpace
);
1186 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1188 * Check for various strange conditions
1190 if (Status
== STATUS_TIMEOUT
)
1192 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1195 if (PageOp
->Status
== STATUS_PENDING
)
1197 DPRINT1("Woke for page op before completion\n");
1201 * Restart the operation
1203 MmLockAddressSpace(AddressSpace
);
1204 MmspCompleteAndReleasePageOp(PageOp
);
1205 DPRINT("Address 0x%.8X\n", Address
);
1206 return(STATUS_MM_RESTART_OPERATION
);
1210 * Release locks now we have the pageop
1212 MmUnlockAddressSpace(AddressSpace
);
1217 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1218 if (!NT_SUCCESS(Status
))
1226 MiCopyFromUserPage(NewPage
, PAddress
);
1229 * Delete the old entry.
1231 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1234 * Set the PTE to point to the new page
1236 MmLockAddressSpace(AddressSpace
);
1237 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1242 if (!NT_SUCCESS(Status
))
1244 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1248 MmInsertRmap(NewPage
, AddressSpace
->Process
, PAddress
);
1249 if (!NT_SUCCESS(Status
))
1251 DbgPrint("Unable to create virtual mapping\n");
1256 MmLockPage(NewPage
);
1257 MmUnlockPage(OldPage
);
1261 * Unshare the old page.
1263 MmDeleteRmap(OldPage
, AddressSpace
->Process
, PAddress
);
1264 MmLockSectionSegment(Segment
);
1265 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1266 MmUnlockSectionSegment(Segment
);
1268 PageOp
->Status
= STATUS_SUCCESS
;
1269 MmspCompleteAndReleasePageOp(PageOp
);
1270 DPRINT("Address 0x%.8X\n", Address
);
1271 return(STATUS_SUCCESS
);
1275 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1277 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1281 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1282 MmDeleteVirtualMapping(Process
,
1289 PageOutContext
->WasDirty
= TRUE
;
1291 if (!PageOutContext
->Private
)
1293 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1294 PageOutContext
->Segment
,
1295 PageOutContext
->Offset
,
1296 PageOutContext
->WasDirty
,
1301 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1304 DPRINT("PhysicalAddress %I64x, Address %x\n", Page
, Address
);
1308 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1309 MEMORY_AREA
* MemoryArea
,
1314 MM_SECTION_PAGEOUT_CONTEXT Context
;
1315 SWAPENTRY SwapEntry
;
1319 PFILE_OBJECT FileObject
;
1321 BOOLEAN DirectMapped
;
1322 BOOLEAN IsImageSection
;
1324 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1327 * Get the segment and section.
1329 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1330 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1332 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1333 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1335 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1337 FileObject
= Context
.Section
->FileObject
;
1338 DirectMapped
= FALSE
;
1339 if (FileObject
!= NULL
&&
1340 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1342 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1345 * If the file system is letting us go directly to the cache and the
1346 * memory area was mapped at an offset in the file which is page aligned
1347 * then note this is a direct mapped page.
1349 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1350 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1352 DirectMapped
= TRUE
;
1358 * This should never happen since mappings of physical memory are never
1359 * placed in the rmap lists.
1361 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1363 DPRINT1("Trying to page out from physical memory section address 0x%X "
1364 "process %d\n", Address
,
1365 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1370 * Get the section segment entry and the physical address.
1372 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1373 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1375 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1376 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1379 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1380 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1383 * Prepare the context structure for the rmap delete call.
1385 Context
.WasDirty
= FALSE
;
1386 if (Context
.Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
||
1387 IS_SWAP_FROM_SSE(Entry
) ||
1388 PFN_FROM_SSE(Entry
) != Page
)
1390 Context
.Private
= TRUE
;
1394 Context
.Private
= FALSE
;
1398 * Take an additional reference to the page or the cache segment.
1400 if (DirectMapped
&& !Context
.Private
)
1402 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1404 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1410 MmReferencePage(Page
);
1413 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1416 * If this wasn't a private page then we should have reduced the entry to
1417 * zero by deleting all the rmaps.
1419 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1421 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1422 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1429 * If the page wasn't dirty then we can just free it as for a readonly page.
1430 * Since we unmapped all the mappings above we know it will not suddenly
1432 * If the page is from a pagefile section and has no swap entry,
1433 * we can't free the page at this point.
1435 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1436 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1438 if (Context
.Private
)
1440 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1441 Context
.WasDirty
? "dirty" : "clean", Address
);
1444 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1446 MmSetSavedSwapEntryPage(Page
, 0);
1447 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1448 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1449 PageOp
->Status
= STATUS_SUCCESS
;
1450 MmspCompleteAndReleasePageOp(PageOp
);
1451 return(STATUS_SUCCESS
);
1454 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1456 if (Context
.Private
)
1458 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1459 Context
.WasDirty
? "dirty" : "clean", Address
);
1462 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1464 MmSetSavedSwapEntryPage(Page
, 0);
1467 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1469 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1470 PageOp
->Status
= STATUS_SUCCESS
;
1471 MmspCompleteAndReleasePageOp(PageOp
);
1472 return(STATUS_SUCCESS
);
1475 else if (!Context
.Private
&& DirectMapped
)
1479 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1483 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1484 if (!NT_SUCCESS(Status
))
1486 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1489 PageOp
->Status
= STATUS_SUCCESS
;
1490 MmspCompleteAndReleasePageOp(PageOp
);
1491 return(STATUS_SUCCESS
);
1493 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1497 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1501 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1502 PageOp
->Status
= STATUS_SUCCESS
;
1503 MmspCompleteAndReleasePageOp(PageOp
);
1504 return(STATUS_SUCCESS
);
1506 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1508 MmSetSavedSwapEntryPage(Page
, 0);
1509 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1512 if (!NT_SUCCESS(Status
))
1516 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1517 PageOp
->Status
= STATUS_SUCCESS
;
1518 MmspCompleteAndReleasePageOp(PageOp
);
1519 return(STATUS_SUCCESS
);
1523 * If necessary, allocate an entry in the paging file for this page
1527 SwapEntry
= MmAllocSwapPage();
1530 MmShowOutOfSpaceMessagePagingFile();
1533 * For private pages restore the old mappings.
1535 if (Context
.Private
)
1537 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1539 MemoryArea
->Attributes
,
1542 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1544 MemoryArea
->Process
,
1550 * For non-private pages if the page wasn't direct mapped then
1551 * set it back into the section segment entry so we don't loose
1552 * our copy. Otherwise it will be handled by the cache manager.
1554 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1556 MemoryArea
->Attributes
,
1559 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1561 MemoryArea
->Process
,
1563 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1564 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1566 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1567 MmspCompleteAndReleasePageOp(PageOp
);
1568 return(STATUS_PAGEFILE_QUOTA
);
1573 * Write the page to the pagefile
1575 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1576 if (!NT_SUCCESS(Status
))
1578 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1581 * As above: undo our actions.
1582 * FIXME: Also free the swap page.
1584 if (Context
.Private
)
1586 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1588 MemoryArea
->Attributes
,
1591 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1593 MemoryArea
->Process
,
1598 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1600 MemoryArea
->Attributes
,
1603 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1605 MemoryArea
->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_UNSUCCESSFUL
);
1616 * Otherwise we have succeeded.
1618 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1619 MmSetSavedSwapEntryPage(Page
, 0);
1620 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1621 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1623 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1627 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1630 if (Context
.Private
)
1632 Status
= MmCreatePageFileMapping(MemoryArea
->Process
,
1635 if (!NT_SUCCESS(Status
))
1642 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1643 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1646 PageOp
->Status
= STATUS_SUCCESS
;
1647 MmspCompleteAndReleasePageOp(PageOp
);
1648 return(STATUS_SUCCESS
);
1652 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1653 PMEMORY_AREA MemoryArea
,
1658 PSECTION_OBJECT Section
;
1659 PMM_SECTION_SEGMENT Segment
;
1661 SWAPENTRY SwapEntry
;
1665 PFILE_OBJECT FileObject
;
1667 BOOLEAN DirectMapped
;
1668 BOOLEAN IsImageSection
;
1670 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1672 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1675 * Get the segment and section.
1677 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1678 Section
= MemoryArea
->Data
.SectionData
.Section
;
1679 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1681 FileObject
= Section
->FileObject
;
1682 DirectMapped
= FALSE
;
1683 if (FileObject
!= NULL
&&
1684 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1686 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1689 * If the file system is letting us go directly to the cache and the
1690 * memory area was mapped at an offset in the file which is page aligned
1691 * then note this is a direct mapped page.
1693 if ((Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
% PAGE_SIZE
) == 0 &&
1694 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1696 DirectMapped
= TRUE
;
1701 * This should never happen since mappings of physical memory are never
1702 * placed in the rmap lists.
1704 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1706 DPRINT1("Trying to write back page from physical memory mapped at %X "
1707 "process %d\n", Address
,
1708 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1713 * Get the section segment entry and the physical address.
1715 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1716 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1718 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1719 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1722 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1723 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1726 * Check for a private (COWed) page.
1728 if (Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
||
1729 IS_SWAP_FROM_SSE(Entry
) ||
1730 PFN_FROM_SSE(Entry
) != Page
)
1740 * Speculatively set all mappings of the page to clean.
1742 MmSetCleanAllRmaps(Page
);
1745 * If this page was direct mapped from the cache then the cache manager
1746 * will take care of writing it back to disk.
1748 if (DirectMapped
&& !Private
)
1750 ASSERT(SwapEntry
== 0);
1751 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
1752 PageOp
->Status
= STATUS_SUCCESS
;
1753 MmspCompleteAndReleasePageOp(PageOp
);
1754 return(STATUS_SUCCESS
);
1758 * If necessary, allocate an entry in the paging file for this page
1762 SwapEntry
= MmAllocSwapPage();
1765 MmSetDirtyAllRmaps(Page
);
1766 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1767 MmspCompleteAndReleasePageOp(PageOp
);
1768 return(STATUS_PAGEFILE_QUOTA
);
1770 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1774 * Write the page to the pagefile
1776 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1777 if (!NT_SUCCESS(Status
))
1779 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1781 MmSetDirtyAllRmaps(Page
);
1782 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1783 MmspCompleteAndReleasePageOp(PageOp
);
1784 return(STATUS_UNSUCCESSFUL
);
1788 * Otherwise we have succeeded.
1790 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1791 PageOp
->Status
= STATUS_SUCCESS
;
1792 MmspCompleteAndReleasePageOp(PageOp
);
1793 return(STATUS_SUCCESS
);
1797 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1805 PMEMORY_AREA MemoryArea
;
1806 PMM_SECTION_SEGMENT Segment
;
1810 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1811 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1813 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1814 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1819 if (OldProtect
!= NewProtect
)
1821 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1823 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1824 ULONG Protect
= NewProtect
;
1827 * If we doing COW for this segment then check if the page is
1830 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1836 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1837 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1838 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1840 Protect
= PAGE_READONLY
;
1841 if (Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
||
1842 IS_SWAP_FROM_SSE(Entry
) ||
1843 PFN_FROM_SSE(Entry
) != Page
)
1845 Protect
= NewProtect
;
1849 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1851 MmSetPageProtect(AddressSpace
->Process
, Address
,
1859 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1860 PMEMORY_AREA MemoryArea
,
1868 ULONG_PTR MaxLength
;
1870 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
1871 if (Length
> MaxLength
)
1874 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1875 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1877 *OldProtect
= Region
->Protect
;
1878 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
1879 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1880 BaseAddress
, Length
, Region
->Type
, Protect
,
1881 MmAlterViewAttributes
);
1887 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
1889 PMEMORY_BASIC_INFORMATION Info
,
1890 PULONG ResultLength
)
1893 PVOID RegionBaseAddress
;
1894 PSECTION_OBJECT Section
;
1895 PLIST_ENTRY CurrentEntry
;
1896 PMEMORY_AREA CurrentMArea
;
1899 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
1900 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1901 Address
, &RegionBaseAddress
);
1904 return STATUS_UNSUCCESSFUL
;
1906 Section
= MemoryArea
->Data
.SectionData
.Section
;
1907 if (Section
->AllocationAttributes
& SEC_IMAGE
)
1909 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
1910 CurrentEntry
= Section
->ViewListHead
.Flink
;
1911 Info
->AllocationBase
= NULL
;
1912 while (CurrentEntry
!= &Section
->ViewListHead
)
1914 CurrentMArea
= CONTAINING_RECORD(CurrentEntry
, MEMORY_AREA
, Data
.SectionData
.ViewListEntry
);
1915 CurrentEntry
= CurrentEntry
->Flink
;
1916 if (Info
->AllocationBase
== NULL
)
1918 Info
->AllocationBase
= CurrentMArea
->StartingAddress
;
1920 else if (CurrentMArea
->StartingAddress
< Info
->AllocationBase
)
1922 Info
->AllocationBase
= CurrentMArea
->StartingAddress
;
1925 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
1926 Info
->BaseAddress
= RegionBaseAddress
;
1927 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1928 Info
->Type
= MEM_IMAGE
;
1932 Info
->BaseAddress
= RegionBaseAddress
;
1933 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
1934 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1935 Info
->Type
= MEM_MAPPED
;
1937 Info
->RegionSize
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
-
1938 (ULONG_PTR
)MemoryArea
->StartingAddress
);
1939 Info
->State
= MEM_COMMIT
;
1940 Info
->Protect
= Region
->Protect
;
1942 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
1943 return(STATUS_SUCCESS
);
1947 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
1952 ULONG SavedSwapEntry
;
1957 Length
= PAGE_ROUND_UP(Segment
->Length
);
1958 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
1960 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1963 if (IS_SWAP_FROM_SSE(Entry
))
1965 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
1969 Page
= PFN_FROM_SSE(Entry
);
1970 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
1971 if (SavedSwapEntry
!= 0)
1973 MmSetSavedSwapEntryPage(Page
, 0);
1974 MmFreeSwapPage(SavedSwapEntry
);
1976 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1978 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
1984 MmpDeleteSection(PVOID ObjectBody
)
1986 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
1988 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
1989 if (Section
->AllocationAttributes
& SEC_IMAGE
)
1994 PMM_SECTION_SEGMENT SectionSegments
;
1997 * NOTE: Section->ImageSection can be NULL for short time
1998 * during the section creating. If we fail for some reason
1999 * until the image section is properly initialized we shouldn't
2000 * process further here.
2002 if (Section
->ImageSection
== NULL
)
2005 SectionSegments
= Section
->ImageSection
->Segments
;
2006 NrSegments
= Section
->ImageSection
->NrSegments
;
2008 for (i
= 0; i
< NrSegments
; i
++)
2010 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2012 MmLockSectionSegment(&SectionSegments
[i
]);
2014 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2015 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2019 MmpFreePageFileSegment(&SectionSegments
[i
]);
2021 MmUnlockSectionSegment(&SectionSegments
[i
]);
2028 * NOTE: Section->Segment can be NULL for short time
2029 * during the section creating.
2031 if (Section
->Segment
== NULL
)
2034 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2036 MmpFreePageFileSegment(Section
->Segment
);
2037 MmFreePageTablesSectionSegment(Section
->Segment
);
2038 ExFreePool(Section
->Segment
);
2039 Section
->Segment
= NULL
;
2043 InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2046 if (Section
->FileObject
!= NULL
)
2048 CcRosDereferenceCache(Section
->FileObject
);
2049 ObDereferenceObject(Section
->FileObject
);
2050 Section
->FileObject
= NULL
;
2055 MmpCloseSection(PVOID ObjectBody
,
2058 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2059 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2063 MmpCreateSection(PVOID ObjectBody
,
2065 PWSTR RemainingPath
,
2066 POBJECT_ATTRIBUTES ObjectAttributes
)
2068 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2069 ObjectBody
, Parent
, RemainingPath
);
2071 if (RemainingPath
== NULL
)
2073 return(STATUS_SUCCESS
);
2076 if (wcschr(RemainingPath
+1, L
'\\') != NULL
)
2078 return(STATUS_UNSUCCESSFUL
);
2080 return(STATUS_SUCCESS
);
2083 NTSTATUS INIT_FUNCTION
2084 MmCreatePhysicalMemorySection(VOID
)
2086 PSECTION_OBJECT PhysSection
;
2088 OBJECT_ATTRIBUTES Obj
;
2089 UNICODE_STRING Name
= ROS_STRING_INITIALIZER(L
"\\Device\\PhysicalMemory");
2090 LARGE_INTEGER SectionSize
;
2093 * Create the section mapping physical memory
2095 SectionSize
.QuadPart
= 0xFFFFFFFF;
2096 InitializeObjectAttributes(&Obj
,
2101 Status
= MmCreateSection(&PhysSection
,
2105 PAGE_EXECUTE_READWRITE
,
2109 if (!NT_SUCCESS(Status
))
2111 DbgPrint("Failed to create PhysicalMemory section\n");
2114 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2116 return(STATUS_SUCCESS
);
2119 NTSTATUS INIT_FUNCTION
2120 MmInitSectionImplementation(VOID
)
2122 MmSectionObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
2124 RtlRosInitUnicodeStringFromLiteral(&MmSectionObjectType
->TypeName
, L
"Section");
2126 MmSectionObjectType
->Tag
= TAG('S', 'E', 'C', 'T');
2127 MmSectionObjectType
->TotalObjects
= 0;
2128 MmSectionObjectType
->TotalHandles
= 0;
2129 MmSectionObjectType
->PeakObjects
= 0;
2130 MmSectionObjectType
->PeakHandles
= 0;
2131 MmSectionObjectType
->PagedPoolCharge
= 0;
2132 MmSectionObjectType
->NonpagedPoolCharge
= sizeof(SECTION_OBJECT
);
2133 MmSectionObjectType
->Mapping
= &MmpSectionMapping
;
2134 MmSectionObjectType
->Dump
= NULL
;
2135 MmSectionObjectType
->Open
= NULL
;
2136 MmSectionObjectType
->Close
= MmpCloseSection
;
2137 MmSectionObjectType
->Delete
= MmpDeleteSection
;
2138 MmSectionObjectType
->Parse
= NULL
;
2139 MmSectionObjectType
->Security
= NULL
;
2140 MmSectionObjectType
->QueryName
= NULL
;
2141 MmSectionObjectType
->OkayToClose
= NULL
;
2142 MmSectionObjectType
->Create
= MmpCreateSection
;
2143 MmSectionObjectType
->DuplicationNotify
= NULL
;
2146 * NOTE: Do not register the section object type here because
2147 * the object manager it not initialized yet!
2148 * The section object type will be created in ObInit().
2150 ObpCreateTypeObject(MmSectionObjectType
);
2152 return(STATUS_SUCCESS
);
2156 MmCreatePageFileSection(PSECTION_OBJECT
*SectionObject
,
2157 ACCESS_MASK DesiredAccess
,
2158 POBJECT_ATTRIBUTES ObjectAttributes
,
2159 PLARGE_INTEGER UMaximumSize
,
2160 ULONG SectionPageProtection
,
2161 ULONG AllocationAttributes
)
2163 * Create a section which is backed by the pagefile
2166 LARGE_INTEGER MaximumSize
;
2167 PSECTION_OBJECT Section
;
2168 PMM_SECTION_SEGMENT Segment
;
2171 if (UMaximumSize
== NULL
)
2173 return(STATUS_UNSUCCESSFUL
);
2175 MaximumSize
= *UMaximumSize
;
2178 * Create the section
2180 Status
= ObCreateObject(ExGetPreviousMode(),
2181 MmSectionObjectType
,
2183 ExGetPreviousMode(),
2185 sizeof(SECTION_OBJECT
),
2188 (PVOID
*)(PVOID
)&Section
);
2189 if (!NT_SUCCESS(Status
))
2197 Section
->SectionPageProtection
= SectionPageProtection
;
2198 Section
->AllocationAttributes
= AllocationAttributes
;
2199 Section
->Segment
= NULL
;
2200 InitializeListHead(&Section
->ViewListHead
);
2201 KeInitializeSpinLock(&Section
->ViewListLock
);
2202 Section
->FileObject
= NULL
;
2203 Section
->MaximumSize
= MaximumSize
;
2204 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2205 TAG_MM_SECTION_SEGMENT
);
2206 if (Segment
== NULL
)
2208 ObDereferenceObject(Section
);
2209 return(STATUS_NO_MEMORY
);
2211 Section
->Segment
= Segment
;
2212 Segment
->ReferenceCount
= 1;
2213 ExInitializeFastMutex(&Segment
->Lock
);
2214 Segment
->FileOffset
= 0;
2215 Segment
->Protection
= SectionPageProtection
;
2216 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2217 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2218 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2219 Segment
->WriteCopy
= FALSE
;
2220 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2221 Segment
->VirtualAddress
= 0;
2222 Segment
->Characteristics
= 0;
2223 *SectionObject
= Section
;
2224 return(STATUS_SUCCESS
);
2229 MmCreateDataFileSection(PSECTION_OBJECT
*SectionObject
,
2230 ACCESS_MASK DesiredAccess
,
2231 POBJECT_ATTRIBUTES ObjectAttributes
,
2232 PLARGE_INTEGER UMaximumSize
,
2233 ULONG SectionPageProtection
,
2234 ULONG AllocationAttributes
,
2237 * Create a section backed by a data file
2240 PSECTION_OBJECT Section
;
2242 LARGE_INTEGER MaximumSize
;
2243 PFILE_OBJECT FileObject
;
2244 PMM_SECTION_SEGMENT Segment
;
2246 IO_STATUS_BLOCK Iosb
;
2247 LARGE_INTEGER Offset
;
2249 FILE_STANDARD_INFORMATION FileInfo
;
2252 * Create the section
2254 Status
= ObCreateObject(ExGetPreviousMode(),
2255 MmSectionObjectType
,
2257 ExGetPreviousMode(),
2259 sizeof(SECTION_OBJECT
),
2262 (PVOID
*)(PVOID
)&Section
);
2263 if (!NT_SUCCESS(Status
))
2271 Section
->SectionPageProtection
= SectionPageProtection
;
2272 Section
->AllocationAttributes
= AllocationAttributes
;
2273 Section
->Segment
= NULL
;
2274 InitializeListHead(&Section
->ViewListHead
);
2275 KeInitializeSpinLock(&Section
->ViewListLock
);
2278 * Check file access required
2280 if (SectionPageProtection
& PAGE_READWRITE
||
2281 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2283 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2287 FileAccess
= FILE_READ_DATA
;
2291 * Reference the file handle
2293 Status
= ObReferenceObjectByHandle(FileHandle
,
2297 (PVOID
*)(PVOID
)&FileObject
,
2299 if (!NT_SUCCESS(Status
))
2301 ObDereferenceObject(Section
);
2306 * FIXME: This is propably not entirely correct. We can't look into
2307 * the standard FCB header because it might not be initialized yet
2308 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2309 * standard file information is filled on first request).
2311 Status
= NtQueryInformationFile(FileHandle
,
2314 sizeof(FILE_STANDARD_INFORMATION
),
2315 FileStandardInformation
);
2316 if (!NT_SUCCESS(Status
))
2318 ObDereferenceObject(Section
);
2319 ObDereferenceObject(FileObject
);
2324 * FIXME: Revise this once a locking order for file size changes is
2327 if (UMaximumSize
!= NULL
)
2329 MaximumSize
= *UMaximumSize
;
2333 MaximumSize
= FileInfo
.EndOfFile
;
2334 /* Mapping zero-sized files isn't allowed. */
2335 if (MaximumSize
.QuadPart
== 0)
2337 ObDereferenceObject(Section
);
2338 ObDereferenceObject(FileObject
);
2339 return STATUS_FILE_INVALID
;
2343 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2345 Status
= NtSetInformationFile(FileHandle
,
2348 sizeof(LARGE_INTEGER
),
2349 FileAllocationInformation
);
2350 if (!NT_SUCCESS(Status
))
2352 ObDereferenceObject(Section
);
2353 ObDereferenceObject(FileObject
);
2354 return(STATUS_SECTION_NOT_EXTENDED
);
2358 if (FileObject
->SectionObjectPointer
== NULL
||
2359 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2362 * Read a bit so caching is initiated for the file object.
2363 * This is only needed because MiReadPage currently cannot
2364 * handle non-cached streams.
2366 Offset
.QuadPart
= 0;
2367 Status
= ZwReadFile(FileHandle
,
2376 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2378 ObDereferenceObject(Section
);
2379 ObDereferenceObject(FileObject
);
2382 if (FileObject
->SectionObjectPointer
== NULL
||
2383 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2385 /* FIXME: handle this situation */
2386 ObDereferenceObject(Section
);
2387 ObDereferenceObject(FileObject
);
2388 return STATUS_INVALID_PARAMETER
;
2395 Status
= MmspWaitForFileLock(FileObject
);
2396 if (Status
!= STATUS_SUCCESS
)
2398 ObDereferenceObject(Section
);
2399 ObDereferenceObject(FileObject
);
2404 * If this file hasn't been mapped as a data file before then allocate a
2405 * section segment to describe the data file mapping
2407 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2409 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2410 TAG_MM_SECTION_SEGMENT
);
2411 if (Segment
== NULL
)
2413 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2414 ObDereferenceObject(Section
);
2415 ObDereferenceObject(FileObject
);
2416 return(STATUS_NO_MEMORY
);
2418 Section
->Segment
= Segment
;
2419 Segment
->ReferenceCount
= 1;
2420 ExInitializeFastMutex(&Segment
->Lock
);
2422 * Set the lock before assigning the segment to the file object
2424 ExAcquireFastMutex(&Segment
->Lock
);
2425 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2427 Segment
->FileOffset
= 0;
2428 Segment
->Protection
= SectionPageProtection
;
2429 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2430 Segment
->Characteristics
= 0;
2431 Segment
->WriteCopy
= FALSE
;
2432 if (AllocationAttributes
& SEC_RESERVE
)
2434 Segment
->Length
= Segment
->RawLength
= 0;
2438 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2439 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2441 Segment
->VirtualAddress
= 0;
2442 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2447 * If the file is already mapped as a data file then we may need
2451 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2453 Section
->Segment
= Segment
;
2454 InterlockedIncrementUL(&Segment
->ReferenceCount
);
2455 MmLockSectionSegment(Segment
);
2457 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2458 !(AllocationAttributes
& SEC_RESERVE
))
2460 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2461 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2464 MmUnlockSectionSegment(Segment
);
2465 Section
->FileObject
= FileObject
;
2466 Section
->MaximumSize
= MaximumSize
;
2467 CcRosReferenceCache(FileObject
);
2468 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2469 *SectionObject
= Section
;
2470 return(STATUS_SUCCESS
);
2474 TODO: not that great (declaring loaders statically, having to declare all of
2475 them, having to keep them extern, etc.), will fix in the future
2477 extern NTSTATUS NTAPI PeFmtCreateSection
2479 IN CONST VOID
* FileHeader
,
2480 IN SIZE_T FileHeaderSize
,
2482 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2484 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2485 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2488 extern NTSTATUS NTAPI ElfFmtCreateSection
2490 IN CONST VOID
* FileHeader
,
2491 IN SIZE_T FileHeaderSize
,
2493 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2495 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2496 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2499 /* TODO: this is a standard DDK/PSDK macro */
2500 #ifndef RTL_NUMBER_OF
2501 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2504 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2513 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2515 SIZE_T SizeOfSegments
;
2516 PMM_SECTION_SEGMENT Segments
;
2518 /* TODO: check for integer overflow */
2519 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2521 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2523 TAG_MM_SECTION_SEGMENT
);
2526 RtlZeroMemory(Segments
, SizeOfSegments
);
2534 ExeFmtpReadFile(IN PVOID File
,
2535 IN PLARGE_INTEGER Offset
,
2538 OUT PVOID
* AllocBase
,
2539 OUT PULONG ReadSize
)
2542 LARGE_INTEGER FileOffset
;
2544 ULONG OffsetAdjustment
;
2549 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2553 KEBUGCHECK(STATUS_INVALID_PARAMETER_4
);
2556 FileOffset
= *Offset
;
2558 /* Negative/special offset: it cannot be used in this context */
2559 if(FileOffset
.u
.HighPart
< 0)
2561 KEBUGCHECK(STATUS_INVALID_PARAMETER_5
);
2564 ASSERT(PAGE_SIZE
<= MAXULONG
);
2565 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2566 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2567 FileOffset
.u
.LowPart
= AdjustOffset
;
2569 BufferSize
= Length
+ OffsetAdjustment
;
2570 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2573 * It's ok to use paged pool, because this is a temporary buffer only used in
2574 * the loading of executables. The assumption is that MmCreateSection is
2575 * always called at low IRQLs and that these buffers don't survive a brief
2576 * initialization phase
2578 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2580 TAG('M', 'm', 'X', 'r'));
2585 Status
= MmspPageRead(File
,
2592 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2593 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2594 * to initialize internal state is even worse. Our cache manager is in need of
2598 IO_STATUS_BLOCK Iosb
;
2600 Status
= ZwReadFile(File
,
2610 if(NT_SUCCESS(Status
))
2612 UsedSize
= Iosb
.Information
;
2617 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2619 Status
= STATUS_IN_PAGE_ERROR
;
2620 ASSERT(!NT_SUCCESS(Status
));
2623 if(NT_SUCCESS(Status
))
2625 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2626 *AllocBase
= Buffer
;
2627 *ReadSize
= UsedSize
- OffsetAdjustment
;
2638 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2639 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2640 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2645 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2649 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2651 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2652 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2659 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2663 MmspAssertSegmentsSorted(ImageSectionObject
);
2665 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2667 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2671 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2672 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2673 ImageSectionObject
->Segments
[i
- 1].Length
));
2681 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2685 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2687 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2688 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2696 MmspCompareSegments(const void * x
,
2699 PMM_SECTION_SEGMENT Segment1
= (PMM_SECTION_SEGMENT
)x
;
2700 PMM_SECTION_SEGMENT Segment2
= (PMM_SECTION_SEGMENT
)y
;
2703 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2704 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2708 * Ensures an image section's segments are sorted in memory
2713 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2716 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2718 MmspAssertSegmentsSorted(ImageSectionObject
);
2722 qsort(ImageSectionObject
->Segments
,
2723 ImageSectionObject
->NrSegments
,
2724 sizeof(ImageSectionObject
->Segments
[0]),
2725 MmspCompareSegments
);
2731 * Ensures an image section's segments don't overlap in memory and don't have
2732 * gaps and don't have a null size. We let them map to overlapping file regions,
2733 * though - that's not necessarily an error
2738 MmspCheckSegmentBounds
2740 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2746 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2748 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2752 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2754 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2756 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2764 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2765 * page could be OK (Windows seems to be OK with them), and larger gaps
2766 * could lead to image sections spanning several discontiguous regions
2767 * (NtMapViewOfSection could then refuse to map them, and they could
2768 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2770 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2771 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2772 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2783 * Merges and pads an image section's segments until they all are page-aligned
2784 * and have a size that is a multiple of the page size
2789 MmspPageAlignSegments
2791 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2797 BOOLEAN Initialized
;
2799 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2801 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2805 Initialized
= FALSE
;
2808 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2810 PMM_SECTION_SEGMENT EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2813 * The first segment requires special handling
2817 ULONG_PTR VirtualAddress
;
2818 ULONG_PTR VirtualOffset
;
2820 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2822 /* Round down the virtual address to the nearest page */
2823 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2825 /* Round up the virtual size to the nearest page */
2826 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2827 EffectiveSegment
->VirtualAddress
;
2829 /* Adjust the raw address and size */
2830 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2832 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
2838 * Garbage in, garbage out: unaligned base addresses make the file
2839 * offset point in curious and odd places, but that's what we were
2842 EffectiveSegment
->FileOffset
-= VirtualOffset
;
2843 EffectiveSegment
->RawLength
+= VirtualOffset
;
2847 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
2848 ULONG_PTR EndOfEffectiveSegment
;
2850 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
2851 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
2854 * The current segment begins exactly where the current effective
2855 * segment ended, therefore beginning a new effective segment
2857 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
2860 ASSERT(LastSegment
<= i
);
2861 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
2863 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2866 * Copy the current segment. If necessary, the effective segment
2867 * will be expanded later
2869 *EffectiveSegment
= *Segment
;
2872 * Page-align the virtual size. We know for sure the virtual address
2875 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
2876 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
2879 * The current segment is still part of the current effective segment:
2880 * extend the effective segment to reflect this
2882 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
2884 static const ULONG FlagsToProtection
[16] =
2892 PAGE_EXECUTE_READWRITE
,
2893 PAGE_EXECUTE_READWRITE
,
2898 PAGE_EXECUTE_WRITECOPY
,
2899 PAGE_EXECUTE_WRITECOPY
,
2900 PAGE_EXECUTE_WRITECOPY
,
2901 PAGE_EXECUTE_WRITECOPY
2904 unsigned ProtectionFlags
;
2907 * Extend the file size
2910 /* Unaligned segments must be contiguous within the file */
2911 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
2912 EffectiveSegment
->RawLength
))
2917 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
2920 * Extend the virtual size
2922 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) > EndOfEffectiveSegment
);
2924 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
2925 EffectiveSegment
->VirtualAddress
;
2928 * Merge the protection
2930 EffectiveSegment
->Protection
|= Segment
->Protection
;
2932 /* Clean up redundance */
2933 ProtectionFlags
= 0;
2935 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
2936 ProtectionFlags
|= 1 << 0;
2938 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
2939 ProtectionFlags
|= 1 << 1;
2941 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
2942 ProtectionFlags
|= 1 << 2;
2944 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2945 ProtectionFlags
|= 1 << 3;
2947 ASSERT(ProtectionFlags
< 16);
2948 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
2950 /* If a segment was required to be shared and cannot, fail */
2951 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
2952 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2958 * We assume no holes between segments at this point
2971 ExeFmtpCreateImageSection(HANDLE FileHandle
,
2972 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2974 LARGE_INTEGER Offset
;
2976 PVOID FileHeaderBuffer
;
2977 ULONG FileHeaderSize
;
2979 ULONG OldNrSegments
;
2984 * Read the beginning of the file (2 pages). Should be enough to contain
2985 * all (or most) of the headers
2987 Offset
.QuadPart
= 0;
2989 /* FIXME: use FileObject instead of FileHandle */
2990 Status
= ExeFmtpReadFile (FileHandle
,
2997 if (!NT_SUCCESS(Status
))
3000 if (FileHeaderSize
== 0)
3002 ExFreePool(FileHeaderBuffer
);
3003 return STATUS_UNSUCCESSFUL
;
3007 * Look for a loader that can handle this executable
3009 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3011 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3014 /* FIXME: use FileObject instead of FileHandle */
3015 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3021 ExeFmtpAllocateSegments
);
3023 if (!NT_SUCCESS(Status
))
3025 if (ImageSectionObject
->Segments
)
3027 ExFreePool(ImageSectionObject
->Segments
);
3028 ImageSectionObject
->Segments
= NULL
;
3032 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3036 ExFreePool(FileHeaderBuffer
);
3039 * No loader handled the format
3041 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3043 Status
= STATUS_INVALID_IMAGE_FORMAT
;
3044 ASSERT(!NT_SUCCESS(Status
));
3047 if (!NT_SUCCESS(Status
))
3050 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3055 /* FIXME? are these values platform-dependent? */
3056 if(ImageSectionObject
->StackReserve
== 0)
3057 ImageSectionObject
->StackReserve
= 0x40000;
3059 if(ImageSectionObject
->StackCommit
== 0)
3060 ImageSectionObject
->StackCommit
= 0x1000;
3062 if(ImageSectionObject
->ImageBase
== 0)
3064 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3065 ImageSectionObject
->ImageBase
= 0x10000000;
3067 ImageSectionObject
->ImageBase
= 0x00400000;
3071 * And now the fun part: fixing the segments
3074 /* Sort them by virtual address */
3075 MmspSortSegments(ImageSectionObject
, Flags
);
3077 /* Ensure they don't overlap in memory */
3078 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3079 return STATUS_INVALID_IMAGE_FORMAT
;
3081 /* Ensure they are aligned */
3082 OldNrSegments
= ImageSectionObject
->NrSegments
;
3084 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3085 return STATUS_INVALID_IMAGE_FORMAT
;
3087 /* Trim them if the alignment phase merged some of them */
3088 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3090 PMM_SECTION_SEGMENT Segments
;
3091 SIZE_T SizeOfSegments
;
3093 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3095 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3097 TAG_MM_SECTION_SEGMENT
);
3099 if (Segments
== NULL
)
3100 return STATUS_INSUFFICIENT_RESOURCES
;
3102 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3103 ExFreePool(ImageSectionObject
->Segments
);
3104 ImageSectionObject
->Segments
= Segments
;
3107 /* And finish their initialization */
3108 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3110 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3111 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3113 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3114 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3117 ASSERT(NT_SUCCESS(Status
));
3122 MmCreateImageSection(PSECTION_OBJECT
*SectionObject
,
3123 ACCESS_MASK DesiredAccess
,
3124 POBJECT_ATTRIBUTES ObjectAttributes
,
3125 PLARGE_INTEGER UMaximumSize
,
3126 ULONG SectionPageProtection
,
3127 ULONG AllocationAttributes
,
3130 PSECTION_OBJECT Section
;
3132 PFILE_OBJECT FileObject
;
3133 PMM_SECTION_SEGMENT SectionSegments
;
3134 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3136 ULONG FileAccess
= 0;
3139 * Specifying a maximum size is meaningless for an image section
3141 if (UMaximumSize
!= NULL
)
3143 return(STATUS_INVALID_PARAMETER_4
);
3147 * Check file access required
3149 if (SectionPageProtection
& PAGE_READWRITE
||
3150 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3152 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3156 FileAccess
= FILE_READ_DATA
;
3160 * Reference the file handle
3162 Status
= ObReferenceObjectByHandle(FileHandle
,
3166 (PVOID
*)(PVOID
)&FileObject
,
3168 if (!NT_SUCCESS(Status
))
3174 * Create the section
3176 Status
= ObCreateObject (ExGetPreviousMode(),
3177 MmSectionObjectType
,
3179 ExGetPreviousMode(),
3181 sizeof(SECTION_OBJECT
),
3184 (PVOID
*)(PVOID
)&Section
);
3185 if (!NT_SUCCESS(Status
))
3187 ObDereferenceObject(FileObject
);
3194 Section
->SectionPageProtection
= SectionPageProtection
;
3195 Section
->AllocationAttributes
= AllocationAttributes
;
3196 InitializeListHead(&Section
->ViewListHead
);
3197 KeInitializeSpinLock(&Section
->ViewListLock
);
3200 * Initialized caching for this file object if previously caching
3201 * was initialized for the same on disk file
3203 Status
= CcTryToInitializeFileCache(FileObject
);
3205 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3207 NTSTATUS StatusExeFmt
;
3209 ImageSectionObject
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3210 if (ImageSectionObject
== NULL
)
3212 ObDereferenceObject(FileObject
);
3213 ObDereferenceObject(Section
);
3214 return(STATUS_NO_MEMORY
);
3217 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3219 if (!NT_SUCCESS(StatusExeFmt
))
3221 if(ImageSectionObject
->Segments
!= NULL
)
3222 ExFreePool(ImageSectionObject
->Segments
);
3224 ExFreePool(ImageSectionObject
);
3225 ObDereferenceObject(Section
);
3226 ObDereferenceObject(FileObject
);
3227 return(StatusExeFmt
);
3230 Section
->ImageSection
= ImageSectionObject
;
3231 ASSERT(ImageSectionObject
->Segments
);
3236 Status
= MmspWaitForFileLock(FileObject
);
3237 if (!NT_SUCCESS(Status
))
3239 ExFreePool(ImageSectionObject
->Segments
);
3240 ExFreePool(ImageSectionObject
);
3241 ObDereferenceObject(Section
);
3242 ObDereferenceObject(FileObject
);
3246 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3247 ImageSectionObject
, NULL
))
3250 * An other thread has initialized the some image in the background
3252 ExFreePool(ImageSectionObject
->Segments
);
3253 ExFreePool(ImageSectionObject
);
3254 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3255 Section
->ImageSection
= ImageSectionObject
;
3256 SectionSegments
= ImageSectionObject
->Segments
;
3258 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3260 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3264 Status
= StatusExeFmt
;
3271 Status
= MmspWaitForFileLock(FileObject
);
3272 if (Status
!= STATUS_SUCCESS
)
3274 ObDereferenceObject(Section
);
3275 ObDereferenceObject(FileObject
);
3279 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3280 Section
->ImageSection
= ImageSectionObject
;
3281 SectionSegments
= ImageSectionObject
->Segments
;
3284 * Otherwise just reference all the section segments
3286 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3288 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3291 Status
= STATUS_SUCCESS
;
3293 Section
->FileObject
= FileObject
;
3294 CcRosReferenceCache(FileObject
);
3295 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
3296 *SectionObject
= Section
;
3304 NtCreateSection (OUT PHANDLE SectionHandle
,
3305 IN ACCESS_MASK DesiredAccess
,
3306 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3307 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3308 IN ULONG SectionPageProtection OPTIONAL
,
3309 IN ULONG AllocationAttributes
,
3310 IN HANDLE FileHandle OPTIONAL
)
3312 PSECTION_OBJECT SectionObject
;
3316 * Check the protection
3318 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
3319 SectionPageProtection
)
3321 return(STATUS_INVALID_PAGE_PROTECTION
);
3324 Status
= MmCreateSection(&SectionObject
,
3328 SectionPageProtection
,
3329 AllocationAttributes
,
3333 if (NT_SUCCESS(Status
))
3335 Status
= ObInsertObject ((PVOID
)SectionObject
,
3341 ObDereferenceObject(SectionObject
);
3348 /**********************************************************************
3366 NtOpenSection(PHANDLE SectionHandle
,
3367 ACCESS_MASK DesiredAccess
,
3368 POBJECT_ATTRIBUTES ObjectAttributes
)
3374 Status
= ObOpenObjectByName(ObjectAttributes
,
3375 MmSectionObjectType
,
3386 MmMapViewOfSegment(PEPROCESS Process
,
3387 PMADDRESS_SPACE AddressSpace
,
3388 PSECTION_OBJECT Section
,
3389 PMM_SECTION_SEGMENT Segment
,
3399 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3401 BoundaryAddressMultiple
.QuadPart
= 0;
3403 Status
= MmCreateMemoryArea(Process
,
3405 MEMORY_AREA_SECTION_VIEW
,
3412 BoundaryAddressMultiple
);
3413 if (!NT_SUCCESS(Status
))
3415 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3416 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3420 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3421 InsertTailList(&Section
->ViewListHead
,
3422 &MArea
->Data
.SectionData
.ViewListEntry
);
3423 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3425 ObReferenceObjectByPointer((PVOID
)Section
,
3428 ExGetPreviousMode());
3429 MArea
->Data
.SectionData
.Segment
= Segment
;
3430 MArea
->Data
.SectionData
.Section
= Section
;
3431 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3432 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3433 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3434 ViewSize
, 0, Protect
);
3436 return(STATUS_SUCCESS
);
3440 /**********************************************************************
3442 * NtMapViewOfSection
3445 * Maps a view of a section into the virtual address space of a
3450 * Handle of the section.
3453 * Handle of the process.
3456 * Desired base address (or NULL) on entry;
3457 * Actual base address of the view on exit.
3460 * Number of high order address bits that must be zero.
3463 * Size in bytes of the initially committed section of
3467 * Offset in bytes from the beginning of the section
3468 * to the beginning of the view.
3471 * Desired length of map (or zero to map all) on entry
3472 * Actual length mapped on exit.
3474 * InheritDisposition
3475 * Specified how the view is to be shared with
3479 * Type of allocation for the pages.
3482 * Protection for the committed region of the view.
3490 NtMapViewOfSection(HANDLE SectionHandle
,
3491 HANDLE ProcessHandle
,
3495 PLARGE_INTEGER SectionOffset
,
3497 SECTION_INHERIT InheritDisposition
,
3498 ULONG AllocationType
,
3501 PSECTION_OBJECT Section
;
3504 PMADDRESS_SPACE AddressSpace
;
3506 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3507 PROCESS_VM_OPERATION
,
3510 (PVOID
*)(PVOID
)&Process
,
3512 if (!NT_SUCCESS(Status
))
3517 AddressSpace
= &Process
->AddressSpace
;
3519 Status
= ObReferenceObjectByHandle(SectionHandle
,
3521 MmSectionObjectType
,
3523 (PVOID
*)(PVOID
)&Section
,
3525 if (!(NT_SUCCESS(Status
)))
3527 DPRINT("ObReference failed rc=%x\n",Status
);
3528 ObDereferenceObject(Process
);
3532 Status
= MmMapViewOfSection(Section
,
3543 ObDereferenceObject(Section
);
3544 ObDereferenceObject(Process
);
3550 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3551 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3555 PFILE_OBJECT FileObject
;
3558 SWAPENTRY SavedSwapEntry
;
3561 PSECTION_OBJECT Section
;
3562 PMM_SECTION_SEGMENT Segment
;
3564 MArea
= (PMEMORY_AREA
)Context
;
3566 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3568 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MArea
->StartingAddress
) +
3569 MemoryArea
->Data
.SectionData
.ViewOffset
;
3571 Section
= MArea
->Data
.SectionData
.Section
;
3572 Segment
= MArea
->Data
.SectionData
.Segment
;
3574 PageOp
= MmCheckForPageOp(MArea
, NULL
, NULL
, Segment
, Offset
);
3578 MmUnlockSectionSegment(Segment
);
3579 MmUnlockAddressSpace(&MArea
->Process
->AddressSpace
);
3581 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3582 if (Status
!= STATUS_SUCCESS
)
3584 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3588 MmLockAddressSpace(&MArea
->Process
->AddressSpace
);
3589 MmLockSectionSegment(Segment
);
3590 MmspCompleteAndReleasePageOp(PageOp
);
3591 PageOp
= MmCheckForPageOp(MArea
, NULL
, NULL
, Segment
, Offset
);
3594 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3597 * For a dirty, datafile, non-private page mark it as dirty in the
3600 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3602 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3604 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3605 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3606 CcRosMarkDirtyCacheSegment(Bcb
, Offset
);
3607 ASSERT(SwapEntry
== 0);
3616 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3618 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3621 MmFreeSwapPage(SwapEntry
);
3625 if (IS_SWAP_FROM_SSE(Entry
) ||
3626 Page
!= PFN_FROM_SSE(Entry
))
3631 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3633 DPRINT1("Found a private page in a pagefile section.\n");
3637 * Just dereference private pages
3639 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3640 if (SavedSwapEntry
!= 0)
3642 MmFreeSwapPage(SavedSwapEntry
);
3643 MmSetSavedSwapEntryPage(Page
, 0);
3645 MmDeleteRmap(Page
, MArea
->Process
, Address
);
3646 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3650 MmDeleteRmap(Page
, MArea
->Process
, Address
);
3651 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3657 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3661 PMEMORY_AREA MemoryArea
;
3662 PSECTION_OBJECT Section
;
3663 PMM_SECTION_SEGMENT Segment
;
3665 PLIST_ENTRY CurrentEntry
;
3666 PMM_REGION CurrentRegion
;
3667 PLIST_ENTRY RegionListHead
;
3669 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3671 if (MemoryArea
== NULL
)
3673 return(STATUS_UNSUCCESSFUL
);
3676 MemoryArea
->DeleteInProgress
= TRUE
;
3677 Section
= MemoryArea
->Data
.SectionData
.Section
;
3678 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3680 MmLockSectionSegment(Segment
);
3681 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3682 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
3683 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3685 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3686 while (!IsListEmpty(RegionListHead
))
3688 CurrentEntry
= RemoveHeadList(RegionListHead
);
3689 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3690 ExFreePool(CurrentRegion
);
3693 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3695 Status
= MmFreeMemoryArea(AddressSpace
,
3702 Status
= MmFreeMemoryArea(AddressSpace
,
3707 MmUnlockSectionSegment(Segment
);
3708 ObDereferenceObject(Section
);
3709 return(STATUS_SUCCESS
);
3716 MmUnmapViewOfSection(PEPROCESS Process
,
3720 PMEMORY_AREA MemoryArea
;
3721 PMADDRESS_SPACE AddressSpace
;
3722 PSECTION_OBJECT Section
;
3724 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3725 Process
, BaseAddress
);
3729 AddressSpace
= &Process
->AddressSpace
;
3730 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3732 if (MemoryArea
== NULL
||
3733 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
3734 MemoryArea
->DeleteInProgress
)
3736 return STATUS_NOT_MAPPED_VIEW
;
3739 Section
= MemoryArea
->Data
.SectionData
.Section
;
3741 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3745 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3746 PMM_SECTION_SEGMENT SectionSegments
;
3747 PVOID ImageBaseAddress
= 0;
3748 PMM_SECTION_SEGMENT Segment
;
3750 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3751 ImageSectionObject
= Section
->ImageSection
;
3752 SectionSegments
= ImageSectionObject
->Segments
;
3753 NrSegments
= ImageSectionObject
->NrSegments
;
3755 /* Search for the current segment within the section segments
3756 * and calculate the image base address */
3757 for (i
= 0; i
< NrSegments
; i
++)
3759 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3761 if (Segment
== &SectionSegments
[i
])
3763 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3768 if (i
>= NrSegments
)
3773 for (i
= 0; i
< NrSegments
; i
++)
3775 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3777 PVOID SBaseAddress
= (PVOID
)
3778 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3780 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
3786 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
3788 return(STATUS_SUCCESS
);
3791 /**********************************************************************
3793 * NtUnmapViewOfSection
3808 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3814 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3815 ProcessHandle
, BaseAddress
);
3817 DPRINT("Referencing process\n");
3818 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3819 PROCESS_VM_OPERATION
,
3822 (PVOID
*)(PVOID
)&Process
,
3824 if (!NT_SUCCESS(Status
))
3826 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3830 MmLockAddressSpace(&Process
->AddressSpace
);
3831 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3832 MmUnlockAddressSpace(&Process
->AddressSpace
);
3834 ObDereferenceObject(Process
);
3841 * Queries the information of a section object.
3843 * @param SectionHandle
3844 * Handle to the section object. It must be opened with SECTION_QUERY
3846 * @param SectionInformationClass
3847 * Index to a certain information structure. Can be either
3848 * SectionBasicInformation or SectionImageInformation. The latter
3849 * is valid only for sections that were created with the SEC_IMAGE
3851 * @param SectionInformation
3852 * Caller supplies storage for resulting information.
3854 * Size of the supplied storage.
3855 * @param ResultLength
3860 * @todo Guard by SEH.
3864 NtQuerySection(IN HANDLE SectionHandle
,
3865 IN CINT SectionInformationClass
,
3866 OUT PVOID SectionInformation
,
3868 OUT PULONG ResultLength
)
3870 PSECTION_OBJECT Section
;
3873 Status
= ObReferenceObjectByHandle(SectionHandle
,
3875 MmSectionObjectType
,
3877 (PVOID
*)(PVOID
)&Section
,
3879 if (!(NT_SUCCESS(Status
)))
3884 switch (SectionInformationClass
)
3886 case SectionBasicInformation
:
3888 PSECTION_BASIC_INFORMATION Sbi
;
3890 if (Length
!= sizeof(SECTION_BASIC_INFORMATION
))
3892 ObDereferenceObject(Section
);
3893 return(STATUS_INFO_LENGTH_MISMATCH
);
3896 Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
3898 Sbi
->Attributes
= Section
->AllocationAttributes
;
3899 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3901 Sbi
->BaseAddress
= 0;
3902 Sbi
->Size
.QuadPart
= 0;
3906 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
3907 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
3910 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
3911 Status
= STATUS_SUCCESS
;
3915 case SectionImageInformation
:
3917 PSECTION_IMAGE_INFORMATION Sii
;
3919 if (Length
!= sizeof(SECTION_IMAGE_INFORMATION
))
3921 ObDereferenceObject(Section
);
3922 return(STATUS_INFO_LENGTH_MISMATCH
);
3925 Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
3926 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
3927 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3929 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3930 ImageSectionObject
= Section
->ImageSection
;
3932 Sii
->EntryPoint
= ImageSectionObject
->EntryPoint
;
3933 Sii
->StackReserve
= ImageSectionObject
->StackReserve
;
3934 Sii
->StackCommit
= ImageSectionObject
->StackCommit
;
3935 Sii
->Subsystem
= ImageSectionObject
->Subsystem
;
3936 Sii
->MinorSubsystemVersion
= ImageSectionObject
->MinorSubsystemVersion
;
3937 Sii
->MajorSubsystemVersion
= ImageSectionObject
->MajorSubsystemVersion
;
3938 Sii
->Characteristics
= ImageSectionObject
->ImageCharacteristics
;
3939 Sii
->ImageNumber
= ImageSectionObject
->Machine
;
3940 Sii
->Executable
= ImageSectionObject
->Executable
;
3942 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
3943 Status
= STATUS_SUCCESS
;
3949 Status
= STATUS_INVALID_INFO_CLASS
;
3951 ObDereferenceObject(Section
);
3957 * Extends size of file backed section.
3959 * @param SectionHandle
3960 * Handle to the section object. It must be opened with
3961 * SECTION_EXTEND_SIZE access.
3962 * @param NewMaximumSize
3963 * New maximum size of the section in bytes.
3967 * @todo Guard by SEH.
3968 * @todo Move the actual code to internal function MmExtendSection.
3972 NtExtendSection(IN HANDLE SectionHandle
,
3973 IN PLARGE_INTEGER NewMaximumSize
)
3975 PSECTION_OBJECT Section
;
3978 Status
= ObReferenceObjectByHandle(SectionHandle
,
3979 SECTION_EXTEND_SIZE
,
3980 MmSectionObjectType
,
3984 if (!NT_SUCCESS(Status
))
3989 if (!(Section
->AllocationAttributes
& SEC_FILE
))
3991 ObfDereferenceObject(Section
);
3992 return STATUS_INVALID_PARAMETER
;
3996 * - Acquire file extneding resource.
3997 * - Check if we're not resizing the section below it's actual size!
3998 * - Extend segments if needed.
3999 * - Set file information (FileAllocationInformation) to the new size.
4000 * - Release file extending resource.
4003 ObDereferenceObject(Section
);
4005 return STATUS_NOT_IMPLEMENTED
;
4009 /**********************************************************************
4011 * MmAllocateSection@4
4021 * Code taken from ntoskrnl/mm/special.c.
4026 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4032 PMADDRESS_SPACE AddressSpace
;
4033 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4035 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4037 BoundaryAddressMultiple
.QuadPart
= 0;
4039 AddressSpace
= MmGetKernelAddressSpace();
4040 Result
= BaseAddress
;
4041 MmLockAddressSpace(AddressSpace
);
4042 Status
= MmCreateMemoryArea (NULL
,
4051 BoundaryAddressMultiple
);
4052 MmUnlockAddressSpace(AddressSpace
);
4054 if (!NT_SUCCESS(Status
))
4058 DPRINT("Result %p\n",Result
);
4059 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
4063 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
4064 if (!NT_SUCCESS(Status
))
4066 DbgPrint("Unable to allocate page\n");
4069 Status
= MmCreateVirtualMapping (NULL
,
4070 (PVOID
)((ULONG_PTR
)Result
+ (i
* PAGE_SIZE
)),
4074 if (!NT_SUCCESS(Status
))
4076 DbgPrint("Unable to create virtual mapping\n");
4080 return ((PVOID
)Result
);
4084 /**********************************************************************
4086 * MmMapViewOfSection
4089 * Maps a view of a section into the virtual address space of a
4094 * Pointer to the section object.
4097 * Pointer to the process.
4100 * Desired base address (or NULL) on entry;
4101 * Actual base address of the view on exit.
4104 * Number of high order address bits that must be zero.
4107 * Size in bytes of the initially committed section of
4111 * Offset in bytes from the beginning of the section
4112 * to the beginning of the view.
4115 * Desired length of map (or zero to map all) on entry
4116 * Actual length mapped on exit.
4118 * InheritDisposition
4119 * Specified how the view is to be shared with
4123 * Type of allocation for the pages.
4126 * Protection for the committed region of the view.
4134 MmMapViewOfSection(IN PVOID SectionObject
,
4135 IN PEPROCESS Process
,
4136 IN OUT PVOID
*BaseAddress
,
4138 IN ULONG CommitSize
,
4139 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4140 IN OUT PULONG ViewSize
,
4141 IN SECTION_INHERIT InheritDisposition
,
4142 IN ULONG AllocationType
,
4145 PSECTION_OBJECT Section
;
4146 PMADDRESS_SPACE AddressSpace
;
4148 NTSTATUS Status
= STATUS_SUCCESS
;
4152 Section
= (PSECTION_OBJECT
)SectionObject
;
4153 AddressSpace
= &Process
->AddressSpace
;
4155 MmLockAddressSpace(AddressSpace
);
4157 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4161 ULONG_PTR ImageBase
;
4163 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4164 PMM_SECTION_SEGMENT SectionSegments
;
4166 ImageSectionObject
= Section
->ImageSection
;
4167 SectionSegments
= ImageSectionObject
->Segments
;
4168 NrSegments
= ImageSectionObject
->NrSegments
;
4171 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4174 ImageBase
= ImageSectionObject
->ImageBase
;
4178 for (i
= 0; i
< NrSegments
; i
++)
4180 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4182 ULONG_PTR MaxExtent
;
4183 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4184 SectionSegments
[i
].Length
;
4185 ImageSize
= max(ImageSize
, MaxExtent
);
4189 /* Check there is enough space to map the section at that point. */
4190 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4191 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4193 /* Fail if the user requested a fixed base address. */
4194 if ((*BaseAddress
) != NULL
)
4196 MmUnlockAddressSpace(AddressSpace
);
4197 return(STATUS_UNSUCCESSFUL
);
4199 /* Otherwise find a gap to map the image. */
4200 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4203 MmUnlockAddressSpace(AddressSpace
);
4204 return(STATUS_UNSUCCESSFUL
);
4208 for (i
= 0; i
< NrSegments
; i
++)
4210 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4212 PVOID SBaseAddress
= (PVOID
)
4213 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4214 MmLockSectionSegment(&SectionSegments
[i
]);
4215 Status
= MmMapViewOfSegment(Process
,
4218 &SectionSegments
[i
],
4220 SectionSegments
[i
].Length
,
4221 SectionSegments
[i
].Protection
,
4224 MmUnlockSectionSegment(&SectionSegments
[i
]);
4225 if (!NT_SUCCESS(Status
))
4227 MmUnlockAddressSpace(AddressSpace
);
4233 *BaseAddress
= (PVOID
)ImageBase
;
4237 if (ViewSize
== NULL
)
4239 /* Following this pointer would lead to us to the dark side */
4240 /* What to do? Bugcheck? Return status? Do the mambo? */
4241 KEBUGCHECK(MEMORY_MANAGEMENT
);
4244 if (SectionOffset
== NULL
)
4250 ViewOffset
= SectionOffset
->u
.LowPart
;
4253 if ((ViewOffset
% PAGE_SIZE
) != 0)
4255 MmUnlockAddressSpace(AddressSpace
);
4256 return(STATUS_MAPPED_ALIGNMENT
);
4259 if ((*ViewSize
) == 0)
4261 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4263 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4265 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4268 MmLockSectionSegment(Section
->Segment
);
4269 Status
= MmMapViewOfSegment(Process
,
4277 (AllocationType
& MEM_TOP_DOWN
));
4278 MmUnlockSectionSegment(Section
->Segment
);
4279 if (!NT_SUCCESS(Status
))
4281 MmUnlockAddressSpace(AddressSpace
);
4286 MmUnlockAddressSpace(AddressSpace
);
4288 return(STATUS_SUCCESS
);
4295 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4296 IN PLARGE_INTEGER NewFileSize
)
4307 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
4317 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4318 IN MMFLUSH_TYPE FlushType
)
4322 case MmFlushForDelete
:
4323 if (SectionObjectPointer
->ImageSectionObject
||
4324 SectionObjectPointer
->DataSectionObject
)
4328 CcRosSetRemoveOnClose(SectionObjectPointer
);
4330 case MmFlushForWrite
:
4340 MmForceSectionClosed (
4341 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4342 IN BOOLEAN DelayClose
)
4353 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4354 OUT PVOID
* MappedBase
,
4355 IN OUT PULONG ViewSize
)
4357 PSECTION_OBJECT Section
;
4358 PMADDRESS_SPACE AddressSpace
;
4361 DPRINT("MmMapViewInSystemSpace() called\n");
4363 Section
= (PSECTION_OBJECT
)SectionObject
;
4364 AddressSpace
= MmGetKernelAddressSpace();
4366 MmLockAddressSpace(AddressSpace
);
4369 if ((*ViewSize
) == 0)
4371 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4373 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4375 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4378 MmLockSectionSegment(Section
->Segment
);
4381 Status
= MmMapViewOfSegment(NULL
,
4391 MmUnlockSectionSegment(Section
->Segment
);
4392 MmUnlockAddressSpace(AddressSpace
);
4402 MmMapViewInSessionSpace (
4404 OUT PVOID
*MappedBase
,
4405 IN OUT PSIZE_T ViewSize
4409 return STATUS_NOT_IMPLEMENTED
;
4417 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4419 PMADDRESS_SPACE AddressSpace
;
4422 DPRINT("MmUnmapViewInSystemSpace() called\n");
4424 AddressSpace
= MmGetKernelAddressSpace();
4426 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4436 MmUnmapViewInSessionSpace (
4441 return STATUS_NOT_IMPLEMENTED
;
4448 MmSetBankedSection (DWORD Unknown0
,
4456 return (STATUS_NOT_IMPLEMENTED
);
4460 /**********************************************************************
4465 * Creates a section object.
4468 * SectionObject (OUT)
4469 * Caller supplied storage for the resulting pointer
4470 * to a SECTION_OBJECT instance;
4473 * Specifies the desired access to the section can be a
4475 * STANDARD_RIGHTS_REQUIRED |
4477 * SECTION_MAP_WRITE |
4478 * SECTION_MAP_READ |
4479 * SECTION_MAP_EXECUTE
4481 * ObjectAttributes [OPTIONAL]
4482 * Initialized attributes for the object can be used
4483 * to create a named section;
4486 * Maximizes the size of the memory section. Must be
4487 * non-NULL for a page-file backed section.
4488 * If value specified for a mapped file and the file is
4489 * not large enough, file will be extended.
4491 * SectionPageProtection
4492 * Can be a combination of:
4498 * AllocationAttributes
4499 * Can be a combination of:
4504 * Handle to a file to create a section mapped to a file
4505 * instead of a memory backed section;
4516 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4517 IN ACCESS_MASK DesiredAccess
,
4518 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4519 IN PLARGE_INTEGER MaximumSize
,
4520 IN ULONG SectionPageProtection
,
4521 IN ULONG AllocationAttributes
,
4522 IN HANDLE FileHandle OPTIONAL
,
4523 IN PFILE_OBJECT File OPTIONAL
)
4525 if (AllocationAttributes
& SEC_IMAGE
)
4527 return(MmCreateImageSection(SectionObject
,
4531 SectionPageProtection
,
4532 AllocationAttributes
,
4536 if (FileHandle
!= NULL
)
4538 return(MmCreateDataFileSection(SectionObject
,
4542 SectionPageProtection
,
4543 AllocationAttributes
,
4547 return(MmCreatePageFileSection(SectionObject
,
4551 SectionPageProtection
,
4552 AllocationAttributes
));