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
));
2071 NTSTATUS INIT_FUNCTION
2072 MmCreatePhysicalMemorySection(VOID
)
2074 PSECTION_OBJECT PhysSection
;
2076 OBJECT_ATTRIBUTES Obj
;
2077 UNICODE_STRING Name
= ROS_STRING_INITIALIZER(L
"\\Device\\PhysicalMemory");
2078 LARGE_INTEGER SectionSize
;
2081 * Create the section mapping physical memory
2083 SectionSize
.QuadPart
= 0xFFFFFFFF;
2084 InitializeObjectAttributes(&Obj
,
2089 Status
= MmCreateSection(&PhysSection
,
2093 PAGE_EXECUTE_READWRITE
,
2097 if (!NT_SUCCESS(Status
))
2099 DbgPrint("Failed to create PhysicalMemory section\n");
2102 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2104 return(STATUS_SUCCESS
);
2107 NTSTATUS INIT_FUNCTION
2108 MmInitSectionImplementation(VOID
)
2110 MmSectionObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
2112 RtlInitUnicodeString(&MmSectionObjectType
->TypeName
, L
"Section");
2114 MmSectionObjectType
->Tag
= TAG('S', 'E', 'C', 'T');
2115 MmSectionObjectType
->TotalObjects
= 0;
2116 MmSectionObjectType
->TotalHandles
= 0;
2117 MmSectionObjectType
->PeakObjects
= 0;
2118 MmSectionObjectType
->PeakHandles
= 0;
2119 MmSectionObjectType
->PagedPoolCharge
= 0;
2120 MmSectionObjectType
->NonpagedPoolCharge
= sizeof(SECTION_OBJECT
);
2121 MmSectionObjectType
->Mapping
= &MmpSectionMapping
;
2122 MmSectionObjectType
->Dump
= NULL
;
2123 MmSectionObjectType
->Open
= NULL
;
2124 MmSectionObjectType
->Close
= MmpCloseSection
;
2125 MmSectionObjectType
->Delete
= MmpDeleteSection
;
2126 MmSectionObjectType
->Parse
= NULL
;
2127 MmSectionObjectType
->Open
= NULL
;
2128 MmSectionObjectType
->Security
= NULL
;
2129 MmSectionObjectType
->QueryName
= NULL
;
2130 MmSectionObjectType
->OkayToClose
= NULL
;
2133 * NOTE: Do not register the section object type here because
2134 * the object manager it not initialized yet!
2135 * The section object type will be created in ObInit().
2137 ObpCreateTypeObject(MmSectionObjectType
);
2139 return(STATUS_SUCCESS
);
2143 MmCreatePageFileSection(PSECTION_OBJECT
*SectionObject
,
2144 ACCESS_MASK DesiredAccess
,
2145 POBJECT_ATTRIBUTES ObjectAttributes
,
2146 PLARGE_INTEGER UMaximumSize
,
2147 ULONG SectionPageProtection
,
2148 ULONG AllocationAttributes
)
2150 * Create a section which is backed by the pagefile
2153 LARGE_INTEGER MaximumSize
;
2154 PSECTION_OBJECT Section
;
2155 PMM_SECTION_SEGMENT Segment
;
2158 if (UMaximumSize
== NULL
)
2160 return(STATUS_UNSUCCESSFUL
);
2162 MaximumSize
= *UMaximumSize
;
2165 * Create the section
2167 Status
= ObCreateObject(ExGetPreviousMode(),
2168 MmSectionObjectType
,
2170 ExGetPreviousMode(),
2172 sizeof(SECTION_OBJECT
),
2175 (PVOID
*)(PVOID
)&Section
);
2176 if (!NT_SUCCESS(Status
))
2184 Section
->SectionPageProtection
= SectionPageProtection
;
2185 Section
->AllocationAttributes
= AllocationAttributes
;
2186 Section
->Segment
= NULL
;
2187 InitializeListHead(&Section
->ViewListHead
);
2188 KeInitializeSpinLock(&Section
->ViewListLock
);
2189 Section
->FileObject
= NULL
;
2190 Section
->MaximumSize
= MaximumSize
;
2191 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2192 TAG_MM_SECTION_SEGMENT
);
2193 if (Segment
== NULL
)
2195 ObDereferenceObject(Section
);
2196 return(STATUS_NO_MEMORY
);
2198 Section
->Segment
= Segment
;
2199 Segment
->ReferenceCount
= 1;
2200 ExInitializeFastMutex(&Segment
->Lock
);
2201 Segment
->FileOffset
= 0;
2202 Segment
->Protection
= SectionPageProtection
;
2203 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2204 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2205 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2206 Segment
->WriteCopy
= FALSE
;
2207 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2208 Segment
->VirtualAddress
= 0;
2209 Segment
->Characteristics
= 0;
2210 *SectionObject
= Section
;
2211 return(STATUS_SUCCESS
);
2216 MmCreateDataFileSection(PSECTION_OBJECT
*SectionObject
,
2217 ACCESS_MASK DesiredAccess
,
2218 POBJECT_ATTRIBUTES ObjectAttributes
,
2219 PLARGE_INTEGER UMaximumSize
,
2220 ULONG SectionPageProtection
,
2221 ULONG AllocationAttributes
,
2224 * Create a section backed by a data file
2227 PSECTION_OBJECT Section
;
2229 LARGE_INTEGER MaximumSize
;
2230 PFILE_OBJECT FileObject
;
2231 PMM_SECTION_SEGMENT Segment
;
2233 IO_STATUS_BLOCK Iosb
;
2234 LARGE_INTEGER Offset
;
2236 FILE_STANDARD_INFORMATION FileInfo
;
2239 * Create the section
2241 Status
= ObCreateObject(ExGetPreviousMode(),
2242 MmSectionObjectType
,
2244 ExGetPreviousMode(),
2246 sizeof(SECTION_OBJECT
),
2249 (PVOID
*)(PVOID
)&Section
);
2250 if (!NT_SUCCESS(Status
))
2258 Section
->SectionPageProtection
= SectionPageProtection
;
2259 Section
->AllocationAttributes
= AllocationAttributes
;
2260 Section
->Segment
= NULL
;
2261 InitializeListHead(&Section
->ViewListHead
);
2262 KeInitializeSpinLock(&Section
->ViewListLock
);
2265 * Check file access required
2267 if (SectionPageProtection
& PAGE_READWRITE
||
2268 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2270 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2274 FileAccess
= FILE_READ_DATA
;
2278 * Reference the file handle
2280 Status
= ObReferenceObjectByHandle(FileHandle
,
2284 (PVOID
*)(PVOID
)&FileObject
,
2286 if (!NT_SUCCESS(Status
))
2288 ObDereferenceObject(Section
);
2293 * FIXME: This is propably not entirely correct. We can't look into
2294 * the standard FCB header because it might not be initialized yet
2295 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2296 * standard file information is filled on first request).
2298 Status
= NtQueryInformationFile(FileHandle
,
2301 sizeof(FILE_STANDARD_INFORMATION
),
2302 FileStandardInformation
);
2303 if (!NT_SUCCESS(Status
))
2305 ObDereferenceObject(Section
);
2306 ObDereferenceObject(FileObject
);
2311 * FIXME: Revise this once a locking order for file size changes is
2314 if (UMaximumSize
!= NULL
)
2316 MaximumSize
= *UMaximumSize
;
2320 MaximumSize
= FileInfo
.EndOfFile
;
2321 /* Mapping zero-sized files isn't allowed. */
2322 if (MaximumSize
.QuadPart
== 0)
2324 ObDereferenceObject(Section
);
2325 ObDereferenceObject(FileObject
);
2326 return STATUS_FILE_INVALID
;
2330 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2332 Status
= NtSetInformationFile(FileHandle
,
2335 sizeof(LARGE_INTEGER
),
2336 FileAllocationInformation
);
2337 if (!NT_SUCCESS(Status
))
2339 ObDereferenceObject(Section
);
2340 ObDereferenceObject(FileObject
);
2341 return(STATUS_SECTION_NOT_EXTENDED
);
2345 if (FileObject
->SectionObjectPointer
== NULL
||
2346 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2349 * Read a bit so caching is initiated for the file object.
2350 * This is only needed because MiReadPage currently cannot
2351 * handle non-cached streams.
2353 Offset
.QuadPart
= 0;
2354 Status
= ZwReadFile(FileHandle
,
2363 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2365 ObDereferenceObject(Section
);
2366 ObDereferenceObject(FileObject
);
2369 if (FileObject
->SectionObjectPointer
== NULL
||
2370 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2372 /* FIXME: handle this situation */
2373 ObDereferenceObject(Section
);
2374 ObDereferenceObject(FileObject
);
2375 return STATUS_INVALID_PARAMETER
;
2382 Status
= MmspWaitForFileLock(FileObject
);
2383 if (Status
!= STATUS_SUCCESS
)
2385 ObDereferenceObject(Section
);
2386 ObDereferenceObject(FileObject
);
2391 * If this file hasn't been mapped as a data file before then allocate a
2392 * section segment to describe the data file mapping
2394 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2396 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2397 TAG_MM_SECTION_SEGMENT
);
2398 if (Segment
== NULL
)
2400 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2401 ObDereferenceObject(Section
);
2402 ObDereferenceObject(FileObject
);
2403 return(STATUS_NO_MEMORY
);
2405 Section
->Segment
= Segment
;
2406 Segment
->ReferenceCount
= 1;
2407 ExInitializeFastMutex(&Segment
->Lock
);
2409 * Set the lock before assigning the segment to the file object
2411 ExAcquireFastMutex(&Segment
->Lock
);
2412 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2414 Segment
->FileOffset
= 0;
2415 Segment
->Protection
= SectionPageProtection
;
2416 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2417 Segment
->Characteristics
= 0;
2418 Segment
->WriteCopy
= FALSE
;
2419 if (AllocationAttributes
& SEC_RESERVE
)
2421 Segment
->Length
= Segment
->RawLength
= 0;
2425 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2426 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2428 Segment
->VirtualAddress
= 0;
2429 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2434 * If the file is already mapped as a data file then we may need
2438 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2440 Section
->Segment
= Segment
;
2441 InterlockedIncrementUL(&Segment
->ReferenceCount
);
2442 MmLockSectionSegment(Segment
);
2444 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2445 !(AllocationAttributes
& SEC_RESERVE
))
2447 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2448 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2451 MmUnlockSectionSegment(Segment
);
2452 Section
->FileObject
= FileObject
;
2453 Section
->MaximumSize
= MaximumSize
;
2454 CcRosReferenceCache(FileObject
);
2455 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2456 *SectionObject
= Section
;
2457 return(STATUS_SUCCESS
);
2461 TODO: not that great (declaring loaders statically, having to declare all of
2462 them, having to keep them extern, etc.), will fix in the future
2464 extern NTSTATUS NTAPI PeFmtCreateSection
2466 IN CONST VOID
* FileHeader
,
2467 IN SIZE_T FileHeaderSize
,
2469 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2471 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2472 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2475 extern NTSTATUS NTAPI ElfFmtCreateSection
2477 IN CONST VOID
* FileHeader
,
2478 IN SIZE_T FileHeaderSize
,
2480 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2482 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2483 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2486 /* TODO: this is a standard DDK/PSDK macro */
2487 #ifndef RTL_NUMBER_OF
2488 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2491 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2500 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2502 SIZE_T SizeOfSegments
;
2503 PMM_SECTION_SEGMENT Segments
;
2505 /* TODO: check for integer overflow */
2506 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2508 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2510 TAG_MM_SECTION_SEGMENT
);
2513 RtlZeroMemory(Segments
, SizeOfSegments
);
2521 ExeFmtpReadFile(IN PVOID File
,
2522 IN PLARGE_INTEGER Offset
,
2525 OUT PVOID
* AllocBase
,
2526 OUT PULONG ReadSize
)
2529 LARGE_INTEGER FileOffset
;
2531 ULONG OffsetAdjustment
;
2536 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2540 KEBUGCHECK(STATUS_INVALID_PARAMETER_4
);
2543 FileOffset
= *Offset
;
2545 /* Negative/special offset: it cannot be used in this context */
2546 if(FileOffset
.u
.HighPart
< 0)
2548 KEBUGCHECK(STATUS_INVALID_PARAMETER_5
);
2551 ASSERT(PAGE_SIZE
<= MAXULONG
);
2552 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2553 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2554 FileOffset
.u
.LowPart
= AdjustOffset
;
2556 BufferSize
= Length
+ OffsetAdjustment
;
2557 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2560 * It's ok to use paged pool, because this is a temporary buffer only used in
2561 * the loading of executables. The assumption is that MmCreateSection is
2562 * always called at low IRQLs and that these buffers don't survive a brief
2563 * initialization phase
2565 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2567 TAG('M', 'm', 'X', 'r'));
2572 Status
= MmspPageRead(File
,
2579 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2580 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2581 * to initialize internal state is even worse. Our cache manager is in need of
2585 IO_STATUS_BLOCK Iosb
;
2587 Status
= ZwReadFile(File
,
2597 if(NT_SUCCESS(Status
))
2599 UsedSize
= Iosb
.Information
;
2604 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2606 Status
= STATUS_IN_PAGE_ERROR
;
2607 ASSERT(!NT_SUCCESS(Status
));
2610 if(NT_SUCCESS(Status
))
2612 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2613 *AllocBase
= Buffer
;
2614 *ReadSize
= UsedSize
- OffsetAdjustment
;
2625 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2626 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2627 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2632 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2636 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2638 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2639 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2646 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2650 MmspAssertSegmentsSorted(ImageSectionObject
);
2652 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2654 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2658 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2659 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2660 ImageSectionObject
->Segments
[i
- 1].Length
));
2668 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2672 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2674 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2675 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2683 MmspCompareSegments(const void * x
,
2686 PMM_SECTION_SEGMENT Segment1
= (PMM_SECTION_SEGMENT
)x
;
2687 PMM_SECTION_SEGMENT Segment2
= (PMM_SECTION_SEGMENT
)y
;
2690 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2691 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2695 * Ensures an image section's segments are sorted in memory
2700 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2703 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2705 MmspAssertSegmentsSorted(ImageSectionObject
);
2709 qsort(ImageSectionObject
->Segments
,
2710 ImageSectionObject
->NrSegments
,
2711 sizeof(ImageSectionObject
->Segments
[0]),
2712 MmspCompareSegments
);
2718 * Ensures an image section's segments don't overlap in memory and don't have
2719 * gaps and don't have a null size. We let them map to overlapping file regions,
2720 * though - that's not necessarily an error
2725 MmspCheckSegmentBounds
2727 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2733 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2735 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2739 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2741 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2743 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2751 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2752 * page could be OK (Windows seems to be OK with them), and larger gaps
2753 * could lead to image sections spanning several discontiguous regions
2754 * (NtMapViewOfSection could then refuse to map them, and they could
2755 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2757 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2758 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2759 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2770 * Merges and pads an image section's segments until they all are page-aligned
2771 * and have a size that is a multiple of the page size
2776 MmspPageAlignSegments
2778 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2784 BOOLEAN Initialized
;
2786 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2788 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2792 Initialized
= FALSE
;
2795 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2797 PMM_SECTION_SEGMENT EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2800 * The first segment requires special handling
2804 ULONG_PTR VirtualAddress
;
2805 ULONG_PTR VirtualOffset
;
2807 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2809 /* Round down the virtual address to the nearest page */
2810 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2812 /* Round up the virtual size to the nearest page */
2813 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2814 EffectiveSegment
->VirtualAddress
;
2816 /* Adjust the raw address and size */
2817 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2819 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
2825 * Garbage in, garbage out: unaligned base addresses make the file
2826 * offset point in curious and odd places, but that's what we were
2829 EffectiveSegment
->FileOffset
-= VirtualOffset
;
2830 EffectiveSegment
->RawLength
+= VirtualOffset
;
2834 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
2835 ULONG_PTR EndOfEffectiveSegment
;
2837 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
2838 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
2841 * The current segment begins exactly where the current effective
2842 * segment ended, therefore beginning a new effective segment
2844 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
2847 ASSERT(LastSegment
<= i
);
2848 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
2850 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2853 * Copy the current segment. If necessary, the effective segment
2854 * will be expanded later
2856 *EffectiveSegment
= *Segment
;
2859 * Page-align the virtual size. We know for sure the virtual address
2862 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
2863 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
2866 * The current segment is still part of the current effective segment:
2867 * extend the effective segment to reflect this
2869 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
2871 static const ULONG FlagsToProtection
[16] =
2879 PAGE_EXECUTE_READWRITE
,
2880 PAGE_EXECUTE_READWRITE
,
2885 PAGE_EXECUTE_WRITECOPY
,
2886 PAGE_EXECUTE_WRITECOPY
,
2887 PAGE_EXECUTE_WRITECOPY
,
2888 PAGE_EXECUTE_WRITECOPY
2891 unsigned ProtectionFlags
;
2894 * Extend the file size
2897 /* Unaligned segments must be contiguous within the file */
2898 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
2899 EffectiveSegment
->RawLength
))
2904 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
2907 * Extend the virtual size
2909 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) > EndOfEffectiveSegment
);
2911 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
2912 EffectiveSegment
->VirtualAddress
;
2915 * Merge the protection
2917 EffectiveSegment
->Protection
|= Segment
->Protection
;
2919 /* Clean up redundance */
2920 ProtectionFlags
= 0;
2922 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
2923 ProtectionFlags
|= 1 << 0;
2925 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
2926 ProtectionFlags
|= 1 << 1;
2928 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
2929 ProtectionFlags
|= 1 << 2;
2931 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2932 ProtectionFlags
|= 1 << 3;
2934 ASSERT(ProtectionFlags
< 16);
2935 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
2937 /* If a segment was required to be shared and cannot, fail */
2938 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
2939 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2945 * We assume no holes between segments at this point
2958 ExeFmtpCreateImageSection(HANDLE FileHandle
,
2959 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2961 LARGE_INTEGER Offset
;
2963 PVOID FileHeaderBuffer
;
2964 ULONG FileHeaderSize
;
2966 ULONG OldNrSegments
;
2971 * Read the beginning of the file (2 pages). Should be enough to contain
2972 * all (or most) of the headers
2974 Offset
.QuadPart
= 0;
2976 /* FIXME: use FileObject instead of FileHandle */
2977 Status
= ExeFmtpReadFile (FileHandle
,
2984 if (!NT_SUCCESS(Status
))
2987 if (FileHeaderSize
== 0)
2989 ExFreePool(FileHeaderBuffer
);
2990 return STATUS_UNSUCCESSFUL
;
2994 * Look for a loader that can handle this executable
2996 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
2998 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3001 /* FIXME: use FileObject instead of FileHandle */
3002 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3008 ExeFmtpAllocateSegments
);
3010 if (!NT_SUCCESS(Status
))
3012 if (ImageSectionObject
->Segments
)
3014 ExFreePool(ImageSectionObject
->Segments
);
3015 ImageSectionObject
->Segments
= NULL
;
3019 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3023 ExFreePool(FileHeaderBuffer
);
3026 * No loader handled the format
3028 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3030 Status
= STATUS_INVALID_IMAGE_FORMAT
;
3031 ASSERT(!NT_SUCCESS(Status
));
3034 if (!NT_SUCCESS(Status
))
3037 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3042 /* FIXME? are these values platform-dependent? */
3043 if(ImageSectionObject
->StackReserve
== 0)
3044 ImageSectionObject
->StackReserve
= 0x40000;
3046 if(ImageSectionObject
->StackCommit
== 0)
3047 ImageSectionObject
->StackCommit
= 0x1000;
3049 if(ImageSectionObject
->ImageBase
== 0)
3051 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3052 ImageSectionObject
->ImageBase
= 0x10000000;
3054 ImageSectionObject
->ImageBase
= 0x00400000;
3058 * And now the fun part: fixing the segments
3061 /* Sort them by virtual address */
3062 MmspSortSegments(ImageSectionObject
, Flags
);
3064 /* Ensure they don't overlap in memory */
3065 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3066 return STATUS_INVALID_IMAGE_FORMAT
;
3068 /* Ensure they are aligned */
3069 OldNrSegments
= ImageSectionObject
->NrSegments
;
3071 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3072 return STATUS_INVALID_IMAGE_FORMAT
;
3074 /* Trim them if the alignment phase merged some of them */
3075 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3077 PMM_SECTION_SEGMENT Segments
;
3078 SIZE_T SizeOfSegments
;
3080 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3082 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
3084 TAG_MM_SECTION_SEGMENT
);
3086 if (Segments
== NULL
)
3087 return STATUS_INSUFFICIENT_RESOURCES
;
3089 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3090 ExFreePool(ImageSectionObject
->Segments
);
3091 ImageSectionObject
->Segments
= Segments
;
3094 /* And finish their initialization */
3095 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3097 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3098 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3100 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3101 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3104 ASSERT(NT_SUCCESS(Status
));
3109 MmCreateImageSection(PSECTION_OBJECT
*SectionObject
,
3110 ACCESS_MASK DesiredAccess
,
3111 POBJECT_ATTRIBUTES ObjectAttributes
,
3112 PLARGE_INTEGER UMaximumSize
,
3113 ULONG SectionPageProtection
,
3114 ULONG AllocationAttributes
,
3117 PSECTION_OBJECT Section
;
3119 PFILE_OBJECT FileObject
;
3120 PMM_SECTION_SEGMENT SectionSegments
;
3121 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3123 ULONG FileAccess
= 0;
3126 * Specifying a maximum size is meaningless for an image section
3128 if (UMaximumSize
!= NULL
)
3130 return(STATUS_INVALID_PARAMETER_4
);
3134 * Check file access required
3136 if (SectionPageProtection
& PAGE_READWRITE
||
3137 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3139 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3143 FileAccess
= FILE_READ_DATA
;
3147 * Reference the file handle
3149 Status
= ObReferenceObjectByHandle(FileHandle
,
3153 (PVOID
*)(PVOID
)&FileObject
,
3155 if (!NT_SUCCESS(Status
))
3161 * Create the section
3163 Status
= ObCreateObject (ExGetPreviousMode(),
3164 MmSectionObjectType
,
3166 ExGetPreviousMode(),
3168 sizeof(SECTION_OBJECT
),
3171 (PVOID
*)(PVOID
)&Section
);
3172 if (!NT_SUCCESS(Status
))
3174 ObDereferenceObject(FileObject
);
3181 Section
->SectionPageProtection
= SectionPageProtection
;
3182 Section
->AllocationAttributes
= AllocationAttributes
;
3183 InitializeListHead(&Section
->ViewListHead
);
3184 KeInitializeSpinLock(&Section
->ViewListLock
);
3187 * Initialized caching for this file object if previously caching
3188 * was initialized for the same on disk file
3190 Status
= CcTryToInitializeFileCache(FileObject
);
3192 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3194 NTSTATUS StatusExeFmt
;
3196 ImageSectionObject
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3197 if (ImageSectionObject
== NULL
)
3199 ObDereferenceObject(FileObject
);
3200 ObDereferenceObject(Section
);
3201 return(STATUS_NO_MEMORY
);
3204 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3206 if (!NT_SUCCESS(StatusExeFmt
))
3208 if(ImageSectionObject
->Segments
!= NULL
)
3209 ExFreePool(ImageSectionObject
->Segments
);
3211 ExFreePool(ImageSectionObject
);
3212 ObDereferenceObject(Section
);
3213 ObDereferenceObject(FileObject
);
3214 return(StatusExeFmt
);
3217 Section
->ImageSection
= ImageSectionObject
;
3218 ASSERT(ImageSectionObject
->Segments
);
3223 Status
= MmspWaitForFileLock(FileObject
);
3224 if (!NT_SUCCESS(Status
))
3226 ExFreePool(ImageSectionObject
->Segments
);
3227 ExFreePool(ImageSectionObject
);
3228 ObDereferenceObject(Section
);
3229 ObDereferenceObject(FileObject
);
3233 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3234 ImageSectionObject
, NULL
))
3237 * An other thread has initialized the some image in the background
3239 ExFreePool(ImageSectionObject
->Segments
);
3240 ExFreePool(ImageSectionObject
);
3241 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3242 Section
->ImageSection
= ImageSectionObject
;
3243 SectionSegments
= ImageSectionObject
->Segments
;
3245 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3247 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3251 Status
= StatusExeFmt
;
3258 Status
= MmspWaitForFileLock(FileObject
);
3259 if (Status
!= STATUS_SUCCESS
)
3261 ObDereferenceObject(Section
);
3262 ObDereferenceObject(FileObject
);
3266 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3267 Section
->ImageSection
= ImageSectionObject
;
3268 SectionSegments
= ImageSectionObject
->Segments
;
3271 * Otherwise just reference all the section segments
3273 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3275 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3278 Status
= STATUS_SUCCESS
;
3280 Section
->FileObject
= FileObject
;
3281 CcRosReferenceCache(FileObject
);
3282 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
3283 *SectionObject
= Section
;
3291 NtCreateSection (OUT PHANDLE SectionHandle
,
3292 IN ACCESS_MASK DesiredAccess
,
3293 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3294 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3295 IN ULONG SectionPageProtection OPTIONAL
,
3296 IN ULONG AllocationAttributes
,
3297 IN HANDLE FileHandle OPTIONAL
)
3299 LARGE_INTEGER SafeMaximumSize
;
3300 PSECTION_OBJECT SectionObject
;
3301 KPROCESSOR_MODE PreviousMode
;
3302 NTSTATUS Status
= STATUS_SUCCESS
;
3304 PreviousMode
= ExGetPreviousMode();
3306 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3310 ProbeForRead(MaximumSize
,
3311 sizeof(LARGE_INTEGER
),
3313 /* make a copy on the stack */
3314 SafeMaximumSize
= *MaximumSize
;
3315 MaximumSize
= &SafeMaximumSize
;
3319 Status
= _SEH_GetExceptionCode();
3323 if(!NT_SUCCESS(Status
))
3330 * Check the protection
3332 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
3333 SectionPageProtection
)
3335 return(STATUS_INVALID_PAGE_PROTECTION
);
3338 Status
= MmCreateSection(&SectionObject
,
3342 SectionPageProtection
,
3343 AllocationAttributes
,
3347 if (NT_SUCCESS(Status
))
3349 Status
= ObInsertObject ((PVOID
)SectionObject
,
3355 ObDereferenceObject(SectionObject
);
3362 /**********************************************************************
3380 NtOpenSection(PHANDLE SectionHandle
,
3381 ACCESS_MASK DesiredAccess
,
3382 POBJECT_ATTRIBUTES ObjectAttributes
)
3385 KPROCESSOR_MODE PreviousMode
;
3386 NTSTATUS Status
= STATUS_SUCCESS
;
3388 PreviousMode
= ExGetPreviousMode();
3390 if(PreviousMode
!= KernelMode
)
3394 ProbeForWrite(SectionHandle
,
3400 Status
= _SEH_GetExceptionCode();
3404 if(!NT_SUCCESS(Status
))
3410 Status
= ObOpenObjectByName(ObjectAttributes
,
3411 MmSectionObjectType
,
3418 if(NT_SUCCESS(Status
))
3422 *SectionHandle
= hSection
;
3426 Status
= _SEH_GetExceptionCode();
3435 MmMapViewOfSegment(PEPROCESS Process
,
3436 PMADDRESS_SPACE AddressSpace
,
3437 PSECTION_OBJECT Section
,
3438 PMM_SECTION_SEGMENT Segment
,
3448 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3450 BoundaryAddressMultiple
.QuadPart
= 0;
3452 Status
= MmCreateMemoryArea(Process
,
3454 MEMORY_AREA_SECTION_VIEW
,
3461 BoundaryAddressMultiple
);
3462 if (!NT_SUCCESS(Status
))
3464 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3465 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3469 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3470 InsertTailList(&Section
->ViewListHead
,
3471 &MArea
->Data
.SectionData
.ViewListEntry
);
3472 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3474 ObReferenceObjectByPointer((PVOID
)Section
,
3477 ExGetPreviousMode());
3478 MArea
->Data
.SectionData
.Segment
= Segment
;
3479 MArea
->Data
.SectionData
.Section
= Section
;
3480 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3481 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3482 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3483 ViewSize
, 0, Protect
);
3485 return(STATUS_SUCCESS
);
3489 /**********************************************************************
3491 * NtMapViewOfSection
3494 * Maps a view of a section into the virtual address space of a
3499 * Handle of the section.
3502 * Handle of the process.
3505 * Desired base address (or NULL) on entry;
3506 * Actual base address of the view on exit.
3509 * Number of high order address bits that must be zero.
3512 * Size in bytes of the initially committed section of
3516 * Offset in bytes from the beginning of the section
3517 * to the beginning of the view.
3520 * Desired length of map (or zero to map all) on entry
3521 * Actual length mapped on exit.
3523 * InheritDisposition
3524 * Specified how the view is to be shared with
3528 * Type of allocation for the pages.
3531 * Protection for the committed region of the view.
3539 NtMapViewOfSection(IN HANDLE SectionHandle
,
3540 IN HANDLE ProcessHandle
,
3541 IN OUT PVOID
* BaseAddress OPTIONAL
,
3542 IN ULONG ZeroBits OPTIONAL
,
3543 IN ULONG CommitSize
,
3544 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3545 IN OUT PULONG ViewSize
,
3546 IN SECTION_INHERIT InheritDisposition
,
3547 IN ULONG AllocationType OPTIONAL
,
3550 PVOID SafeBaseAddress
;
3551 LARGE_INTEGER SafeSectionOffset
;
3553 PSECTION_OBJECT Section
;
3555 KPROCESSOR_MODE PreviousMode
;
3556 PMADDRESS_SPACE AddressSpace
;
3557 NTSTATUS Status
= STATUS_SUCCESS
;
3559 PreviousMode
= ExGetPreviousMode();
3561 if(PreviousMode
!= KernelMode
)
3563 SafeBaseAddress
= NULL
;
3564 SafeSectionOffset
.QuadPart
= 0;
3569 if(BaseAddress
!= NULL
)
3571 ProbeForWrite(BaseAddress
,
3574 SafeBaseAddress
= *BaseAddress
;
3576 if(SectionOffset
!= NULL
)
3578 ProbeForWrite(SectionOffset
,
3579 sizeof(LARGE_INTEGER
),
3581 SafeSectionOffset
= *SectionOffset
;
3583 ProbeForWrite(ViewSize
,
3586 SafeViewSize
= *ViewSize
;
3590 Status
= _SEH_GetExceptionCode();
3594 if(!NT_SUCCESS(Status
))
3601 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3602 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3603 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3606 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3607 PROCESS_VM_OPERATION
,
3610 (PVOID
*)(PVOID
)&Process
,
3612 if (!NT_SUCCESS(Status
))
3617 AddressSpace
= &Process
->AddressSpace
;
3619 Status
= ObReferenceObjectByHandle(SectionHandle
,
3621 MmSectionObjectType
,
3623 (PVOID
*)(PVOID
)&Section
,
3625 if (!(NT_SUCCESS(Status
)))
3627 DPRINT("ObReference failed rc=%x\n",Status
);
3628 ObDereferenceObject(Process
);
3632 Status
= MmMapViewOfSection(Section
,
3634 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3637 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3638 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3643 ObDereferenceObject(Section
);
3644 ObDereferenceObject(Process
);
3646 if(NT_SUCCESS(Status
))
3648 /* copy parameters back to the caller */
3651 if(BaseAddress
!= NULL
)
3653 *BaseAddress
= SafeBaseAddress
;
3655 if(SectionOffset
!= NULL
)
3657 *SectionOffset
= SafeSectionOffset
;
3659 if(ViewSize
!= NULL
)
3661 *ViewSize
= SafeViewSize
;
3666 Status
= _SEH_GetExceptionCode();
3675 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3676 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3680 PFILE_OBJECT FileObject
;
3683 SWAPENTRY SavedSwapEntry
;
3686 PSECTION_OBJECT Section
;
3687 PMM_SECTION_SEGMENT Segment
;
3689 MArea
= (PMEMORY_AREA
)Context
;
3691 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3693 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MArea
->StartingAddress
) +
3694 MemoryArea
->Data
.SectionData
.ViewOffset
;
3696 Section
= MArea
->Data
.SectionData
.Section
;
3697 Segment
= MArea
->Data
.SectionData
.Segment
;
3699 PageOp
= MmCheckForPageOp(MArea
, NULL
, NULL
, Segment
, Offset
);
3703 MmUnlockSectionSegment(Segment
);
3704 MmUnlockAddressSpace(&MArea
->Process
->AddressSpace
);
3706 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3707 if (Status
!= STATUS_SUCCESS
)
3709 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3713 MmLockAddressSpace(&MArea
->Process
->AddressSpace
);
3714 MmLockSectionSegment(Segment
);
3715 MmspCompleteAndReleasePageOp(PageOp
);
3716 PageOp
= MmCheckForPageOp(MArea
, NULL
, NULL
, Segment
, Offset
);
3719 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3722 * For a dirty, datafile, non-private page mark it as dirty in the
3725 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3727 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3729 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3730 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3731 CcRosMarkDirtyCacheSegment(Bcb
, Offset
);
3732 ASSERT(SwapEntry
== 0);
3741 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3743 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3746 MmFreeSwapPage(SwapEntry
);
3750 if (IS_SWAP_FROM_SSE(Entry
) ||
3751 Page
!= PFN_FROM_SSE(Entry
))
3756 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3758 DPRINT1("Found a private page in a pagefile section.\n");
3762 * Just dereference private pages
3764 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3765 if (SavedSwapEntry
!= 0)
3767 MmFreeSwapPage(SavedSwapEntry
);
3768 MmSetSavedSwapEntryPage(Page
, 0);
3770 MmDeleteRmap(Page
, MArea
->Process
, Address
);
3771 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3775 MmDeleteRmap(Page
, MArea
->Process
, Address
);
3776 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3782 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3786 PMEMORY_AREA MemoryArea
;
3787 PSECTION_OBJECT Section
;
3788 PMM_SECTION_SEGMENT Segment
;
3790 PLIST_ENTRY CurrentEntry
;
3791 PMM_REGION CurrentRegion
;
3792 PLIST_ENTRY RegionListHead
;
3794 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3796 if (MemoryArea
== NULL
)
3798 return(STATUS_UNSUCCESSFUL
);
3801 MemoryArea
->DeleteInProgress
= TRUE
;
3802 Section
= MemoryArea
->Data
.SectionData
.Section
;
3803 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3805 MmLockSectionSegment(Segment
);
3806 KeAcquireSpinLock(&Section
->ViewListLock
, &oldIrql
);
3807 RemoveEntryList(&MemoryArea
->Data
.SectionData
.ViewListEntry
);
3808 KeReleaseSpinLock(&Section
->ViewListLock
, oldIrql
);
3810 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3811 while (!IsListEmpty(RegionListHead
))
3813 CurrentEntry
= RemoveHeadList(RegionListHead
);
3814 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3815 ExFreePool(CurrentRegion
);
3818 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3820 Status
= MmFreeMemoryArea(AddressSpace
,
3827 Status
= MmFreeMemoryArea(AddressSpace
,
3832 MmUnlockSectionSegment(Segment
);
3833 ObDereferenceObject(Section
);
3834 return(STATUS_SUCCESS
);
3841 MmUnmapViewOfSection(PEPROCESS Process
,
3845 PMEMORY_AREA MemoryArea
;
3846 PMADDRESS_SPACE AddressSpace
;
3847 PSECTION_OBJECT Section
;
3849 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3850 Process
, BaseAddress
);
3854 AddressSpace
= &Process
->AddressSpace
;
3855 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3857 if (MemoryArea
== NULL
||
3858 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
3859 MemoryArea
->DeleteInProgress
)
3861 return STATUS_NOT_MAPPED_VIEW
;
3864 Section
= MemoryArea
->Data
.SectionData
.Section
;
3866 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3870 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3871 PMM_SECTION_SEGMENT SectionSegments
;
3872 PVOID ImageBaseAddress
= 0;
3873 PMM_SECTION_SEGMENT Segment
;
3875 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3876 ImageSectionObject
= Section
->ImageSection
;
3877 SectionSegments
= ImageSectionObject
->Segments
;
3878 NrSegments
= ImageSectionObject
->NrSegments
;
3880 /* Search for the current segment within the section segments
3881 * and calculate the image base address */
3882 for (i
= 0; i
< NrSegments
; i
++)
3884 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3886 if (Segment
== &SectionSegments
[i
])
3888 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3893 if (i
>= NrSegments
)
3898 for (i
= 0; i
< NrSegments
; i
++)
3900 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3902 PVOID SBaseAddress
= (PVOID
)
3903 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3905 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
3911 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
3913 return(STATUS_SUCCESS
);
3916 /**********************************************************************
3918 * NtUnmapViewOfSection
3933 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3937 KPROCESSOR_MODE PreviousMode
;
3940 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3941 ProcessHandle
, BaseAddress
);
3943 PreviousMode
= ExGetPreviousMode();
3945 DPRINT("Referencing process\n");
3946 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3947 PROCESS_VM_OPERATION
,
3950 (PVOID
*)(PVOID
)&Process
,
3952 if (!NT_SUCCESS(Status
))
3954 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3958 MmLockAddressSpace(&Process
->AddressSpace
);
3959 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3960 MmUnlockAddressSpace(&Process
->AddressSpace
);
3962 ObDereferenceObject(Process
);
3969 * Queries the information of a section object.
3971 * @param SectionHandle
3972 * Handle to the section object. It must be opened with SECTION_QUERY
3974 * @param SectionInformationClass
3975 * Index to a certain information structure. Can be either
3976 * SectionBasicInformation or SectionImageInformation. The latter
3977 * is valid only for sections that were created with the SEC_IMAGE
3979 * @param SectionInformation
3980 * Caller supplies storage for resulting information.
3982 * Size of the supplied storage.
3983 * @param ResultLength
3991 NtQuerySection(IN HANDLE SectionHandle
,
3992 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
3993 OUT PVOID SectionInformation
,
3994 IN ULONG SectionInformationLength
,
3995 OUT PULONG ResultLength OPTIONAL
)
3997 PSECTION_OBJECT Section
;
3998 KPROCESSOR_MODE PreviousMode
;
3999 NTSTATUS Status
= STATUS_SUCCESS
;
4001 PreviousMode
= ExGetPreviousMode();
4003 DefaultQueryInfoBufferCheck(SectionInformationClass
,
4006 SectionInformationLength
,
4011 if(!NT_SUCCESS(Status
))
4013 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4017 Status
= ObReferenceObjectByHandle(SectionHandle
,
4019 MmSectionObjectType
,
4021 (PVOID
*)(PVOID
)&Section
,
4023 if (NT_SUCCESS(Status
))
4025 switch (SectionInformationClass
)
4027 case SectionBasicInformation
:
4029 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4033 Sbi
->Attributes
= Section
->AllocationAttributes
;
4034 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4036 Sbi
->BaseAddress
= 0;
4037 Sbi
->Size
.QuadPart
= 0;
4041 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4042 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4045 if (ResultLength
!= NULL
)
4047 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4049 Status
= STATUS_SUCCESS
;
4053 Status
= _SEH_GetExceptionCode();
4060 case SectionImageInformation
:
4062 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4066 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4067 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4069 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4070 ImageSectionObject
= Section
->ImageSection
;
4072 Sii
->EntryPoint
= ImageSectionObject
->EntryPoint
;
4073 Sii
->StackReserve
= ImageSectionObject
->StackReserve
;
4074 Sii
->StackCommit
= ImageSectionObject
->StackCommit
;
4075 Sii
->Subsystem
= ImageSectionObject
->Subsystem
;
4076 Sii
->MinorSubsystemVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4077 Sii
->MajorSubsystemVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4078 Sii
->Characteristics
= ImageSectionObject
->ImageCharacteristics
;
4079 Sii
->ImageNumber
= ImageSectionObject
->Machine
;
4080 Sii
->Executable
= ImageSectionObject
->Executable
;
4083 if (ResultLength
!= NULL
)
4085 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4087 Status
= STATUS_SUCCESS
;
4091 Status
= _SEH_GetExceptionCode();
4099 ObDereferenceObject(Section
);
4107 * Extends size of file backed section.
4109 * @param SectionHandle
4110 * Handle to the section object. It must be opened with
4111 * SECTION_EXTEND_SIZE access.
4112 * @param NewMaximumSize
4113 * New maximum size of the section in bytes.
4117 * @todo Move the actual code to internal function MmExtendSection.
4121 NtExtendSection(IN HANDLE SectionHandle
,
4122 IN PLARGE_INTEGER NewMaximumSize
)
4124 LARGE_INTEGER SafeNewMaximumSize
;
4125 PSECTION_OBJECT Section
;
4126 KPROCESSOR_MODE PreviousMode
;
4127 NTSTATUS Status
= STATUS_SUCCESS
;
4129 PreviousMode
= ExGetPreviousMode();
4131 if(PreviousMode
!= KernelMode
)
4135 ProbeForRead(NewMaximumSize
,
4136 sizeof(LARGE_INTEGER
),
4138 /* make a copy on the stack */
4139 SafeNewMaximumSize
= *NewMaximumSize
;
4140 NewMaximumSize
= &SafeNewMaximumSize
;
4144 Status
= _SEH_GetExceptionCode();
4148 if(!NT_SUCCESS(Status
))
4154 Status
= ObReferenceObjectByHandle(SectionHandle
,
4155 SECTION_EXTEND_SIZE
,
4156 MmSectionObjectType
,
4160 if (!NT_SUCCESS(Status
))
4165 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4167 ObfDereferenceObject(Section
);
4168 return STATUS_INVALID_PARAMETER
;
4172 * - Acquire file extneding resource.
4173 * - Check if we're not resizing the section below it's actual size!
4174 * - Extend segments if needed.
4175 * - Set file information (FileAllocationInformation) to the new size.
4176 * - Release file extending resource.
4179 ObDereferenceObject(Section
);
4181 return STATUS_NOT_IMPLEMENTED
;
4185 /**********************************************************************
4187 * MmAllocateSection@4
4197 * Code taken from ntoskrnl/mm/special.c.
4202 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4208 PMADDRESS_SPACE AddressSpace
;
4209 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4211 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4213 BoundaryAddressMultiple
.QuadPart
= 0;
4215 AddressSpace
= MmGetKernelAddressSpace();
4216 Result
= BaseAddress
;
4217 MmLockAddressSpace(AddressSpace
);
4218 Status
= MmCreateMemoryArea (NULL
,
4227 BoundaryAddressMultiple
);
4228 MmUnlockAddressSpace(AddressSpace
);
4230 if (!NT_SUCCESS(Status
))
4234 DPRINT("Result %p\n",Result
);
4235 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
4239 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
4240 if (!NT_SUCCESS(Status
))
4242 DbgPrint("Unable to allocate page\n");
4245 Status
= MmCreateVirtualMapping (NULL
,
4246 (PVOID
)((ULONG_PTR
)Result
+ (i
* PAGE_SIZE
)),
4250 if (!NT_SUCCESS(Status
))
4252 DbgPrint("Unable to create virtual mapping\n");
4256 return ((PVOID
)Result
);
4260 /**********************************************************************
4262 * MmMapViewOfSection
4265 * Maps a view of a section into the virtual address space of a
4270 * Pointer to the section object.
4273 * Pointer to the process.
4276 * Desired base address (or NULL) on entry;
4277 * Actual base address of the view on exit.
4280 * Number of high order address bits that must be zero.
4283 * Size in bytes of the initially committed section of
4287 * Offset in bytes from the beginning of the section
4288 * to the beginning of the view.
4291 * Desired length of map (or zero to map all) on entry
4292 * Actual length mapped on exit.
4294 * InheritDisposition
4295 * Specified how the view is to be shared with
4299 * Type of allocation for the pages.
4302 * Protection for the committed region of the view.
4310 MmMapViewOfSection(IN PVOID SectionObject
,
4311 IN PEPROCESS Process
,
4312 IN OUT PVOID
*BaseAddress
,
4314 IN ULONG CommitSize
,
4315 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4316 IN OUT PULONG ViewSize
,
4317 IN SECTION_INHERIT InheritDisposition
,
4318 IN ULONG AllocationType
,
4321 PSECTION_OBJECT Section
;
4322 PMADDRESS_SPACE AddressSpace
;
4324 NTSTATUS Status
= STATUS_SUCCESS
;
4328 Section
= (PSECTION_OBJECT
)SectionObject
;
4329 AddressSpace
= &Process
->AddressSpace
;
4331 MmLockAddressSpace(AddressSpace
);
4333 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4337 ULONG_PTR ImageBase
;
4339 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4340 PMM_SECTION_SEGMENT SectionSegments
;
4342 ImageSectionObject
= Section
->ImageSection
;
4343 SectionSegments
= ImageSectionObject
->Segments
;
4344 NrSegments
= ImageSectionObject
->NrSegments
;
4347 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4350 ImageBase
= ImageSectionObject
->ImageBase
;
4354 for (i
= 0; i
< NrSegments
; i
++)
4356 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4358 ULONG_PTR MaxExtent
;
4359 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4360 SectionSegments
[i
].Length
;
4361 ImageSize
= max(ImageSize
, MaxExtent
);
4365 /* Check there is enough space to map the section at that point. */
4366 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4367 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4369 /* Fail if the user requested a fixed base address. */
4370 if ((*BaseAddress
) != NULL
)
4372 MmUnlockAddressSpace(AddressSpace
);
4373 return(STATUS_UNSUCCESSFUL
);
4375 /* Otherwise find a gap to map the image. */
4376 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4379 MmUnlockAddressSpace(AddressSpace
);
4380 return(STATUS_UNSUCCESSFUL
);
4384 for (i
= 0; i
< NrSegments
; i
++)
4386 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4388 PVOID SBaseAddress
= (PVOID
)
4389 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4390 MmLockSectionSegment(&SectionSegments
[i
]);
4391 Status
= MmMapViewOfSegment(Process
,
4394 &SectionSegments
[i
],
4396 SectionSegments
[i
].Length
,
4397 SectionSegments
[i
].Protection
,
4400 MmUnlockSectionSegment(&SectionSegments
[i
]);
4401 if (!NT_SUCCESS(Status
))
4403 MmUnlockAddressSpace(AddressSpace
);
4409 *BaseAddress
= (PVOID
)ImageBase
;
4413 if (ViewSize
== NULL
)
4415 /* Following this pointer would lead to us to the dark side */
4416 /* What to do? Bugcheck? Return status? Do the mambo? */
4417 KEBUGCHECK(MEMORY_MANAGEMENT
);
4420 if (SectionOffset
== NULL
)
4426 ViewOffset
= SectionOffset
->u
.LowPart
;
4429 if ((ViewOffset
% PAGE_SIZE
) != 0)
4431 MmUnlockAddressSpace(AddressSpace
);
4432 return(STATUS_MAPPED_ALIGNMENT
);
4435 if ((*ViewSize
) == 0)
4437 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4439 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4441 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4444 MmLockSectionSegment(Section
->Segment
);
4445 Status
= MmMapViewOfSegment(Process
,
4453 (AllocationType
& MEM_TOP_DOWN
));
4454 MmUnlockSectionSegment(Section
->Segment
);
4455 if (!NT_SUCCESS(Status
))
4457 MmUnlockAddressSpace(AddressSpace
);
4462 MmUnlockAddressSpace(AddressSpace
);
4464 return(STATUS_SUCCESS
);
4471 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4472 IN PLARGE_INTEGER NewFileSize
)
4483 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
4493 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4494 IN MMFLUSH_TYPE FlushType
)
4498 case MmFlushForDelete
:
4499 if (SectionObjectPointer
->ImageSectionObject
||
4500 SectionObjectPointer
->DataSectionObject
)
4504 CcRosSetRemoveOnClose(SectionObjectPointer
);
4506 case MmFlushForWrite
:
4516 MmForceSectionClosed (
4517 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4518 IN BOOLEAN DelayClose
)
4529 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4530 OUT PVOID
* MappedBase
,
4531 IN OUT PULONG ViewSize
)
4533 PSECTION_OBJECT Section
;
4534 PMADDRESS_SPACE AddressSpace
;
4537 DPRINT("MmMapViewInSystemSpace() called\n");
4539 Section
= (PSECTION_OBJECT
)SectionObject
;
4540 AddressSpace
= MmGetKernelAddressSpace();
4542 MmLockAddressSpace(AddressSpace
);
4545 if ((*ViewSize
) == 0)
4547 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4549 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4551 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4554 MmLockSectionSegment(Section
->Segment
);
4557 Status
= MmMapViewOfSegment(NULL
,
4567 MmUnlockSectionSegment(Section
->Segment
);
4568 MmUnlockAddressSpace(AddressSpace
);
4578 MmMapViewInSessionSpace (
4580 OUT PVOID
*MappedBase
,
4581 IN OUT PSIZE_T ViewSize
4585 return STATUS_NOT_IMPLEMENTED
;
4593 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4595 PMADDRESS_SPACE AddressSpace
;
4598 DPRINT("MmUnmapViewInSystemSpace() called\n");
4600 AddressSpace
= MmGetKernelAddressSpace();
4602 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4612 MmUnmapViewInSessionSpace (
4617 return STATUS_NOT_IMPLEMENTED
;
4624 MmSetBankedSection (DWORD Unknown0
,
4632 return (STATUS_NOT_IMPLEMENTED
);
4636 /**********************************************************************
4641 * Creates a section object.
4644 * SectionObject (OUT)
4645 * Caller supplied storage for the resulting pointer
4646 * to a SECTION_OBJECT instance;
4649 * Specifies the desired access to the section can be a
4651 * STANDARD_RIGHTS_REQUIRED |
4653 * SECTION_MAP_WRITE |
4654 * SECTION_MAP_READ |
4655 * SECTION_MAP_EXECUTE
4657 * ObjectAttributes [OPTIONAL]
4658 * Initialized attributes for the object can be used
4659 * to create a named section;
4662 * Maximizes the size of the memory section. Must be
4663 * non-NULL for a page-file backed section.
4664 * If value specified for a mapped file and the file is
4665 * not large enough, file will be extended.
4667 * SectionPageProtection
4668 * Can be a combination of:
4674 * AllocationAttributes
4675 * Can be a combination of:
4680 * Handle to a file to create a section mapped to a file
4681 * instead of a memory backed section;
4692 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4693 IN ACCESS_MASK DesiredAccess
,
4694 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4695 IN PLARGE_INTEGER MaximumSize
,
4696 IN ULONG SectionPageProtection
,
4697 IN ULONG AllocationAttributes
,
4698 IN HANDLE FileHandle OPTIONAL
,
4699 IN PFILE_OBJECT File OPTIONAL
)
4701 if (AllocationAttributes
& SEC_IMAGE
)
4703 return(MmCreateImageSection(SectionObject
,
4707 SectionPageProtection
,
4708 AllocationAttributes
,
4712 if (FileHandle
!= NULL
)
4714 return(MmCreateDataFileSection(SectionObject
,
4718 SectionPageProtection
,
4719 AllocationAttributes
,
4723 return(MmCreatePageFileSection(SectionObject
,
4727 SectionPageProtection
,
4728 AllocationAttributes
));