3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/section.c
6 * PURPOSE: Implements section objects
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
17 #include <reactos/exeformat.h>
19 /* TYPES *********************************************************************/
23 PSECTION_OBJECT Section
;
24 PMM_SECTION_SEGMENT Segment
;
29 MM_SECTION_PAGEOUT_CONTEXT
;
31 /* GLOBALS *******************************************************************/
33 POBJECT_TYPE EXPORTED MmSectionObjectType
= NULL
;
35 static GENERIC_MAPPING MmpSectionMapping
= {
36 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
37 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
38 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
41 #define TAG_MM_SECTION_SEGMENT TAG('M', 'M', 'S', 'S')
42 #define TAG_SECTION_PAGE_TABLE TAG('M', 'S', 'P', 'T')
44 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
45 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
46 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
47 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
48 #define MAX_SHARE_COUNT 0x7FF
49 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
50 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
51 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
53 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
55 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
56 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
59 /* FUNCTIONS *****************************************************************/
61 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
64 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
65 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
66 * RETURNS: Status of the wait.
69 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
71 LARGE_INTEGER Timeout
;
72 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
74 Timeout
.QuadPart
= -100000000LL; // 10 sec
77 Timeout
.QuadPart
= -100000000; // 10 sec
80 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
85 * FUNCTION: Sets the page op completion event and releases the page op.
86 * ARGUMENTS: PMM_PAGEOP.
87 * RETURNS: In shorter time than it takes you to even read this
88 * description, so don't even think about geting a mug of coffee.
91 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
93 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
94 MmReleasePageOp(PageOp
);
99 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
100 * ARGUMENTS: PFILE_OBJECT to wait for.
101 * RETURNS: Status of the wait.
104 MmspWaitForFileLock(PFILE_OBJECT File
)
106 return KeWaitForSingleObject(&File
->Lock
, 0, KernelMode
, FALSE
, NULL
);
111 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
114 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
116 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
118 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
120 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
127 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
129 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
131 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
132 PMM_SECTION_SEGMENT SectionSegments
;
136 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
137 NrSegments
= ImageSectionObject
->NrSegments
;
138 SectionSegments
= ImageSectionObject
->Segments
;
139 for (i
= 0; i
< NrSegments
; i
++)
141 if (SectionSegments
[i
].ReferenceCount
!= 0)
143 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
144 SectionSegments
[i
].ReferenceCount
);
147 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
149 ExFreePool(ImageSectionObject
->Segments
);
150 ExFreePool(ImageSectionObject
);
151 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
153 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
155 PMM_SECTION_SEGMENT Segment
;
157 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
160 if (Segment
->ReferenceCount
!= 0)
162 DPRINT1("Data segment still referenced\n");
165 MmFreePageTablesSectionSegment(Segment
);
167 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
172 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
174 ExAcquireFastMutex(&Segment
->Lock
);
178 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
180 ExReleaseFastMutex(&Segment
->Lock
);
184 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
188 PSECTION_PAGE_TABLE Table
;
189 ULONG DirectoryOffset
;
192 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
194 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
198 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
199 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
203 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
204 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
205 TAG_SECTION_PAGE_TABLE
);
210 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
211 DPRINT("Table %x\n", Table
);
214 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
215 Table
->Entry
[TableOffset
] = Entry
;
220 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
223 PSECTION_PAGE_TABLE Table
;
225 ULONG DirectoryOffset
;
228 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
230 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
232 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
236 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
237 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
238 DPRINT("Table %x\n", Table
);
244 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
245 Entry
= Table
->Entry
[TableOffset
];
250 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
255 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
258 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
261 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
263 DPRINT1("Maximum share count reached\n");
266 if (IS_SWAP_FROM_SSE(Entry
))
270 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
271 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
275 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section
,
276 PMM_SECTION_SEGMENT Segment
,
282 BOOLEAN IsDirectMapped
= FALSE
;
284 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
287 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
290 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
292 DPRINT1("Zero share count for unshare\n");
295 if (IS_SWAP_FROM_SSE(Entry
))
299 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
301 * If we reducing the share count of this entry to zero then set the entry
302 * to zero and tell the cache the page is no longer mapped.
304 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
306 PFILE_OBJECT FileObject
;
308 SWAPENTRY SavedSwapEntry
;
310 BOOLEAN IsImageSection
;
313 FileOffset
= Offset
+ Segment
->FileOffset
;
315 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
317 Page
= PFN_FROM_SSE(Entry
);
318 FileObject
= Section
->FileObject
;
319 if (FileObject
!= NULL
&&
320 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
323 if ((FileOffset
% PAGE_SIZE
) == 0 &&
324 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
327 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
328 IsDirectMapped
= TRUE
;
329 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
330 if (!NT_SUCCESS(Status
))
332 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
338 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
339 if (SavedSwapEntry
== 0)
342 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
343 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
347 * Try to page out this page and set the swap entry
348 * within the section segment. There exist no rmap entry
349 * for this page. The pager thread can't page out a
350 * page without a rmap entry.
352 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
356 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
359 MmReleasePageMemoryConsumer(MC_USER
, Page
);
365 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
366 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
374 * We hold all locks. Nobody can do something with the current
375 * process and the current segment (also not within an other process).
378 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
379 if (!NT_SUCCESS(Status
))
381 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
385 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
386 MmSetSavedSwapEntryPage(Page
, 0);
388 MmReleasePageMemoryConsumer(MC_USER
, Page
);
392 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
399 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
401 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
404 BOOL
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
407 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
410 PCACHE_SEGMENT CacheSeg
;
411 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
412 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
415 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
423 MiReadPage(PMEMORY_AREA MemoryArea
,
427 * FUNCTION: Read a page for a section backed memory area.
429 * MemoryArea - Memory area to read the page for.
430 * Offset - Offset of the page to read.
431 * Page - Variable that receives a page contains the read data.
438 PCACHE_SEGMENT CacheSeg
;
439 PFILE_OBJECT FileObject
;
443 BOOLEAN IsImageSection
;
446 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
447 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
448 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
449 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
450 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
454 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
457 * If the file system is letting us go directly to the cache and the
458 * memory area was mapped at an offset in the file which is page aligned
459 * then get the related cache segment.
461 if ((FileOffset
% PAGE_SIZE
) == 0 &&
462 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
463 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
467 * Get the related cache segment; we use a lower level interface than
468 * filesystems do because it is safe for us to use an offset with a
469 * alignment less than the file system block size.
471 Status
= CcRosGetCacheSegment(Bcb
,
477 if (!NT_SUCCESS(Status
))
484 * If the cache segment isn't up to date then call the file
485 * system to read in the data.
487 Status
= ReadCacheSegment(CacheSeg
);
488 if (!NT_SUCCESS(Status
))
490 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
495 * Retrieve the page from the cache segment that we actually want.
497 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
498 FileOffset
- BaseOffset
).QuadPart
>> PAGE_SHIFT
;
500 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
505 ULONG CacheSegOffset
;
507 * Allocate a page, this is rather complicated by the possibility
508 * we might have to move other things out of memory
510 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
511 if (!NT_SUCCESS(Status
))
515 Status
= CcRosGetCacheSegment(Bcb
,
521 if (!NT_SUCCESS(Status
))
528 * If the cache segment isn't up to date then call the file
529 * system to read in the data.
531 Status
= ReadCacheSegment(CacheSeg
);
532 if (!NT_SUCCESS(Status
))
534 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
538 PageAddr
= MmCreateHyperspaceMapping(*Page
);
539 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
540 Length
= RawLength
- SegOffset
;
541 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
543 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
545 else if (CacheSegOffset
>= PAGE_SIZE
)
547 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
551 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
552 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
553 Status
= CcRosGetCacheSegment(Bcb
,
554 FileOffset
+ CacheSegOffset
,
559 if (!NT_SUCCESS(Status
))
561 MmDeleteHyperspaceMapping(PageAddr
);
567 * If the cache segment isn't up to date then call the file
568 * system to read in the data.
570 Status
= ReadCacheSegment(CacheSeg
);
571 if (!NT_SUCCESS(Status
))
573 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
574 MmDeleteHyperspaceMapping(PageAddr
);
578 if (Length
< PAGE_SIZE
)
580 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
584 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
587 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
588 MmDeleteHyperspaceMapping(PageAddr
);
590 return(STATUS_SUCCESS
);
594 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
595 MEMORY_AREA
* MemoryArea
,
603 PSECTION_OBJECT Section
;
604 PMM_SECTION_SEGMENT Segment
;
613 * There is a window between taking the page fault and locking the
614 * address space when another thread could load the page so we check
617 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
621 MmLockPage(MmGetPfnForProcess(AddressSpace
->Process
, Address
));
623 return(STATUS_SUCCESS
);
626 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
627 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
629 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
630 Section
= MemoryArea
->Data
.SectionData
.Section
;
631 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
632 &MemoryArea
->Data
.SectionData
.RegionListHead
,
637 MmLockSectionSegment(Segment
);
640 * Check if this page needs to be mapped COW
642 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
643 (Region
->Protect
== PAGE_READWRITE
||
644 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
646 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
650 Attributes
= Region
->Protect
;
654 * Get or create a page operation descriptor
656 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
659 DPRINT1("MmGetPageOp failed\n");
664 * Check if someone else is already handling this fault, if so wait
667 if (PageOp
->Thread
!= PsGetCurrentThread())
669 MmUnlockSectionSegment(Segment
);
670 MmUnlockAddressSpace(AddressSpace
);
671 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
673 * Check for various strange conditions
675 if (Status
!= STATUS_SUCCESS
)
677 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
680 if (PageOp
->Status
== STATUS_PENDING
)
682 DPRINT1("Woke for page op before completion\n");
685 MmLockAddressSpace(AddressSpace
);
687 * If this wasn't a pagein then restart the operation
689 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
691 MmspCompleteAndReleasePageOp(PageOp
);
692 DPRINT("Address 0x%.8X\n", Address
);
693 return(STATUS_MM_RESTART_OPERATION
);
697 * If the thread handling this fault has failed then we don't retry
699 if (!NT_SUCCESS(PageOp
->Status
))
701 Status
= PageOp
->Status
;
702 MmspCompleteAndReleasePageOp(PageOp
);
703 DPRINT("Address 0x%.8X\n", Address
);
706 MmLockSectionSegment(Segment
);
708 * If the completed fault was for another address space then set the
711 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
713 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
714 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
716 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
719 * The page was a private page in another or in our address space
721 MmUnlockSectionSegment(Segment
);
722 MmspCompleteAndReleasePageOp(PageOp
);
723 return(STATUS_MM_RESTART_OPERATION
);
726 Page
= PFN_FROM_SSE(Entry
);
728 MmSharePageEntrySectionSegment(Segment
, Offset
);
730 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
731 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
733 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
738 if (!NT_SUCCESS(Status
))
740 DbgPrint("Unable to create virtual mapping\n");
743 MmInsertRmap(Page
, MemoryArea
->Process
, (PVOID
)PAddress
);
749 MmUnlockSectionSegment(Segment
);
750 PageOp
->Status
= STATUS_SUCCESS
;
751 MmspCompleteAndReleasePageOp(PageOp
);
752 DPRINT("Address 0x%.8X\n", Address
);
753 return(STATUS_SUCCESS
);
756 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
760 * Must be private page we have swapped out.
767 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
769 DPRINT1("Found a swaped out private page in a pagefile section.\n");
773 MmUnlockSectionSegment(Segment
);
774 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
776 MmUnlockAddressSpace(AddressSpace
);
777 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
778 if (!NT_SUCCESS(Status
))
783 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
784 if (!NT_SUCCESS(Status
))
786 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
789 MmLockAddressSpace(AddressSpace
);
790 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
795 if (!NT_SUCCESS(Status
))
797 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
803 * Store the swap entry for later use.
805 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
808 * Add the page to the process's working set
810 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
813 * Finish the operation
819 PageOp
->Status
= STATUS_SUCCESS
;
820 MmspCompleteAndReleasePageOp(PageOp
);
821 DPRINT("Address 0x%.8X\n", Address
);
822 return(STATUS_SUCCESS
);
826 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
828 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
830 MmUnlockSectionSegment(Segment
);
832 * Just map the desired physical page
834 Page
= (Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
) >> PAGE_SHIFT
;
835 Status
= MmCreateVirtualMappingUnsafe(AddressSpace
->Process
,
840 if (!NT_SUCCESS(Status
))
842 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
847 * Don't add an rmap entry since the page mapped could be for
852 MmLockPageUnsafe(Page
);
856 * Cleanup and release locks
858 PageOp
->Status
= STATUS_SUCCESS
;
859 MmspCompleteAndReleasePageOp(PageOp
);
860 DPRINT("Address 0x%.8X\n", Address
);
861 return(STATUS_SUCCESS
);
865 * Map anonymous memory for BSS sections
867 if (Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
)
869 MmUnlockSectionSegment(Segment
);
870 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
871 if (!NT_SUCCESS(Status
))
873 MmUnlockAddressSpace(AddressSpace
);
874 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
875 MmLockAddressSpace(AddressSpace
);
877 if (!NT_SUCCESS(Status
))
881 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
886 if (!NT_SUCCESS(Status
))
888 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
892 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
899 * Cleanup and release locks
901 PageOp
->Status
= STATUS_SUCCESS
;
902 MmspCompleteAndReleasePageOp(PageOp
);
903 DPRINT("Address 0x%.8X\n", Address
);
904 return(STATUS_SUCCESS
);
908 * Get the entry corresponding to the offset within the section
910 Offset
+= MemoryArea
->Data
.SectionData
.ViewOffset
;
911 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
916 * If the entry is zero (and it can't change because we have
917 * locked the segment) then we need to load the page.
921 * Release all our locks and read in the page from disk
923 MmUnlockSectionSegment(Segment
);
924 MmUnlockAddressSpace(AddressSpace
);
926 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
927 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
929 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
930 if (!NT_SUCCESS(Status
))
932 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
937 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
938 if (!NT_SUCCESS(Status
))
940 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
943 if (!NT_SUCCESS(Status
))
946 * FIXME: What do we know in this case?
949 * Cleanup and release locks
951 MmLockAddressSpace(AddressSpace
);
952 PageOp
->Status
= Status
;
953 MmspCompleteAndReleasePageOp(PageOp
);
954 DPRINT("Address 0x%.8X\n", Address
);
958 * Relock the address space and segment
960 MmLockAddressSpace(AddressSpace
);
961 MmLockSectionSegment(Segment
);
964 * Check the entry. No one should change the status of a page
965 * that has a pending page-in.
967 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
970 DbgPrint("Someone changed ppte entry while we slept\n");
975 * Mark the offset within the section as having valid, in-memory
978 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
979 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
980 MmUnlockSectionSegment(Segment
);
982 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
987 if (!NT_SUCCESS(Status
))
989 DbgPrint("Unable to create virtual mapping\n");
992 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
998 PageOp
->Status
= STATUS_SUCCESS
;
999 MmspCompleteAndReleasePageOp(PageOp
);
1000 DPRINT("Address 0x%.8X\n", Address
);
1001 return(STATUS_SUCCESS
);
1003 else if (IS_SWAP_FROM_SSE(Entry
))
1005 SWAPENTRY SwapEntry
;
1007 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1010 * Release all our locks and read in the page from disk
1012 MmUnlockSectionSegment(Segment
);
1014 MmUnlockAddressSpace(AddressSpace
);
1016 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1017 if (!NT_SUCCESS(Status
))
1022 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1023 if (!NT_SUCCESS(Status
))
1029 * Relock the address space and segment
1031 MmLockAddressSpace(AddressSpace
);
1032 MmLockSectionSegment(Segment
);
1035 * Check the entry. No one should change the status of a page
1036 * that has a pending page-in.
1038 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1039 if (Entry
!= Entry1
)
1041 DbgPrint("Someone changed ppte entry while we slept\n");
1046 * Mark the offset within the section as having valid, in-memory
1049 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1050 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1051 MmUnlockSectionSegment(Segment
);
1054 * Save the swap entry.
1056 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1057 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1062 if (!NT_SUCCESS(Status
))
1064 DbgPrint("Unable to create virtual mapping\n");
1067 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1072 PageOp
->Status
= STATUS_SUCCESS
;
1073 MmspCompleteAndReleasePageOp(PageOp
);
1074 DPRINT("Address 0x%.8X\n", Address
);
1075 return(STATUS_SUCCESS
);
1080 * If the section offset is already in-memory and valid then just
1081 * take another reference to the page
1084 Page
= PFN_FROM_SSE(Entry
);
1086 MmSharePageEntrySectionSegment(Segment
, Offset
);
1087 MmUnlockSectionSegment(Segment
);
1089 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1094 if (!NT_SUCCESS(Status
))
1096 DbgPrint("Unable to create virtual mapping\n");
1099 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1104 PageOp
->Status
= STATUS_SUCCESS
;
1105 MmspCompleteAndReleasePageOp(PageOp
);
1106 DPRINT("Address 0x%.8X\n", Address
);
1107 return(STATUS_SUCCESS
);
1112 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1113 MEMORY_AREA
* MemoryArea
,
1117 PMM_SECTION_SEGMENT Segment
;
1118 PSECTION_OBJECT Section
;
1129 * Check if the page has been paged out or has already been set readwrite
1131 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1132 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1134 DPRINT("Address 0x%.8X\n", Address
);
1135 return(STATUS_SUCCESS
);
1139 * Find the offset of the page
1141 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1142 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1144 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1145 Section
= MemoryArea
->Data
.SectionData
.Section
;
1146 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1147 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1152 MmLockSectionSegment(Segment
);
1154 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1155 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1157 MmUnlockSectionSegment(Segment
);
1160 * Check if we are doing COW
1162 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1163 (Region
->Protect
== PAGE_READWRITE
||
1164 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1166 DPRINT("Address 0x%.8X\n", Address
);
1167 return(STATUS_UNSUCCESSFUL
);
1170 if (IS_SWAP_FROM_SSE(Entry
) ||
1171 PFN_FROM_SSE(Entry
) != OldPage
)
1173 /* This is a private page. We must only change the page protection. */
1174 MmSetPageProtect(AddressSpace
->Process
, PAddress
, Region
->Protect
);
1175 return(STATUS_SUCCESS
);
1179 * Get or create a pageop
1181 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1182 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1185 DPRINT1("MmGetPageOp failed\n");
1190 * Wait for any other operations to complete
1192 if (PageOp
->Thread
!= PsGetCurrentThread())
1194 MmUnlockAddressSpace(AddressSpace
);
1195 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1197 * Check for various strange conditions
1199 if (Status
== STATUS_TIMEOUT
)
1201 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1204 if (PageOp
->Status
== STATUS_PENDING
)
1206 DPRINT1("Woke for page op before completion\n");
1210 * Restart the operation
1212 MmLockAddressSpace(AddressSpace
);
1213 MmspCompleteAndReleasePageOp(PageOp
);
1214 DPRINT("Address 0x%.8X\n", Address
);
1215 return(STATUS_MM_RESTART_OPERATION
);
1219 * Release locks now we have the pageop
1221 MmUnlockAddressSpace(AddressSpace
);
1226 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1227 if (!NT_SUCCESS(Status
))
1235 MiCopyFromUserPage(NewPage
, PAddress
);
1238 * Delete the old entry.
1240 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1243 * Set the PTE to point to the new page
1245 MmLockAddressSpace(AddressSpace
);
1246 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1251 if (!NT_SUCCESS(Status
))
1253 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1257 MmInsertRmap(NewPage
, AddressSpace
->Process
, PAddress
);
1258 if (!NT_SUCCESS(Status
))
1260 DbgPrint("Unable to create virtual mapping\n");
1265 MmLockPage(NewPage
);
1266 MmUnlockPage(OldPage
);
1270 * Unshare the old page.
1272 MmDeleteRmap(OldPage
, AddressSpace
->Process
, PAddress
);
1273 MmLockSectionSegment(Segment
);
1274 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1275 MmUnlockSectionSegment(Segment
);
1277 PageOp
->Status
= STATUS_SUCCESS
;
1278 MmspCompleteAndReleasePageOp(PageOp
);
1279 DPRINT("Address 0x%.8X\n", Address
);
1280 return(STATUS_SUCCESS
);
1284 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1286 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1290 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1291 MmDeleteVirtualMapping(Process
,
1298 PageOutContext
->WasDirty
= TRUE
;
1300 if (!PageOutContext
->Private
)
1302 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1303 PageOutContext
->Segment
,
1304 PageOutContext
->Offset
,
1305 PageOutContext
->WasDirty
,
1310 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1313 DPRINT("PhysicalAddress %I64x, Address %x\n", Page
, Address
);
1317 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1318 MEMORY_AREA
* MemoryArea
,
1323 MM_SECTION_PAGEOUT_CONTEXT Context
;
1324 SWAPENTRY SwapEntry
;
1328 PFILE_OBJECT FileObject
;
1330 BOOLEAN DirectMapped
;
1331 BOOLEAN IsImageSection
;
1333 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1336 * Get the segment and section.
1338 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1339 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1341 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1342 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1344 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1346 FileObject
= Context
.Section
->FileObject
;
1347 DirectMapped
= FALSE
;
1348 if (FileObject
!= NULL
&&
1349 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1351 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1354 * If the file system is letting us go directly to the cache and the
1355 * memory area was mapped at an offset in the file which is page aligned
1356 * then note this is a direct mapped page.
1358 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1359 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1361 DirectMapped
= TRUE
;
1367 * This should never happen since mappings of physical memory are never
1368 * placed in the rmap lists.
1370 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1372 DPRINT1("Trying to page out from physical memory section address 0x%X "
1373 "process %d\n", Address
,
1374 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1379 * Get the section segment entry and the physical address.
1381 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1382 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1384 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1385 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1388 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1389 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1392 * Prepare the context structure for the rmap delete call.
1394 Context
.WasDirty
= FALSE
;
1395 if (Context
.Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
||
1396 IS_SWAP_FROM_SSE(Entry
) ||
1397 PFN_FROM_SSE(Entry
) != Page
)
1399 Context
.Private
= TRUE
;
1403 Context
.Private
= FALSE
;
1407 * Take an additional reference to the page or the cache segment.
1409 if (DirectMapped
&& !Context
.Private
)
1411 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1413 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1419 MmReferencePage(Page
);
1422 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1425 * If this wasn't a private page then we should have reduced the entry to
1426 * zero by deleting all the rmaps.
1428 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1430 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1431 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1438 * If the page wasn't dirty then we can just free it as for a readonly page.
1439 * Since we unmapped all the mappings above we know it will not suddenly
1441 * If the page is from a pagefile section and has no swap entry,
1442 * we can't free the page at this point.
1444 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1445 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1447 if (Context
.Private
)
1449 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1450 Context
.WasDirty
? "dirty" : "clean", Address
);
1453 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1455 MmSetSavedSwapEntryPage(Page
, 0);
1456 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1457 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1458 PageOp
->Status
= STATUS_SUCCESS
;
1459 MmspCompleteAndReleasePageOp(PageOp
);
1460 return(STATUS_SUCCESS
);
1463 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1465 if (Context
.Private
)
1467 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1468 Context
.WasDirty
? "dirty" : "clean", Address
);
1471 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1473 MmSetSavedSwapEntryPage(Page
, 0);
1476 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1478 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1479 PageOp
->Status
= STATUS_SUCCESS
;
1480 MmspCompleteAndReleasePageOp(PageOp
);
1481 return(STATUS_SUCCESS
);
1484 else if (!Context
.Private
&& DirectMapped
)
1488 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1492 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1493 if (!NT_SUCCESS(Status
))
1495 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1498 PageOp
->Status
= STATUS_SUCCESS
;
1499 MmspCompleteAndReleasePageOp(PageOp
);
1500 return(STATUS_SUCCESS
);
1502 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1506 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1510 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1511 PageOp
->Status
= STATUS_SUCCESS
;
1512 MmspCompleteAndReleasePageOp(PageOp
);
1513 return(STATUS_SUCCESS
);
1515 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1517 MmSetSavedSwapEntryPage(Page
, 0);
1518 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1521 if (!NT_SUCCESS(Status
))
1525 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1526 PageOp
->Status
= STATUS_SUCCESS
;
1527 MmspCompleteAndReleasePageOp(PageOp
);
1528 return(STATUS_SUCCESS
);
1532 * If necessary, allocate an entry in the paging file for this page
1536 SwapEntry
= MmAllocSwapPage();
1539 MmShowOutOfSpaceMessagePagingFile();
1542 * For private pages restore the old mappings.
1544 if (Context
.Private
)
1546 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1548 MemoryArea
->Attributes
,
1551 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1553 MemoryArea
->Process
,
1559 * For non-private pages if the page wasn't direct mapped then
1560 * set it back into the section segment entry so we don't loose
1561 * our copy. Otherwise it will be handled by the cache manager.
1563 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1565 MemoryArea
->Attributes
,
1568 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1570 MemoryArea
->Process
,
1572 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1573 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1575 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1576 MmspCompleteAndReleasePageOp(PageOp
);
1577 return(STATUS_PAGEFILE_QUOTA
);
1582 * Write the page to the pagefile
1584 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1585 if (!NT_SUCCESS(Status
))
1587 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1590 * As above: undo our actions.
1591 * FIXME: Also free the swap page.
1593 if (Context
.Private
)
1595 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1597 MemoryArea
->Attributes
,
1600 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1602 MemoryArea
->Process
,
1607 Status
= MmCreateVirtualMapping(MemoryArea
->Process
,
1609 MemoryArea
->Attributes
,
1612 MmSetDirtyPage(MemoryArea
->Process
, Address
);
1614 MemoryArea
->Process
,
1616 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1617 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1619 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1620 MmspCompleteAndReleasePageOp(PageOp
);
1621 return(STATUS_UNSUCCESSFUL
);
1625 * Otherwise we have succeeded.
1627 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1628 MmSetSavedSwapEntryPage(Page
, 0);
1629 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1630 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1632 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1636 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1639 if (Context
.Private
)
1641 Status
= MmCreatePageFileMapping(MemoryArea
->Process
,
1644 if (!NT_SUCCESS(Status
))
1651 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1652 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1655 PageOp
->Status
= STATUS_SUCCESS
;
1656 MmspCompleteAndReleasePageOp(PageOp
);
1657 return(STATUS_SUCCESS
);
1661 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1662 PMEMORY_AREA MemoryArea
,
1667 PSECTION_OBJECT Section
;
1668 PMM_SECTION_SEGMENT Segment
;
1670 SWAPENTRY SwapEntry
;
1674 PFILE_OBJECT FileObject
;
1676 BOOLEAN DirectMapped
;
1677 BOOLEAN IsImageSection
;
1679 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1681 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1684 * Get the segment and section.
1686 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1687 Section
= MemoryArea
->Data
.SectionData
.Section
;
1688 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1690 FileObject
= Section
->FileObject
;
1691 DirectMapped
= FALSE
;
1692 if (FileObject
!= NULL
&&
1693 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1695 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1698 * If the file system is letting us go directly to the cache and the
1699 * memory area was mapped at an offset in the file which is page aligned
1700 * then note this is a direct mapped page.
1702 if ((Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
% PAGE_SIZE
) == 0 &&
1703 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1705 DirectMapped
= TRUE
;
1710 * This should never happen since mappings of physical memory are never
1711 * placed in the rmap lists.
1713 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1715 DPRINT1("Trying to write back page from physical memory mapped at %X "
1716 "process %d\n", Address
,
1717 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1722 * Get the section segment entry and the physical address.
1724 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1725 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1727 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1728 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1731 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1732 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1735 * Check for a private (COWed) page.
1737 if (Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
||
1738 IS_SWAP_FROM_SSE(Entry
) ||
1739 PFN_FROM_SSE(Entry
) != Page
)
1749 * Speculatively set all mappings of the page to clean.
1751 MmSetCleanAllRmaps(Page
);
1754 * If this page was direct mapped from the cache then the cache manager
1755 * will take care of writing it back to disk.
1757 if (DirectMapped
&& !Private
)
1759 ASSERT(SwapEntry
== 0);
1760 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
1761 PageOp
->Status
= STATUS_SUCCESS
;
1762 MmspCompleteAndReleasePageOp(PageOp
);
1763 return(STATUS_SUCCESS
);
1767 * If necessary, allocate an entry in the paging file for this page
1771 SwapEntry
= MmAllocSwapPage();
1774 MmSetDirtyAllRmaps(Page
);
1775 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1776 MmspCompleteAndReleasePageOp(PageOp
);
1777 return(STATUS_PAGEFILE_QUOTA
);
1779 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1783 * Write the page to the pagefile
1785 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1786 if (!NT_SUCCESS(Status
))
1788 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1790 MmSetDirtyAllRmaps(Page
);
1791 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1792 MmspCompleteAndReleasePageOp(PageOp
);
1793 return(STATUS_UNSUCCESSFUL
);
1797 * Otherwise we have succeeded.
1799 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1800 PageOp
->Status
= STATUS_SUCCESS
;
1801 MmspCompleteAndReleasePageOp(PageOp
);
1802 return(STATUS_SUCCESS
);
1806 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1814 PMEMORY_AREA MemoryArea
;
1815 PMM_SECTION_SEGMENT Segment
;
1819 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1820 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1822 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1823 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1828 if (OldProtect
!= NewProtect
)
1830 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1832 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1833 ULONG Protect
= NewProtect
;
1836 * If we doing COW for this segment then check if the page is
1839 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1845 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1846 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1847 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1849 Protect
= PAGE_READONLY
;
1850 if (Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
||
1851 IS_SWAP_FROM_SSE(Entry
) ||
1852 PFN_FROM_SSE(Entry
) != Page
)
1854 Protect
= NewProtect
;
1858 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1860 MmSetPageProtect(AddressSpace
->Process
, Address
,
1868 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1869 PMEMORY_AREA MemoryArea
,
1877 ULONG_PTR MaxLength
;
1879 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
1880 if (Length
> MaxLength
)
1883 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1884 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1886 *OldProtect
= Region
->Protect
;
1887 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
1888 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1889 BaseAddress
, Length
, Region
->Type
, Protect
,
1890 MmAlterViewAttributes
);
1896 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
1898 PMEMORY_BASIC_INFORMATION Info
,
1899 PULONG ResultLength
)
1902 PVOID RegionBaseAddress
;
1903 PSECTION_OBJECT Section
;
1904 PLIST_ENTRY CurrentEntry
;
1905 PMEMORY_AREA CurrentMArea
;
1908 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
1909 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1910 Address
, &RegionBaseAddress
);
1913 return STATUS_UNSUCCESSFUL
;
1915 Section
= MemoryArea
->Data
.SectionData
.Section
;
1916 if (Section
->AllocationAttributes
& SEC_IMAGE
)
1918 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
1919 CurrentEntry
= Section
->ViewListHead
.Flink
;
1920 Info
->AllocationBase
= NULL
;
1921 while (CurrentEntry
!= &Section
->ViewListHead
)
1923 CurrentMArea
= CONTAINING_RECORD(CurrentEntry
, MEMORY_AREA
, Data
.SectionData
.ViewListEntry
);
1924 CurrentEntry
= CurrentEntry
->Flink
;
1925 if (Info
->AllocationBase
== NULL
)
1927 Info
->AllocationBase
= CurrentMArea
->StartingAddress
;
1929 else if (CurrentMArea
->StartingAddress
< Info
->AllocationBase
)
1931 Info
->AllocationBase
= CurrentMArea
->StartingAddress
;
1934 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
1935 Info
->BaseAddress
= RegionBaseAddress
;
1936 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1937 Info
->Type
= MEM_IMAGE
;
1941 Info
->BaseAddress
= RegionBaseAddress
;
1942 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
1943 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1944 Info
->Type
= MEM_MAPPED
;
1946 Info
->RegionSize
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
-
1947 (ULONG_PTR
)MemoryArea
->StartingAddress
);
1948 Info
->State
= MEM_COMMIT
;
1949 Info
->Protect
= Region
->Protect
;
1951 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
1952 return(STATUS_SUCCESS
);
1956 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
1961 ULONG SavedSwapEntry
;
1966 Length
= PAGE_ROUND_UP(Segment
->Length
);
1967 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
1969 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1972 if (IS_SWAP_FROM_SSE(Entry
))
1974 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
1978 Page
= PFN_FROM_SSE(Entry
);
1979 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
1980 if (SavedSwapEntry
!= 0)
1982 MmSetSavedSwapEntryPage(Page
, 0);
1983 MmFreeSwapPage(SavedSwapEntry
);
1985 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1987 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
1993 MmpDeleteSection(PVOID ObjectBody
)
1995 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
1997 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
1998 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2003 PMM_SECTION_SEGMENT SectionSegments
;
2006 * NOTE: Section->ImageSection can be NULL for short time
2007 * during the section creating. If we fail for some reason
2008 * until the image section is properly initialized we shouldn't
2009 * process further here.
2011 if (Section
->ImageSection
== NULL
)
2014 SectionSegments
= Section
->ImageSection
->Segments
;
2015 NrSegments
= Section
->ImageSection
->NrSegments
;
2017 for (i
= 0; i
< NrSegments
; i
++)
2019 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2021 MmLockSectionSegment(&SectionSegments
[i
]);
2023 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2024 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2028 MmpFreePageFileSegment(&SectionSegments
[i
]);
2030 MmUnlockSectionSegment(&SectionSegments
[i
]);
2037 * NOTE: Section->Segment can be NULL for short time
2038 * during the section creating.
2040 if (Section
->Segment
== NULL
)
2043 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2045 MmpFreePageFileSegment(Section
->Segment
);
2046 MmFreePageTablesSectionSegment(Section
->Segment
);
2047 ExFreePool(Section
->Segment
);
2048 Section
->Segment
= NULL
;
2052 InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2055 if (Section
->FileObject
!= NULL
)
2057 CcRosDereferenceCache(Section
->FileObject
);
2058 ObDereferenceObject(Section
->FileObject
);
2059 Section
->FileObject
= NULL
;
2064 MmpCloseSection(PVOID ObjectBody
,
2067 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2068 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2072 MmpCreateSection(PVOID ObjectBody
,
2074 PWSTR RemainingPath
,
2075 POBJECT_ATTRIBUTES ObjectAttributes
)
2077 DPRINT("MmpCreateSection(ObjectBody %x, Parent %x, RemainingPath %S)\n",
2078 ObjectBody
, Parent
, RemainingPath
);
2080 if (RemainingPath
== NULL
)
2082 return(STATUS_SUCCESS
);
2085 if (wcschr(RemainingPath
+1, L
'\\') != NULL
)
2087 return(STATUS_UNSUCCESSFUL
);
2089 return(STATUS_SUCCESS
);
2092 NTSTATUS INIT_FUNCTION
2093 MmCreatePhysicalMemorySection(VOID
)
2095 PSECTION_OBJECT PhysSection
;
2097 OBJECT_ATTRIBUTES Obj
;
2098 UNICODE_STRING Name
= ROS_STRING_INITIALIZER(L
"\\Device\\PhysicalMemory");
2099 LARGE_INTEGER SectionSize
;
2102 * Create the section mapping physical memory
2104 SectionSize
.QuadPart
= 0xFFFFFFFF;
2105 InitializeObjectAttributes(&Obj
,
2110 Status
= MmCreateSection(&PhysSection
,
2114 PAGE_EXECUTE_READWRITE
,
2118 if (!NT_SUCCESS(Status
))
2120 DbgPrint("Failed to create PhysicalMemory section\n");
2123 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2125 return(STATUS_SUCCESS
);
2128 NTSTATUS INIT_FUNCTION
2129 MmInitSectionImplementation(VOID
)
2131 MmSectionObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
2133 RtlInitUnicodeString(&MmSectionObjectType
->TypeName
, L
"Section");
2135 MmSectionObjectType
->Tag
= TAG('S', 'E', 'C', 'T');
2136 MmSectionObjectType
->TotalObjects
= 0;
2137 MmSectionObjectType
->TotalHandles
= 0;
2138 MmSectionObjectType
->PeakObjects
= 0;
2139 MmSectionObjectType
->PeakHandles
= 0;
2140 MmSectionObjectType
->PagedPoolCharge
= 0;
2141 MmSectionObjectType
->NonpagedPoolCharge
= sizeof(SECTION_OBJECT
);
2142 MmSectionObjectType
->Mapping
= &MmpSectionMapping
;
2143 MmSectionObjectType
->Dump
= NULL
;
2144 MmSectionObjectType
->Open
= NULL
;
2145 MmSectionObjectType
->Close
= MmpCloseSection
;
2146 MmSectionObjectType
->Delete
= MmpDeleteSection
;
2147 MmSectionObjectType
->Parse
= NULL
;
2148 MmSectionObjectType
->Security
= NULL
;
2149 MmSectionObjectType
->QueryName
= NULL
;
2150 MmSectionObjectType
->OkayToClose
= NULL
;
2151 MmSectionObjectType
->Create
= MmpCreateSection
;
2152 MmSectionObjectType
->DuplicationNotify
= NULL
;
2155 * NOTE: Do not register the section object type here because
2156 * the object manager it not initialized yet!
2157 * The section object type will be created in ObInit().
2159 ObpCreateTypeObject(MmSectionObjectType
);
2161 return(STATUS_SUCCESS
);
2165 MmCreatePageFileSection(PSECTION_OBJECT
*SectionObject
,
2166 ACCESS_MASK DesiredAccess
,
2167 POBJECT_ATTRIBUTES ObjectAttributes
,
2168 PLARGE_INTEGER UMaximumSize
,
2169 ULONG SectionPageProtection
,
2170 ULONG AllocationAttributes
)
2172 * Create a section which is backed by the pagefile
2175 LARGE_INTEGER MaximumSize
;
2176 PSECTION_OBJECT Section
;
2177 PMM_SECTION_SEGMENT Segment
;
2180 if (UMaximumSize
== NULL
)
2182 return(STATUS_UNSUCCESSFUL
);
2184 MaximumSize
= *UMaximumSize
;
2187 * Create the section
2189 Status
= ObCreateObject(ExGetPreviousMode(),
2190 MmSectionObjectType
,
2192 ExGetPreviousMode(),
2194 sizeof(SECTION_OBJECT
),
2197 (PVOID
*)(PVOID
)&Section
);
2198 if (!NT_SUCCESS(Status
))
2206 Section
->SectionPageProtection
= SectionPageProtection
;
2207 Section
->AllocationAttributes
= AllocationAttributes
;
2208 Section
->Segment
= NULL
;
2209 InitializeListHead(&Section
->ViewListHead
);
2210 KeInitializeSpinLock(&Section
->ViewListLock
);
2211 Section
->FileObject
= NULL
;
2212 Section
->MaximumSize
= MaximumSize
;
2213 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2214 TAG_MM_SECTION_SEGMENT
);
2215 if (Segment
== NULL
)
2217 ObDereferenceObject(Section
);
2218 return(STATUS_NO_MEMORY
);
2220 Section
->Segment
= Segment
;
2221 Segment
->ReferenceCount
= 1;
2222 ExInitializeFastMutex(&Segment
->Lock
);
2223 Segment
->FileOffset
= 0;
2224 Segment
->Protection
= SectionPageProtection
;
2225 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2226 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2227 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2228 Segment
->WriteCopy
= FALSE
;
2229 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2230 Segment
->VirtualAddress
= 0;
2231 Segment
->Characteristics
= 0;
2232 *SectionObject
= Section
;
2233 return(STATUS_SUCCESS
);
2238 MmCreateDataFileSection(PSECTION_OBJECT
*SectionObject
,
2239 ACCESS_MASK DesiredAccess
,
2240 POBJECT_ATTRIBUTES ObjectAttributes
,
2241 PLARGE_INTEGER UMaximumSize
,
2242 ULONG SectionPageProtection
,
2243 ULONG AllocationAttributes
,
2246 * Create a section backed by a data file
2249 PSECTION_OBJECT Section
;
2251 LARGE_INTEGER MaximumSize
;
2252 PFILE_OBJECT FileObject
;
2253 PMM_SECTION_SEGMENT Segment
;
2255 IO_STATUS_BLOCK Iosb
;
2256 LARGE_INTEGER Offset
;
2258 FILE_STANDARD_INFORMATION FileInfo
;
2261 * Create the section
2263 Status
= ObCreateObject(ExGetPreviousMode(),
2264 MmSectionObjectType
,
2266 ExGetPreviousMode(),
2268 sizeof(SECTION_OBJECT
),
2271 (PVOID
*)(PVOID
)&Section
);
2272 if (!NT_SUCCESS(Status
))
2280 Section
->SectionPageProtection
= SectionPageProtection
;
2281 Section
->AllocationAttributes
= AllocationAttributes
;
2282 Section
->Segment
= NULL
;
2283 InitializeListHead(&Section
->ViewListHead
);
2284 KeInitializeSpinLock(&Section
->ViewListLock
);
2287 * Check file access required
2289 if (SectionPageProtection
& PAGE_READWRITE
||
2290 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2292 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2296 FileAccess
= FILE_READ_DATA
;
2300 * Reference the file handle
2302 Status
= ObReferenceObjectByHandle(FileHandle
,
2306 (PVOID
*)(PVOID
)&FileObject
,
2308 if (!NT_SUCCESS(Status
))
2310 ObDereferenceObject(Section
);
2315 * FIXME: This is propably not entirely correct. We can't look into
2316 * the standard FCB header because it might not be initialized yet
2317 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2318 * standard file information is filled on first request).
2320 Status
= NtQueryInformationFile(FileHandle
,
2323 sizeof(FILE_STANDARD_INFORMATION
),
2324 FileStandardInformation
);
2325 if (!NT_SUCCESS(Status
))
2327 ObDereferenceObject(Section
);
2328 ObDereferenceObject(FileObject
);
2333 * FIXME: Revise this once a locking order for file size changes is
2336 if (UMaximumSize
!= NULL
)
2338 MaximumSize
= *UMaximumSize
;
2342 MaximumSize
= FileInfo
.EndOfFile
;
2343 /* Mapping zero-sized files isn't allowed. */
2344 if (MaximumSize
.QuadPart
== 0)
2346 ObDereferenceObject(Section
);
2347 ObDereferenceObject(FileObject
);
2348 return STATUS_FILE_INVALID
;
2352 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2354 Status
= NtSetInformationFile(FileHandle
,
2357 sizeof(LARGE_INTEGER
),
2358 FileAllocationInformation
);
2359 if (!NT_SUCCESS(Status
))
2361 ObDereferenceObject(Section
);
2362 ObDereferenceObject(FileObject
);
2363 return(STATUS_SECTION_NOT_EXTENDED
);
2367 if (FileObject
->SectionObjectPointer
== NULL
||
2368 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2371 * Read a bit so caching is initiated for the file object.
2372 * This is only needed because MiReadPage currently cannot
2373 * handle non-cached streams.
2375 Offset
.QuadPart
= 0;
2376 Status
= ZwReadFile(FileHandle
,
2385 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2387 ObDereferenceObject(Section
);
2388 ObDereferenceObject(FileObject
);
2391 if (FileObject
->SectionObjectPointer
== NULL
||
2392 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2394 /* FIXME: handle this situation */
2395 ObDereferenceObject(Section
);
2396 ObDereferenceObject(FileObject
);
2397 return STATUS_INVALID_PARAMETER
;
2404 Status
= MmspWaitForFileLock(FileObject
);
2405 if (Status
!= STATUS_SUCCESS
)
2407 ObDereferenceObject(Section
);
2408 ObDereferenceObject(FileObject
);
2413 * If this file hasn't been mapped as a data file before then allocate a
2414 * section segment to describe the data file mapping
2416 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2418 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2419 TAG_MM_SECTION_SEGMENT
);
2420 if (Segment
== NULL
)
2422 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2423 ObDereferenceObject(Section
);
2424 ObDereferenceObject(FileObject
);
2425 return(STATUS_NO_MEMORY
);
2427 Section
->Segment
= Segment
;
2428 Segment
->ReferenceCount
= 1;
2429 ExInitializeFastMutex(&Segment
->Lock
);
2431 * Set the lock before assigning the segment to the file object
2433 ExAcquireFastMutex(&Segment
->Lock
);
2434 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2436 Segment
->FileOffset
= 0;
2437 Segment
->Protection
= SectionPageProtection
;
2438 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2439 Segment
->Characteristics
= 0;
2440 Segment
->WriteCopy
= FALSE
;
2441 if (AllocationAttributes
& SEC_RESERVE
)
2443 Segment
->Length
= Segment
->RawLength
= 0;
2447 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2448 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2450 Segment
->VirtualAddress
= 0;
2451 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2456 * If the file is already mapped as a data file then we may need
2460 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2462 Section
->Segment
= Segment
;
2463 InterlockedIncrementUL(&Segment
->ReferenceCount
);
2464 MmLockSectionSegment(Segment
);
2466 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2467 !(AllocationAttributes
& SEC_RESERVE
))
2469 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2470 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2473 MmUnlockSectionSegment(Segment
);
2474 Section
->FileObject
= FileObject
;
2475 Section
->MaximumSize
= MaximumSize
;
2476 CcRosReferenceCache(FileObject
);
2477 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2478 *SectionObject
= Section
;
2479 return(STATUS_SUCCESS
);
2483 TODO: not that great (declaring loaders statically, having to declare all of
2484 them, having to keep them extern, etc.), will fix in the future
2486 extern NTSTATUS NTAPI PeFmtCreateSection
2488 IN CONST VOID
* FileHeader
,
2489 IN SIZE_T FileHeaderSize
,
2491 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2493 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2494 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2497 extern NTSTATUS NTAPI ElfFmtCreateSection
2499 IN CONST VOID
* FileHeader
,
2500 IN SIZE_T FileHeaderSize
,
2502 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2504 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2505 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2508 /* TODO: this is a standard DDK/PSDK macro */
2509 #ifndef RTL_NUMBER_OF
2510 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2513 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2522 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2524 SIZE_T SizeOfSegments
;
2525 PMM_SECTION_SEGMENT Segments
;
2527 /* TODO: check for integer overflow */
2528 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2530 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2532 TAG_MM_SECTION_SEGMENT
);
2535 RtlZeroMemory(Segments
, SizeOfSegments
);
2543 ExeFmtpReadFile(IN PVOID File
,
2544 IN PLARGE_INTEGER Offset
,
2547 OUT PVOID
* AllocBase
,
2548 OUT PULONG ReadSize
)
2551 LARGE_INTEGER FileOffset
;
2553 ULONG OffsetAdjustment
;
2558 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2562 KEBUGCHECK(STATUS_INVALID_PARAMETER_4
);
2565 FileOffset
= *Offset
;
2567 /* Negative/special offset: it cannot be used in this context */
2568 if(FileOffset
.u
.HighPart
< 0)
2570 KEBUGCHECK(STATUS_INVALID_PARAMETER_5
);
2573 ASSERT(PAGE_SIZE
<= MAXULONG
);
2574 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2575 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2576 FileOffset
.u
.LowPart
= AdjustOffset
;
2578 BufferSize
= Length
+ OffsetAdjustment
;
2579 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2582 * It's ok to use paged pool, because this is a temporary buffer only used in
2583 * the loading of executables. The assumption is that MmCreateSection is
2584 * always called at low IRQLs and that these buffers don't survive a brief
2585 * initialization phase
2587 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2589 TAG('M', 'm', 'X', 'r'));
2594 Status
= MmspPageRead(File
,
2601 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2602 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2603 * to initialize internal state is even worse. Our cache manager is in need of
2607 IO_STATUS_BLOCK Iosb
;
2609 Status
= ZwReadFile(File
,
2619 if(NT_SUCCESS(Status
))
2621 UsedSize
= Iosb
.Information
;
2626 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2628 Status
= STATUS_IN_PAGE_ERROR
;
2629 ASSERT(!NT_SUCCESS(Status
));
2632 if(NT_SUCCESS(Status
))
2634 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2635 *AllocBase
= Buffer
;
2636 *ReadSize
= UsedSize
- OffsetAdjustment
;
2647 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2648 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2649 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2654 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2658 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2660 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2661 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2668 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2672 MmspAssertSegmentsSorted(ImageSectionObject
);
2674 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2676 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2680 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2681 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2682 ImageSectionObject
->Segments
[i
- 1].Length
));
2690 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2694 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2696 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2697 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2705 MmspCompareSegments(const void * x
,
2708 PMM_SECTION_SEGMENT Segment1
= (PMM_SECTION_SEGMENT
)x
;
2709 PMM_SECTION_SEGMENT Segment2
= (PMM_SECTION_SEGMENT
)y
;
2712 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2713 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2717 * Ensures an image section's segments are sorted in memory
2722 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2725 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2727 MmspAssertSegmentsSorted(ImageSectionObject
);
2731 qsort(ImageSectionObject
->Segments
,
2732 ImageSectionObject
->NrSegments
,
2733 sizeof(ImageSectionObject
->Segments
[0]),
2734 MmspCompareSegments
);
2740 * Ensures an image section's segments don't overlap in memory and don't have
2741 * gaps and don't have a null size. We let them map to overlapping file regions,
2742 * though - that's not necessarily an error
2747 MmspCheckSegmentBounds
2749 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2755 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2757 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2761 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2763 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2765 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2773 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2774 * page could be OK (Windows seems to be OK with them), and larger gaps
2775 * could lead to image sections spanning several discontiguous regions
2776 * (NtMapViewOfSection could then refuse to map them, and they could
2777 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2779 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2780 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2781 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2792 * Merges and pads an image section's segments until they all are page-aligned
2793 * and have a size that is a multiple of the page size
2798 MmspPageAlignSegments
2800 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2806 BOOLEAN Initialized
;
2808 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2810 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2814 Initialized
= FALSE
;
2817 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2819 PMM_SECTION_SEGMENT EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2822 * The first segment requires special handling
2826 ULONG_PTR VirtualAddress
;
2827 ULONG_PTR VirtualOffset
;
2829 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2831 /* Round down the virtual address to the nearest page */
2832 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2834 /* Round up the virtual size to the nearest page */
2835 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2836 EffectiveSegment
->VirtualAddress
;
2838 /* Adjust the raw address and size */
2839 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2841 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
2847 * Garbage in, garbage out: unaligned base addresses make the file
2848 * offset point in curious and odd places, but that's what we were
2851 EffectiveSegment
->FileOffset
-= VirtualOffset
;
2852 EffectiveSegment
->RawLength
+= VirtualOffset
;
2856 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
2857 ULONG_PTR EndOfEffectiveSegment
;
2859 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
2860 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
2863 * The current segment begins exactly where the current effective
2864 * segment ended, therefore beginning a new effective segment
2866 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
2869 ASSERT(LastSegment
<= i
);
2870 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
2872 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2875 * Copy the current segment. If necessary, the effective segment
2876 * will be expanded later
2878 *EffectiveSegment
= *Segment
;
2881 * Page-align the virtual size. We know for sure the virtual address
2884 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
2885 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
2888 * The current segment is still part of the current effective segment:
2889 * extend the effective segment to reflect this
2891 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
2893 static const ULONG FlagsToProtection
[16] =
2901 PAGE_EXECUTE_READWRITE
,
2902 PAGE_EXECUTE_READWRITE
,
2907 PAGE_EXECUTE_WRITECOPY
,
2908 PAGE_EXECUTE_WRITECOPY
,
2909 PAGE_EXECUTE_WRITECOPY
,
2910 PAGE_EXECUTE_WRITECOPY
2913 unsigned ProtectionFlags
;
2916 * Extend the file size
2919 /* Unaligned segments must be contiguous within the file */
2920 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
2921 EffectiveSegment
->RawLength
))
2926 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
2929 * Extend the virtual size
2931 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) > EndOfEffectiveSegment
);
2933 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
2934 EffectiveSegment
->VirtualAddress
;
2937 * Merge the protection
2939 EffectiveSegment
->Protection
|= Segment
->Protection
;
2941 /* Clean up redundance */
2942 ProtectionFlags
= 0;
2944 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
2945 ProtectionFlags
|= 1 << 0;
2947 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
2948 ProtectionFlags
|= 1 << 1;
2950 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
2951 ProtectionFlags
|= 1 << 2;
2953 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2954 ProtectionFlags
|= 1 << 3;
2956 ASSERT(ProtectionFlags
< 16);
2957 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
2959 /* If a segment was required to be shared and cannot, fail */
2960 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
2961 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2967 * We assume no holes between segments at this point
2980 ExeFmtpCreateImageSection(HANDLE FileHandle
,
2981 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2983 LARGE_INTEGER Offset
;
2985 PVOID FileHeaderBuffer
;
2986 ULONG FileHeaderSize
;
2988 ULONG OldNrSegments
;
2993 * Read the beginning of the file (2 pages). Should be enough to contain
2994 * all (or most) of the headers
2996 Offset
.QuadPart
= 0;
2998 /* FIXME: use FileObject instead of FileHandle */
2999 Status
= ExeFmtpReadFile (FileHandle
,
3006 if (!NT_SUCCESS(Status
))
3009 if (FileHeaderSize
== 0)
3011 ExFreePool(FileHeaderBuffer
);
3012 return STATUS_UNSUCCESSFUL
;
3016 * Look for a loader that can handle this executable
3018 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3020 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3023 /* FIXME: use FileObject instead of FileHandle */
3024 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3030 ExeFmtpAllocateSegments
);
3032 if (!NT_SUCCESS(Status
))
3034 if (ImageSectionObject
->Segments
)
3036 ExFreePool(ImageSectionObject
->Segments
);
3037 ImageSectionObject
->Segments
= NULL
;
3041 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3045 ExFreePool(FileHeaderBuffer
);
3048 * No loader handled the format
3050 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3052 Status
= STATUS_INVALID_IMAGE_FORMAT
;
3053 ASSERT(!NT_SUCCESS(Status
));
3056 if (!NT_SUCCESS(Status
))
3059 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3064 /* FIXME? are these values platform-dependent? */
3065 if(ImageSectionObject
->StackReserve
== 0)
3066 ImageSectionObject
->StackReserve
= 0x40000;
3068 if(ImageSectionObject
->StackCommit
== 0)
3069 ImageSectionObject
->StackCommit
= 0x1000;
3071 if(ImageSectionObject
->ImageBase
== 0)
3073 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3074 ImageSectionObject
->ImageBase
= 0x10000000;
3076 ImageSectionObject
->ImageBase
= 0x00400000;
3080 * And now the fun part: fixing the segments
3083 /* Sort them by virtual address */
3084 MmspSortSegments(ImageSectionObject
, Flags
);
3086 /* Ensure they don't overlap in memory */
3087 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3088 return STATUS_INVALID_IMAGE_FORMAT
;
3090 /* Ensure they are aligned */
3091 OldNrSegments
= ImageSectionObject
->NrSegments
;
3093 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3094 return STATUS_INVALID_IMAGE_FORMAT
;
3096 /* Trim them if the alignment phase merged some of them */
3097 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3099 PMM_SECTION_SEGMENT Segments
;
3100 SIZE_T SizeOfSegments
;
3102 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3104 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3106 TAG_MM_SECTION_SEGMENT
);
3108 if (Segments
== NULL
)
3109 return STATUS_INSUFFICIENT_RESOURCES
;
3111 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3112 ExFreePool(ImageSectionObject
->Segments
);
3113 ImageSectionObject
->Segments
= Segments
;
3116 /* And finish their initialization */
3117 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3119 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3120 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3122 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3123 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3126 ASSERT(NT_SUCCESS(Status
));
3131 MmCreateImageSection(PSECTION_OBJECT
*SectionObject
,
3132 ACCESS_MASK DesiredAccess
,
3133 POBJECT_ATTRIBUTES ObjectAttributes
,
3134 PLARGE_INTEGER UMaximumSize
,
3135 ULONG SectionPageProtection
,
3136 ULONG AllocationAttributes
,
3139 PSECTION_OBJECT Section
;
3141 PFILE_OBJECT FileObject
;
3142 PMM_SECTION_SEGMENT SectionSegments
;
3143 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3145 ULONG FileAccess
= 0;
3148 * Specifying a maximum size is meaningless for an image section
3150 if (UMaximumSize
!= NULL
)
3152 return(STATUS_INVALID_PARAMETER_4
);
3156 * Check file access required
3158 if (SectionPageProtection
& PAGE_READWRITE
||
3159 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3161 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3165 FileAccess
= FILE_READ_DATA
;
3169 * Reference the file handle
3171 Status
= ObReferenceObjectByHandle(FileHandle
,
3175 (PVOID
*)(PVOID
)&FileObject
,
3177 if (!NT_SUCCESS(Status
))
3183 * Create the section
3185 Status
= ObCreateObject (ExGetPreviousMode(),
3186 MmSectionObjectType
,
3188 ExGetPreviousMode(),
3190 sizeof(SECTION_OBJECT
),
3193 (PVOID
*)(PVOID
)&Section
);
3194 if (!NT_SUCCESS(Status
))
3196 ObDereferenceObject(FileObject
);
3203 Section
->SectionPageProtection
= SectionPageProtection
;
3204 Section
->AllocationAttributes
= AllocationAttributes
;
3205 InitializeListHead(&Section
->ViewListHead
);
3206 KeInitializeSpinLock(&Section
->ViewListLock
);
3209 * Initialized caching for this file object if previously caching
3210 * was initialized for the same on disk file
3212 Status
= CcTryToInitializeFileCache(FileObject
);
3214 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3216 NTSTATUS StatusExeFmt
;
3218 ImageSectionObject
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3219 if (ImageSectionObject
== NULL
)
3221 ObDereferenceObject(FileObject
);
3222 ObDereferenceObject(Section
);
3223 return(STATUS_NO_MEMORY
);
3226 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3228 if (!NT_SUCCESS(StatusExeFmt
))
3230 if(ImageSectionObject
->Segments
!= NULL
)
3231 ExFreePool(ImageSectionObject
->Segments
);
3233 ExFreePool(ImageSectionObject
);
3234 ObDereferenceObject(Section
);
3235 ObDereferenceObject(FileObject
);
3236 return(StatusExeFmt
);
3239 Section
->ImageSection
= ImageSectionObject
;
3240 ASSERT(ImageSectionObject
->Segments
);
3245 Status
= MmspWaitForFileLock(FileObject
);
3246 if (!NT_SUCCESS(Status
))
3248 ExFreePool(ImageSectionObject
->Segments
);
3249 ExFreePool(ImageSectionObject
);
3250 ObDereferenceObject(Section
);
3251 ObDereferenceObject(FileObject
);
3255 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3256 ImageSectionObject
, NULL
))
3259 * An other thread has initialized the some image in the background
3261 ExFreePool(ImageSectionObject
->Segments
);
3262 ExFreePool(ImageSectionObject
);
3263 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3264 Section
->ImageSection
= ImageSectionObject
;
3265 SectionSegments
= ImageSectionObject
->Segments
;
3267 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3269 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3273 Status
= StatusExeFmt
;
3280 Status
= MmspWaitForFileLock(FileObject
);
3281 if (Status
!= STATUS_SUCCESS
)
3283 ObDereferenceObject(Section
);
3284 ObDereferenceObject(FileObject
);
3288 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3289 Section
->ImageSection
= ImageSectionObject
;
3290 SectionSegments
= ImageSectionObject
->Segments
;
3293 * Otherwise just reference all the section segments
3295 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3297 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3300 Status
= STATUS_SUCCESS
;
3302 Section
->FileObject
= FileObject
;
3303 CcRosReferenceCache(FileObject
);
3304 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
3305 *SectionObject
= Section
;
3313 NtCreateSection (OUT PHANDLE SectionHandle
,
3314 IN ACCESS_MASK DesiredAccess
,
3315 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3316 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3317 IN ULONG SectionPageProtection OPTIONAL
,
3318 IN ULONG AllocationAttributes
,
3319 IN HANDLE FileHandle OPTIONAL
)
3321 LARGE_INTEGER SafeMaximumSize
;
3322 PSECTION_OBJECT SectionObject
;
3323 KPROCESSOR_MODE PreviousMode
;
3324 NTSTATUS Status
= STATUS_SUCCESS
;
3326 PreviousMode
= ExGetPreviousMode();
3328 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3332 ProbeForRead(MaximumSize
,
3333 sizeof(LARGE_INTEGER
),
3335 /* make a copy on the stack */
3336 SafeMaximumSize
= *MaximumSize
;
3337 MaximumSize
= &SafeMaximumSize
;
3341 Status
= _SEH_GetExceptionCode();
3345 if(!NT_SUCCESS(Status
))
3352 * Check the protection
3354 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
3355 SectionPageProtection
)
3357 return(STATUS_INVALID_PAGE_PROTECTION
);
3360 Status
= MmCreateSection(&SectionObject
,
3364 SectionPageProtection
,
3365 AllocationAttributes
,
3369 if (NT_SUCCESS(Status
))
3371 Status
= ObInsertObject ((PVOID
)SectionObject
,
3377 ObDereferenceObject(SectionObject
);
3384 /**********************************************************************
3402 NtOpenSection(PHANDLE SectionHandle
,
3403 ACCESS_MASK DesiredAccess
,
3404 POBJECT_ATTRIBUTES ObjectAttributes
)
3407 KPROCESSOR_MODE PreviousMode
;
3408 NTSTATUS Status
= STATUS_SUCCESS
;
3410 PreviousMode
= ExGetPreviousMode();
3412 if(PreviousMode
!= KernelMode
)
3416 ProbeForWrite(SectionHandle
,
3422 Status
= _SEH_GetExceptionCode();
3426 if(!NT_SUCCESS(Status
))
3432 Status
= ObOpenObjectByName(ObjectAttributes
,
3433 MmSectionObjectType
,
3440 if(NT_SUCCESS(Status
))
3444 *SectionHandle
= hSection
;
3448 Status
= _SEH_GetExceptionCode();
3457 MmMapViewOfSegment(PEPROCESS Process
,
3458 PMADDRESS_SPACE AddressSpace
,
3459 PSECTION_OBJECT Section
,
3460 PMM_SECTION_SEGMENT Segment
,
3470 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3472 BoundaryAddressMultiple
.QuadPart
= 0;
3474 Status
= MmCreateMemoryArea(Process
,
3476 MEMORY_AREA_SECTION_VIEW
,
3483 BoundaryAddressMultiple
);
3484 if (!NT_SUCCESS(Status
))
3486 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3487 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3491 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3492 InsertTailList(&Section
->ViewListHead
,
3493 &MArea
->Data
.SectionData
.ViewListEntry
);
3494 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3496 ObReferenceObjectByPointer((PVOID
)Section
,
3499 ExGetPreviousMode());
3500 MArea
->Data
.SectionData
.Segment
= Segment
;
3501 MArea
->Data
.SectionData
.Section
= Section
;
3502 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3503 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3504 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3505 ViewSize
, 0, Protect
);
3507 return(STATUS_SUCCESS
);
3511 /**********************************************************************
3513 * NtMapViewOfSection
3516 * Maps a view of a section into the virtual address space of a
3521 * Handle of the section.
3524 * Handle of the process.
3527 * Desired base address (or NULL) on entry;
3528 * Actual base address of the view on exit.
3531 * Number of high order address bits that must be zero.
3534 * Size in bytes of the initially committed section of
3538 * Offset in bytes from the beginning of the section
3539 * to the beginning of the view.
3542 * Desired length of map (or zero to map all) on entry
3543 * Actual length mapped on exit.
3545 * InheritDisposition
3546 * Specified how the view is to be shared with
3550 * Type of allocation for the pages.
3553 * Protection for the committed region of the view.
3561 NtMapViewOfSection(IN HANDLE SectionHandle
,
3562 IN HANDLE ProcessHandle
,
3563 IN OUT PVOID
* BaseAddress OPTIONAL
,
3564 IN ULONG ZeroBits OPTIONAL
,
3565 IN ULONG CommitSize
,
3566 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3567 IN OUT PULONG ViewSize
,
3568 IN SECTION_INHERIT InheritDisposition
,
3569 IN ULONG AllocationType OPTIONAL
,
3572 PVOID SafeBaseAddress
;
3573 LARGE_INTEGER SafeSectionOffset
;
3575 PSECTION_OBJECT Section
;
3577 KPROCESSOR_MODE PreviousMode
;
3578 PMADDRESS_SPACE AddressSpace
;
3579 NTSTATUS Status
= STATUS_SUCCESS
;
3581 PreviousMode
= ExGetPreviousMode();
3583 if(PreviousMode
!= KernelMode
)
3585 SafeBaseAddress
= NULL
;
3586 SafeSectionOffset
.QuadPart
= 0;
3591 if(BaseAddress
!= NULL
)
3593 ProbeForWrite(BaseAddress
,
3596 SafeBaseAddress
= *BaseAddress
;
3598 if(SectionOffset
!= NULL
)
3600 ProbeForWrite(SectionOffset
,
3601 sizeof(LARGE_INTEGER
),
3603 SafeSectionOffset
= *SectionOffset
;
3605 ProbeForWrite(ViewSize
,
3608 SafeViewSize
= *ViewSize
;
3612 Status
= _SEH_GetExceptionCode();
3616 if(!NT_SUCCESS(Status
))
3623 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3624 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3625 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3628 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3629 PROCESS_VM_OPERATION
,
3632 (PVOID
*)(PVOID
)&Process
,
3634 if (!NT_SUCCESS(Status
))
3639 AddressSpace
= &Process
->AddressSpace
;
3641 Status
= ObReferenceObjectByHandle(SectionHandle
,
3643 MmSectionObjectType
,
3645 (PVOID
*)(PVOID
)&Section
,
3647 if (!(NT_SUCCESS(Status
)))
3649 DPRINT("ObReference failed rc=%x\n",Status
);
3650 ObDereferenceObject(Process
);
3654 Status
= MmMapViewOfSection(Section
,
3656 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3659 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3660 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3665 ObDereferenceObject(Section
);
3666 ObDereferenceObject(Process
);
3668 if(NT_SUCCESS(Status
))
3670 /* copy parameters back to the caller */
3673 if(BaseAddress
!= NULL
)
3675 *BaseAddress
= SafeBaseAddress
;
3677 if(SectionOffset
!= NULL
)
3679 *SectionOffset
= SafeSectionOffset
;
3681 if(ViewSize
!= NULL
)
3683 *ViewSize
= SafeViewSize
;
3688 Status
= _SEH_GetExceptionCode();
3697 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3698 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3702 PFILE_OBJECT FileObject
;
3705 SWAPENTRY SavedSwapEntry
;
3708 PSECTION_OBJECT Section
;
3709 PMM_SECTION_SEGMENT Segment
;
3711 MArea
= (PMEMORY_AREA
)Context
;
3713 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3715 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MArea
->StartingAddress
) +
3716 MemoryArea
->Data
.SectionData
.ViewOffset
;
3718 Section
= MArea
->Data
.SectionData
.Section
;
3719 Segment
= MArea
->Data
.SectionData
.Segment
;
3721 PageOp
= MmCheckForPageOp(MArea
, NULL
, NULL
, Segment
, Offset
);
3725 MmUnlockSectionSegment(Segment
);
3726 MmUnlockAddressSpace(&MArea
->Process
->AddressSpace
);
3728 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3729 if (Status
!= STATUS_SUCCESS
)
3731 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3735 MmLockAddressSpace(&MArea
->Process
->AddressSpace
);
3736 MmLockSectionSegment(Segment
);
3737 MmspCompleteAndReleasePageOp(PageOp
);
3738 PageOp
= MmCheckForPageOp(MArea
, NULL
, NULL
, Segment
, Offset
);
3741 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3744 * For a dirty, datafile, non-private page mark it as dirty in the
3747 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3749 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3751 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3752 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3753 CcRosMarkDirtyCacheSegment(Bcb
, Offset
);
3754 ASSERT(SwapEntry
== 0);
3763 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3765 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3768 MmFreeSwapPage(SwapEntry
);
3772 if (IS_SWAP_FROM_SSE(Entry
) ||
3773 Page
!= PFN_FROM_SSE(Entry
))
3778 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3780 DPRINT1("Found a private page in a pagefile section.\n");
3784 * Just dereference private pages
3786 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3787 if (SavedSwapEntry
!= 0)
3789 MmFreeSwapPage(SavedSwapEntry
);
3790 MmSetSavedSwapEntryPage(Page
, 0);
3792 MmDeleteRmap(Page
, MArea
->Process
, Address
);
3793 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3797 MmDeleteRmap(Page
, MArea
->Process
, Address
);
3798 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3804 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3808 PMEMORY_AREA MemoryArea
;
3809 PSECTION_OBJECT Section
;
3810 PMM_SECTION_SEGMENT Segment
;
3812 PLIST_ENTRY CurrentEntry
;
3813 PMM_REGION CurrentRegion
;
3814 PLIST_ENTRY RegionListHead
;
3816 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3818 if (MemoryArea
== NULL
)
3820 return(STATUS_UNSUCCESSFUL
);
3823 MemoryArea
->DeleteInProgress
= TRUE
;
3824 Section
= MemoryArea
->Data
.SectionData
.Section
;
3825 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3827 MmLockSectionSegment(Segment
);
3828 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3829 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
3830 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3832 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3833 while (!IsListEmpty(RegionListHead
))
3835 CurrentEntry
= RemoveHeadList(RegionListHead
);
3836 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3837 ExFreePool(CurrentRegion
);
3840 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3842 Status
= MmFreeMemoryArea(AddressSpace
,
3849 Status
= MmFreeMemoryArea(AddressSpace
,
3854 MmUnlockSectionSegment(Segment
);
3855 ObDereferenceObject(Section
);
3856 return(STATUS_SUCCESS
);
3863 MmUnmapViewOfSection(PEPROCESS Process
,
3867 PMEMORY_AREA MemoryArea
;
3868 PMADDRESS_SPACE AddressSpace
;
3869 PSECTION_OBJECT Section
;
3871 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3872 Process
, BaseAddress
);
3876 AddressSpace
= &Process
->AddressSpace
;
3877 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3879 if (MemoryArea
== NULL
||
3880 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
3881 MemoryArea
->DeleteInProgress
)
3883 return STATUS_NOT_MAPPED_VIEW
;
3886 Section
= MemoryArea
->Data
.SectionData
.Section
;
3888 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3892 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3893 PMM_SECTION_SEGMENT SectionSegments
;
3894 PVOID ImageBaseAddress
= 0;
3895 PMM_SECTION_SEGMENT Segment
;
3897 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3898 ImageSectionObject
= Section
->ImageSection
;
3899 SectionSegments
= ImageSectionObject
->Segments
;
3900 NrSegments
= ImageSectionObject
->NrSegments
;
3902 /* Search for the current segment within the section segments
3903 * and calculate the image base address */
3904 for (i
= 0; i
< NrSegments
; i
++)
3906 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3908 if (Segment
== &SectionSegments
[i
])
3910 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3915 if (i
>= NrSegments
)
3920 for (i
= 0; i
< NrSegments
; i
++)
3922 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3924 PVOID SBaseAddress
= (PVOID
)
3925 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3927 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
3933 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
3935 return(STATUS_SUCCESS
);
3938 /**********************************************************************
3940 * NtUnmapViewOfSection
3955 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3959 KPROCESSOR_MODE PreviousMode
;
3962 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3963 ProcessHandle
, BaseAddress
);
3965 PreviousMode
= ExGetPreviousMode();
3967 DPRINT("Referencing process\n");
3968 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3969 PROCESS_VM_OPERATION
,
3972 (PVOID
*)(PVOID
)&Process
,
3974 if (!NT_SUCCESS(Status
))
3976 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3980 MmLockAddressSpace(&Process
->AddressSpace
);
3981 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3982 MmUnlockAddressSpace(&Process
->AddressSpace
);
3984 ObDereferenceObject(Process
);
3991 * Queries the information of a section object.
3993 * @param SectionHandle
3994 * Handle to the section object. It must be opened with SECTION_QUERY
3996 * @param SectionInformationClass
3997 * Index to a certain information structure. Can be either
3998 * SectionBasicInformation or SectionImageInformation. The latter
3999 * is valid only for sections that were created with the SEC_IMAGE
4001 * @param SectionInformation
4002 * Caller supplies storage for resulting information.
4004 * Size of the supplied storage.
4005 * @param ResultLength
4013 NtQuerySection(IN HANDLE SectionHandle
,
4014 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4015 OUT PVOID SectionInformation
,
4016 IN ULONG SectionInformationLength
,
4017 OUT PULONG ResultLength OPTIONAL
)
4019 PSECTION_OBJECT Section
;
4020 KPROCESSOR_MODE PreviousMode
;
4021 NTSTATUS Status
= STATUS_SUCCESS
;
4023 PreviousMode
= ExGetPreviousMode();
4025 DefaultQueryInfoBufferCheck(SectionInformationClass
,
4028 SectionInformationLength
,
4033 if(!NT_SUCCESS(Status
))
4035 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4039 Status
= ObReferenceObjectByHandle(SectionHandle
,
4041 MmSectionObjectType
,
4043 (PVOID
*)(PVOID
)&Section
,
4045 if (NT_SUCCESS(Status
))
4047 switch (SectionInformationClass
)
4049 case SectionBasicInformation
:
4051 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4055 Sbi
->Attributes
= Section
->AllocationAttributes
;
4056 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4058 Sbi
->BaseAddress
= 0;
4059 Sbi
->Size
.QuadPart
= 0;
4063 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4064 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4067 if (ResultLength
!= NULL
)
4069 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4071 Status
= STATUS_SUCCESS
;
4075 Status
= _SEH_GetExceptionCode();
4082 case SectionImageInformation
:
4084 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4088 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4089 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4091 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4092 ImageSectionObject
= Section
->ImageSection
;
4094 Sii
->EntryPoint
= ImageSectionObject
->EntryPoint
;
4095 Sii
->StackReserve
= ImageSectionObject
->StackReserve
;
4096 Sii
->StackCommit
= ImageSectionObject
->StackCommit
;
4097 Sii
->Subsystem
= ImageSectionObject
->Subsystem
;
4098 Sii
->MinorSubsystemVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4099 Sii
->MajorSubsystemVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4100 Sii
->Characteristics
= ImageSectionObject
->ImageCharacteristics
;
4101 Sii
->ImageNumber
= ImageSectionObject
->Machine
;
4102 Sii
->Executable
= ImageSectionObject
->Executable
;
4105 if (ResultLength
!= NULL
)
4107 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4109 Status
= STATUS_SUCCESS
;
4113 Status
= _SEH_GetExceptionCode();
4121 ObDereferenceObject(Section
);
4129 * Extends size of file backed section.
4131 * @param SectionHandle
4132 * Handle to the section object. It must be opened with
4133 * SECTION_EXTEND_SIZE access.
4134 * @param NewMaximumSize
4135 * New maximum size of the section in bytes.
4139 * @todo Move the actual code to internal function MmExtendSection.
4143 NtExtendSection(IN HANDLE SectionHandle
,
4144 IN PLARGE_INTEGER NewMaximumSize
)
4146 LARGE_INTEGER SafeNewMaximumSize
;
4147 PSECTION_OBJECT Section
;
4148 KPROCESSOR_MODE PreviousMode
;
4149 NTSTATUS Status
= STATUS_SUCCESS
;
4151 PreviousMode
= ExGetPreviousMode();
4153 if(PreviousMode
!= KernelMode
)
4157 ProbeForRead(NewMaximumSize
,
4158 sizeof(LARGE_INTEGER
),
4160 /* make a copy on the stack */
4161 SafeNewMaximumSize
= *NewMaximumSize
;
4162 NewMaximumSize
= &SafeNewMaximumSize
;
4166 Status
= _SEH_GetExceptionCode();
4170 if(!NT_SUCCESS(Status
))
4176 Status
= ObReferenceObjectByHandle(SectionHandle
,
4177 SECTION_EXTEND_SIZE
,
4178 MmSectionObjectType
,
4182 if (!NT_SUCCESS(Status
))
4187 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4189 ObfDereferenceObject(Section
);
4190 return STATUS_INVALID_PARAMETER
;
4194 * - Acquire file extneding resource.
4195 * - Check if we're not resizing the section below it's actual size!
4196 * - Extend segments if needed.
4197 * - Set file information (FileAllocationInformation) to the new size.
4198 * - Release file extending resource.
4201 ObDereferenceObject(Section
);
4203 return STATUS_NOT_IMPLEMENTED
;
4207 /**********************************************************************
4209 * MmAllocateSection@4
4219 * Code taken from ntoskrnl/mm/special.c.
4224 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4230 PMADDRESS_SPACE AddressSpace
;
4231 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4233 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4235 BoundaryAddressMultiple
.QuadPart
= 0;
4237 AddressSpace
= MmGetKernelAddressSpace();
4238 Result
= BaseAddress
;
4239 MmLockAddressSpace(AddressSpace
);
4240 Status
= MmCreateMemoryArea (NULL
,
4249 BoundaryAddressMultiple
);
4250 MmUnlockAddressSpace(AddressSpace
);
4252 if (!NT_SUCCESS(Status
))
4256 DPRINT("Result %p\n",Result
);
4257 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
4261 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
4262 if (!NT_SUCCESS(Status
))
4264 DbgPrint("Unable to allocate page\n");
4267 Status
= MmCreateVirtualMapping (NULL
,
4268 (PVOID
)((ULONG_PTR
)Result
+ (i
* PAGE_SIZE
)),
4272 if (!NT_SUCCESS(Status
))
4274 DbgPrint("Unable to create virtual mapping\n");
4278 return ((PVOID
)Result
);
4282 /**********************************************************************
4284 * MmMapViewOfSection
4287 * Maps a view of a section into the virtual address space of a
4292 * Pointer to the section object.
4295 * Pointer to the process.
4298 * Desired base address (or NULL) on entry;
4299 * Actual base address of the view on exit.
4302 * Number of high order address bits that must be zero.
4305 * Size in bytes of the initially committed section of
4309 * Offset in bytes from the beginning of the section
4310 * to the beginning of the view.
4313 * Desired length of map (or zero to map all) on entry
4314 * Actual length mapped on exit.
4316 * InheritDisposition
4317 * Specified how the view is to be shared with
4321 * Type of allocation for the pages.
4324 * Protection for the committed region of the view.
4332 MmMapViewOfSection(IN PVOID SectionObject
,
4333 IN PEPROCESS Process
,
4334 IN OUT PVOID
*BaseAddress
,
4336 IN ULONG CommitSize
,
4337 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4338 IN OUT PULONG ViewSize
,
4339 IN SECTION_INHERIT InheritDisposition
,
4340 IN ULONG AllocationType
,
4343 PSECTION_OBJECT Section
;
4344 PMADDRESS_SPACE AddressSpace
;
4346 NTSTATUS Status
= STATUS_SUCCESS
;
4350 Section
= (PSECTION_OBJECT
)SectionObject
;
4351 AddressSpace
= &Process
->AddressSpace
;
4353 MmLockAddressSpace(AddressSpace
);
4355 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4359 ULONG_PTR ImageBase
;
4361 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4362 PMM_SECTION_SEGMENT SectionSegments
;
4364 ImageSectionObject
= Section
->ImageSection
;
4365 SectionSegments
= ImageSectionObject
->Segments
;
4366 NrSegments
= ImageSectionObject
->NrSegments
;
4369 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4372 ImageBase
= ImageSectionObject
->ImageBase
;
4376 for (i
= 0; i
< NrSegments
; i
++)
4378 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4380 ULONG_PTR MaxExtent
;
4381 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4382 SectionSegments
[i
].Length
;
4383 ImageSize
= max(ImageSize
, MaxExtent
);
4387 /* Check there is enough space to map the section at that point. */
4388 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4389 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4391 /* Fail if the user requested a fixed base address. */
4392 if ((*BaseAddress
) != NULL
)
4394 MmUnlockAddressSpace(AddressSpace
);
4395 return(STATUS_UNSUCCESSFUL
);
4397 /* Otherwise find a gap to map the image. */
4398 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4401 MmUnlockAddressSpace(AddressSpace
);
4402 return(STATUS_UNSUCCESSFUL
);
4406 for (i
= 0; i
< NrSegments
; i
++)
4408 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4410 PVOID SBaseAddress
= (PVOID
)
4411 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4412 MmLockSectionSegment(&SectionSegments
[i
]);
4413 Status
= MmMapViewOfSegment(Process
,
4416 &SectionSegments
[i
],
4418 SectionSegments
[i
].Length
,
4419 SectionSegments
[i
].Protection
,
4422 MmUnlockSectionSegment(&SectionSegments
[i
]);
4423 if (!NT_SUCCESS(Status
))
4425 MmUnlockAddressSpace(AddressSpace
);
4431 *BaseAddress
= (PVOID
)ImageBase
;
4435 if (ViewSize
== NULL
)
4437 /* Following this pointer would lead to us to the dark side */
4438 /* What to do? Bugcheck? Return status? Do the mambo? */
4439 KEBUGCHECK(MEMORY_MANAGEMENT
);
4442 if (SectionOffset
== NULL
)
4448 ViewOffset
= SectionOffset
->u
.LowPart
;
4451 if ((ViewOffset
% PAGE_SIZE
) != 0)
4453 MmUnlockAddressSpace(AddressSpace
);
4454 return(STATUS_MAPPED_ALIGNMENT
);
4457 if ((*ViewSize
) == 0)
4459 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4461 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4463 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4466 MmLockSectionSegment(Section
->Segment
);
4467 Status
= MmMapViewOfSegment(Process
,
4475 (AllocationType
& MEM_TOP_DOWN
));
4476 MmUnlockSectionSegment(Section
->Segment
);
4477 if (!NT_SUCCESS(Status
))
4479 MmUnlockAddressSpace(AddressSpace
);
4484 MmUnlockAddressSpace(AddressSpace
);
4486 return(STATUS_SUCCESS
);
4493 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4494 IN PLARGE_INTEGER NewFileSize
)
4505 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
4515 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4516 IN MMFLUSH_TYPE FlushType
)
4520 case MmFlushForDelete
:
4521 if (SectionObjectPointer
->ImageSectionObject
||
4522 SectionObjectPointer
->DataSectionObject
)
4526 CcRosSetRemoveOnClose(SectionObjectPointer
);
4528 case MmFlushForWrite
:
4538 MmForceSectionClosed (
4539 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4540 IN BOOLEAN DelayClose
)
4551 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4552 OUT PVOID
* MappedBase
,
4553 IN OUT PULONG ViewSize
)
4555 PSECTION_OBJECT Section
;
4556 PMADDRESS_SPACE AddressSpace
;
4559 DPRINT("MmMapViewInSystemSpace() called\n");
4561 Section
= (PSECTION_OBJECT
)SectionObject
;
4562 AddressSpace
= MmGetKernelAddressSpace();
4564 MmLockAddressSpace(AddressSpace
);
4567 if ((*ViewSize
) == 0)
4569 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4571 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4573 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4576 MmLockSectionSegment(Section
->Segment
);
4579 Status
= MmMapViewOfSegment(NULL
,
4589 MmUnlockSectionSegment(Section
->Segment
);
4590 MmUnlockAddressSpace(AddressSpace
);
4600 MmMapViewInSessionSpace (
4602 OUT PVOID
*MappedBase
,
4603 IN OUT PSIZE_T ViewSize
4607 return STATUS_NOT_IMPLEMENTED
;
4615 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4617 PMADDRESS_SPACE AddressSpace
;
4620 DPRINT("MmUnmapViewInSystemSpace() called\n");
4622 AddressSpace
= MmGetKernelAddressSpace();
4624 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4634 MmUnmapViewInSessionSpace (
4639 return STATUS_NOT_IMPLEMENTED
;
4646 MmSetBankedSection (DWORD Unknown0
,
4654 return (STATUS_NOT_IMPLEMENTED
);
4658 /**********************************************************************
4663 * Creates a section object.
4666 * SectionObject (OUT)
4667 * Caller supplied storage for the resulting pointer
4668 * to a SECTION_OBJECT instance;
4671 * Specifies the desired access to the section can be a
4673 * STANDARD_RIGHTS_REQUIRED |
4675 * SECTION_MAP_WRITE |
4676 * SECTION_MAP_READ |
4677 * SECTION_MAP_EXECUTE
4679 * ObjectAttributes [OPTIONAL]
4680 * Initialized attributes for the object can be used
4681 * to create a named section;
4684 * Maximizes the size of the memory section. Must be
4685 * non-NULL for a page-file backed section.
4686 * If value specified for a mapped file and the file is
4687 * not large enough, file will be extended.
4689 * SectionPageProtection
4690 * Can be a combination of:
4696 * AllocationAttributes
4697 * Can be a combination of:
4702 * Handle to a file to create a section mapped to a file
4703 * instead of a memory backed section;
4714 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4715 IN ACCESS_MASK DesiredAccess
,
4716 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4717 IN PLARGE_INTEGER MaximumSize
,
4718 IN ULONG SectionPageProtection
,
4719 IN ULONG AllocationAttributes
,
4720 IN HANDLE FileHandle OPTIONAL
,
4721 IN PFILE_OBJECT File OPTIONAL
)
4723 if (AllocationAttributes
& SEC_IMAGE
)
4725 return(MmCreateImageSection(SectionObject
,
4729 SectionPageProtection
,
4730 AllocationAttributes
,
4734 if (FileHandle
!= NULL
)
4736 return(MmCreateDataFileSection(SectionObject
,
4740 SectionPageProtection
,
4741 AllocationAttributes
,
4745 return(MmCreatePageFileSection(SectionObject
,
4749 SectionPageProtection
,
4750 AllocationAttributes
));