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 PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
42 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
43 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
44 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
45 #define MAX_SHARE_COUNT 0x7FF
46 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
47 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
48 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
50 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
52 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
53 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
56 /* FUNCTIONS *****************************************************************/
58 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
61 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
62 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
63 * RETURNS: Status of the wait.
66 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
68 LARGE_INTEGER Timeout
;
69 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
71 Timeout
.QuadPart
= -100000000LL; // 10 sec
74 Timeout
.QuadPart
= -100000000; // 10 sec
77 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
82 * FUNCTION: Sets the page op completion event and releases the page op.
83 * ARGUMENTS: PMM_PAGEOP.
84 * RETURNS: In shorter time than it takes you to even read this
85 * description, so don't even think about geting a mug of coffee.
88 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
90 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
91 MmReleasePageOp(PageOp
);
96 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
97 * ARGUMENTS: PFILE_OBJECT to wait for.
98 * RETURNS: Status of the wait.
101 MmspWaitForFileLock(PFILE_OBJECT File
)
103 return KeWaitForSingleObject(&File
->Lock
, 0, KernelMode
, FALSE
, NULL
);
108 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
111 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
113 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
115 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
117 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
124 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
126 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
128 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
129 PMM_SECTION_SEGMENT SectionSegments
;
133 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
134 NrSegments
= ImageSectionObject
->NrSegments
;
135 SectionSegments
= ImageSectionObject
->Segments
;
136 for (i
= 0; i
< NrSegments
; i
++)
138 if (SectionSegments
[i
].ReferenceCount
!= 0)
140 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
141 SectionSegments
[i
].ReferenceCount
);
144 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
146 ExFreePool(ImageSectionObject
->Segments
);
147 ExFreePool(ImageSectionObject
);
148 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
150 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
152 PMM_SECTION_SEGMENT Segment
;
154 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
157 if (Segment
->ReferenceCount
!= 0)
159 DPRINT1("Data segment still referenced\n");
162 MmFreePageTablesSectionSegment(Segment
);
164 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
169 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
171 ExAcquireFastMutex(&Segment
->Lock
);
175 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
177 ExReleaseFastMutex(&Segment
->Lock
);
181 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
185 PSECTION_PAGE_TABLE Table
;
186 ULONG DirectoryOffset
;
189 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
191 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
195 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
196 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
200 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
201 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
202 TAG_SECTION_PAGE_TABLE
);
207 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
208 DPRINT("Table %x\n", Table
);
211 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
212 Table
->Entry
[TableOffset
] = Entry
;
217 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
220 PSECTION_PAGE_TABLE Table
;
222 ULONG DirectoryOffset
;
225 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
227 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
229 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
233 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
234 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
235 DPRINT("Table %x\n", Table
);
241 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
242 Entry
= Table
->Entry
[TableOffset
];
247 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
252 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
255 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
258 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
260 DPRINT1("Maximum share count reached\n");
263 if (IS_SWAP_FROM_SSE(Entry
))
267 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
268 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
272 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section
,
273 PMM_SECTION_SEGMENT Segment
,
279 BOOLEAN IsDirectMapped
= FALSE
;
281 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
284 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
287 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
289 DPRINT1("Zero share count for unshare\n");
292 if (IS_SWAP_FROM_SSE(Entry
))
296 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
298 * If we reducing the share count of this entry to zero then set the entry
299 * to zero and tell the cache the page is no longer mapped.
301 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
303 PFILE_OBJECT FileObject
;
305 SWAPENTRY SavedSwapEntry
;
307 BOOLEAN IsImageSection
;
310 FileOffset
= Offset
+ Segment
->FileOffset
;
312 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
314 Page
= PFN_FROM_SSE(Entry
);
315 FileObject
= Section
->FileObject
;
316 if (FileObject
!= NULL
&&
317 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
320 if ((FileOffset
% PAGE_SIZE
) == 0 &&
321 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
324 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
325 IsDirectMapped
= TRUE
;
326 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
327 if (!NT_SUCCESS(Status
))
329 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
335 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
336 if (SavedSwapEntry
== 0)
339 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
340 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
344 * Try to page out this page and set the swap entry
345 * within the section segment. There exist no rmap entry
346 * for this page. The pager thread can't page out a
347 * page without a rmap entry.
349 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
353 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
356 MmReleasePageMemoryConsumer(MC_USER
, Page
);
362 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
363 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
371 * We hold all locks. Nobody can do something with the current
372 * process and the current segment (also not within an other process).
375 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
376 if (!NT_SUCCESS(Status
))
378 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
382 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
383 MmSetSavedSwapEntryPage(Page
, 0);
385 MmReleasePageMemoryConsumer(MC_USER
, Page
);
389 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
396 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
398 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
401 BOOL
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
404 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
407 PCACHE_SEGMENT CacheSeg
;
408 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
409 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
412 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
420 MiReadPage(PMEMORY_AREA MemoryArea
,
424 * FUNCTION: Read a page for a section backed memory area.
426 * MemoryArea - Memory area to read the page for.
427 * Offset - Offset of the page to read.
428 * Page - Variable that receives a page contains the read data.
435 PCACHE_SEGMENT CacheSeg
;
436 PFILE_OBJECT FileObject
;
440 BOOLEAN IsImageSection
;
443 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
444 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
445 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
446 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
447 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
451 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
454 * If the file system is letting us go directly to the cache and the
455 * memory area was mapped at an offset in the file which is page aligned
456 * then get the related cache segment.
458 if ((FileOffset
% PAGE_SIZE
) == 0 &&
459 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
460 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
464 * Get the related cache segment; we use a lower level interface than
465 * filesystems do because it is safe for us to use an offset with a
466 * alignment less than the file system block size.
468 Status
= CcRosGetCacheSegment(Bcb
,
474 if (!NT_SUCCESS(Status
))
481 * If the cache segment isn't up to date then call the file
482 * system to read in the data.
484 Status
= ReadCacheSegment(CacheSeg
);
485 if (!NT_SUCCESS(Status
))
487 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
492 * Retrieve the page from the cache segment that we actually want.
494 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
495 FileOffset
- BaseOffset
).QuadPart
>> PAGE_SHIFT
;
497 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
502 ULONG CacheSegOffset
;
504 * Allocate a page, this is rather complicated by the possibility
505 * we might have to move other things out of memory
507 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
508 if (!NT_SUCCESS(Status
))
512 Status
= CcRosGetCacheSegment(Bcb
,
518 if (!NT_SUCCESS(Status
))
525 * If the cache segment isn't up to date then call the file
526 * system to read in the data.
528 Status
= ReadCacheSegment(CacheSeg
);
529 if (!NT_SUCCESS(Status
))
531 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
535 PageAddr
= MmCreateHyperspaceMapping(*Page
);
536 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
537 Length
= RawLength
- SegOffset
;
538 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
540 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
542 else if (CacheSegOffset
>= PAGE_SIZE
)
544 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
548 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
549 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
550 Status
= CcRosGetCacheSegment(Bcb
,
551 FileOffset
+ CacheSegOffset
,
556 if (!NT_SUCCESS(Status
))
558 MmDeleteHyperspaceMapping(PageAddr
);
564 * If the cache segment isn't up to date then call the file
565 * system to read in the data.
567 Status
= ReadCacheSegment(CacheSeg
);
568 if (!NT_SUCCESS(Status
))
570 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
571 MmDeleteHyperspaceMapping(PageAddr
);
575 if (Length
< PAGE_SIZE
)
577 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
581 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
584 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
585 MmDeleteHyperspaceMapping(PageAddr
);
587 return(STATUS_SUCCESS
);
591 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
592 MEMORY_AREA
* MemoryArea
,
600 PSECTION_OBJECT Section
;
601 PMM_SECTION_SEGMENT Segment
;
610 * There is a window between taking the page fault and locking the
611 * address space when another thread could load the page so we check
614 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
618 MmLockPage(MmGetPfnForProcess(AddressSpace
->Process
, Address
));
620 return(STATUS_SUCCESS
);
623 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
624 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
626 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
627 Section
= MemoryArea
->Data
.SectionData
.Section
;
628 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
629 &MemoryArea
->Data
.SectionData
.RegionListHead
,
634 MmLockSectionSegment(Segment
);
637 * Check if this page needs to be mapped COW
639 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
640 (Region
->Protect
== PAGE_READWRITE
||
641 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
643 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
647 Attributes
= Region
->Protect
;
651 * Get or create a page operation descriptor
653 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
656 DPRINT1("MmGetPageOp failed\n");
661 * Check if someone else is already handling this fault, if so wait
664 if (PageOp
->Thread
!= PsGetCurrentThread())
666 MmUnlockSectionSegment(Segment
);
667 MmUnlockAddressSpace(AddressSpace
);
668 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
670 * Check for various strange conditions
672 if (Status
!= STATUS_SUCCESS
)
674 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
677 if (PageOp
->Status
== STATUS_PENDING
)
679 DPRINT1("Woke for page op before completion\n");
682 MmLockAddressSpace(AddressSpace
);
684 * If this wasn't a pagein then restart the operation
686 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
688 MmspCompleteAndReleasePageOp(PageOp
);
689 DPRINT("Address 0x%.8X\n", Address
);
690 return(STATUS_MM_RESTART_OPERATION
);
694 * If the thread handling this fault has failed then we don't retry
696 if (!NT_SUCCESS(PageOp
->Status
))
698 Status
= PageOp
->Status
;
699 MmspCompleteAndReleasePageOp(PageOp
);
700 DPRINT("Address 0x%.8X\n", Address
);
703 MmLockSectionSegment(Segment
);
705 * If the completed fault was for another address space then set the
708 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
710 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
711 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
713 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
716 * The page was a private page in another or in our address space
718 MmUnlockSectionSegment(Segment
);
719 MmspCompleteAndReleasePageOp(PageOp
);
720 return(STATUS_MM_RESTART_OPERATION
);
723 Page
= PFN_FROM_SSE(Entry
);
725 MmSharePageEntrySectionSegment(Segment
, Offset
);
727 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
728 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
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
= MmCreateVirtualMappingUnsafe(AddressSpace
->Process
,
837 if (!NT_SUCCESS(Status
))
839 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
844 * Don't add an rmap entry since the page mapped could be for
849 MmLockPageUnsafe(Page
);
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
));
2068 NTSTATUS INIT_FUNCTION
2069 MmCreatePhysicalMemorySection(VOID
)
2071 PSECTION_OBJECT PhysSection
;
2073 OBJECT_ATTRIBUTES Obj
;
2074 UNICODE_STRING Name
= ROS_STRING_INITIALIZER(L
"\\Device\\PhysicalMemory");
2075 LARGE_INTEGER SectionSize
;
2078 * Create the section mapping physical memory
2080 SectionSize
.QuadPart
= 0xFFFFFFFF;
2081 InitializeObjectAttributes(&Obj
,
2086 Status
= MmCreateSection(&PhysSection
,
2090 PAGE_EXECUTE_READWRITE
,
2094 if (!NT_SUCCESS(Status
))
2096 DbgPrint("Failed to create PhysicalMemory section\n");
2099 Status
= ObInsertObject(PhysSection
,
2105 if (!NT_SUCCESS(Status
))
2107 ObDereferenceObject(PhysSection
);
2109 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2111 return(STATUS_SUCCESS
);
2114 NTSTATUS INIT_FUNCTION
2115 MmInitSectionImplementation(VOID
)
2117 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2118 UNICODE_STRING Name
;
2120 DPRINT1("Creating Section Object Type\n");
2122 /* Initialize the Section object type */
2123 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2124 RtlInitUnicodeString(&Name
, L
"Section");
2125 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2126 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(SECTION_OBJECT
);
2127 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
2128 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2129 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2130 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2131 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2132 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &MmSectionObjectType
);
2134 return(STATUS_SUCCESS
);
2138 MmCreatePageFileSection(PSECTION_OBJECT
*SectionObject
,
2139 ACCESS_MASK DesiredAccess
,
2140 POBJECT_ATTRIBUTES ObjectAttributes
,
2141 PLARGE_INTEGER UMaximumSize
,
2142 ULONG SectionPageProtection
,
2143 ULONG AllocationAttributes
)
2145 * Create a section which is backed by the pagefile
2148 LARGE_INTEGER MaximumSize
;
2149 PSECTION_OBJECT Section
;
2150 PMM_SECTION_SEGMENT Segment
;
2153 if (UMaximumSize
== NULL
)
2155 return(STATUS_UNSUCCESSFUL
);
2157 MaximumSize
= *UMaximumSize
;
2160 * Create the section
2162 Status
= ObCreateObject(ExGetPreviousMode(),
2163 MmSectionObjectType
,
2165 ExGetPreviousMode(),
2167 sizeof(SECTION_OBJECT
),
2170 (PVOID
*)(PVOID
)&Section
);
2171 if (!NT_SUCCESS(Status
))
2179 Section
->SectionPageProtection
= SectionPageProtection
;
2180 Section
->AllocationAttributes
= AllocationAttributes
;
2181 Section
->Segment
= NULL
;
2182 InitializeListHead(&Section
->ViewListHead
);
2183 KeInitializeSpinLock(&Section
->ViewListLock
);
2184 Section
->FileObject
= NULL
;
2185 Section
->MaximumSize
= MaximumSize
;
2186 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2187 TAG_MM_SECTION_SEGMENT
);
2188 if (Segment
== NULL
)
2190 ObDereferenceObject(Section
);
2191 return(STATUS_NO_MEMORY
);
2193 Section
->Segment
= Segment
;
2194 Segment
->ReferenceCount
= 1;
2195 ExInitializeFastMutex(&Segment
->Lock
);
2196 Segment
->FileOffset
= 0;
2197 Segment
->Protection
= SectionPageProtection
;
2198 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2199 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2200 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2201 Segment
->WriteCopy
= FALSE
;
2202 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2203 Segment
->VirtualAddress
= 0;
2204 Segment
->Characteristics
= 0;
2205 *SectionObject
= Section
;
2206 return(STATUS_SUCCESS
);
2211 MmCreateDataFileSection(PSECTION_OBJECT
*SectionObject
,
2212 ACCESS_MASK DesiredAccess
,
2213 POBJECT_ATTRIBUTES ObjectAttributes
,
2214 PLARGE_INTEGER UMaximumSize
,
2215 ULONG SectionPageProtection
,
2216 ULONG AllocationAttributes
,
2219 * Create a section backed by a data file
2222 PSECTION_OBJECT Section
;
2224 LARGE_INTEGER MaximumSize
;
2225 PFILE_OBJECT FileObject
;
2226 PMM_SECTION_SEGMENT Segment
;
2228 IO_STATUS_BLOCK Iosb
;
2229 LARGE_INTEGER Offset
;
2231 FILE_STANDARD_INFORMATION FileInfo
;
2234 * Create the section
2236 Status
= ObCreateObject(ExGetPreviousMode(),
2237 MmSectionObjectType
,
2239 ExGetPreviousMode(),
2241 sizeof(SECTION_OBJECT
),
2244 (PVOID
*)(PVOID
)&Section
);
2245 if (!NT_SUCCESS(Status
))
2252 Section
->SectionPageProtection
= SectionPageProtection
;
2253 Section
->AllocationAttributes
= AllocationAttributes
;
2254 Section
->Segment
= NULL
;
2255 InitializeListHead(&Section
->ViewListHead
);
2256 KeInitializeSpinLock(&Section
->ViewListLock
);
2259 * Check file access required
2261 if (SectionPageProtection
& PAGE_READWRITE
||
2262 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2264 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2268 FileAccess
= FILE_READ_DATA
;
2272 * Reference the file handle
2274 Status
= ObReferenceObjectByHandle(FileHandle
,
2278 (PVOID
*)(PVOID
)&FileObject
,
2280 if (!NT_SUCCESS(Status
))
2282 ObDereferenceObject(Section
);
2287 * FIXME: This is propably not entirely correct. We can't look into
2288 * the standard FCB header because it might not be initialized yet
2289 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2290 * standard file information is filled on first request).
2292 Status
= NtQueryInformationFile(FileHandle
,
2295 sizeof(FILE_STANDARD_INFORMATION
),
2296 FileStandardInformation
);
2297 if (!NT_SUCCESS(Status
))
2299 ObDereferenceObject(Section
);
2300 ObDereferenceObject(FileObject
);
2305 * FIXME: Revise this once a locking order for file size changes is
2308 if (UMaximumSize
!= NULL
)
2310 MaximumSize
= *UMaximumSize
;
2314 MaximumSize
= FileInfo
.EndOfFile
;
2315 /* Mapping zero-sized files isn't allowed. */
2316 if (MaximumSize
.QuadPart
== 0)
2318 ObDereferenceObject(Section
);
2319 ObDereferenceObject(FileObject
);
2320 return STATUS_FILE_INVALID
;
2324 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2326 Status
= NtSetInformationFile(FileHandle
,
2329 sizeof(LARGE_INTEGER
),
2330 FileAllocationInformation
);
2331 if (!NT_SUCCESS(Status
))
2333 ObDereferenceObject(Section
);
2334 ObDereferenceObject(FileObject
);
2335 return(STATUS_SECTION_NOT_EXTENDED
);
2339 if (FileObject
->SectionObjectPointer
== NULL
||
2340 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2343 * Read a bit so caching is initiated for the file object.
2344 * This is only needed because MiReadPage currently cannot
2345 * handle non-cached streams.
2347 Offset
.QuadPart
= 0;
2348 Status
= ZwReadFile(FileHandle
,
2357 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2359 ObDereferenceObject(Section
);
2360 ObDereferenceObject(FileObject
);
2363 if (FileObject
->SectionObjectPointer
== NULL
||
2364 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2366 /* FIXME: handle this situation */
2367 ObDereferenceObject(Section
);
2368 ObDereferenceObject(FileObject
);
2369 return STATUS_INVALID_PARAMETER
;
2376 Status
= MmspWaitForFileLock(FileObject
);
2377 if (Status
!= STATUS_SUCCESS
)
2379 ObDereferenceObject(Section
);
2380 ObDereferenceObject(FileObject
);
2385 * If this file hasn't been mapped as a data file before then allocate a
2386 * section segment to describe the data file mapping
2388 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2390 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2391 TAG_MM_SECTION_SEGMENT
);
2392 if (Segment
== NULL
)
2394 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2395 ObDereferenceObject(Section
);
2396 ObDereferenceObject(FileObject
);
2397 return(STATUS_NO_MEMORY
);
2399 Section
->Segment
= Segment
;
2400 Segment
->ReferenceCount
= 1;
2401 ExInitializeFastMutex(&Segment
->Lock
);
2403 * Set the lock before assigning the segment to the file object
2405 ExAcquireFastMutex(&Segment
->Lock
);
2406 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2408 Segment
->FileOffset
= 0;
2409 Segment
->Protection
= SectionPageProtection
;
2410 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2411 Segment
->Characteristics
= 0;
2412 Segment
->WriteCopy
= FALSE
;
2413 if (AllocationAttributes
& SEC_RESERVE
)
2415 Segment
->Length
= Segment
->RawLength
= 0;
2419 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2420 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2422 Segment
->VirtualAddress
= 0;
2423 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2428 * If the file is already mapped as a data file then we may need
2432 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2434 Section
->Segment
= Segment
;
2435 InterlockedIncrementUL(&Segment
->ReferenceCount
);
2436 MmLockSectionSegment(Segment
);
2438 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2439 !(AllocationAttributes
& SEC_RESERVE
))
2441 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2442 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2445 MmUnlockSectionSegment(Segment
);
2446 Section
->FileObject
= FileObject
;
2447 Section
->MaximumSize
= MaximumSize
;
2448 CcRosReferenceCache(FileObject
);
2449 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2450 *SectionObject
= Section
;
2451 return(STATUS_SUCCESS
);
2455 TODO: not that great (declaring loaders statically, having to declare all of
2456 them, having to keep them extern, etc.), will fix in the future
2458 extern NTSTATUS NTAPI PeFmtCreateSection
2460 IN CONST VOID
* FileHeader
,
2461 IN SIZE_T FileHeaderSize
,
2463 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2465 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2466 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2469 extern NTSTATUS NTAPI ElfFmtCreateSection
2471 IN CONST VOID
* FileHeader
,
2472 IN SIZE_T FileHeaderSize
,
2474 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2476 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2477 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2480 /* TODO: this is a standard DDK/PSDK macro */
2481 #ifndef RTL_NUMBER_OF
2482 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2485 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2494 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2496 SIZE_T SizeOfSegments
;
2497 PMM_SECTION_SEGMENT Segments
;
2499 /* TODO: check for integer overflow */
2500 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2502 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2504 TAG_MM_SECTION_SEGMENT
);
2507 RtlZeroMemory(Segments
, SizeOfSegments
);
2515 ExeFmtpReadFile(IN PVOID File
,
2516 IN PLARGE_INTEGER Offset
,
2519 OUT PVOID
* AllocBase
,
2520 OUT PULONG ReadSize
)
2523 LARGE_INTEGER FileOffset
;
2525 ULONG OffsetAdjustment
;
2530 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2534 KEBUGCHECK(STATUS_INVALID_PARAMETER_4
);
2537 FileOffset
= *Offset
;
2539 /* Negative/special offset: it cannot be used in this context */
2540 if(FileOffset
.u
.HighPart
< 0)
2542 KEBUGCHECK(STATUS_INVALID_PARAMETER_5
);
2545 ASSERT(PAGE_SIZE
<= MAXULONG
);
2546 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2547 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2548 FileOffset
.u
.LowPart
= AdjustOffset
;
2550 BufferSize
= Length
+ OffsetAdjustment
;
2551 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2554 * It's ok to use paged pool, because this is a temporary buffer only used in
2555 * the loading of executables. The assumption is that MmCreateSection is
2556 * always called at low IRQLs and that these buffers don't survive a brief
2557 * initialization phase
2559 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2561 TAG('M', 'm', 'X', 'r'));
2566 Status
= MmspPageRead(File
,
2573 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2574 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2575 * to initialize internal state is even worse. Our cache manager is in need of
2579 IO_STATUS_BLOCK Iosb
;
2581 Status
= ZwReadFile(File
,
2591 if(NT_SUCCESS(Status
))
2593 UsedSize
= Iosb
.Information
;
2598 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2600 Status
= STATUS_IN_PAGE_ERROR
;
2601 ASSERT(!NT_SUCCESS(Status
));
2604 if(NT_SUCCESS(Status
))
2606 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2607 *AllocBase
= Buffer
;
2608 *ReadSize
= UsedSize
- OffsetAdjustment
;
2619 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2620 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2621 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2626 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2630 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2632 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2633 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2640 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2644 MmspAssertSegmentsSorted(ImageSectionObject
);
2646 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2648 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2652 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2653 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2654 ImageSectionObject
->Segments
[i
- 1].Length
));
2662 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2666 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2668 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2669 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2677 MmspCompareSegments(const void * x
,
2680 PMM_SECTION_SEGMENT Segment1
= (PMM_SECTION_SEGMENT
)x
;
2681 PMM_SECTION_SEGMENT Segment2
= (PMM_SECTION_SEGMENT
)y
;
2684 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2685 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2689 * Ensures an image section's segments are sorted in memory
2694 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2697 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2699 MmspAssertSegmentsSorted(ImageSectionObject
);
2703 qsort(ImageSectionObject
->Segments
,
2704 ImageSectionObject
->NrSegments
,
2705 sizeof(ImageSectionObject
->Segments
[0]),
2706 MmspCompareSegments
);
2712 * Ensures an image section's segments don't overlap in memory and don't have
2713 * gaps and don't have a null size. We let them map to overlapping file regions,
2714 * though - that's not necessarily an error
2719 MmspCheckSegmentBounds
2721 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2727 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2729 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2733 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2735 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2737 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2745 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2746 * page could be OK (Windows seems to be OK with them), and larger gaps
2747 * could lead to image sections spanning several discontiguous regions
2748 * (NtMapViewOfSection could then refuse to map them, and they could
2749 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2751 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2752 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2753 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2764 * Merges and pads an image section's segments until they all are page-aligned
2765 * and have a size that is a multiple of the page size
2770 MmspPageAlignSegments
2772 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2778 BOOLEAN Initialized
;
2780 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2782 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2786 Initialized
= FALSE
;
2789 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2791 PMM_SECTION_SEGMENT EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2794 * The first segment requires special handling
2798 ULONG_PTR VirtualAddress
;
2799 ULONG_PTR VirtualOffset
;
2801 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2803 /* Round down the virtual address to the nearest page */
2804 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2806 /* Round up the virtual size to the nearest page */
2807 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2808 EffectiveSegment
->VirtualAddress
;
2810 /* Adjust the raw address and size */
2811 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2813 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
2819 * Garbage in, garbage out: unaligned base addresses make the file
2820 * offset point in curious and odd places, but that's what we were
2823 EffectiveSegment
->FileOffset
-= VirtualOffset
;
2824 EffectiveSegment
->RawLength
+= VirtualOffset
;
2828 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
2829 ULONG_PTR EndOfEffectiveSegment
;
2831 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
2832 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
2835 * The current segment begins exactly where the current effective
2836 * segment ended, therefore beginning a new effective segment
2838 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
2841 ASSERT(LastSegment
<= i
);
2842 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
2844 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2847 * Copy the current segment. If necessary, the effective segment
2848 * will be expanded later
2850 *EffectiveSegment
= *Segment
;
2853 * Page-align the virtual size. We know for sure the virtual address
2856 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
2857 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
2860 * The current segment is still part of the current effective segment:
2861 * extend the effective segment to reflect this
2863 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
2865 static const ULONG FlagsToProtection
[16] =
2873 PAGE_EXECUTE_READWRITE
,
2874 PAGE_EXECUTE_READWRITE
,
2879 PAGE_EXECUTE_WRITECOPY
,
2880 PAGE_EXECUTE_WRITECOPY
,
2881 PAGE_EXECUTE_WRITECOPY
,
2882 PAGE_EXECUTE_WRITECOPY
2885 unsigned ProtectionFlags
;
2888 * Extend the file size
2891 /* Unaligned segments must be contiguous within the file */
2892 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
2893 EffectiveSegment
->RawLength
))
2898 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
2901 * Extend the virtual size
2903 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) > EndOfEffectiveSegment
);
2905 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
2906 EffectiveSegment
->VirtualAddress
;
2909 * Merge the protection
2911 EffectiveSegment
->Protection
|= Segment
->Protection
;
2913 /* Clean up redundance */
2914 ProtectionFlags
= 0;
2916 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
2917 ProtectionFlags
|= 1 << 0;
2919 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
2920 ProtectionFlags
|= 1 << 1;
2922 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
2923 ProtectionFlags
|= 1 << 2;
2925 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2926 ProtectionFlags
|= 1 << 3;
2928 ASSERT(ProtectionFlags
< 16);
2929 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
2931 /* If a segment was required to be shared and cannot, fail */
2932 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
2933 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2939 * We assume no holes between segments at this point
2952 ExeFmtpCreateImageSection(HANDLE FileHandle
,
2953 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2955 LARGE_INTEGER Offset
;
2957 PVOID FileHeaderBuffer
;
2958 ULONG FileHeaderSize
;
2960 ULONG OldNrSegments
;
2965 * Read the beginning of the file (2 pages). Should be enough to contain
2966 * all (or most) of the headers
2968 Offset
.QuadPart
= 0;
2970 /* FIXME: use FileObject instead of FileHandle */
2971 Status
= ExeFmtpReadFile (FileHandle
,
2978 if (!NT_SUCCESS(Status
))
2981 if (FileHeaderSize
== 0)
2983 ExFreePool(FileHeaderBuffer
);
2984 return STATUS_UNSUCCESSFUL
;
2988 * Look for a loader that can handle this executable
2990 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
2992 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
2995 /* FIXME: use FileObject instead of FileHandle */
2996 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3002 ExeFmtpAllocateSegments
);
3004 if (!NT_SUCCESS(Status
))
3006 if (ImageSectionObject
->Segments
)
3008 ExFreePool(ImageSectionObject
->Segments
);
3009 ImageSectionObject
->Segments
= NULL
;
3013 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3017 ExFreePool(FileHeaderBuffer
);
3020 * No loader handled the format
3022 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3024 Status
= STATUS_INVALID_IMAGE_FORMAT
;
3025 ASSERT(!NT_SUCCESS(Status
));
3028 if (!NT_SUCCESS(Status
))
3031 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3036 /* FIXME? are these values platform-dependent? */
3037 if(ImageSectionObject
->StackReserve
== 0)
3038 ImageSectionObject
->StackReserve
= 0x40000;
3040 if(ImageSectionObject
->StackCommit
== 0)
3041 ImageSectionObject
->StackCommit
= 0x1000;
3043 if(ImageSectionObject
->ImageBase
== 0)
3045 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3046 ImageSectionObject
->ImageBase
= 0x10000000;
3048 ImageSectionObject
->ImageBase
= 0x00400000;
3052 * And now the fun part: fixing the segments
3055 /* Sort them by virtual address */
3056 MmspSortSegments(ImageSectionObject
, Flags
);
3058 /* Ensure they don't overlap in memory */
3059 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3060 return STATUS_INVALID_IMAGE_FORMAT
;
3062 /* Ensure they are aligned */
3063 OldNrSegments
= ImageSectionObject
->NrSegments
;
3065 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3066 return STATUS_INVALID_IMAGE_FORMAT
;
3068 /* Trim them if the alignment phase merged some of them */
3069 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3071 PMM_SECTION_SEGMENT Segments
;
3072 SIZE_T SizeOfSegments
;
3074 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3076 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3078 TAG_MM_SECTION_SEGMENT
);
3080 if (Segments
== NULL
)
3081 return STATUS_INSUFFICIENT_RESOURCES
;
3083 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3084 ExFreePool(ImageSectionObject
->Segments
);
3085 ImageSectionObject
->Segments
= Segments
;
3088 /* And finish their initialization */
3089 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3091 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3092 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3094 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3095 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3098 ASSERT(NT_SUCCESS(Status
));
3103 MmCreateImageSection(PSECTION_OBJECT
*SectionObject
,
3104 ACCESS_MASK DesiredAccess
,
3105 POBJECT_ATTRIBUTES ObjectAttributes
,
3106 PLARGE_INTEGER UMaximumSize
,
3107 ULONG SectionPageProtection
,
3108 ULONG AllocationAttributes
,
3111 PSECTION_OBJECT Section
;
3113 PFILE_OBJECT FileObject
;
3114 PMM_SECTION_SEGMENT SectionSegments
;
3115 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3117 ULONG FileAccess
= 0;
3120 * Specifying a maximum size is meaningless for an image section
3122 if (UMaximumSize
!= NULL
)
3124 return(STATUS_INVALID_PARAMETER_4
);
3128 * Check file access required
3130 if (SectionPageProtection
& PAGE_READWRITE
||
3131 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3133 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3137 FileAccess
= FILE_READ_DATA
;
3141 * Reference the file handle
3143 Status
= ObReferenceObjectByHandle(FileHandle
,
3147 (PVOID
*)(PVOID
)&FileObject
,
3150 if (!NT_SUCCESS(Status
))
3156 * Create the section
3158 Status
= ObCreateObject (ExGetPreviousMode(),
3159 MmSectionObjectType
,
3161 ExGetPreviousMode(),
3163 sizeof(SECTION_OBJECT
),
3166 (PVOID
*)(PVOID
)&Section
);
3167 if (!NT_SUCCESS(Status
))
3169 ObDereferenceObject(FileObject
);
3176 Section
->SectionPageProtection
= SectionPageProtection
;
3177 Section
->AllocationAttributes
= AllocationAttributes
;
3178 InitializeListHead(&Section
->ViewListHead
);
3179 KeInitializeSpinLock(&Section
->ViewListLock
);
3182 * Initialized caching for this file object if previously caching
3183 * was initialized for the same on disk file
3185 Status
= CcTryToInitializeFileCache(FileObject
);
3187 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3189 NTSTATUS StatusExeFmt
;
3191 ImageSectionObject
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3192 if (ImageSectionObject
== NULL
)
3194 ObDereferenceObject(FileObject
);
3195 ObDereferenceObject(Section
);
3196 return(STATUS_NO_MEMORY
);
3199 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3201 if (!NT_SUCCESS(StatusExeFmt
))
3203 if(ImageSectionObject
->Segments
!= NULL
)
3204 ExFreePool(ImageSectionObject
->Segments
);
3206 ExFreePool(ImageSectionObject
);
3207 ObDereferenceObject(Section
);
3208 ObDereferenceObject(FileObject
);
3209 return(StatusExeFmt
);
3212 Section
->ImageSection
= ImageSectionObject
;
3213 ASSERT(ImageSectionObject
->Segments
);
3218 Status
= MmspWaitForFileLock(FileObject
);
3219 if (!NT_SUCCESS(Status
))
3221 ExFreePool(ImageSectionObject
->Segments
);
3222 ExFreePool(ImageSectionObject
);
3223 ObDereferenceObject(Section
);
3224 ObDereferenceObject(FileObject
);
3228 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3229 ImageSectionObject
, NULL
))
3232 * An other thread has initialized the some image in the background
3234 ExFreePool(ImageSectionObject
->Segments
);
3235 ExFreePool(ImageSectionObject
);
3236 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3237 Section
->ImageSection
= ImageSectionObject
;
3238 SectionSegments
= ImageSectionObject
->Segments
;
3240 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3242 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3246 Status
= StatusExeFmt
;
3253 Status
= MmspWaitForFileLock(FileObject
);
3254 if (Status
!= STATUS_SUCCESS
)
3256 ObDereferenceObject(Section
);
3257 ObDereferenceObject(FileObject
);
3261 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3262 Section
->ImageSection
= ImageSectionObject
;
3263 SectionSegments
= ImageSectionObject
->Segments
;
3266 * Otherwise just reference all the section segments
3268 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3270 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3273 Status
= STATUS_SUCCESS
;
3275 Section
->FileObject
= FileObject
;
3276 CcRosReferenceCache(FileObject
);
3277 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
3278 *SectionObject
= Section
;
3286 NtCreateSection (OUT PHANDLE SectionHandle
,
3287 IN ACCESS_MASK DesiredAccess
,
3288 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3289 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3290 IN ULONG SectionPageProtection OPTIONAL
,
3291 IN ULONG AllocationAttributes
,
3292 IN HANDLE FileHandle OPTIONAL
)
3294 LARGE_INTEGER SafeMaximumSize
;
3295 PSECTION_OBJECT SectionObject
;
3296 KPROCESSOR_MODE PreviousMode
;
3297 NTSTATUS Status
= STATUS_SUCCESS
;
3299 PreviousMode
= ExGetPreviousMode();
3301 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3305 ProbeForRead(MaximumSize
,
3306 sizeof(LARGE_INTEGER
),
3308 /* make a copy on the stack */
3309 SafeMaximumSize
= *MaximumSize
;
3310 MaximumSize
= &SafeMaximumSize
;
3314 Status
= _SEH_GetExceptionCode();
3318 if(!NT_SUCCESS(Status
))
3325 * Check the protection
3327 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
3328 SectionPageProtection
)
3330 return(STATUS_INVALID_PAGE_PROTECTION
);
3333 Status
= MmCreateSection(&SectionObject
,
3337 SectionPageProtection
,
3338 AllocationAttributes
,
3342 if (NT_SUCCESS(Status
))
3344 Status
= ObInsertObject ((PVOID
)SectionObject
,
3350 ObDereferenceObject(SectionObject
);
3357 /**********************************************************************
3375 NtOpenSection(PHANDLE SectionHandle
,
3376 ACCESS_MASK DesiredAccess
,
3377 POBJECT_ATTRIBUTES ObjectAttributes
)
3380 KPROCESSOR_MODE PreviousMode
;
3381 NTSTATUS Status
= STATUS_SUCCESS
;
3383 PreviousMode
= ExGetPreviousMode();
3385 if(PreviousMode
!= KernelMode
)
3389 ProbeForWrite(SectionHandle
,
3395 Status
= _SEH_GetExceptionCode();
3399 if(!NT_SUCCESS(Status
))
3405 Status
= ObOpenObjectByName(ObjectAttributes
,
3406 MmSectionObjectType
,
3413 if(NT_SUCCESS(Status
))
3417 *SectionHandle
= hSection
;
3421 Status
= _SEH_GetExceptionCode();
3430 MmMapViewOfSegment(PEPROCESS Process
,
3431 PMADDRESS_SPACE AddressSpace
,
3432 PSECTION_OBJECT Section
,
3433 PMM_SECTION_SEGMENT Segment
,
3443 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3445 BoundaryAddressMultiple
.QuadPart
= 0;
3447 Status
= MmCreateMemoryArea(Process
,
3449 MEMORY_AREA_SECTION_VIEW
,
3456 BoundaryAddressMultiple
);
3457 if (!NT_SUCCESS(Status
))
3459 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3460 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3464 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3465 InsertTailList(&Section
->ViewListHead
,
3466 &MArea
->Data
.SectionData
.ViewListEntry
);
3467 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3469 ObReferenceObjectByPointer((PVOID
)Section
,
3472 ExGetPreviousMode());
3473 MArea
->Data
.SectionData
.Segment
= Segment
;
3474 MArea
->Data
.SectionData
.Section
= Section
;
3475 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3476 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3477 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3478 ViewSize
, 0, Protect
);
3480 return(STATUS_SUCCESS
);
3484 /**********************************************************************
3486 * NtMapViewOfSection
3489 * Maps a view of a section into the virtual address space of a
3494 * Handle of the section.
3497 * Handle of the process.
3500 * Desired base address (or NULL) on entry;
3501 * Actual base address of the view on exit.
3504 * Number of high order address bits that must be zero.
3507 * Size in bytes of the initially committed section of
3511 * Offset in bytes from the beginning of the section
3512 * to the beginning of the view.
3515 * Desired length of map (or zero to map all) on entry
3516 * Actual length mapped on exit.
3518 * InheritDisposition
3519 * Specified how the view is to be shared with
3523 * Type of allocation for the pages.
3526 * Protection for the committed region of the view.
3534 NtMapViewOfSection(IN HANDLE SectionHandle
,
3535 IN HANDLE ProcessHandle
,
3536 IN OUT PVOID
* BaseAddress OPTIONAL
,
3537 IN ULONG ZeroBits OPTIONAL
,
3538 IN ULONG CommitSize
,
3539 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3540 IN OUT PULONG ViewSize
,
3541 IN SECTION_INHERIT InheritDisposition
,
3542 IN ULONG AllocationType OPTIONAL
,
3545 PVOID SafeBaseAddress
;
3546 LARGE_INTEGER SafeSectionOffset
;
3548 PSECTION_OBJECT Section
;
3550 KPROCESSOR_MODE PreviousMode
;
3551 PMADDRESS_SPACE AddressSpace
;
3552 NTSTATUS Status
= STATUS_SUCCESS
;
3554 PreviousMode
= ExGetPreviousMode();
3556 if(PreviousMode
!= KernelMode
)
3558 SafeBaseAddress
= NULL
;
3559 SafeSectionOffset
.QuadPart
= 0;
3564 if(BaseAddress
!= NULL
)
3566 ProbeForWrite(BaseAddress
,
3569 SafeBaseAddress
= *BaseAddress
;
3571 if(SectionOffset
!= NULL
)
3573 ProbeForWrite(SectionOffset
,
3574 sizeof(LARGE_INTEGER
),
3576 SafeSectionOffset
= *SectionOffset
;
3578 ProbeForWrite(ViewSize
,
3581 SafeViewSize
= *ViewSize
;
3585 Status
= _SEH_GetExceptionCode();
3589 if(!NT_SUCCESS(Status
))
3596 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3597 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3598 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3601 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3602 PROCESS_VM_OPERATION
,
3605 (PVOID
*)(PVOID
)&Process
,
3607 if (!NT_SUCCESS(Status
))
3612 AddressSpace
= &Process
->AddressSpace
;
3614 Status
= ObReferenceObjectByHandle(SectionHandle
,
3616 MmSectionObjectType
,
3618 (PVOID
*)(PVOID
)&Section
,
3620 if (!(NT_SUCCESS(Status
)))
3622 DPRINT("ObReference failed rc=%x\n",Status
);
3623 ObDereferenceObject(Process
);
3627 Status
= MmMapViewOfSection(Section
,
3629 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3632 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3633 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3638 ObDereferenceObject(Section
);
3639 ObDereferenceObject(Process
);
3641 if(NT_SUCCESS(Status
))
3643 /* copy parameters back to the caller */
3646 if(BaseAddress
!= NULL
)
3648 *BaseAddress
= SafeBaseAddress
;
3650 if(SectionOffset
!= NULL
)
3652 *SectionOffset
= SafeSectionOffset
;
3654 if(ViewSize
!= NULL
)
3656 *ViewSize
= SafeViewSize
;
3661 Status
= _SEH_GetExceptionCode();
3670 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3671 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3675 PFILE_OBJECT FileObject
;
3678 SWAPENTRY SavedSwapEntry
;
3681 PSECTION_OBJECT Section
;
3682 PMM_SECTION_SEGMENT Segment
;
3684 MArea
= (PMEMORY_AREA
)Context
;
3686 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3688 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MArea
->StartingAddress
) +
3689 MemoryArea
->Data
.SectionData
.ViewOffset
;
3691 Section
= MArea
->Data
.SectionData
.Section
;
3692 Segment
= MArea
->Data
.SectionData
.Segment
;
3694 PageOp
= MmCheckForPageOp(MArea
, NULL
, NULL
, Segment
, Offset
);
3698 MmUnlockSectionSegment(Segment
);
3699 MmUnlockAddressSpace(&MArea
->Process
->AddressSpace
);
3701 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3702 if (Status
!= STATUS_SUCCESS
)
3704 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3708 MmLockAddressSpace(&MArea
->Process
->AddressSpace
);
3709 MmLockSectionSegment(Segment
);
3710 MmspCompleteAndReleasePageOp(PageOp
);
3711 PageOp
= MmCheckForPageOp(MArea
, NULL
, NULL
, Segment
, Offset
);
3714 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3717 * For a dirty, datafile, non-private page mark it as dirty in the
3720 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3722 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3724 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3725 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3726 CcRosMarkDirtyCacheSegment(Bcb
, Offset
);
3727 ASSERT(SwapEntry
== 0);
3736 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3738 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3741 MmFreeSwapPage(SwapEntry
);
3745 if (IS_SWAP_FROM_SSE(Entry
) ||
3746 Page
!= PFN_FROM_SSE(Entry
))
3751 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3753 DPRINT1("Found a private page in a pagefile section.\n");
3757 * Just dereference private pages
3759 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3760 if (SavedSwapEntry
!= 0)
3762 MmFreeSwapPage(SavedSwapEntry
);
3763 MmSetSavedSwapEntryPage(Page
, 0);
3765 MmDeleteRmap(Page
, MArea
->Process
, Address
);
3766 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3770 MmDeleteRmap(Page
, MArea
->Process
, Address
);
3771 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3777 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3781 PMEMORY_AREA MemoryArea
;
3782 PSECTION_OBJECT Section
;
3783 PMM_SECTION_SEGMENT Segment
;
3785 PLIST_ENTRY CurrentEntry
;
3786 PMM_REGION CurrentRegion
;
3787 PLIST_ENTRY RegionListHead
;
3789 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3791 if (MemoryArea
== NULL
)
3793 return(STATUS_UNSUCCESSFUL
);
3796 MemoryArea
->DeleteInProgress
= TRUE
;
3797 Section
= MemoryArea
->Data
.SectionData
.Section
;
3798 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3800 MmLockSectionSegment(Segment
);
3801 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3802 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
3803 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3805 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3806 while (!IsListEmpty(RegionListHead
))
3808 CurrentEntry
= RemoveHeadList(RegionListHead
);
3809 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3810 ExFreePool(CurrentRegion
);
3813 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3815 Status
= MmFreeMemoryArea(AddressSpace
,
3822 Status
= MmFreeMemoryArea(AddressSpace
,
3827 MmUnlockSectionSegment(Segment
);
3828 ObDereferenceObject(Section
);
3829 return(STATUS_SUCCESS
);
3836 MmUnmapViewOfSection(PEPROCESS Process
,
3840 PMEMORY_AREA MemoryArea
;
3841 PMADDRESS_SPACE AddressSpace
;
3842 PSECTION_OBJECT Section
;
3844 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3845 Process
, BaseAddress
);
3849 AddressSpace
= &Process
->AddressSpace
;
3850 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3852 if (MemoryArea
== NULL
||
3853 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
3854 MemoryArea
->DeleteInProgress
)
3856 return STATUS_NOT_MAPPED_VIEW
;
3859 Section
= MemoryArea
->Data
.SectionData
.Section
;
3861 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3865 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3866 PMM_SECTION_SEGMENT SectionSegments
;
3867 PVOID ImageBaseAddress
= 0;
3868 PMM_SECTION_SEGMENT Segment
;
3870 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3871 ImageSectionObject
= Section
->ImageSection
;
3872 SectionSegments
= ImageSectionObject
->Segments
;
3873 NrSegments
= ImageSectionObject
->NrSegments
;
3875 /* Search for the current segment within the section segments
3876 * and calculate the image base address */
3877 for (i
= 0; i
< NrSegments
; i
++)
3879 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3881 if (Segment
== &SectionSegments
[i
])
3883 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3888 if (i
>= NrSegments
)
3893 for (i
= 0; i
< NrSegments
; i
++)
3895 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3897 PVOID SBaseAddress
= (PVOID
)
3898 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3900 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
3906 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
3908 return(STATUS_SUCCESS
);
3911 /**********************************************************************
3913 * NtUnmapViewOfSection
3928 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3932 KPROCESSOR_MODE PreviousMode
;
3935 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3936 ProcessHandle
, BaseAddress
);
3938 PreviousMode
= ExGetPreviousMode();
3940 DPRINT("Referencing process\n");
3941 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3942 PROCESS_VM_OPERATION
,
3945 (PVOID
*)(PVOID
)&Process
,
3947 if (!NT_SUCCESS(Status
))
3949 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3953 MmLockAddressSpace(&Process
->AddressSpace
);
3954 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3955 MmUnlockAddressSpace(&Process
->AddressSpace
);
3957 ObDereferenceObject(Process
);
3964 * Queries the information of a section object.
3966 * @param SectionHandle
3967 * Handle to the section object. It must be opened with SECTION_QUERY
3969 * @param SectionInformationClass
3970 * Index to a certain information structure. Can be either
3971 * SectionBasicInformation or SectionImageInformation. The latter
3972 * is valid only for sections that were created with the SEC_IMAGE
3974 * @param SectionInformation
3975 * Caller supplies storage for resulting information.
3977 * Size of the supplied storage.
3978 * @param ResultLength
3986 NtQuerySection(IN HANDLE SectionHandle
,
3987 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
3988 OUT PVOID SectionInformation
,
3989 IN ULONG SectionInformationLength
,
3990 OUT PULONG ResultLength OPTIONAL
)
3992 PSECTION_OBJECT Section
;
3993 KPROCESSOR_MODE PreviousMode
;
3994 NTSTATUS Status
= STATUS_SUCCESS
;
3996 PreviousMode
= ExGetPreviousMode();
3998 DefaultQueryInfoBufferCheck(SectionInformationClass
,
4001 SectionInformationLength
,
4006 if(!NT_SUCCESS(Status
))
4008 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4012 Status
= ObReferenceObjectByHandle(SectionHandle
,
4014 MmSectionObjectType
,
4016 (PVOID
*)(PVOID
)&Section
,
4018 if (NT_SUCCESS(Status
))
4020 switch (SectionInformationClass
)
4022 case SectionBasicInformation
:
4024 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4028 Sbi
->Attributes
= Section
->AllocationAttributes
;
4029 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4031 Sbi
->BaseAddress
= 0;
4032 Sbi
->Size
.QuadPart
= 0;
4036 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4037 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4040 if (ResultLength
!= NULL
)
4042 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4044 Status
= STATUS_SUCCESS
;
4048 Status
= _SEH_GetExceptionCode();
4055 case SectionImageInformation
:
4057 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4061 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4062 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4064 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4065 ImageSectionObject
= Section
->ImageSection
;
4067 Sii
->EntryPoint
= ImageSectionObject
->EntryPoint
;
4068 Sii
->StackReserve
= ImageSectionObject
->StackReserve
;
4069 Sii
->StackCommit
= ImageSectionObject
->StackCommit
;
4070 Sii
->Subsystem
= ImageSectionObject
->Subsystem
;
4071 Sii
->MinorSubsystemVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4072 Sii
->MajorSubsystemVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4073 Sii
->Characteristics
= ImageSectionObject
->ImageCharacteristics
;
4074 Sii
->ImageNumber
= ImageSectionObject
->Machine
;
4075 Sii
->Executable
= ImageSectionObject
->Executable
;
4078 if (ResultLength
!= NULL
)
4080 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4082 Status
= STATUS_SUCCESS
;
4086 Status
= _SEH_GetExceptionCode();
4094 ObDereferenceObject(Section
);
4102 * Extends size of file backed section.
4104 * @param SectionHandle
4105 * Handle to the section object. It must be opened with
4106 * SECTION_EXTEND_SIZE access.
4107 * @param NewMaximumSize
4108 * New maximum size of the section in bytes.
4112 * @todo Move the actual code to internal function MmExtendSection.
4116 NtExtendSection(IN HANDLE SectionHandle
,
4117 IN PLARGE_INTEGER NewMaximumSize
)
4119 LARGE_INTEGER SafeNewMaximumSize
;
4120 PSECTION_OBJECT Section
;
4121 KPROCESSOR_MODE PreviousMode
;
4122 NTSTATUS Status
= STATUS_SUCCESS
;
4124 PreviousMode
= ExGetPreviousMode();
4126 if(PreviousMode
!= KernelMode
)
4130 ProbeForRead(NewMaximumSize
,
4131 sizeof(LARGE_INTEGER
),
4133 /* make a copy on the stack */
4134 SafeNewMaximumSize
= *NewMaximumSize
;
4135 NewMaximumSize
= &SafeNewMaximumSize
;
4139 Status
= _SEH_GetExceptionCode();
4143 if(!NT_SUCCESS(Status
))
4149 Status
= ObReferenceObjectByHandle(SectionHandle
,
4150 SECTION_EXTEND_SIZE
,
4151 MmSectionObjectType
,
4155 if (!NT_SUCCESS(Status
))
4160 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4162 ObfDereferenceObject(Section
);
4163 return STATUS_INVALID_PARAMETER
;
4167 * - Acquire file extneding resource.
4168 * - Check if we're not resizing the section below it's actual size!
4169 * - Extend segments if needed.
4170 * - Set file information (FileAllocationInformation) to the new size.
4171 * - Release file extending resource.
4174 ObDereferenceObject(Section
);
4176 return STATUS_NOT_IMPLEMENTED
;
4180 /**********************************************************************
4182 * MmAllocateSection@4
4192 * Code taken from ntoskrnl/mm/special.c.
4197 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4203 PMADDRESS_SPACE AddressSpace
;
4204 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4206 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4208 BoundaryAddressMultiple
.QuadPart
= 0;
4210 AddressSpace
= MmGetKernelAddressSpace();
4211 Result
= BaseAddress
;
4212 MmLockAddressSpace(AddressSpace
);
4213 Status
= MmCreateMemoryArea (NULL
,
4222 BoundaryAddressMultiple
);
4223 MmUnlockAddressSpace(AddressSpace
);
4225 if (!NT_SUCCESS(Status
))
4229 DPRINT("Result %p\n",Result
);
4230 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
4234 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
4235 if (!NT_SUCCESS(Status
))
4237 DbgPrint("Unable to allocate page\n");
4240 Status
= MmCreateVirtualMapping (NULL
,
4241 (PVOID
)((ULONG_PTR
)Result
+ (i
* PAGE_SIZE
)),
4245 if (!NT_SUCCESS(Status
))
4247 DbgPrint("Unable to create virtual mapping\n");
4251 return ((PVOID
)Result
);
4255 /**********************************************************************
4257 * MmMapViewOfSection
4260 * Maps a view of a section into the virtual address space of a
4265 * Pointer to the section object.
4268 * Pointer to the process.
4271 * Desired base address (or NULL) on entry;
4272 * Actual base address of the view on exit.
4275 * Number of high order address bits that must be zero.
4278 * Size in bytes of the initially committed section of
4282 * Offset in bytes from the beginning of the section
4283 * to the beginning of the view.
4286 * Desired length of map (or zero to map all) on entry
4287 * Actual length mapped on exit.
4289 * InheritDisposition
4290 * Specified how the view is to be shared with
4294 * Type of allocation for the pages.
4297 * Protection for the committed region of the view.
4305 MmMapViewOfSection(IN PVOID SectionObject
,
4306 IN PEPROCESS Process
,
4307 IN OUT PVOID
*BaseAddress
,
4309 IN ULONG CommitSize
,
4310 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4311 IN OUT PULONG ViewSize
,
4312 IN SECTION_INHERIT InheritDisposition
,
4313 IN ULONG AllocationType
,
4316 PSECTION_OBJECT Section
;
4317 PMADDRESS_SPACE AddressSpace
;
4319 NTSTATUS Status
= STATUS_SUCCESS
;
4323 Section
= (PSECTION_OBJECT
)SectionObject
;
4324 AddressSpace
= &Process
->AddressSpace
;
4326 MmLockAddressSpace(AddressSpace
);
4328 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4332 ULONG_PTR ImageBase
;
4334 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4335 PMM_SECTION_SEGMENT SectionSegments
;
4337 ImageSectionObject
= Section
->ImageSection
;
4338 SectionSegments
= ImageSectionObject
->Segments
;
4339 NrSegments
= ImageSectionObject
->NrSegments
;
4342 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4345 ImageBase
= ImageSectionObject
->ImageBase
;
4349 for (i
= 0; i
< NrSegments
; i
++)
4351 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4353 ULONG_PTR MaxExtent
;
4354 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4355 SectionSegments
[i
].Length
;
4356 ImageSize
= max(ImageSize
, MaxExtent
);
4360 /* Check there is enough space to map the section at that point. */
4361 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4362 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4364 /* Fail if the user requested a fixed base address. */
4365 if ((*BaseAddress
) != NULL
)
4367 MmUnlockAddressSpace(AddressSpace
);
4368 return(STATUS_UNSUCCESSFUL
);
4370 /* Otherwise find a gap to map the image. */
4371 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4374 MmUnlockAddressSpace(AddressSpace
);
4375 return(STATUS_UNSUCCESSFUL
);
4379 for (i
= 0; i
< NrSegments
; i
++)
4381 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4383 PVOID SBaseAddress
= (PVOID
)
4384 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4385 MmLockSectionSegment(&SectionSegments
[i
]);
4386 Status
= MmMapViewOfSegment(Process
,
4389 &SectionSegments
[i
],
4391 SectionSegments
[i
].Length
,
4392 SectionSegments
[i
].Protection
,
4395 MmUnlockSectionSegment(&SectionSegments
[i
]);
4396 if (!NT_SUCCESS(Status
))
4398 MmUnlockAddressSpace(AddressSpace
);
4404 *BaseAddress
= (PVOID
)ImageBase
;
4408 if (ViewSize
== NULL
)
4410 /* Following this pointer would lead to us to the dark side */
4411 /* What to do? Bugcheck? Return status? Do the mambo? */
4412 KEBUGCHECK(MEMORY_MANAGEMENT
);
4415 if (SectionOffset
== NULL
)
4421 ViewOffset
= SectionOffset
->u
.LowPart
;
4424 if ((ViewOffset
% PAGE_SIZE
) != 0)
4426 MmUnlockAddressSpace(AddressSpace
);
4427 return(STATUS_MAPPED_ALIGNMENT
);
4430 if ((*ViewSize
) == 0)
4432 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4434 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4436 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4439 MmLockSectionSegment(Section
->Segment
);
4440 Status
= MmMapViewOfSegment(Process
,
4448 (AllocationType
& MEM_TOP_DOWN
));
4449 MmUnlockSectionSegment(Section
->Segment
);
4450 if (!NT_SUCCESS(Status
))
4452 MmUnlockAddressSpace(AddressSpace
);
4457 MmUnlockAddressSpace(AddressSpace
);
4459 return(STATUS_SUCCESS
);
4466 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4467 IN PLARGE_INTEGER NewFileSize
)
4478 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
4488 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4489 IN MMFLUSH_TYPE FlushType
)
4493 case MmFlushForDelete
:
4494 if (SectionObjectPointer
->ImageSectionObject
||
4495 SectionObjectPointer
->DataSectionObject
)
4499 CcRosSetRemoveOnClose(SectionObjectPointer
);
4501 case MmFlushForWrite
:
4511 MmForceSectionClosed (
4512 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4513 IN BOOLEAN DelayClose
)
4524 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4525 OUT PVOID
* MappedBase
,
4526 IN OUT PULONG ViewSize
)
4528 PSECTION_OBJECT Section
;
4529 PMADDRESS_SPACE AddressSpace
;
4532 DPRINT("MmMapViewInSystemSpace() called\n");
4534 Section
= (PSECTION_OBJECT
)SectionObject
;
4535 AddressSpace
= MmGetKernelAddressSpace();
4537 MmLockAddressSpace(AddressSpace
);
4540 if ((*ViewSize
) == 0)
4542 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4544 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4546 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4549 MmLockSectionSegment(Section
->Segment
);
4552 Status
= MmMapViewOfSegment(NULL
,
4562 MmUnlockSectionSegment(Section
->Segment
);
4563 MmUnlockAddressSpace(AddressSpace
);
4573 MmMapViewInSessionSpace (
4575 OUT PVOID
*MappedBase
,
4576 IN OUT PSIZE_T ViewSize
4580 return STATUS_NOT_IMPLEMENTED
;
4588 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4590 PMADDRESS_SPACE AddressSpace
;
4593 DPRINT("MmUnmapViewInSystemSpace() called\n");
4595 AddressSpace
= MmGetKernelAddressSpace();
4597 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4607 MmUnmapViewInSessionSpace (
4612 return STATUS_NOT_IMPLEMENTED
;
4619 MmSetBankedSection (DWORD Unknown0
,
4627 return (STATUS_NOT_IMPLEMENTED
);
4631 /**********************************************************************
4636 * Creates a section object.
4639 * SectionObject (OUT)
4640 * Caller supplied storage for the resulting pointer
4641 * to a SECTION_OBJECT instance;
4644 * Specifies the desired access to the section can be a
4646 * STANDARD_RIGHTS_REQUIRED |
4648 * SECTION_MAP_WRITE |
4649 * SECTION_MAP_READ |
4650 * SECTION_MAP_EXECUTE
4652 * ObjectAttributes [OPTIONAL]
4653 * Initialized attributes for the object can be used
4654 * to create a named section;
4657 * Maximizes the size of the memory section. Must be
4658 * non-NULL for a page-file backed section.
4659 * If value specified for a mapped file and the file is
4660 * not large enough, file will be extended.
4662 * SectionPageProtection
4663 * Can be a combination of:
4669 * AllocationAttributes
4670 * Can be a combination of:
4675 * Handle to a file to create a section mapped to a file
4676 * instead of a memory backed section;
4687 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4688 IN ACCESS_MASK DesiredAccess
,
4689 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4690 IN PLARGE_INTEGER MaximumSize
,
4691 IN ULONG SectionPageProtection
,
4692 IN ULONG AllocationAttributes
,
4693 IN HANDLE FileHandle OPTIONAL
,
4694 IN PFILE_OBJECT File OPTIONAL
)
4696 if (AllocationAttributes
& SEC_IMAGE
)
4698 return(MmCreateImageSection(SectionObject
,
4702 SectionPageProtection
,
4703 AllocationAttributes
,
4707 if (FileHandle
!= NULL
)
4709 return(MmCreateDataFileSection(SectionObject
,
4713 SectionPageProtection
,
4714 AllocationAttributes
,
4718 return(MmCreatePageFileSection(SectionObject
,
4722 SectionPageProtection
,
4723 AllocationAttributes
));