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 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
55 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
56 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
59 /* FUNCTIONS *****************************************************************/
61 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
64 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
65 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
66 * RETURNS: Status of the wait.
69 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
71 LARGE_INTEGER Timeout
;
72 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
74 Timeout
.QuadPart
= -100000000LL; // 10 sec
77 Timeout
.QuadPart
= -100000000; // 10 sec
80 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
85 * FUNCTION: Sets the page op completion event and releases the page op.
86 * ARGUMENTS: PMM_PAGEOP.
87 * RETURNS: In shorter time than it takes you to even read this
88 * description, so don't even think about geting a mug of coffee.
91 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
93 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
94 MmReleasePageOp(PageOp
);
99 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
100 * ARGUMENTS: PFILE_OBJECT to wait for.
101 * RETURNS: Status of the wait.
104 MmspWaitForFileLock(PFILE_OBJECT File
)
106 return KeWaitForSingleObject(&File
->Lock
, 0, KernelMode
, FALSE
, NULL
);
111 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
114 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
116 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
118 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
120 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
127 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
129 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
131 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
132 PMM_SECTION_SEGMENT SectionSegments
;
136 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
137 NrSegments
= ImageSectionObject
->NrSegments
;
138 SectionSegments
= ImageSectionObject
->Segments
;
139 for (i
= 0; i
< NrSegments
; i
++)
141 if (SectionSegments
[i
].ReferenceCount
!= 0)
143 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
144 SectionSegments
[i
].ReferenceCount
);
147 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
149 ExFreePool(ImageSectionObject
->Segments
);
150 ExFreePool(ImageSectionObject
);
151 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
153 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
155 PMM_SECTION_SEGMENT Segment
;
157 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
160 if (Segment
->ReferenceCount
!= 0)
162 DPRINT1("Data segment still referenced\n");
165 MmFreePageTablesSectionSegment(Segment
);
167 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
172 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
174 ExAcquireFastMutex(&Segment
->Lock
);
178 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
180 ExReleaseFastMutex(&Segment
->Lock
);
184 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
188 PSECTION_PAGE_TABLE Table
;
189 ULONG DirectoryOffset
;
192 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
194 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
198 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
199 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
203 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
204 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
205 TAG_SECTION_PAGE_TABLE
);
210 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
211 DPRINT("Table %x\n", Table
);
214 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
215 Table
->Entry
[TableOffset
] = Entry
;
220 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
223 PSECTION_PAGE_TABLE Table
;
225 ULONG DirectoryOffset
;
228 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
230 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
232 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
236 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
237 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
238 DPRINT("Table %x\n", Table
);
244 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
245 Entry
= Table
->Entry
[TableOffset
];
250 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
255 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
258 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
261 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
263 DPRINT1("Maximum share count reached\n");
266 if (IS_SWAP_FROM_SSE(Entry
))
270 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
271 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
275 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section
,
276 PMM_SECTION_SEGMENT Segment
,
282 BOOLEAN IsDirectMapped
= FALSE
;
284 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
287 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
290 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
292 DPRINT1("Zero share count for unshare\n");
295 if (IS_SWAP_FROM_SSE(Entry
))
299 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
301 * If we reducing the share count of this entry to zero then set the entry
302 * to zero and tell the cache the page is no longer mapped.
304 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
306 PFILE_OBJECT FileObject
;
308 SWAPENTRY SavedSwapEntry
;
310 BOOLEAN IsImageSection
;
313 FileOffset
= Offset
+ Segment
->FileOffset
;
315 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
317 Page
= PFN_FROM_SSE(Entry
);
318 FileObject
= Section
->FileObject
;
319 if (FileObject
!= NULL
&&
320 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
323 if ((FileOffset
% PAGE_SIZE
) == 0 &&
324 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
327 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
328 IsDirectMapped
= TRUE
;
329 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
330 if (!NT_SUCCESS(Status
))
332 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
338 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
339 if (SavedSwapEntry
== 0)
342 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
343 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
347 * Try to page out this page and set the swap entry
348 * within the section segment. There exist no rmap entry
349 * for this page. The pager thread can't page out a
350 * page without a rmap entry.
352 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
356 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
359 MmReleasePageMemoryConsumer(MC_USER
, Page
);
365 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
366 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
374 * We hold all locks. Nobody can do something with the current
375 * process and the current segment (also not within an other process).
378 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
379 if (!NT_SUCCESS(Status
))
381 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
385 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
386 MmSetSavedSwapEntryPage(Page
, 0);
388 MmReleasePageMemoryConsumer(MC_USER
, Page
);
392 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
399 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
401 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
404 BOOL
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
407 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
410 PCACHE_SEGMENT CacheSeg
;
411 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
412 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
415 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
423 MiReadPage(PMEMORY_AREA MemoryArea
,
427 * FUNCTION: Read a page for a section backed memory area.
429 * MemoryArea - Memory area to read the page for.
430 * Offset - Offset of the page to read.
431 * Page - Variable that receives a page contains the read data.
438 PCACHE_SEGMENT CacheSeg
;
439 PFILE_OBJECT FileObject
;
443 BOOLEAN IsImageSection
;
446 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
447 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
448 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
449 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
450 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
454 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
457 * If the file system is letting us go directly to the cache and the
458 * memory area was mapped at an offset in the file which is page aligned
459 * then get the related cache segment.
461 if ((FileOffset
% PAGE_SIZE
) == 0 &&
462 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
463 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
467 * Get the related cache segment; we use a lower level interface than
468 * filesystems do because it is safe for us to use an offset with a
469 * alignment less than the file system block size.
471 Status
= CcRosGetCacheSegment(Bcb
,
477 if (!NT_SUCCESS(Status
))
484 * If the cache segment isn't up to date then call the file
485 * system to read in the data.
487 Status
= ReadCacheSegment(CacheSeg
);
488 if (!NT_SUCCESS(Status
))
490 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
495 * Retrieve the page from the cache segment that we actually want.
497 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
498 FileOffset
- BaseOffset
).QuadPart
>> PAGE_SHIFT
;
500 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
505 ULONG CacheSegOffset
;
507 * Allocate a page, this is rather complicated by the possibility
508 * we might have to move other things out of memory
510 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
511 if (!NT_SUCCESS(Status
))
515 Status
= CcRosGetCacheSegment(Bcb
,
521 if (!NT_SUCCESS(Status
))
528 * If the cache segment isn't up to date then call the file
529 * system to read in the data.
531 Status
= ReadCacheSegment(CacheSeg
);
532 if (!NT_SUCCESS(Status
))
534 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
538 PageAddr
= MmCreateHyperspaceMapping(*Page
);
539 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
540 Length
= RawLength
- SegOffset
;
541 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
543 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
545 else if (CacheSegOffset
>= PAGE_SIZE
)
547 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
551 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
552 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
553 Status
= CcRosGetCacheSegment(Bcb
,
554 FileOffset
+ CacheSegOffset
,
559 if (!NT_SUCCESS(Status
))
561 MmDeleteHyperspaceMapping(PageAddr
);
567 * If the cache segment isn't up to date then call the file
568 * system to read in the data.
570 Status
= ReadCacheSegment(CacheSeg
);
571 if (!NT_SUCCESS(Status
))
573 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
574 MmDeleteHyperspaceMapping(PageAddr
);
578 if (Length
< PAGE_SIZE
)
580 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
584 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
587 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
588 MmDeleteHyperspaceMapping(PageAddr
);
590 return(STATUS_SUCCESS
);
594 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
595 MEMORY_AREA
* MemoryArea
,
603 PSECTION_OBJECT Section
;
604 PMM_SECTION_SEGMENT Segment
;
613 * There is a window between taking the page fault and locking the
614 * address space when another thread could load the page so we check
617 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
621 MmLockPage(MmGetPfnForProcess(AddressSpace
->Process
, Address
));
623 return(STATUS_SUCCESS
);
626 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
627 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
629 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
630 Section
= MemoryArea
->Data
.SectionData
.Section
;
631 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
632 &MemoryArea
->Data
.SectionData
.RegionListHead
,
637 MmLockSectionSegment(Segment
);
640 * Check if this page needs to be mapped COW
642 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
643 (Region
->Protect
== PAGE_READWRITE
||
644 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
646 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
650 Attributes
= Region
->Protect
;
654 * Get or create a page operation descriptor
656 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
659 DPRINT1("MmGetPageOp failed\n");
664 * Check if someone else is already handling this fault, if so wait
667 if (PageOp
->Thread
!= PsGetCurrentThread())
669 MmUnlockSectionSegment(Segment
);
670 MmUnlockAddressSpace(AddressSpace
);
671 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
673 * Check for various strange conditions
675 if (Status
!= STATUS_SUCCESS
)
677 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
680 if (PageOp
->Status
== STATUS_PENDING
)
682 DPRINT1("Woke for page op before completion\n");
685 MmLockAddressSpace(AddressSpace
);
687 * If this wasn't a pagein then restart the operation
689 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
691 MmspCompleteAndReleasePageOp(PageOp
);
692 DPRINT("Address 0x%.8X\n", Address
);
693 return(STATUS_MM_RESTART_OPERATION
);
697 * If the thread handling this fault has failed then we don't retry
699 if (!NT_SUCCESS(PageOp
->Status
))
701 Status
= PageOp
->Status
;
702 MmspCompleteAndReleasePageOp(PageOp
);
703 DPRINT("Address 0x%.8X\n", Address
);
706 MmLockSectionSegment(Segment
);
708 * If the completed fault was for another address space then set the
711 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
713 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
714 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
716 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
719 * The page was a private page in another or in our address space
721 MmUnlockSectionSegment(Segment
);
722 MmspCompleteAndReleasePageOp(PageOp
);
723 return(STATUS_MM_RESTART_OPERATION
);
726 Page
= PFN_FROM_SSE(Entry
);
728 MmSharePageEntrySectionSegment(Segment
, Offset
);
730 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
735 if (!NT_SUCCESS(Status
))
737 DbgPrint("Unable to create virtual mapping\n");
740 MmInsertRmap(Page
, MemoryArea
->Process
, (PVOID
)PAddress
);
746 MmUnlockSectionSegment(Segment
);
747 PageOp
->Status
= STATUS_SUCCESS
;
748 MmspCompleteAndReleasePageOp(PageOp
);
749 DPRINT("Address 0x%.8X\n", Address
);
750 return(STATUS_SUCCESS
);
753 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
757 * Must be private page we have swapped out.
764 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
766 DPRINT1("Found a swaped out private page in a pagefile section.\n");
770 MmUnlockSectionSegment(Segment
);
771 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
773 MmUnlockAddressSpace(AddressSpace
);
774 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
775 if (!NT_SUCCESS(Status
))
780 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
781 if (!NT_SUCCESS(Status
))
783 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
786 MmLockAddressSpace(AddressSpace
);
787 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
792 if (!NT_SUCCESS(Status
))
794 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
800 * Store the swap entry for later use.
802 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
805 * Add the page to the process's working set
807 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
810 * Finish the operation
816 PageOp
->Status
= STATUS_SUCCESS
;
817 MmspCompleteAndReleasePageOp(PageOp
);
818 DPRINT("Address 0x%.8X\n", Address
);
819 return(STATUS_SUCCESS
);
823 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
825 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
827 MmUnlockSectionSegment(Segment
);
829 * Just map the desired physical page
831 Page
= (Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
) >> PAGE_SHIFT
;
832 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
837 if (!NT_SUCCESS(Status
))
839 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
844 * Don't add an rmap entry since the page mapped could be for
853 * Cleanup and release locks
855 PageOp
->Status
= STATUS_SUCCESS
;
856 MmspCompleteAndReleasePageOp(PageOp
);
857 DPRINT("Address 0x%.8X\n", Address
);
858 return(STATUS_SUCCESS
);
862 * Map anonymous memory for BSS sections
864 if (Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
)
866 MmUnlockSectionSegment(Segment
);
867 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
868 if (!NT_SUCCESS(Status
))
870 MmUnlockAddressSpace(AddressSpace
);
871 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
872 MmLockAddressSpace(AddressSpace
);
874 if (!NT_SUCCESS(Status
))
878 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
883 if (!NT_SUCCESS(Status
))
885 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
889 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
896 * Cleanup and release locks
898 PageOp
->Status
= STATUS_SUCCESS
;
899 MmspCompleteAndReleasePageOp(PageOp
);
900 DPRINT("Address 0x%.8X\n", Address
);
901 return(STATUS_SUCCESS
);
905 * Get the entry corresponding to the offset within the section
907 Offset
+= MemoryArea
->Data
.SectionData
.ViewOffset
;
908 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
913 * If the entry is zero (and it can't change because we have
914 * locked the segment) then we need to load the page.
918 * Release all our locks and read in the page from disk
920 MmUnlockSectionSegment(Segment
);
921 MmUnlockAddressSpace(AddressSpace
);
923 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
924 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
926 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
927 if (!NT_SUCCESS(Status
))
929 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
934 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
935 if (!NT_SUCCESS(Status
))
937 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
940 if (!NT_SUCCESS(Status
))
943 * FIXME: What do we know in this case?
946 * Cleanup and release locks
948 MmLockAddressSpace(AddressSpace
);
949 PageOp
->Status
= Status
;
950 MmspCompleteAndReleasePageOp(PageOp
);
951 DPRINT("Address 0x%.8X\n", Address
);
955 * Relock the address space and segment
957 MmLockAddressSpace(AddressSpace
);
958 MmLockSectionSegment(Segment
);
961 * Check the entry. No one should change the status of a page
962 * that has a pending page-in.
964 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
967 DbgPrint("Someone changed ppte entry while we slept\n");
972 * Mark the offset within the section as having valid, in-memory
975 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
976 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
977 MmUnlockSectionSegment(Segment
);
979 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
984 if (!NT_SUCCESS(Status
))
986 DbgPrint("Unable to create virtual mapping\n");
989 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
995 PageOp
->Status
= STATUS_SUCCESS
;
996 MmspCompleteAndReleasePageOp(PageOp
);
997 DPRINT("Address 0x%.8X\n", Address
);
998 return(STATUS_SUCCESS
);
1000 else if (IS_SWAP_FROM_SSE(Entry
))
1002 SWAPENTRY SwapEntry
;
1004 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1007 * Release all our locks and read in the page from disk
1009 MmUnlockSectionSegment(Segment
);
1011 MmUnlockAddressSpace(AddressSpace
);
1013 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1014 if (!NT_SUCCESS(Status
))
1019 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1020 if (!NT_SUCCESS(Status
))
1026 * Relock the address space and segment
1028 MmLockAddressSpace(AddressSpace
);
1029 MmLockSectionSegment(Segment
);
1032 * Check the entry. No one should change the status of a page
1033 * that has a pending page-in.
1035 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1036 if (Entry
!= Entry1
)
1038 DbgPrint("Someone changed ppte entry while we slept\n");
1043 * Mark the offset within the section as having valid, in-memory
1046 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1047 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1048 MmUnlockSectionSegment(Segment
);
1051 * Save the swap entry.
1053 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1054 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1059 if (!NT_SUCCESS(Status
))
1061 DbgPrint("Unable to create virtual mapping\n");
1064 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1069 PageOp
->Status
= STATUS_SUCCESS
;
1070 MmspCompleteAndReleasePageOp(PageOp
);
1071 DPRINT("Address 0x%.8X\n", Address
);
1072 return(STATUS_SUCCESS
);
1077 * If the section offset is already in-memory and valid then just
1078 * take another reference to the page
1081 Page
= PFN_FROM_SSE(Entry
);
1083 MmSharePageEntrySectionSegment(Segment
, Offset
);
1084 MmUnlockSectionSegment(Segment
);
1086 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1091 if (!NT_SUCCESS(Status
))
1093 DbgPrint("Unable to create virtual mapping\n");
1096 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1101 PageOp
->Status
= STATUS_SUCCESS
;
1102 MmspCompleteAndReleasePageOp(PageOp
);
1103 DPRINT("Address 0x%.8X\n", Address
);
1104 return(STATUS_SUCCESS
);
1109 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1110 MEMORY_AREA
* MemoryArea
,
1114 PMM_SECTION_SEGMENT Segment
;
1115 PSECTION_OBJECT Section
;
1126 * Check if the page has been paged out or has already been set readwrite
1128 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1129 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1131 DPRINT("Address 0x%.8X\n", Address
);
1132 return(STATUS_SUCCESS
);
1136 * Find the offset of the page
1138 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1139 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1141 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1142 Section
= MemoryArea
->Data
.SectionData
.Section
;
1143 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1144 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1149 MmLockSectionSegment(Segment
);
1151 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1152 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1154 MmUnlockSectionSegment(Segment
);
1157 * Check if we are doing COW
1159 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1160 (Region
->Protect
== PAGE_READWRITE
||
1161 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1163 DPRINT("Address 0x%.8X\n", Address
);
1164 return(STATUS_UNSUCCESSFUL
);
1167 if (IS_SWAP_FROM_SSE(Entry
) ||
1168 PFN_FROM_SSE(Entry
) != OldPage
)
1170 /* This is a private page. We must only change the page protection. */
1171 MmSetPageProtect(AddressSpace
->Process
, PAddress
, Region
->Protect
);
1172 return(STATUS_SUCCESS
);
1176 * Get or create a pageop
1178 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1179 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1182 DPRINT1("MmGetPageOp failed\n");
1187 * Wait for any other operations to complete
1189 if (PageOp
->Thread
!= PsGetCurrentThread())
1191 MmUnlockAddressSpace(AddressSpace
);
1192 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1194 * Check for various strange conditions
1196 if (Status
== STATUS_TIMEOUT
)
1198 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1201 if (PageOp
->Status
== STATUS_PENDING
)
1203 DPRINT1("Woke for page op before completion\n");
1207 * Restart the operation
1209 MmLockAddressSpace(AddressSpace
);
1210 MmspCompleteAndReleasePageOp(PageOp
);
1211 DPRINT("Address 0x%.8X\n", Address
);
1212 return(STATUS_MM_RESTART_OPERATION
);
1216 * Release locks now we have the pageop
1218 MmUnlockAddressSpace(AddressSpace
);
1223 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1224 if (!NT_SUCCESS(Status
))
1232 MiCopyFromUserPage(NewPage
, PAddress
);
1235 * Delete the old entry.
1237 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1240 * Set the PTE to point to the new page
1242 MmLockAddressSpace(AddressSpace
);
1243 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1248 if (!NT_SUCCESS(Status
))
1250 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1254 MmInsertRmap(NewPage
, AddressSpace
->Process
, PAddress
);
1255 if (!NT_SUCCESS(Status
))
1257 DbgPrint("Unable to create virtual mapping\n");
1262 MmLockPage(NewPage
);
1263 MmUnlockPage(OldPage
);
1267 * Unshare the old page.
1269 MmDeleteRmap(OldPage
, AddressSpace
->Process
, PAddress
);
1270 MmLockSectionSegment(Segment
);
1271 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1272 MmUnlockSectionSegment(Segment
);
1274 PageOp
->Status
= STATUS_SUCCESS
;
1275 MmspCompleteAndReleasePageOp(PageOp
);
1276 DPRINT("Address 0x%.8X\n", Address
);
1277 return(STATUS_SUCCESS
);
1281 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1283 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1287 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1288 MmDeleteVirtualMapping(Process
,
1295 PageOutContext
->WasDirty
= TRUE
;
1297 if (!PageOutContext
->Private
)
1299 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1300 PageOutContext
->Segment
,
1301 PageOutContext
->Offset
,
1302 PageOutContext
->WasDirty
,
1307 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1310 DPRINT("PhysicalAddress %I64x, Address %x\n", Page
, Address
);
1314 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1315 MEMORY_AREA
* MemoryArea
,
1320 MM_SECTION_PAGEOUT_CONTEXT Context
;
1321 SWAPENTRY SwapEntry
;
1325 PFILE_OBJECT FileObject
;
1327 BOOLEAN DirectMapped
;
1328 BOOLEAN IsImageSection
;
1330 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1333 * Get the segment and section.
1335 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1336 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1338 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1339 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1341 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1343 FileObject
= Context
.Section
->FileObject
;
1344 DirectMapped
= FALSE
;
1345 if (FileObject
!= NULL
&&
1346 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1348 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1351 * If the file system is letting us go directly to the cache and the
1352 * memory area was mapped at an offset in the file which is page aligned
1353 * then note this is a direct mapped page.
1355 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1356 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1358 DirectMapped
= TRUE
;
1364 * This should never happen since mappings of physical memory are never
1365 * placed in the rmap lists.
1367 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1369 DPRINT1("Trying to page out from physical memory section address 0x%X "
1370 "process %d\n", Address
,
1371 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1376 * Get the section segment entry and the physical address.
1378 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1379 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1381 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1382 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1385 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1386 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1389 * Prepare the context structure for the rmap delete call.
1391 Context
.WasDirty
= FALSE
;
1392 if (Context
.Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
||
1393 IS_SWAP_FROM_SSE(Entry
) ||
1394 PFN_FROM_SSE(Entry
) != Page
)
1396 Context
.Private
= TRUE
;
1400 Context
.Private
= FALSE
;
1404 * Take an additional reference to the page or the cache segment.
1406 if (DirectMapped
&& !Context
.Private
)
1408 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1410 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1416 MmReferencePage(Page
);
1419 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1422 * If this wasn't a private page then we should have reduced the entry to
1423 * zero by deleting all the rmaps.
1425 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1427 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1428 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1435 * If the page wasn't dirty then we can just free it as for a readonly page.
1436 * Since we unmapped all the mappings above we know it will not suddenly
1438 * If the page is from a pagefile section and has no swap entry,
1439 * we can't free the page at this point.
1441 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1442 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1444 if (Context
.Private
)
1446 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1447 Context
.WasDirty
? "dirty" : "clean", Address
);
1450 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1452 MmSetSavedSwapEntryPage(Page
, 0);
1453 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1454 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1455 PageOp
->Status
= STATUS_SUCCESS
;
1456 MmspCompleteAndReleasePageOp(PageOp
);
1457 return(STATUS_SUCCESS
);
1460 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1462 if (Context
.Private
)
1464 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1465 Context
.WasDirty
? "dirty" : "clean", Address
);
1468 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1470 MmSetSavedSwapEntryPage(Page
, 0);
1473 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1475 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1476 PageOp
->Status
= STATUS_SUCCESS
;
1477 MmspCompleteAndReleasePageOp(PageOp
);
1478 return(STATUS_SUCCESS
);
1481 else if (!Context
.Private
&& DirectMapped
)
1485 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1489 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1490 if (!NT_SUCCESS(Status
))
1492 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1495 PageOp
->Status
= STATUS_SUCCESS
;
1496 MmspCompleteAndReleasePageOp(PageOp
);
1497 return(STATUS_SUCCESS
);
1499 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1503 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1507 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1508 PageOp
->Status
= STATUS_SUCCESS
;
1509 MmspCompleteAndReleasePageOp(PageOp
);
1510 return(STATUS_SUCCESS
);
1512 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1514 MmSetSavedSwapEntryPage(Page
, 0);
1515 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1518 if (!NT_SUCCESS(Status
))
1522 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1523 PageOp
->Status
= STATUS_SUCCESS
;
1524 MmspCompleteAndReleasePageOp(PageOp
);
1525 return(STATUS_SUCCESS
);
1529 * If necessary, allocate an entry in the paging file for this page
1533 SwapEntry
= MmAllocSwapPage();
1536 MmShowOutOfSpaceMessagePagingFile();
1539 * For private pages restore the old mappings.
1541 if (Context
.Private
)
1543 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1545 MemoryArea
->Attributes
,
1548 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1550 MemoryArea
->Process
,
1556 * For non-private pages if the page wasn't direct mapped then
1557 * set it back into the section segment entry so we don't loose
1558 * our copy. Otherwise it will be handled by the cache manager.
1560 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1562 MemoryArea
->Attributes
,
1565 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1567 MemoryArea
->Process
,
1569 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1570 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1572 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1573 MmspCompleteAndReleasePageOp(PageOp
);
1574 return(STATUS_PAGEFILE_QUOTA
);
1579 * Write the page to the pagefile
1581 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1582 if (!NT_SUCCESS(Status
))
1584 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1587 * As above: undo our actions.
1588 * FIXME: Also free the swap page.
1590 if (Context
.Private
)
1592 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1594 MemoryArea
->Attributes
,
1597 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1599 MemoryArea
->Process
,
1604 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1606 MemoryArea
->Attributes
,
1609 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1611 MemoryArea
->Process
,
1613 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1614 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1616 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1617 MmspCompleteAndReleasePageOp(PageOp
);
1618 return(STATUS_UNSUCCESSFUL
);
1622 * Otherwise we have succeeded.
1624 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1625 MmSetSavedSwapEntryPage(Page
, 0);
1626 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1627 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1629 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1633 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1636 if (Context
.Private
)
1638 Status
= MmCreatePageFileMapping(MemoryArea
->Process
,
1641 if (!NT_SUCCESS(Status
))
1648 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1649 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1652 PageOp
->Status
= STATUS_SUCCESS
;
1653 MmspCompleteAndReleasePageOp(PageOp
);
1654 return(STATUS_SUCCESS
);
1658 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1659 PMEMORY_AREA MemoryArea
,
1664 PSECTION_OBJECT Section
;
1665 PMM_SECTION_SEGMENT Segment
;
1667 SWAPENTRY SwapEntry
;
1671 PFILE_OBJECT FileObject
;
1673 BOOLEAN DirectMapped
;
1674 BOOLEAN IsImageSection
;
1676 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1678 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1681 * Get the segment and section.
1683 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1684 Section
= MemoryArea
->Data
.SectionData
.Section
;
1685 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1687 FileObject
= Section
->FileObject
;
1688 DirectMapped
= FALSE
;
1689 if (FileObject
!= NULL
&&
1690 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1692 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1695 * If the file system is letting us go directly to the cache and the
1696 * memory area was mapped at an offset in the file which is page aligned
1697 * then note this is a direct mapped page.
1699 if ((Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
% PAGE_SIZE
) == 0 &&
1700 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1702 DirectMapped
= TRUE
;
1707 * This should never happen since mappings of physical memory are never
1708 * placed in the rmap lists.
1710 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1712 DPRINT1("Trying to write back page from physical memory mapped at %X "
1713 "process %d\n", Address
,
1714 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1719 * Get the section segment entry and the physical address.
1721 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1722 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1724 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1725 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1728 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1729 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1732 * Check for a private (COWed) page.
1734 if (Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
||
1735 IS_SWAP_FROM_SSE(Entry
) ||
1736 PFN_FROM_SSE(Entry
) != Page
)
1746 * Speculatively set all mappings of the page to clean.
1748 MmSetCleanAllRmaps(Page
);
1751 * If this page was direct mapped from the cache then the cache manager
1752 * will take care of writing it back to disk.
1754 if (DirectMapped
&& !Private
)
1756 ASSERT(SwapEntry
== 0);
1757 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
1758 PageOp
->Status
= STATUS_SUCCESS
;
1759 MmspCompleteAndReleasePageOp(PageOp
);
1760 return(STATUS_SUCCESS
);
1764 * If necessary, allocate an entry in the paging file for this page
1768 SwapEntry
= MmAllocSwapPage();
1771 MmSetDirtyAllRmaps(Page
);
1772 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1773 MmspCompleteAndReleasePageOp(PageOp
);
1774 return(STATUS_PAGEFILE_QUOTA
);
1776 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1780 * Write the page to the pagefile
1782 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1783 if (!NT_SUCCESS(Status
))
1785 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1787 MmSetDirtyAllRmaps(Page
);
1788 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1789 MmspCompleteAndReleasePageOp(PageOp
);
1790 return(STATUS_UNSUCCESSFUL
);
1794 * Otherwise we have succeeded.
1796 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1797 PageOp
->Status
= STATUS_SUCCESS
;
1798 MmspCompleteAndReleasePageOp(PageOp
);
1799 return(STATUS_SUCCESS
);
1803 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1811 PMEMORY_AREA MemoryArea
;
1812 PMM_SECTION_SEGMENT Segment
;
1816 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1817 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1819 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1820 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1825 if (OldProtect
!= NewProtect
)
1827 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1829 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1830 ULONG Protect
= NewProtect
;
1833 * If we doing COW for this segment then check if the page is
1836 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1842 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1843 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1844 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1846 Protect
= PAGE_READONLY
;
1847 if (Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
||
1848 IS_SWAP_FROM_SSE(Entry
) ||
1849 PFN_FROM_SSE(Entry
) != Page
)
1851 Protect
= NewProtect
;
1855 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1857 MmSetPageProtect(AddressSpace
->Process
, Address
,
1865 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1866 PMEMORY_AREA MemoryArea
,
1874 ULONG_PTR MaxLength
;
1876 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
1877 if (Length
> MaxLength
)
1880 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1881 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1883 *OldProtect
= Region
->Protect
;
1884 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
1885 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1886 BaseAddress
, Length
, Region
->Type
, Protect
,
1887 MmAlterViewAttributes
);
1893 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
1895 PMEMORY_BASIC_INFORMATION Info
,
1896 PULONG ResultLength
)
1899 PVOID RegionBaseAddress
;
1900 PSECTION_OBJECT Section
;
1901 PLIST_ENTRY CurrentEntry
;
1902 PMEMORY_AREA CurrentMArea
;
1905 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
1906 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1907 Address
, &RegionBaseAddress
);
1910 return STATUS_UNSUCCESSFUL
;
1912 Section
= MemoryArea
->Data
.SectionData
.Section
;
1913 if (Section
->AllocationAttributes
& SEC_IMAGE
)
1915 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
1916 CurrentEntry
= Section
->ViewListHead
.Flink
;
1917 Info
->AllocationBase
= NULL
;
1918 while (CurrentEntry
!= &Section
->ViewListHead
)
1920 CurrentMArea
= CONTAINING_RECORD(CurrentEntry
, MEMORY_AREA
, Data
.SectionData
.ViewListEntry
);
1921 CurrentEntry
= CurrentEntry
->Flink
;
1922 if (Info
->AllocationBase
== NULL
)
1924 Info
->AllocationBase
= CurrentMArea
->StartingAddress
;
1926 else if (CurrentMArea
->StartingAddress
< Info
->AllocationBase
)
1928 Info
->AllocationBase
= CurrentMArea
->StartingAddress
;
1931 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
1932 Info
->BaseAddress
= RegionBaseAddress
;
1933 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1934 Info
->Type
= MEM_IMAGE
;
1938 Info
->BaseAddress
= RegionBaseAddress
;
1939 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
1940 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1941 Info
->Type
= MEM_MAPPED
;
1943 Info
->RegionSize
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
-
1944 (ULONG_PTR
)MemoryArea
->StartingAddress
);
1945 Info
->State
= MEM_COMMIT
;
1946 Info
->Protect
= Region
->Protect
;
1948 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
1949 return(STATUS_SUCCESS
);
1953 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
1958 ULONG SavedSwapEntry
;
1963 Length
= PAGE_ROUND_UP(Segment
->Length
);
1964 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
1966 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1969 if (IS_SWAP_FROM_SSE(Entry
))
1971 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
1975 Page
= PFN_FROM_SSE(Entry
);
1976 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
1977 if (SavedSwapEntry
!= 0)
1979 MmSetSavedSwapEntryPage(Page
, 0);
1980 MmFreeSwapPage(SavedSwapEntry
);
1982 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1984 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
1990 MmpDeleteSection(PVOID ObjectBody
)
1992 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
1994 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
1995 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2000 PMM_SECTION_SEGMENT SectionSegments
;
2003 * NOTE: Section->ImageSection can be NULL for short time
2004 * during the section creating. If we fail for some reason
2005 * until the image section is properly initialized we shouldn't
2006 * process further here.
2008 if (Section
->ImageSection
== NULL
)
2011 SectionSegments
= Section
->ImageSection
->Segments
;
2012 NrSegments
= Section
->ImageSection
->NrSegments
;
2014 for (i
= 0; i
< NrSegments
; i
++)
2016 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2018 MmLockSectionSegment(&SectionSegments
[i
]);
2020 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2021 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2025 MmpFreePageFileSegment(&SectionSegments
[i
]);
2027 MmUnlockSectionSegment(&SectionSegments
[i
]);
2034 * NOTE: Section->Segment can be NULL for short time
2035 * during the section creating.
2037 if (Section
->Segment
== NULL
)
2040 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2042 MmpFreePageFileSegment(Section
->Segment
);
2043 MmFreePageTablesSectionSegment(Section
->Segment
);
2044 ExFreePool(Section
->Segment
);
2045 Section
->Segment
= NULL
;
2049 InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2052 if (Section
->FileObject
!= NULL
)
2054 CcRosDereferenceCache(Section
->FileObject
);
2055 ObDereferenceObject(Section
->FileObject
);
2056 Section
->FileObject
= NULL
;
2061 MmpCloseSection(PVOID ObjectBody
,
2064 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2065 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2069 MmpCreateSection(PVOID ObjectBody
,
2071 PWSTR RemainingPath
,
2072 POBJECT_ATTRIBUTES ObjectAttributes
)
2074 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2075 ObjectBody
, Parent
, RemainingPath
);
2077 if (RemainingPath
== NULL
)
2079 return(STATUS_SUCCESS
);
2082 if (wcschr(RemainingPath
+1, L
'\\') != NULL
)
2084 return(STATUS_UNSUCCESSFUL
);
2086 return(STATUS_SUCCESS
);
2089 NTSTATUS INIT_FUNCTION
2090 MmCreatePhysicalMemorySection(VOID
)
2092 PSECTION_OBJECT PhysSection
;
2094 OBJECT_ATTRIBUTES Obj
;
2095 UNICODE_STRING Name
= ROS_STRING_INITIALIZER(L
"\\Device\\PhysicalMemory");
2096 LARGE_INTEGER SectionSize
;
2099 * Create the section mapping physical memory
2101 SectionSize
.QuadPart
= 0xFFFFFFFF;
2102 InitializeObjectAttributes(&Obj
,
2107 Status
= MmCreateSection(&PhysSection
,
2111 PAGE_EXECUTE_READWRITE
,
2115 if (!NT_SUCCESS(Status
))
2117 DbgPrint("Failed to create PhysicalMemory section\n");
2120 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2122 return(STATUS_SUCCESS
);
2125 NTSTATUS INIT_FUNCTION
2126 MmInitSectionImplementation(VOID
)
2128 MmSectionObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
2130 RtlRosInitUnicodeStringFromLiteral(&MmSectionObjectType
->TypeName
, L
"Section");
2132 MmSectionObjectType
->Tag
= TAG('S', 'E', 'C', 'T');
2133 MmSectionObjectType
->TotalObjects
= 0;
2134 MmSectionObjectType
->TotalHandles
= 0;
2135 MmSectionObjectType
->PeakObjects
= 0;
2136 MmSectionObjectType
->PeakHandles
= 0;
2137 MmSectionObjectType
->PagedPoolCharge
= 0;
2138 MmSectionObjectType
->NonpagedPoolCharge
= sizeof(SECTION_OBJECT
);
2139 MmSectionObjectType
->Mapping
= &MmpSectionMapping
;
2140 MmSectionObjectType
->Dump
= NULL
;
2141 MmSectionObjectType
->Open
= NULL
;
2142 MmSectionObjectType
->Close
= MmpCloseSection
;
2143 MmSectionObjectType
->Delete
= MmpDeleteSection
;
2144 MmSectionObjectType
->Parse
= NULL
;
2145 MmSectionObjectType
->Security
= NULL
;
2146 MmSectionObjectType
->QueryName
= NULL
;
2147 MmSectionObjectType
->OkayToClose
= NULL
;
2148 MmSectionObjectType
->Create
= MmpCreateSection
;
2149 MmSectionObjectType
->DuplicationNotify
= NULL
;
2152 * NOTE: Do not register the section object type here because
2153 * the object manager it not initialized yet!
2154 * The section object type will be created in ObInit().
2156 ObpCreateTypeObject(MmSectionObjectType
);
2158 return(STATUS_SUCCESS
);
2162 MmCreatePageFileSection(PSECTION_OBJECT
*SectionObject
,
2163 ACCESS_MASK DesiredAccess
,
2164 POBJECT_ATTRIBUTES ObjectAttributes
,
2165 PLARGE_INTEGER UMaximumSize
,
2166 ULONG SectionPageProtection
,
2167 ULONG AllocationAttributes
)
2169 * Create a section which is backed by the pagefile
2172 LARGE_INTEGER MaximumSize
;
2173 PSECTION_OBJECT Section
;
2174 PMM_SECTION_SEGMENT Segment
;
2177 if (UMaximumSize
== NULL
)
2179 return(STATUS_UNSUCCESSFUL
);
2181 MaximumSize
= *UMaximumSize
;
2184 * Create the section
2186 Status
= ObCreateObject(ExGetPreviousMode(),
2187 MmSectionObjectType
,
2189 ExGetPreviousMode(),
2191 sizeof(SECTION_OBJECT
),
2194 (PVOID
*)(PVOID
)&Section
);
2195 if (!NT_SUCCESS(Status
))
2203 Section
->SectionPageProtection
= SectionPageProtection
;
2204 Section
->AllocationAttributes
= AllocationAttributes
;
2205 Section
->Segment
= NULL
;
2206 InitializeListHead(&Section
->ViewListHead
);
2207 KeInitializeSpinLock(&Section
->ViewListLock
);
2208 Section
->FileObject
= NULL
;
2209 Section
->MaximumSize
= MaximumSize
;
2210 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2211 TAG_MM_SECTION_SEGMENT
);
2212 if (Segment
== NULL
)
2214 ObDereferenceObject(Section
);
2215 return(STATUS_NO_MEMORY
);
2217 Section
->Segment
= Segment
;
2218 Segment
->ReferenceCount
= 1;
2219 ExInitializeFastMutex(&Segment
->Lock
);
2220 Segment
->FileOffset
= 0;
2221 Segment
->Protection
= SectionPageProtection
;
2222 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2223 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2224 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2225 Segment
->WriteCopy
= FALSE
;
2226 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2227 Segment
->VirtualAddress
= 0;
2228 Segment
->Characteristics
= 0;
2229 *SectionObject
= Section
;
2230 return(STATUS_SUCCESS
);
2235 MmCreateDataFileSection(PSECTION_OBJECT
*SectionObject
,
2236 ACCESS_MASK DesiredAccess
,
2237 POBJECT_ATTRIBUTES ObjectAttributes
,
2238 PLARGE_INTEGER UMaximumSize
,
2239 ULONG SectionPageProtection
,
2240 ULONG AllocationAttributes
,
2243 * Create a section backed by a data file
2246 PSECTION_OBJECT Section
;
2248 LARGE_INTEGER MaximumSize
;
2249 PFILE_OBJECT FileObject
;
2250 PMM_SECTION_SEGMENT Segment
;
2252 IO_STATUS_BLOCK Iosb
;
2253 LARGE_INTEGER Offset
;
2255 FILE_STANDARD_INFORMATION FileInfo
;
2258 * Create the section
2260 Status
= ObCreateObject(ExGetPreviousMode(),
2261 MmSectionObjectType
,
2263 ExGetPreviousMode(),
2265 sizeof(SECTION_OBJECT
),
2268 (PVOID
*)(PVOID
)&Section
);
2269 if (!NT_SUCCESS(Status
))
2277 Section
->SectionPageProtection
= SectionPageProtection
;
2278 Section
->AllocationAttributes
= AllocationAttributes
;
2279 Section
->Segment
= NULL
;
2280 InitializeListHead(&Section
->ViewListHead
);
2281 KeInitializeSpinLock(&Section
->ViewListLock
);
2284 * Check file access required
2286 if (SectionPageProtection
& PAGE_READWRITE
||
2287 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2289 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2293 FileAccess
= FILE_READ_DATA
;
2297 * Reference the file handle
2299 Status
= ObReferenceObjectByHandle(FileHandle
,
2303 (PVOID
*)(PVOID
)&FileObject
,
2305 if (!NT_SUCCESS(Status
))
2307 ObDereferenceObject(Section
);
2312 * FIXME: This is propably not entirely correct. We can't look into
2313 * the standard FCB header because it might not be initialized yet
2314 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2315 * standard file information is filled on first request).
2317 Status
= NtQueryInformationFile(FileHandle
,
2320 sizeof(FILE_STANDARD_INFORMATION
),
2321 FileStandardInformation
);
2322 if (!NT_SUCCESS(Status
))
2324 ObDereferenceObject(Section
);
2325 ObDereferenceObject(FileObject
);
2330 * FIXME: Revise this once a locking order for file size changes is
2333 if (UMaximumSize
!= NULL
)
2335 MaximumSize
= *UMaximumSize
;
2339 MaximumSize
= FileInfo
.EndOfFile
;
2340 /* Mapping zero-sized files isn't allowed. */
2341 if (MaximumSize
.QuadPart
== 0)
2343 ObDereferenceObject(Section
);
2344 ObDereferenceObject(FileObject
);
2345 return STATUS_FILE_INVALID
;
2349 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2351 Status
= NtSetInformationFile(FileHandle
,
2354 sizeof(LARGE_INTEGER
),
2355 FileAllocationInformation
);
2356 if (!NT_SUCCESS(Status
))
2358 ObDereferenceObject(Section
);
2359 ObDereferenceObject(FileObject
);
2360 return(STATUS_SECTION_NOT_EXTENDED
);
2364 if (FileObject
->SectionObjectPointer
== NULL
||
2365 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2368 * Read a bit so caching is initiated for the file object.
2369 * This is only needed because MiReadPage currently cannot
2370 * handle non-cached streams.
2372 Offset
.QuadPart
= 0;
2373 Status
= ZwReadFile(FileHandle
,
2382 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2384 ObDereferenceObject(Section
);
2385 ObDereferenceObject(FileObject
);
2388 if (FileObject
->SectionObjectPointer
== NULL
||
2389 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2391 /* FIXME: handle this situation */
2392 ObDereferenceObject(Section
);
2393 ObDereferenceObject(FileObject
);
2394 return STATUS_INVALID_PARAMETER
;
2401 Status
= MmspWaitForFileLock(FileObject
);
2402 if (Status
!= STATUS_SUCCESS
)
2404 ObDereferenceObject(Section
);
2405 ObDereferenceObject(FileObject
);
2410 * If this file hasn't been mapped as a data file before then allocate a
2411 * section segment to describe the data file mapping
2413 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2415 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2416 TAG_MM_SECTION_SEGMENT
);
2417 if (Segment
== NULL
)
2419 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2420 ObDereferenceObject(Section
);
2421 ObDereferenceObject(FileObject
);
2422 return(STATUS_NO_MEMORY
);
2424 Section
->Segment
= Segment
;
2425 Segment
->ReferenceCount
= 1;
2426 ExInitializeFastMutex(&Segment
->Lock
);
2428 * Set the lock before assigning the segment to the file object
2430 ExAcquireFastMutex(&Segment
->Lock
);
2431 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2433 Segment
->FileOffset
= 0;
2434 Segment
->Protection
= SectionPageProtection
;
2435 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2436 Segment
->Characteristics
= 0;
2437 Segment
->WriteCopy
= FALSE
;
2438 if (AllocationAttributes
& SEC_RESERVE
)
2440 Segment
->Length
= Segment
->RawLength
= 0;
2444 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2445 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2447 Segment
->VirtualAddress
= 0;
2448 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2453 * If the file is already mapped as a data file then we may need
2457 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2459 Section
->Segment
= Segment
;
2460 InterlockedIncrementUL(&Segment
->ReferenceCount
);
2461 MmLockSectionSegment(Segment
);
2463 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2464 !(AllocationAttributes
& SEC_RESERVE
))
2466 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2467 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2470 MmUnlockSectionSegment(Segment
);
2471 Section
->FileObject
= FileObject
;
2472 Section
->MaximumSize
= MaximumSize
;
2473 CcRosReferenceCache(FileObject
);
2474 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2475 *SectionObject
= Section
;
2476 return(STATUS_SUCCESS
);
2480 TODO: not that great (declaring loaders statically, having to declare all of
2481 them, having to keep them extern, etc.), will fix in the future
2483 extern NTSTATUS NTAPI PeFmtCreateSection
2485 IN CONST VOID
* FileHeader
,
2486 IN SIZE_T FileHeaderSize
,
2488 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2490 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2491 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2494 extern NTSTATUS NTAPI ElfFmtCreateSection
2496 IN CONST VOID
* FileHeader
,
2497 IN SIZE_T FileHeaderSize
,
2499 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2501 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2502 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2505 /* TODO: this is a standard DDK/PSDK macro */
2506 #ifndef RTL_NUMBER_OF
2507 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2510 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2519 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2521 SIZE_T SizeOfSegments
;
2522 PMM_SECTION_SEGMENT Segments
;
2524 /* TODO: check for integer overflow */
2525 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2527 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2529 TAG_MM_SECTION_SEGMENT
);
2532 RtlZeroMemory(Segments
, SizeOfSegments
);
2540 ExeFmtpReadFile(IN PVOID File
,
2541 IN PLARGE_INTEGER Offset
,
2544 OUT PVOID
* AllocBase
,
2545 OUT PULONG ReadSize
)
2548 LARGE_INTEGER FileOffset
;
2550 ULONG OffsetAdjustment
;
2555 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2559 KEBUGCHECK(STATUS_INVALID_PARAMETER_4
);
2562 FileOffset
= *Offset
;
2564 /* Negative/special offset: it cannot be used in this context */
2565 if(FileOffset
.u
.HighPart
< 0)
2567 KEBUGCHECK(STATUS_INVALID_PARAMETER_5
);
2570 ASSERT(PAGE_SIZE
<= MAXULONG
);
2571 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2572 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2573 FileOffset
.u
.LowPart
= AdjustOffset
;
2575 BufferSize
= Length
+ OffsetAdjustment
;
2576 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2579 * It's ok to use paged pool, because this is a temporary buffer only used in
2580 * the loading of executables. The assumption is that MmCreateSection is
2581 * always called at low IRQLs and that these buffers don't survive a brief
2582 * initialization phase
2584 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2586 TAG('M', 'm', 'X', 'r'));
2591 Status
= MmspPageRead(File
,
2598 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2599 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2600 * to initialize internal state is even worse. Our cache manager is in need of
2604 IO_STATUS_BLOCK Iosb
;
2606 Status
= ZwReadFile(File
,
2616 if(NT_SUCCESS(Status
))
2618 UsedSize
= Iosb
.Information
;
2623 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2625 Status
= STATUS_IN_PAGE_ERROR
;
2626 ASSERT(!NT_SUCCESS(Status
));
2629 if(NT_SUCCESS(Status
))
2631 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2632 *AllocBase
= Buffer
;
2633 *ReadSize
= UsedSize
- OffsetAdjustment
;
2644 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2645 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2646 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2651 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2655 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2657 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2658 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2665 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2669 MmspAssertSegmentsSorted(ImageSectionObject
);
2671 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2673 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2677 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2678 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2679 ImageSectionObject
->Segments
[i
- 1].Length
));
2687 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2691 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2693 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2694 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2702 MmspCompareSegments(const void * x
,
2705 PMM_SECTION_SEGMENT Segment1
= (PMM_SECTION_SEGMENT
)x
;
2706 PMM_SECTION_SEGMENT Segment2
= (PMM_SECTION_SEGMENT
)y
;
2709 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2710 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2714 * Ensures an image section's segments are sorted in memory
2719 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2722 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2724 MmspAssertSegmentsSorted(ImageSectionObject
);
2728 qsort(ImageSectionObject
->Segments
,
2729 ImageSectionObject
->NrSegments
,
2730 sizeof(ImageSectionObject
->Segments
[0]),
2731 MmspCompareSegments
);
2737 * Ensures an image section's segments don't overlap in memory and don't have
2738 * gaps and don't have a null size. We let them map to overlapping file regions,
2739 * though - that's not necessarily an error
2744 MmspCheckSegmentBounds
2746 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2752 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2754 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2758 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2760 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2762 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2770 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2771 * page could be OK (Windows seems to be OK with them), and larger gaps
2772 * could lead to image sections spanning several discontiguous regions
2773 * (NtMapViewOfSection could then refuse to map them, and they could
2774 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2776 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2777 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2778 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2789 * Merges and pads an image section's segments until they all are page-aligned
2790 * and have a size that is a multiple of the page size
2795 MmspPageAlignSegments
2797 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2803 BOOLEAN Initialized
;
2805 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2807 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2811 Initialized
= FALSE
;
2814 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2816 PMM_SECTION_SEGMENT EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2819 * The first segment requires special handling
2823 ULONG_PTR VirtualAddress
;
2824 ULONG_PTR VirtualOffset
;
2826 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2828 /* Round down the virtual address to the nearest page */
2829 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2831 /* Round up the virtual size to the nearest page */
2832 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2833 EffectiveSegment
->VirtualAddress
;
2835 /* Adjust the raw address and size */
2836 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2838 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
2844 * Garbage in, garbage out: unaligned base addresses make the file
2845 * offset point in curious and odd places, but that's what we were
2848 EffectiveSegment
->FileOffset
-= VirtualOffset
;
2849 EffectiveSegment
->RawLength
+= VirtualOffset
;
2853 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
2854 ULONG_PTR EndOfEffectiveSegment
;
2856 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
2857 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
2860 * The current segment begins exactly where the current effective
2861 * segment ended, therefore beginning a new effective segment
2863 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
2866 ASSERT(LastSegment
<= i
);
2867 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
2869 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2872 * Copy the current segment. If necessary, the effective segment
2873 * will be expanded later
2875 *EffectiveSegment
= *Segment
;
2878 * Page-align the virtual size. We know for sure the virtual address
2881 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
2882 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
2885 * The current segment is still part of the current effective segment:
2886 * extend the effective segment to reflect this
2888 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
2890 static const ULONG FlagsToProtection
[16] =
2898 PAGE_EXECUTE_READWRITE
,
2899 PAGE_EXECUTE_READWRITE
,
2904 PAGE_EXECUTE_WRITECOPY
,
2905 PAGE_EXECUTE_WRITECOPY
,
2906 PAGE_EXECUTE_WRITECOPY
,
2907 PAGE_EXECUTE_WRITECOPY
2910 unsigned ProtectionFlags
;
2913 * Extend the file size
2916 /* Unaligned segments must be contiguous within the file */
2917 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
2918 EffectiveSegment
->RawLength
))
2923 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
2926 * Extend the virtual size
2928 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) > EndOfEffectiveSegment
);
2930 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
2931 EffectiveSegment
->VirtualAddress
;
2934 * Merge the protection
2936 EffectiveSegment
->Protection
|= Segment
->Protection
;
2938 /* Clean up redundance */
2939 ProtectionFlags
= 0;
2941 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
2942 ProtectionFlags
|= 1 << 0;
2944 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
2945 ProtectionFlags
|= 1 << 1;
2947 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
2948 ProtectionFlags
|= 1 << 2;
2950 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2951 ProtectionFlags
|= 1 << 3;
2953 ASSERT(ProtectionFlags
< 16);
2954 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
2956 /* If a segment was required to be shared and cannot, fail */
2957 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
2958 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2964 * We assume no holes between segments at this point
2977 ExeFmtpCreateImageSection(HANDLE FileHandle
,
2978 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2980 LARGE_INTEGER Offset
;
2982 PVOID FileHeaderBuffer
;
2983 ULONG FileHeaderSize
;
2985 ULONG OldNrSegments
;
2990 * Read the beginning of the file (2 pages). Should be enough to contain
2991 * all (or most) of the headers
2993 Offset
.QuadPart
= 0;
2995 /* FIXME: use FileObject instead of FileHandle */
2996 Status
= ExeFmtpReadFile (FileHandle
,
3003 if (!NT_SUCCESS(Status
))
3006 if (FileHeaderSize
== 0)
3008 ExFreePool(FileHeaderBuffer
);
3009 return STATUS_UNSUCCESSFUL
;
3013 * Look for a loader that can handle this executable
3015 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3017 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3020 /* FIXME: use FileObject instead of FileHandle */
3021 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3027 ExeFmtpAllocateSegments
);
3029 if (!NT_SUCCESS(Status
))
3031 if (ImageSectionObject
->Segments
)
3033 ExFreePool(ImageSectionObject
->Segments
);
3034 ImageSectionObject
->Segments
= NULL
;
3038 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3042 ExFreePool(FileHeaderBuffer
);
3045 * No loader handled the format
3047 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3049 Status
= STATUS_INVALID_IMAGE_FORMAT
;
3050 ASSERT(!NT_SUCCESS(Status
));
3053 if (!NT_SUCCESS(Status
))
3056 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3061 /* FIXME? are these values platform-dependent? */
3062 if(ImageSectionObject
->StackReserve
== 0)
3063 ImageSectionObject
->StackReserve
= 0x40000;
3065 if(ImageSectionObject
->StackCommit
== 0)
3066 ImageSectionObject
->StackCommit
= 0x1000;
3068 if(ImageSectionObject
->ImageBase
== 0)
3070 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3071 ImageSectionObject
->ImageBase
= 0x10000000;
3073 ImageSectionObject
->ImageBase
= 0x00400000;
3077 * And now the fun part: fixing the segments
3080 /* Sort them by virtual address */
3081 MmspSortSegments(ImageSectionObject
, Flags
);
3083 /* Ensure they don't overlap in memory */
3084 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3085 return STATUS_INVALID_IMAGE_FORMAT
;
3087 /* Ensure they are aligned */
3088 OldNrSegments
= ImageSectionObject
->NrSegments
;
3090 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3091 return STATUS_INVALID_IMAGE_FORMAT
;
3093 /* Trim them if the alignment phase merged some of them */
3094 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3096 PMM_SECTION_SEGMENT Segments
;
3097 SIZE_T SizeOfSegments
;
3099 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3101 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3103 TAG_MM_SECTION_SEGMENT
);
3105 if (Segments
== NULL
)
3106 return STATUS_INSUFFICIENT_RESOURCES
;
3108 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3109 ExFreePool(ImageSectionObject
->Segments
);
3110 ImageSectionObject
->Segments
= Segments
;
3113 /* And finish their initialization */
3114 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3116 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3117 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3119 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3120 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3123 ASSERT(NT_SUCCESS(Status
));
3128 MmCreateImageSection(PSECTION_OBJECT
*SectionObject
,
3129 ACCESS_MASK DesiredAccess
,
3130 POBJECT_ATTRIBUTES ObjectAttributes
,
3131 PLARGE_INTEGER UMaximumSize
,
3132 ULONG SectionPageProtection
,
3133 ULONG AllocationAttributes
,
3136 PSECTION_OBJECT Section
;
3138 PFILE_OBJECT FileObject
;
3139 PMM_SECTION_SEGMENT SectionSegments
;
3140 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3142 ULONG FileAccess
= 0;
3145 * Specifying a maximum size is meaningless for an image section
3147 if (UMaximumSize
!= NULL
)
3149 return(STATUS_INVALID_PARAMETER_4
);
3153 * Check file access required
3155 if (SectionPageProtection
& PAGE_READWRITE
||
3156 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3158 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3162 FileAccess
= FILE_READ_DATA
;
3166 * Reference the file handle
3168 Status
= ObReferenceObjectByHandle(FileHandle
,
3172 (PVOID
*)(PVOID
)&FileObject
,
3174 if (!NT_SUCCESS(Status
))
3180 * Create the section
3182 Status
= ObCreateObject (ExGetPreviousMode(),
3183 MmSectionObjectType
,
3185 ExGetPreviousMode(),
3187 sizeof(SECTION_OBJECT
),
3190 (PVOID
*)(PVOID
)&Section
);
3191 if (!NT_SUCCESS(Status
))
3193 ObDereferenceObject(FileObject
);
3200 Section
->SectionPageProtection
= SectionPageProtection
;
3201 Section
->AllocationAttributes
= AllocationAttributes
;
3202 InitializeListHead(&Section
->ViewListHead
);
3203 KeInitializeSpinLock(&Section
->ViewListLock
);
3206 * Initialized caching for this file object if previously caching
3207 * was initialized for the same on disk file
3209 Status
= CcTryToInitializeFileCache(FileObject
);
3211 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3213 NTSTATUS StatusExeFmt
;
3215 ImageSectionObject
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3216 if (ImageSectionObject
== NULL
)
3218 ObDereferenceObject(FileObject
);
3219 ObDereferenceObject(Section
);
3220 return(STATUS_NO_MEMORY
);
3223 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3225 if (!NT_SUCCESS(StatusExeFmt
))
3227 if(ImageSectionObject
->Segments
!= NULL
)
3228 ExFreePool(ImageSectionObject
->Segments
);
3230 ExFreePool(ImageSectionObject
);
3231 ObDereferenceObject(Section
);
3232 ObDereferenceObject(FileObject
);
3233 return(StatusExeFmt
);
3236 Section
->ImageSection
= ImageSectionObject
;
3237 ASSERT(ImageSectionObject
->Segments
);
3242 Status
= MmspWaitForFileLock(FileObject
);
3243 if (!NT_SUCCESS(Status
))
3245 ExFreePool(ImageSectionObject
->Segments
);
3246 ExFreePool(ImageSectionObject
);
3247 ObDereferenceObject(Section
);
3248 ObDereferenceObject(FileObject
);
3252 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3253 ImageSectionObject
, NULL
))
3256 * An other thread has initialized the some image in the background
3258 ExFreePool(ImageSectionObject
->Segments
);
3259 ExFreePool(ImageSectionObject
);
3260 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3261 Section
->ImageSection
= ImageSectionObject
;
3262 SectionSegments
= ImageSectionObject
->Segments
;
3264 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3266 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3270 Status
= StatusExeFmt
;
3277 Status
= MmspWaitForFileLock(FileObject
);
3278 if (Status
!= STATUS_SUCCESS
)
3280 ObDereferenceObject(Section
);
3281 ObDereferenceObject(FileObject
);
3285 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3286 Section
->ImageSection
= ImageSectionObject
;
3287 SectionSegments
= ImageSectionObject
->Segments
;
3290 * Otherwise just reference all the section segments
3292 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3294 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3297 Status
= STATUS_SUCCESS
;
3299 Section
->FileObject
= FileObject
;
3300 CcRosReferenceCache(FileObject
);
3301 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
3302 *SectionObject
= Section
;
3310 NtCreateSection (OUT PHANDLE SectionHandle
,
3311 IN ACCESS_MASK DesiredAccess
,
3312 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3313 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3314 IN ULONG SectionPageProtection OPTIONAL
,
3315 IN ULONG AllocationAttributes
,
3316 IN HANDLE FileHandle OPTIONAL
)
3318 LARGE_INTEGER SafeMaximumSize
;
3319 PSECTION_OBJECT SectionObject
;
3320 KPROCESSOR_MODE PreviousMode
;
3321 NTSTATUS Status
= STATUS_SUCCESS
;
3323 PreviousMode
= ExGetPreviousMode();
3325 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3329 ProbeForRead(MaximumSize
,
3330 sizeof(LARGE_INTEGER
),
3332 /* make a copy on the stack */
3333 SafeMaximumSize
= *MaximumSize
;
3334 MaximumSize
= &SafeMaximumSize
;
3338 Status
= _SEH_GetExceptionCode();
3342 if(!NT_SUCCESS(Status
))
3349 * Check the protection
3351 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
3352 SectionPageProtection
)
3354 return(STATUS_INVALID_PAGE_PROTECTION
);
3357 Status
= MmCreateSection(&SectionObject
,
3361 SectionPageProtection
,
3362 AllocationAttributes
,
3366 if (NT_SUCCESS(Status
))
3368 Status
= ObInsertObject ((PVOID
)SectionObject
,
3374 ObDereferenceObject(SectionObject
);
3381 /**********************************************************************
3399 NtOpenSection(PHANDLE SectionHandle
,
3400 ACCESS_MASK DesiredAccess
,
3401 POBJECT_ATTRIBUTES ObjectAttributes
)
3404 KPROCESSOR_MODE PreviousMode
;
3405 NTSTATUS Status
= STATUS_SUCCESS
;
3407 PreviousMode
= ExGetPreviousMode();
3409 if(PreviousMode
!= KernelMode
)
3413 ProbeForWrite(SectionHandle
,
3419 Status
= _SEH_GetExceptionCode();
3423 if(!NT_SUCCESS(Status
))
3429 Status
= ObOpenObjectByName(ObjectAttributes
,
3430 MmSectionObjectType
,
3437 if(NT_SUCCESS(Status
))
3441 *SectionHandle
= hSection
;
3445 Status
= _SEH_GetExceptionCode();
3454 MmMapViewOfSegment(PEPROCESS Process
,
3455 PMADDRESS_SPACE AddressSpace
,
3456 PSECTION_OBJECT Section
,
3457 PMM_SECTION_SEGMENT Segment
,
3467 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3469 BoundaryAddressMultiple
.QuadPart
= 0;
3471 Status
= MmCreateMemoryArea(Process
,
3473 MEMORY_AREA_SECTION_VIEW
,
3480 BoundaryAddressMultiple
);
3481 if (!NT_SUCCESS(Status
))
3483 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3484 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3488 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3489 InsertTailList(&Section
->ViewListHead
,
3490 &MArea
->Data
.SectionData
.ViewListEntry
);
3491 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3493 ObReferenceObjectByPointer((PVOID
)Section
,
3496 ExGetPreviousMode());
3497 MArea
->Data
.SectionData
.Segment
= Segment
;
3498 MArea
->Data
.SectionData
.Section
= Section
;
3499 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3500 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3501 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3502 ViewSize
, 0, Protect
);
3504 return(STATUS_SUCCESS
);
3508 /**********************************************************************
3510 * NtMapViewOfSection
3513 * Maps a view of a section into the virtual address space of a
3518 * Handle of the section.
3521 * Handle of the process.
3524 * Desired base address (or NULL) on entry;
3525 * Actual base address of the view on exit.
3528 * Number of high order address bits that must be zero.
3531 * Size in bytes of the initially committed section of
3535 * Offset in bytes from the beginning of the section
3536 * to the beginning of the view.
3539 * Desired length of map (or zero to map all) on entry
3540 * Actual length mapped on exit.
3542 * InheritDisposition
3543 * Specified how the view is to be shared with
3547 * Type of allocation for the pages.
3550 * Protection for the committed region of the view.
3558 NtMapViewOfSection(IN HANDLE SectionHandle
,
3559 IN HANDLE ProcessHandle
,
3560 IN OUT PVOID
* BaseAddress OPTIONAL
,
3561 IN ULONG ZeroBits OPTIONAL
,
3562 IN ULONG CommitSize
,
3563 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3564 IN OUT PULONG ViewSize
,
3565 IN SECTION_INHERIT InheritDisposition
,
3566 IN ULONG AllocationType OPTIONAL
,
3569 PVOID SafeBaseAddress
;
3570 LARGE_INTEGER SafeSectionOffset
;
3572 PSECTION_OBJECT Section
;
3574 KPROCESSOR_MODE PreviousMode
;
3575 PMADDRESS_SPACE AddressSpace
;
3576 NTSTATUS Status
= STATUS_SUCCESS
;
3578 PreviousMode
= ExGetPreviousMode();
3580 if(PreviousMode
!= KernelMode
)
3582 SafeBaseAddress
= NULL
;
3583 SafeSectionOffset
.QuadPart
= 0;
3588 if(BaseAddress
!= NULL
)
3590 ProbeForWrite(BaseAddress
,
3593 SafeBaseAddress
= *BaseAddress
;
3595 if(SectionOffset
!= NULL
)
3597 ProbeForWrite(SectionOffset
,
3598 sizeof(LARGE_INTEGER
),
3600 SafeSectionOffset
= *SectionOffset
;
3602 ProbeForWrite(ViewSize
,
3605 SafeViewSize
= *ViewSize
;
3609 Status
= _SEH_GetExceptionCode();
3613 if(!NT_SUCCESS(Status
))
3620 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3621 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3622 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3625 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3626 PROCESS_VM_OPERATION
,
3629 (PVOID
*)(PVOID
)&Process
,
3631 if (!NT_SUCCESS(Status
))
3636 AddressSpace
= &Process
->AddressSpace
;
3638 Status
= ObReferenceObjectByHandle(SectionHandle
,
3640 MmSectionObjectType
,
3642 (PVOID
*)(PVOID
)&Section
,
3644 if (!(NT_SUCCESS(Status
)))
3646 DPRINT("ObReference failed rc=%x\n",Status
);
3647 ObDereferenceObject(Process
);
3651 Status
= MmMapViewOfSection(Section
,
3653 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3656 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3657 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3662 ObDereferenceObject(Section
);
3663 ObDereferenceObject(Process
);
3665 if(NT_SUCCESS(Status
))
3667 /* copy parameters back to the caller */
3670 if(BaseAddress
!= NULL
)
3672 *BaseAddress
= SafeBaseAddress
;
3674 if(SectionOffset
!= NULL
)
3676 *SectionOffset
= SafeSectionOffset
;
3678 if(ViewSize
!= NULL
)
3680 *ViewSize
= SafeViewSize
;
3685 Status
= _SEH_GetExceptionCode();
3694 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3695 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3699 PFILE_OBJECT FileObject
;
3702 SWAPENTRY SavedSwapEntry
;
3705 PSECTION_OBJECT Section
;
3706 PMM_SECTION_SEGMENT Segment
;
3708 MArea
= (PMEMORY_AREA
)Context
;
3710 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3712 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MArea
->StartingAddress
) +
3713 MemoryArea
->Data
.SectionData
.ViewOffset
;
3715 Section
= MArea
->Data
.SectionData
.Section
;
3716 Segment
= MArea
->Data
.SectionData
.Segment
;
3718 PageOp
= MmCheckForPageOp(MArea
, NULL
, NULL
, Segment
, Offset
);
3722 MmUnlockSectionSegment(Segment
);
3723 MmUnlockAddressSpace(&MArea
->Process
->AddressSpace
);
3725 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3726 if (Status
!= STATUS_SUCCESS
)
3728 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3732 MmLockAddressSpace(&MArea
->Process
->AddressSpace
);
3733 MmLockSectionSegment(Segment
);
3734 MmspCompleteAndReleasePageOp(PageOp
);
3735 PageOp
= MmCheckForPageOp(MArea
, NULL
, NULL
, Segment
, Offset
);
3738 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3741 * For a dirty, datafile, non-private page mark it as dirty in the
3744 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3746 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3748 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3749 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3750 CcRosMarkDirtyCacheSegment(Bcb
, Offset
);
3751 ASSERT(SwapEntry
== 0);
3760 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3762 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3765 MmFreeSwapPage(SwapEntry
);
3769 if (IS_SWAP_FROM_SSE(Entry
) ||
3770 Page
!= PFN_FROM_SSE(Entry
))
3775 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3777 DPRINT1("Found a private page in a pagefile section.\n");
3781 * Just dereference private pages
3783 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3784 if (SavedSwapEntry
!= 0)
3786 MmFreeSwapPage(SavedSwapEntry
);
3787 MmSetSavedSwapEntryPage(Page
, 0);
3789 MmDeleteRmap(Page
, MArea
->Process
, Address
);
3790 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3794 MmDeleteRmap(Page
, MArea
->Process
, Address
);
3795 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3801 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3805 PMEMORY_AREA MemoryArea
;
3806 PSECTION_OBJECT Section
;
3807 PMM_SECTION_SEGMENT Segment
;
3809 PLIST_ENTRY CurrentEntry
;
3810 PMM_REGION CurrentRegion
;
3811 PLIST_ENTRY RegionListHead
;
3813 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3815 if (MemoryArea
== NULL
)
3817 return(STATUS_UNSUCCESSFUL
);
3820 MemoryArea
->DeleteInProgress
= TRUE
;
3821 Section
= MemoryArea
->Data
.SectionData
.Section
;
3822 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3824 MmLockSectionSegment(Segment
);
3825 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3826 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
3827 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3829 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3830 while (!IsListEmpty(RegionListHead
))
3832 CurrentEntry
= RemoveHeadList(RegionListHead
);
3833 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3834 ExFreePool(CurrentRegion
);
3837 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3839 Status
= MmFreeMemoryArea(AddressSpace
,
3846 Status
= MmFreeMemoryArea(AddressSpace
,
3851 MmUnlockSectionSegment(Segment
);
3852 ObDereferenceObject(Section
);
3853 return(STATUS_SUCCESS
);
3860 MmUnmapViewOfSection(PEPROCESS Process
,
3864 PMEMORY_AREA MemoryArea
;
3865 PMADDRESS_SPACE AddressSpace
;
3866 PSECTION_OBJECT Section
;
3868 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3869 Process
, BaseAddress
);
3873 AddressSpace
= &Process
->AddressSpace
;
3874 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3876 if (MemoryArea
== NULL
||
3877 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
3878 MemoryArea
->DeleteInProgress
)
3880 return STATUS_NOT_MAPPED_VIEW
;
3883 Section
= MemoryArea
->Data
.SectionData
.Section
;
3885 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3889 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3890 PMM_SECTION_SEGMENT SectionSegments
;
3891 PVOID ImageBaseAddress
= 0;
3892 PMM_SECTION_SEGMENT Segment
;
3894 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3895 ImageSectionObject
= Section
->ImageSection
;
3896 SectionSegments
= ImageSectionObject
->Segments
;
3897 NrSegments
= ImageSectionObject
->NrSegments
;
3899 /* Search for the current segment within the section segments
3900 * and calculate the image base address */
3901 for (i
= 0; i
< NrSegments
; i
++)
3903 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3905 if (Segment
== &SectionSegments
[i
])
3907 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3912 if (i
>= NrSegments
)
3917 for (i
= 0; i
< NrSegments
; i
++)
3919 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3921 PVOID SBaseAddress
= (PVOID
)
3922 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3924 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
3930 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
3932 return(STATUS_SUCCESS
);
3935 /**********************************************************************
3937 * NtUnmapViewOfSection
3952 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3956 KPROCESSOR_MODE PreviousMode
;
3959 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3960 ProcessHandle
, BaseAddress
);
3962 PreviousMode
= ExGetPreviousMode();
3964 DPRINT("Referencing process\n");
3965 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3966 PROCESS_VM_OPERATION
,
3969 (PVOID
*)(PVOID
)&Process
,
3971 if (!NT_SUCCESS(Status
))
3973 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3977 MmLockAddressSpace(&Process
->AddressSpace
);
3978 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3979 MmUnlockAddressSpace(&Process
->AddressSpace
);
3981 ObDereferenceObject(Process
);
3988 * Queries the information of a section object.
3990 * @param SectionHandle
3991 * Handle to the section object. It must be opened with SECTION_QUERY
3993 * @param SectionInformationClass
3994 * Index to a certain information structure. Can be either
3995 * SectionBasicInformation or SectionImageInformation. The latter
3996 * is valid only for sections that were created with the SEC_IMAGE
3998 * @param SectionInformation
3999 * Caller supplies storage for resulting information.
4001 * Size of the supplied storage.
4002 * @param ResultLength
4010 NtQuerySection(IN HANDLE SectionHandle
,
4011 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4012 OUT PVOID SectionInformation
,
4013 IN ULONG SectionInformationLength
,
4014 OUT PULONG ResultLength OPTIONAL
)
4016 PSECTION_OBJECT Section
;
4017 KPROCESSOR_MODE PreviousMode
;
4018 NTSTATUS Status
= STATUS_SUCCESS
;
4020 PreviousMode
= ExGetPreviousMode();
4022 DefaultQueryInfoBufferCheck(SectionInformationClass
,
4025 SectionInformationLength
,
4030 if(!NT_SUCCESS(Status
))
4032 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4036 Status
= ObReferenceObjectByHandle(SectionHandle
,
4038 MmSectionObjectType
,
4040 (PVOID
*)(PVOID
)&Section
,
4042 if (NT_SUCCESS(Status
))
4044 switch (SectionInformationClass
)
4046 case SectionBasicInformation
:
4048 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4052 Sbi
->Attributes
= Section
->AllocationAttributes
;
4053 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4055 Sbi
->BaseAddress
= 0;
4056 Sbi
->Size
.QuadPart
= 0;
4060 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4061 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4064 if (ResultLength
!= NULL
)
4066 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4068 Status
= STATUS_SUCCESS
;
4072 Status
= _SEH_GetExceptionCode();
4079 case SectionImageInformation
:
4081 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4085 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4086 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4088 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4089 ImageSectionObject
= Section
->ImageSection
;
4091 Sii
->EntryPoint
= ImageSectionObject
->EntryPoint
;
4092 Sii
->StackReserve
= ImageSectionObject
->StackReserve
;
4093 Sii
->StackCommit
= ImageSectionObject
->StackCommit
;
4094 Sii
->Subsystem
= ImageSectionObject
->Subsystem
;
4095 Sii
->MinorSubsystemVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4096 Sii
->MajorSubsystemVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4097 Sii
->Characteristics
= ImageSectionObject
->ImageCharacteristics
;
4098 Sii
->ImageNumber
= ImageSectionObject
->Machine
;
4099 Sii
->Executable
= ImageSectionObject
->Executable
;
4102 if (ResultLength
!= NULL
)
4104 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4106 Status
= STATUS_SUCCESS
;
4110 Status
= _SEH_GetExceptionCode();
4118 ObDereferenceObject(Section
);
4126 * Extends size of file backed section.
4128 * @param SectionHandle
4129 * Handle to the section object. It must be opened with
4130 * SECTION_EXTEND_SIZE access.
4131 * @param NewMaximumSize
4132 * New maximum size of the section in bytes.
4136 * @todo Move the actual code to internal function MmExtendSection.
4140 NtExtendSection(IN HANDLE SectionHandle
,
4141 IN PLARGE_INTEGER NewMaximumSize
)
4143 LARGE_INTEGER SafeNewMaximumSize
;
4144 PSECTION_OBJECT Section
;
4145 KPROCESSOR_MODE PreviousMode
;
4146 NTSTATUS Status
= STATUS_SUCCESS
;
4148 PreviousMode
= ExGetPreviousMode();
4150 if(PreviousMode
!= KernelMode
)
4154 ProbeForRead(NewMaximumSize
,
4155 sizeof(LARGE_INTEGER
),
4157 /* make a copy on the stack */
4158 SafeNewMaximumSize
= *NewMaximumSize
;
4159 NewMaximumSize
= &SafeNewMaximumSize
;
4163 Status
= _SEH_GetExceptionCode();
4167 if(!NT_SUCCESS(Status
))
4173 Status
= ObReferenceObjectByHandle(SectionHandle
,
4174 SECTION_EXTEND_SIZE
,
4175 MmSectionObjectType
,
4179 if (!NT_SUCCESS(Status
))
4184 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4186 ObfDereferenceObject(Section
);
4187 return STATUS_INVALID_PARAMETER
;
4191 * - Acquire file extneding resource.
4192 * - Check if we're not resizing the section below it's actual size!
4193 * - Extend segments if needed.
4194 * - Set file information (FileAllocationInformation) to the new size.
4195 * - Release file extending resource.
4198 ObDereferenceObject(Section
);
4200 return STATUS_NOT_IMPLEMENTED
;
4204 /**********************************************************************
4206 * MmAllocateSection@4
4216 * Code taken from ntoskrnl/mm/special.c.
4221 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4227 PMADDRESS_SPACE AddressSpace
;
4228 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4230 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4232 BoundaryAddressMultiple
.QuadPart
= 0;
4234 AddressSpace
= MmGetKernelAddressSpace();
4235 Result
= BaseAddress
;
4236 MmLockAddressSpace(AddressSpace
);
4237 Status
= MmCreateMemoryArea (NULL
,
4246 BoundaryAddressMultiple
);
4247 MmUnlockAddressSpace(AddressSpace
);
4249 if (!NT_SUCCESS(Status
))
4253 DPRINT("Result %p\n",Result
);
4254 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
4258 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
4259 if (!NT_SUCCESS(Status
))
4261 DbgPrint("Unable to allocate page\n");
4264 Status
= MmCreateVirtualMapping (NULL
,
4265 (PVOID
)((ULONG_PTR
)Result
+ (i
* PAGE_SIZE
)),
4269 if (!NT_SUCCESS(Status
))
4271 DbgPrint("Unable to create virtual mapping\n");
4275 return ((PVOID
)Result
);
4279 /**********************************************************************
4281 * MmMapViewOfSection
4284 * Maps a view of a section into the virtual address space of a
4289 * Pointer to the section object.
4292 * Pointer to the process.
4295 * Desired base address (or NULL) on entry;
4296 * Actual base address of the view on exit.
4299 * Number of high order address bits that must be zero.
4302 * Size in bytes of the initially committed section of
4306 * Offset in bytes from the beginning of the section
4307 * to the beginning of the view.
4310 * Desired length of map (or zero to map all) on entry
4311 * Actual length mapped on exit.
4313 * InheritDisposition
4314 * Specified how the view is to be shared with
4318 * Type of allocation for the pages.
4321 * Protection for the committed region of the view.
4329 MmMapViewOfSection(IN PVOID SectionObject
,
4330 IN PEPROCESS Process
,
4331 IN OUT PVOID
*BaseAddress
,
4333 IN ULONG CommitSize
,
4334 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4335 IN OUT PULONG ViewSize
,
4336 IN SECTION_INHERIT InheritDisposition
,
4337 IN ULONG AllocationType
,
4340 PSECTION_OBJECT Section
;
4341 PMADDRESS_SPACE AddressSpace
;
4343 NTSTATUS Status
= STATUS_SUCCESS
;
4347 Section
= (PSECTION_OBJECT
)SectionObject
;
4348 AddressSpace
= &Process
->AddressSpace
;
4350 MmLockAddressSpace(AddressSpace
);
4352 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4356 ULONG_PTR ImageBase
;
4358 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4359 PMM_SECTION_SEGMENT SectionSegments
;
4361 ImageSectionObject
= Section
->ImageSection
;
4362 SectionSegments
= ImageSectionObject
->Segments
;
4363 NrSegments
= ImageSectionObject
->NrSegments
;
4366 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4369 ImageBase
= ImageSectionObject
->ImageBase
;
4373 for (i
= 0; i
< NrSegments
; i
++)
4375 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4377 ULONG_PTR MaxExtent
;
4378 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4379 SectionSegments
[i
].Length
;
4380 ImageSize
= max(ImageSize
, MaxExtent
);
4384 /* Check there is enough space to map the section at that point. */
4385 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4386 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4388 /* Fail if the user requested a fixed base address. */
4389 if ((*BaseAddress
) != NULL
)
4391 MmUnlockAddressSpace(AddressSpace
);
4392 return(STATUS_UNSUCCESSFUL
);
4394 /* Otherwise find a gap to map the image. */
4395 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4398 MmUnlockAddressSpace(AddressSpace
);
4399 return(STATUS_UNSUCCESSFUL
);
4403 for (i
= 0; i
< NrSegments
; i
++)
4405 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4407 PVOID SBaseAddress
= (PVOID
)
4408 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4409 MmLockSectionSegment(&SectionSegments
[i
]);
4410 Status
= MmMapViewOfSegment(Process
,
4413 &SectionSegments
[i
],
4415 SectionSegments
[i
].Length
,
4416 SectionSegments
[i
].Protection
,
4419 MmUnlockSectionSegment(&SectionSegments
[i
]);
4420 if (!NT_SUCCESS(Status
))
4422 MmUnlockAddressSpace(AddressSpace
);
4428 *BaseAddress
= (PVOID
)ImageBase
;
4432 if (ViewSize
== NULL
)
4434 /* Following this pointer would lead to us to the dark side */
4435 /* What to do? Bugcheck? Return status? Do the mambo? */
4436 KEBUGCHECK(MEMORY_MANAGEMENT
);
4439 if (SectionOffset
== NULL
)
4445 ViewOffset
= SectionOffset
->u
.LowPart
;
4448 if ((ViewOffset
% PAGE_SIZE
) != 0)
4450 MmUnlockAddressSpace(AddressSpace
);
4451 return(STATUS_MAPPED_ALIGNMENT
);
4454 if ((*ViewSize
) == 0)
4456 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4458 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4460 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4463 MmLockSectionSegment(Section
->Segment
);
4464 Status
= MmMapViewOfSegment(Process
,
4472 (AllocationType
& MEM_TOP_DOWN
));
4473 MmUnlockSectionSegment(Section
->Segment
);
4474 if (!NT_SUCCESS(Status
))
4476 MmUnlockAddressSpace(AddressSpace
);
4481 MmUnlockAddressSpace(AddressSpace
);
4483 return(STATUS_SUCCESS
);
4490 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4491 IN PLARGE_INTEGER NewFileSize
)
4502 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
4512 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4513 IN MMFLUSH_TYPE FlushType
)
4517 case MmFlushForDelete
:
4518 if (SectionObjectPointer
->ImageSectionObject
||
4519 SectionObjectPointer
->DataSectionObject
)
4523 CcRosSetRemoveOnClose(SectionObjectPointer
);
4525 case MmFlushForWrite
:
4535 MmForceSectionClosed (
4536 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4537 IN BOOLEAN DelayClose
)
4548 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4549 OUT PVOID
* MappedBase
,
4550 IN OUT PULONG ViewSize
)
4552 PSECTION_OBJECT Section
;
4553 PMADDRESS_SPACE AddressSpace
;
4556 DPRINT("MmMapViewInSystemSpace() called\n");
4558 Section
= (PSECTION_OBJECT
)SectionObject
;
4559 AddressSpace
= MmGetKernelAddressSpace();
4561 MmLockAddressSpace(AddressSpace
);
4564 if ((*ViewSize
) == 0)
4566 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4568 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4570 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4573 MmLockSectionSegment(Section
->Segment
);
4576 Status
= MmMapViewOfSegment(NULL
,
4586 MmUnlockSectionSegment(Section
->Segment
);
4587 MmUnlockAddressSpace(AddressSpace
);
4597 MmMapViewInSessionSpace (
4599 OUT PVOID
*MappedBase
,
4600 IN OUT PSIZE_T ViewSize
4604 return STATUS_NOT_IMPLEMENTED
;
4612 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4614 PMADDRESS_SPACE AddressSpace
;
4617 DPRINT("MmUnmapViewInSystemSpace() called\n");
4619 AddressSpace
= MmGetKernelAddressSpace();
4621 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4631 MmUnmapViewInSessionSpace (
4636 return STATUS_NOT_IMPLEMENTED
;
4643 MmSetBankedSection (DWORD Unknown0
,
4651 return (STATUS_NOT_IMPLEMENTED
);
4655 /**********************************************************************
4660 * Creates a section object.
4663 * SectionObject (OUT)
4664 * Caller supplied storage for the resulting pointer
4665 * to a SECTION_OBJECT instance;
4668 * Specifies the desired access to the section can be a
4670 * STANDARD_RIGHTS_REQUIRED |
4672 * SECTION_MAP_WRITE |
4673 * SECTION_MAP_READ |
4674 * SECTION_MAP_EXECUTE
4676 * ObjectAttributes [OPTIONAL]
4677 * Initialized attributes for the object can be used
4678 * to create a named section;
4681 * Maximizes the size of the memory section. Must be
4682 * non-NULL for a page-file backed section.
4683 * If value specified for a mapped file and the file is
4684 * not large enough, file will be extended.
4686 * SectionPageProtection
4687 * Can be a combination of:
4693 * AllocationAttributes
4694 * Can be a combination of:
4699 * Handle to a file to create a section mapped to a file
4700 * instead of a memory backed section;
4711 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4712 IN ACCESS_MASK DesiredAccess
,
4713 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4714 IN PLARGE_INTEGER MaximumSize
,
4715 IN ULONG SectionPageProtection
,
4716 IN ULONG AllocationAttributes
,
4717 IN HANDLE FileHandle OPTIONAL
,
4718 IN PFILE_OBJECT File OPTIONAL
)
4720 if (AllocationAttributes
& SEC_IMAGE
)
4722 return(MmCreateImageSection(SectionObject
,
4726 SectionPageProtection
,
4727 AllocationAttributes
,
4731 if (FileHandle
!= NULL
)
4733 return(MmCreateDataFileSection(SectionObject
,
4737 SectionPageProtection
,
4738 AllocationAttributes
,
4742 return(MmCreatePageFileSection(SectionObject
,
4746 SectionPageProtection
,
4747 AllocationAttributes
));