3 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/mm/section.c
22 * PURPOSE: Implements section objects
24 * PROGRAMMERS: Rex Jolliff
38 * Thomas Weidenmueller
39 * Gunnar Andre' Dalsnes
47 /* INCLUDES *****************************************************************/
51 #include <internal/debug.h>
52 #include <reactos/exeformat.h>
54 #if defined (ALLOC_PRAGMA)
55 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
56 #pragma alloc_text(INIT, MmInitSectionImplementation)
60 /* TYPES *********************************************************************/
64 PSECTION_OBJECT Section
;
65 PMM_SECTION_SEGMENT Segment
;
70 MM_SECTION_PAGEOUT_CONTEXT
;
72 /* GLOBALS *******************************************************************/
74 POBJECT_TYPE MmSectionObjectType
= NULL
;
76 static GENERIC_MAPPING MmpSectionMapping
= {
77 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
78 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
79 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
82 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
83 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
84 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
85 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
86 #define MAX_SHARE_COUNT 0x7FF
87 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
88 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
89 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
91 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
93 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
94 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
97 /* FUNCTIONS *****************************************************************/
99 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
102 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
103 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
104 * RETURNS: Status of the wait.
107 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
109 LARGE_INTEGER Timeout
;
110 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
112 Timeout
.QuadPart
= -100000000LL; // 10 sec
115 Timeout
.QuadPart
= -100000000; // 10 sec
118 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
123 * FUNCTION: Sets the page op completion event and releases the page op.
124 * ARGUMENTS: PMM_PAGEOP.
125 * RETURNS: In shorter time than it takes you to even read this
126 * description, so don't even think about geting a mug of coffee.
129 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
131 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
132 MmReleasePageOp(PageOp
);
137 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
138 * ARGUMENTS: PFILE_OBJECT to wait for.
139 * RETURNS: Status of the wait.
142 MmspWaitForFileLock(PFILE_OBJECT File
)
144 return KeWaitForSingleObject(&File
->Lock
, 0, KernelMode
, FALSE
, NULL
);
149 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
152 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
154 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
156 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
158 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
166 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
168 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
170 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
171 PMM_SECTION_SEGMENT SectionSegments
;
175 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
176 NrSegments
= ImageSectionObject
->NrSegments
;
177 SectionSegments
= ImageSectionObject
->Segments
;
178 for (i
= 0; i
< NrSegments
; i
++)
180 if (SectionSegments
[i
].ReferenceCount
!= 0)
182 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
183 SectionSegments
[i
].ReferenceCount
);
186 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
188 ExFreePool(ImageSectionObject
->Segments
);
189 ExFreePool(ImageSectionObject
);
190 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
192 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
194 PMM_SECTION_SEGMENT Segment
;
196 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
199 if (Segment
->ReferenceCount
!= 0)
201 DPRINT1("Data segment still referenced\n");
204 MmFreePageTablesSectionSegment(Segment
);
206 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
212 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
214 ExAcquireFastMutex(&Segment
->Lock
);
219 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
221 ExReleaseFastMutex(&Segment
->Lock
);
226 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
230 PSECTION_PAGE_TABLE Table
;
231 ULONG DirectoryOffset
;
234 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
236 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
240 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
241 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
245 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
246 ExAllocatePoolWithTag(PagedPool
, sizeof(SECTION_PAGE_TABLE
),
247 TAG_SECTION_PAGE_TABLE
);
252 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
253 DPRINT("Table %x\n", Table
);
256 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
257 Table
->Entry
[TableOffset
] = Entry
;
263 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
266 PSECTION_PAGE_TABLE Table
;
268 ULONG DirectoryOffset
;
271 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
273 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
275 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
279 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
280 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
281 DPRINT("Table %x\n", Table
);
287 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
288 Entry
= Table
->Entry
[TableOffset
];
294 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
299 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
302 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
305 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
307 DPRINT1("Maximum share count reached\n");
310 if (IS_SWAP_FROM_SSE(Entry
))
314 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
315 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
320 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section
,
321 PMM_SECTION_SEGMENT Segment
,
327 BOOLEAN IsDirectMapped
= FALSE
;
329 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
332 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
335 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
337 DPRINT1("Zero share count for unshare\n");
340 if (IS_SWAP_FROM_SSE(Entry
))
344 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
346 * If we reducing the share count of this entry to zero then set the entry
347 * to zero and tell the cache the page is no longer mapped.
349 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
351 PFILE_OBJECT FileObject
;
353 SWAPENTRY SavedSwapEntry
;
355 BOOLEAN IsImageSection
;
358 FileOffset
= Offset
+ Segment
->FileOffset
;
360 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
362 Page
= PFN_FROM_SSE(Entry
);
363 FileObject
= Section
->FileObject
;
364 if (FileObject
!= NULL
&&
365 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
368 if ((FileOffset
% PAGE_SIZE
) == 0 &&
369 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
372 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
373 IsDirectMapped
= TRUE
;
374 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
375 if (!NT_SUCCESS(Status
))
377 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
383 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
384 if (SavedSwapEntry
== 0)
387 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
388 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
392 * Try to page out this page and set the swap entry
393 * within the section segment. There exist no rmap entry
394 * for this page. The pager thread can't page out a
395 * page without a rmap entry.
397 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
401 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
404 MmReleasePageMemoryConsumer(MC_USER
, Page
);
410 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
411 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
419 * We hold all locks. Nobody can do something with the current
420 * process and the current segment (also not within an other process).
423 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
424 if (!NT_SUCCESS(Status
))
426 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
430 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
431 MmSetSavedSwapEntryPage(Page
, 0);
433 MmReleasePageMemoryConsumer(MC_USER
, Page
);
437 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
444 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
446 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
449 BOOL
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
452 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
455 PCACHE_SEGMENT CacheSeg
;
456 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
457 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
460 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
469 MiReadPage(PMEMORY_AREA MemoryArea
,
473 * FUNCTION: Read a page for a section backed memory area.
475 * MemoryArea - Memory area to read the page for.
476 * Offset - Offset of the page to read.
477 * Page - Variable that receives a page contains the read data.
484 PCACHE_SEGMENT CacheSeg
;
485 PFILE_OBJECT FileObject
;
489 BOOLEAN IsImageSection
;
492 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
493 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
494 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
495 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
496 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
500 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
503 * If the file system is letting us go directly to the cache and the
504 * memory area was mapped at an offset in the file which is page aligned
505 * then get the related cache segment.
507 if ((FileOffset
% PAGE_SIZE
) == 0 &&
508 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
509 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
513 * Get the related cache segment; we use a lower level interface than
514 * filesystems do because it is safe for us to use an offset with a
515 * alignment less than the file system block size.
517 Status
= CcRosGetCacheSegment(Bcb
,
523 if (!NT_SUCCESS(Status
))
530 * If the cache segment isn't up to date then call the file
531 * system to read in the data.
533 Status
= ReadCacheSegment(CacheSeg
);
534 if (!NT_SUCCESS(Status
))
536 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
541 * Retrieve the page from the cache segment that we actually want.
543 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
544 FileOffset
- BaseOffset
).QuadPart
>> PAGE_SHIFT
;
546 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
551 ULONG CacheSegOffset
;
553 * Allocate a page, this is rather complicated by the possibility
554 * we might have to move other things out of memory
556 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
557 if (!NT_SUCCESS(Status
))
561 Status
= CcRosGetCacheSegment(Bcb
,
567 if (!NT_SUCCESS(Status
))
574 * If the cache segment isn't up to date then call the file
575 * system to read in the data.
577 Status
= ReadCacheSegment(CacheSeg
);
578 if (!NT_SUCCESS(Status
))
580 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
584 PageAddr
= MmCreateHyperspaceMapping(*Page
);
585 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
586 Length
= RawLength
- SegOffset
;
587 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
589 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
591 else if (CacheSegOffset
>= PAGE_SIZE
)
593 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
597 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
598 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
599 Status
= CcRosGetCacheSegment(Bcb
,
600 FileOffset
+ CacheSegOffset
,
605 if (!NT_SUCCESS(Status
))
607 MmDeleteHyperspaceMapping(PageAddr
);
613 * If the cache segment isn't up to date then call the file
614 * system to read in the data.
616 Status
= ReadCacheSegment(CacheSeg
);
617 if (!NT_SUCCESS(Status
))
619 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
620 MmDeleteHyperspaceMapping(PageAddr
);
624 if (Length
< PAGE_SIZE
)
626 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
630 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
633 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
634 MmDeleteHyperspaceMapping(PageAddr
);
636 return(STATUS_SUCCESS
);
641 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
642 MEMORY_AREA
* MemoryArea
,
650 PSECTION_OBJECT Section
;
651 PMM_SECTION_SEGMENT Segment
;
660 * There is a window between taking the page fault and locking the
661 * address space when another thread could load the page so we check
664 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
668 MmLockPage(MmGetPfnForProcess(AddressSpace
->Process
, Address
));
670 return(STATUS_SUCCESS
);
673 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
674 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
675 + MemoryArea
->Data
.SectionData
.ViewOffset
;
677 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
678 Section
= MemoryArea
->Data
.SectionData
.Section
;
679 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
680 &MemoryArea
->Data
.SectionData
.RegionListHead
,
685 MmLockSectionSegment(Segment
);
688 * Check if this page needs to be mapped COW
690 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
691 (Region
->Protect
== PAGE_READWRITE
||
692 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
694 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
698 Attributes
= Region
->Protect
;
702 * Get or create a page operation descriptor
704 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
707 DPRINT1("MmGetPageOp failed\n");
712 * Check if someone else is already handling this fault, if so wait
715 if (PageOp
->Thread
!= PsGetCurrentThread())
717 MmUnlockSectionSegment(Segment
);
718 MmUnlockAddressSpace(AddressSpace
);
719 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
721 * Check for various strange conditions
723 if (Status
!= STATUS_SUCCESS
)
725 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
728 if (PageOp
->Status
== STATUS_PENDING
)
730 DPRINT1("Woke for page op before completion\n");
733 MmLockAddressSpace(AddressSpace
);
735 * If this wasn't a pagein then restart the operation
737 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
739 MmspCompleteAndReleasePageOp(PageOp
);
740 DPRINT("Address 0x%.8X\n", Address
);
741 return(STATUS_MM_RESTART_OPERATION
);
745 * If the thread handling this fault has failed then we don't retry
747 if (!NT_SUCCESS(PageOp
->Status
))
749 Status
= PageOp
->Status
;
750 MmspCompleteAndReleasePageOp(PageOp
);
751 DPRINT("Address 0x%.8X\n", Address
);
754 MmLockSectionSegment(Segment
);
756 * If the completed fault was for another address space then set the
759 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
761 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
762 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
764 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
767 * The page was a private page in another or in our address space
769 MmUnlockSectionSegment(Segment
);
770 MmspCompleteAndReleasePageOp(PageOp
);
771 return(STATUS_MM_RESTART_OPERATION
);
774 Page
= PFN_FROM_SSE(Entry
);
776 MmSharePageEntrySectionSegment(Segment
, Offset
);
778 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
779 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
781 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
786 if (!NT_SUCCESS(Status
))
788 DbgPrint("Unable to create virtual mapping\n");
791 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
797 MmUnlockSectionSegment(Segment
);
798 PageOp
->Status
= STATUS_SUCCESS
;
799 MmspCompleteAndReleasePageOp(PageOp
);
800 DPRINT("Address 0x%.8X\n", Address
);
801 return(STATUS_SUCCESS
);
804 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
808 * Must be private page we have swapped out.
815 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
817 DPRINT1("Found a swaped out private page in a pagefile section.\n");
821 MmUnlockSectionSegment(Segment
);
822 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
824 MmUnlockAddressSpace(AddressSpace
);
825 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
826 if (!NT_SUCCESS(Status
))
831 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
832 if (!NT_SUCCESS(Status
))
834 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
837 MmLockAddressSpace(AddressSpace
);
838 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
843 if (!NT_SUCCESS(Status
))
845 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
851 * Store the swap entry for later use.
853 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
856 * Add the page to the process's working set
858 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
861 * Finish the operation
867 PageOp
->Status
= STATUS_SUCCESS
;
868 MmspCompleteAndReleasePageOp(PageOp
);
869 DPRINT("Address 0x%.8X\n", Address
);
870 return(STATUS_SUCCESS
);
874 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
876 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
878 MmUnlockSectionSegment(Segment
);
880 * Just map the desired physical page
882 Page
= Offset
>> PAGE_SHIFT
;
883 Status
= MmCreateVirtualMappingUnsafe(AddressSpace
->Process
,
888 if (!NT_SUCCESS(Status
))
890 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
895 * Don't add an rmap entry since the page mapped could be for
900 MmLockPageUnsafe(Page
);
904 * Cleanup and release locks
906 PageOp
->Status
= STATUS_SUCCESS
;
907 MmspCompleteAndReleasePageOp(PageOp
);
908 DPRINT("Address 0x%.8X\n", Address
);
909 return(STATUS_SUCCESS
);
913 * Map anonymous memory for BSS sections
915 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
917 MmUnlockSectionSegment(Segment
);
918 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
919 if (!NT_SUCCESS(Status
))
921 MmUnlockAddressSpace(AddressSpace
);
922 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
923 MmLockAddressSpace(AddressSpace
);
925 if (!NT_SUCCESS(Status
))
929 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
934 if (!NT_SUCCESS(Status
))
936 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
940 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
947 * Cleanup and release locks
949 PageOp
->Status
= STATUS_SUCCESS
;
950 MmspCompleteAndReleasePageOp(PageOp
);
951 DPRINT("Address 0x%.8X\n", Address
);
952 return(STATUS_SUCCESS
);
956 * Get the entry corresponding to the offset within the section
958 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
963 * If the entry is zero (and it can't change because we have
964 * locked the segment) then we need to load the page.
968 * Release all our locks and read in the page from disk
970 MmUnlockSectionSegment(Segment
);
971 MmUnlockAddressSpace(AddressSpace
);
973 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
974 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
976 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
977 if (!NT_SUCCESS(Status
))
979 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
984 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
985 if (!NT_SUCCESS(Status
))
987 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
990 if (!NT_SUCCESS(Status
))
993 * FIXME: What do we know in this case?
996 * Cleanup and release locks
998 MmLockAddressSpace(AddressSpace
);
999 PageOp
->Status
= Status
;
1000 MmspCompleteAndReleasePageOp(PageOp
);
1001 DPRINT("Address 0x%.8X\n", Address
);
1005 * Relock the address space and segment
1007 MmLockAddressSpace(AddressSpace
);
1008 MmLockSectionSegment(Segment
);
1011 * Check the entry. No one should change the status of a page
1012 * that has a pending page-in.
1014 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1015 if (Entry
!= Entry1
)
1017 DbgPrint("Someone changed ppte entry while we slept\n");
1022 * Mark the offset within the section as having valid, in-memory
1025 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1026 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1027 MmUnlockSectionSegment(Segment
);
1029 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1034 if (!NT_SUCCESS(Status
))
1036 DbgPrint("Unable to create virtual mapping\n");
1039 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1045 PageOp
->Status
= STATUS_SUCCESS
;
1046 MmspCompleteAndReleasePageOp(PageOp
);
1047 DPRINT("Address 0x%.8X\n", Address
);
1048 return(STATUS_SUCCESS
);
1050 else if (IS_SWAP_FROM_SSE(Entry
))
1052 SWAPENTRY SwapEntry
;
1054 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1057 * Release all our locks and read in the page from disk
1059 MmUnlockSectionSegment(Segment
);
1061 MmUnlockAddressSpace(AddressSpace
);
1063 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1064 if (!NT_SUCCESS(Status
))
1069 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1070 if (!NT_SUCCESS(Status
))
1076 * Relock the address space and segment
1078 MmLockAddressSpace(AddressSpace
);
1079 MmLockSectionSegment(Segment
);
1082 * Check the entry. No one should change the status of a page
1083 * that has a pending page-in.
1085 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1086 if (Entry
!= Entry1
)
1088 DbgPrint("Someone changed ppte entry while we slept\n");
1093 * Mark the offset within the section as having valid, in-memory
1096 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1097 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1098 MmUnlockSectionSegment(Segment
);
1101 * Save the swap entry.
1103 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1104 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1109 if (!NT_SUCCESS(Status
))
1111 DbgPrint("Unable to create virtual mapping\n");
1114 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1119 PageOp
->Status
= STATUS_SUCCESS
;
1120 MmspCompleteAndReleasePageOp(PageOp
);
1121 DPRINT("Address 0x%.8X\n", Address
);
1122 return(STATUS_SUCCESS
);
1127 * If the section offset is already in-memory and valid then just
1128 * take another reference to the page
1131 Page
= PFN_FROM_SSE(Entry
);
1133 MmSharePageEntrySectionSegment(Segment
, Offset
);
1134 MmUnlockSectionSegment(Segment
);
1136 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1141 if (!NT_SUCCESS(Status
))
1143 DbgPrint("Unable to create virtual mapping\n");
1146 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1151 PageOp
->Status
= STATUS_SUCCESS
;
1152 MmspCompleteAndReleasePageOp(PageOp
);
1153 DPRINT("Address 0x%.8X\n", Address
);
1154 return(STATUS_SUCCESS
);
1160 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1161 MEMORY_AREA
* MemoryArea
,
1165 PMM_SECTION_SEGMENT Segment
;
1166 PSECTION_OBJECT Section
;
1177 * Check if the page has been paged out or has already been set readwrite
1179 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1180 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1182 DPRINT("Address 0x%.8X\n", Address
);
1183 return(STATUS_SUCCESS
);
1187 * Find the offset of the page
1189 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1190 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1191 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1193 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1194 Section
= MemoryArea
->Data
.SectionData
.Section
;
1195 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1196 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1201 MmLockSectionSegment(Segment
);
1203 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1204 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1206 MmUnlockSectionSegment(Segment
);
1209 * Check if we are doing COW
1211 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1212 (Region
->Protect
== PAGE_READWRITE
||
1213 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1215 DPRINT("Address 0x%.8X\n", Address
);
1216 return(STATUS_UNSUCCESSFUL
);
1219 if (IS_SWAP_FROM_SSE(Entry
) ||
1220 PFN_FROM_SSE(Entry
) != OldPage
)
1222 /* This is a private page. We must only change the page protection. */
1223 MmSetPageProtect(AddressSpace
->Process
, PAddress
, Region
->Protect
);
1224 return(STATUS_SUCCESS
);
1228 * Get or create a pageop
1230 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1231 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1234 DPRINT1("MmGetPageOp failed\n");
1239 * Wait for any other operations to complete
1241 if (PageOp
->Thread
!= PsGetCurrentThread())
1243 MmUnlockAddressSpace(AddressSpace
);
1244 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1246 * Check for various strange conditions
1248 if (Status
== STATUS_TIMEOUT
)
1250 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1253 if (PageOp
->Status
== STATUS_PENDING
)
1255 DPRINT1("Woke for page op before completion\n");
1259 * Restart the operation
1261 MmLockAddressSpace(AddressSpace
);
1262 MmspCompleteAndReleasePageOp(PageOp
);
1263 DPRINT("Address 0x%.8X\n", Address
);
1264 return(STATUS_MM_RESTART_OPERATION
);
1268 * Release locks now we have the pageop
1270 MmUnlockAddressSpace(AddressSpace
);
1275 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1276 if (!NT_SUCCESS(Status
))
1284 MiCopyFromUserPage(NewPage
, PAddress
);
1286 MmLockAddressSpace(AddressSpace
);
1288 * Delete the old entry.
1290 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1293 * Set the PTE to point to the new page
1295 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1300 if (!NT_SUCCESS(Status
))
1302 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1306 if (!NT_SUCCESS(Status
))
1308 DbgPrint("Unable to create virtual mapping\n");
1313 MmLockPage(NewPage
);
1314 MmUnlockPage(OldPage
);
1318 * Unshare the old page.
1320 MmDeleteRmap(OldPage
, AddressSpace
->Process
, PAddress
);
1321 MmInsertRmap(NewPage
, AddressSpace
->Process
, PAddress
);
1322 MmLockSectionSegment(Segment
);
1323 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1324 MmUnlockSectionSegment(Segment
);
1326 PageOp
->Status
= STATUS_SUCCESS
;
1327 MmspCompleteAndReleasePageOp(PageOp
);
1328 DPRINT("Address 0x%.8X\n", Address
);
1329 return(STATUS_SUCCESS
);
1333 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1335 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1339 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1342 MmLockAddressSpace(&Process
->AddressSpace
);
1345 MmDeleteVirtualMapping(Process
,
1352 PageOutContext
->WasDirty
= TRUE
;
1354 if (!PageOutContext
->Private
)
1356 MmLockSectionSegment(PageOutContext
->Segment
);
1357 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1358 PageOutContext
->Segment
,
1359 PageOutContext
->Offset
,
1360 PageOutContext
->WasDirty
,
1362 MmUnlockSectionSegment(PageOutContext
->Segment
);
1366 MmUnlockAddressSpace(&Process
->AddressSpace
);
1369 if (PageOutContext
->Private
)
1371 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1374 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1379 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1380 MEMORY_AREA
* MemoryArea
,
1385 MM_SECTION_PAGEOUT_CONTEXT Context
;
1386 SWAPENTRY SwapEntry
;
1390 PFILE_OBJECT FileObject
;
1392 BOOLEAN DirectMapped
;
1393 BOOLEAN IsImageSection
;
1395 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1398 * Get the segment and section.
1400 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1401 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1403 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1404 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1405 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1407 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1409 FileObject
= Context
.Section
->FileObject
;
1410 DirectMapped
= FALSE
;
1411 if (FileObject
!= NULL
&&
1412 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1414 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1417 * If the file system is letting us go directly to the cache and the
1418 * memory area was mapped at an offset in the file which is page aligned
1419 * then note this is a direct mapped page.
1421 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1422 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1424 DirectMapped
= TRUE
;
1430 * This should never happen since mappings of physical memory are never
1431 * placed in the rmap lists.
1433 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1435 DPRINT1("Trying to page out from physical memory section address 0x%X "
1436 "process %d\n", Address
,
1437 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1442 * Get the section segment entry and the physical address.
1444 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1445 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1447 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1448 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1451 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1452 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1455 * Prepare the context structure for the rmap delete call.
1457 Context
.WasDirty
= FALSE
;
1458 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1459 IS_SWAP_FROM_SSE(Entry
) ||
1460 PFN_FROM_SSE(Entry
) != Page
)
1462 Context
.Private
= TRUE
;
1466 Context
.Private
= FALSE
;
1470 * Take an additional reference to the page or the cache segment.
1472 if (DirectMapped
&& !Context
.Private
)
1474 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1476 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1482 MmReferencePage(Page
);
1485 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1488 * If this wasn't a private page then we should have reduced the entry to
1489 * zero by deleting all the rmaps.
1491 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1493 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1494 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1501 * If the page wasn't dirty then we can just free it as for a readonly page.
1502 * Since we unmapped all the mappings above we know it will not suddenly
1504 * If the page is from a pagefile section and has no swap entry,
1505 * we can't free the page at this point.
1507 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1508 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1510 if (Context
.Private
)
1512 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1513 Context
.WasDirty
? "dirty" : "clean", Address
);
1516 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1518 MmSetSavedSwapEntryPage(Page
, 0);
1519 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1520 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1521 PageOp
->Status
= STATUS_SUCCESS
;
1522 MmspCompleteAndReleasePageOp(PageOp
);
1523 return(STATUS_SUCCESS
);
1526 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1528 if (Context
.Private
)
1530 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1531 Context
.WasDirty
? "dirty" : "clean", Address
);
1534 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1536 MmSetSavedSwapEntryPage(Page
, 0);
1539 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1541 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1542 PageOp
->Status
= STATUS_SUCCESS
;
1543 MmspCompleteAndReleasePageOp(PageOp
);
1544 return(STATUS_SUCCESS
);
1547 else if (!Context
.Private
&& DirectMapped
)
1551 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1555 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1556 if (!NT_SUCCESS(Status
))
1558 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1561 PageOp
->Status
= STATUS_SUCCESS
;
1562 MmspCompleteAndReleasePageOp(PageOp
);
1563 return(STATUS_SUCCESS
);
1565 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1569 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1573 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1574 PageOp
->Status
= STATUS_SUCCESS
;
1575 MmspCompleteAndReleasePageOp(PageOp
);
1576 return(STATUS_SUCCESS
);
1578 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1580 MmSetSavedSwapEntryPage(Page
, 0);
1581 MmLockAddressSpace(AddressSpace
);
1582 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1585 MmUnlockAddressSpace(AddressSpace
);
1586 if (!NT_SUCCESS(Status
))
1590 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1591 PageOp
->Status
= STATUS_SUCCESS
;
1592 MmspCompleteAndReleasePageOp(PageOp
);
1593 return(STATUS_SUCCESS
);
1597 * If necessary, allocate an entry in the paging file for this page
1601 SwapEntry
= MmAllocSwapPage();
1604 MmShowOutOfSpaceMessagePagingFile();
1605 MmLockAddressSpace(AddressSpace
);
1607 * For private pages restore the old mappings.
1609 if (Context
.Private
)
1611 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1613 MemoryArea
->Protect
,
1616 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1618 AddressSpace
->Process
,
1624 * For non-private pages if the page wasn't direct mapped then
1625 * set it back into the section segment entry so we don't loose
1626 * our copy. Otherwise it will be handled by the cache manager.
1628 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1630 MemoryArea
->Protect
,
1633 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1635 AddressSpace
->Process
,
1637 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1638 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1640 MmUnlockAddressSpace(AddressSpace
);
1641 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1642 MmspCompleteAndReleasePageOp(PageOp
);
1643 return(STATUS_PAGEFILE_QUOTA
);
1648 * Write the page to the pagefile
1650 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1651 if (!NT_SUCCESS(Status
))
1653 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1656 * As above: undo our actions.
1657 * FIXME: Also free the swap page.
1659 MmLockAddressSpace(AddressSpace
);
1660 if (Context
.Private
)
1662 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1664 MemoryArea
->Protect
,
1667 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1669 AddressSpace
->Process
,
1674 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1676 MemoryArea
->Protect
,
1679 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1681 AddressSpace
->Process
,
1683 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1684 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1686 MmUnlockAddressSpace(AddressSpace
);
1687 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1688 MmspCompleteAndReleasePageOp(PageOp
);
1689 return(STATUS_UNSUCCESSFUL
);
1693 * Otherwise we have succeeded.
1695 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1696 MmSetSavedSwapEntryPage(Page
, 0);
1697 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1698 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1700 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1704 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1707 if (Context
.Private
)
1709 MmLockAddressSpace(AddressSpace
);
1710 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1713 MmUnlockAddressSpace(AddressSpace
);
1714 if (!NT_SUCCESS(Status
))
1721 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1722 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1725 PageOp
->Status
= STATUS_SUCCESS
;
1726 MmspCompleteAndReleasePageOp(PageOp
);
1727 return(STATUS_SUCCESS
);
1732 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1733 PMEMORY_AREA MemoryArea
,
1738 PSECTION_OBJECT Section
;
1739 PMM_SECTION_SEGMENT Segment
;
1741 SWAPENTRY SwapEntry
;
1745 PFILE_OBJECT FileObject
;
1747 BOOLEAN DirectMapped
;
1748 BOOLEAN IsImageSection
;
1750 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1752 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1753 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1756 * Get the segment and section.
1758 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1759 Section
= MemoryArea
->Data
.SectionData
.Section
;
1760 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1762 FileObject
= Section
->FileObject
;
1763 DirectMapped
= FALSE
;
1764 if (FileObject
!= NULL
&&
1765 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1767 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1770 * If the file system is letting us go directly to the cache and the
1771 * memory area was mapped at an offset in the file which is page aligned
1772 * then note this is a direct mapped page.
1774 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1775 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1777 DirectMapped
= TRUE
;
1782 * This should never happen since mappings of physical memory are never
1783 * placed in the rmap lists.
1785 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1787 DPRINT1("Trying to write back page from physical memory mapped at %X "
1788 "process %d\n", Address
,
1789 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1794 * Get the section segment entry and the physical address.
1796 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1797 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1799 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1800 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1803 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1804 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1807 * Check for a private (COWed) page.
1809 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1810 IS_SWAP_FROM_SSE(Entry
) ||
1811 PFN_FROM_SSE(Entry
) != Page
)
1821 * Speculatively set all mappings of the page to clean.
1823 MmSetCleanAllRmaps(Page
);
1826 * If this page was direct mapped from the cache then the cache manager
1827 * will take care of writing it back to disk.
1829 if (DirectMapped
&& !Private
)
1831 ASSERT(SwapEntry
== 0);
1832 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1833 PageOp
->Status
= STATUS_SUCCESS
;
1834 MmspCompleteAndReleasePageOp(PageOp
);
1835 return(STATUS_SUCCESS
);
1839 * If necessary, allocate an entry in the paging file for this page
1843 SwapEntry
= MmAllocSwapPage();
1846 MmSetDirtyAllRmaps(Page
);
1847 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1848 MmspCompleteAndReleasePageOp(PageOp
);
1849 return(STATUS_PAGEFILE_QUOTA
);
1851 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1855 * Write the page to the pagefile
1857 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1858 if (!NT_SUCCESS(Status
))
1860 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1862 MmSetDirtyAllRmaps(Page
);
1863 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1864 MmspCompleteAndReleasePageOp(PageOp
);
1865 return(STATUS_UNSUCCESSFUL
);
1869 * Otherwise we have succeeded.
1871 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1872 PageOp
->Status
= STATUS_SUCCESS
;
1873 MmspCompleteAndReleasePageOp(PageOp
);
1874 return(STATUS_SUCCESS
);
1878 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1886 PMEMORY_AREA MemoryArea
;
1887 PMM_SECTION_SEGMENT Segment
;
1891 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1892 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1894 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1895 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1900 if (OldProtect
!= NewProtect
)
1902 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1904 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1905 ULONG Protect
= NewProtect
;
1908 * If we doing COW for this segment then check if the page is
1911 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1917 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1918 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1919 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1920 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1922 Protect
= PAGE_READONLY
;
1923 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1924 IS_SWAP_FROM_SSE(Entry
) ||
1925 PFN_FROM_SSE(Entry
) != Page
)
1927 Protect
= NewProtect
;
1931 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1933 MmSetPageProtect(AddressSpace
->Process
, Address
,
1942 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1943 PMEMORY_AREA MemoryArea
,
1951 ULONG_PTR MaxLength
;
1953 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
1954 if (Length
> MaxLength
)
1957 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1958 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1960 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
1961 Region
->Protect
!= Protect
)
1964 return STATUS_INVALID_PAGE_PROTECTION
;
1967 *OldProtect
= Region
->Protect
;
1968 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
1969 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1970 BaseAddress
, Length
, Region
->Type
, Protect
,
1971 MmAlterViewAttributes
);
1977 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
1979 PMEMORY_BASIC_INFORMATION Info
,
1980 PULONG ResultLength
)
1983 PVOID RegionBaseAddress
;
1984 PSECTION_OBJECT Section
;
1985 PMM_SECTION_SEGMENT Segment
;
1987 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
1988 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1989 Address
, &RegionBaseAddress
);
1992 return STATUS_UNSUCCESSFUL
;
1995 Section
= MemoryArea
->Data
.SectionData
.Section
;
1996 if (Section
->AllocationAttributes
& SEC_IMAGE
)
1998 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1999 Info
->AllocationBase
= (PBYTE
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2000 Info
->Type
= MEM_IMAGE
;
2004 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2005 Info
->Type
= MEM_MAPPED
;
2007 Info
->BaseAddress
= RegionBaseAddress
;
2008 Info
->AllocationProtect
= MemoryArea
->Protect
;
2009 Info
->RegionSize
= Region
->Length
;
2010 Info
->State
= MEM_COMMIT
;
2011 Info
->Protect
= Region
->Protect
;
2013 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2014 return(STATUS_SUCCESS
);
2019 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2024 ULONG SavedSwapEntry
;
2029 Length
= PAGE_ROUND_UP(Segment
->Length
);
2030 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2032 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2035 if (IS_SWAP_FROM_SSE(Entry
))
2037 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2041 Page
= PFN_FROM_SSE(Entry
);
2042 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2043 if (SavedSwapEntry
!= 0)
2045 MmSetSavedSwapEntryPage(Page
, 0);
2046 MmFreeSwapPage(SavedSwapEntry
);
2048 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2050 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2056 MmpDeleteSection(PVOID ObjectBody
)
2058 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
2060 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2061 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2066 PMM_SECTION_SEGMENT SectionSegments
;
2069 * NOTE: Section->ImageSection can be NULL for short time
2070 * during the section creating. If we fail for some reason
2071 * until the image section is properly initialized we shouldn't
2072 * process further here.
2074 if (Section
->ImageSection
== NULL
)
2077 SectionSegments
= Section
->ImageSection
->Segments
;
2078 NrSegments
= Section
->ImageSection
->NrSegments
;
2080 for (i
= 0; i
< NrSegments
; i
++)
2082 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2084 MmLockSectionSegment(&SectionSegments
[i
]);
2086 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2087 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2091 MmpFreePageFileSegment(&SectionSegments
[i
]);
2093 MmUnlockSectionSegment(&SectionSegments
[i
]);
2100 * NOTE: Section->Segment can be NULL for short time
2101 * during the section creating.
2103 if (Section
->Segment
== NULL
)
2106 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2108 MmpFreePageFileSegment(Section
->Segment
);
2109 MmFreePageTablesSectionSegment(Section
->Segment
);
2110 ExFreePool(Section
->Segment
);
2111 Section
->Segment
= NULL
;
2115 InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2118 if (Section
->FileObject
!= NULL
)
2120 CcRosDereferenceCache(Section
->FileObject
);
2121 ObDereferenceObject(Section
->FileObject
);
2122 Section
->FileObject
= NULL
;
2127 MmpCloseSection(PVOID ObjectBody
,
2130 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2131 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2137 MmCreatePhysicalMemorySection(VOID
)
2139 PSECTION_OBJECT PhysSection
;
2141 OBJECT_ATTRIBUTES Obj
;
2142 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2143 LARGE_INTEGER SectionSize
;
2146 * Create the section mapping physical memory
2148 SectionSize
.QuadPart
= 0xFFFFFFFF;
2149 InitializeObjectAttributes(&Obj
,
2154 Status
= MmCreateSection(&PhysSection
,
2158 PAGE_EXECUTE_READWRITE
,
2162 if (!NT_SUCCESS(Status
))
2164 DbgPrint("Failed to create PhysicalMemory section\n");
2167 Status
= ObInsertObject(PhysSection
,
2173 if (!NT_SUCCESS(Status
))
2175 ObDereferenceObject(PhysSection
);
2177 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2178 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2180 return(STATUS_SUCCESS
);
2186 MmInitSectionImplementation(VOID
)
2188 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2189 UNICODE_STRING Name
;
2191 DPRINT("Creating Section Object Type\n");
2193 /* Initialize the Section object type */
2194 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2195 RtlInitUnicodeString(&Name
, L
"Section");
2196 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2197 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(SECTION_OBJECT
);
2198 ObjectTypeInitializer
.PoolType
= PagedPool
;
2199 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2200 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2201 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2202 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2203 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &MmSectionObjectType
);
2205 return(STATUS_SUCCESS
);
2210 MmCreatePageFileSection(PSECTION_OBJECT
*SectionObject
,
2211 ACCESS_MASK DesiredAccess
,
2212 POBJECT_ATTRIBUTES ObjectAttributes
,
2213 PLARGE_INTEGER UMaximumSize
,
2214 ULONG SectionPageProtection
,
2215 ULONG AllocationAttributes
)
2217 * Create a section which is backed by the pagefile
2220 LARGE_INTEGER MaximumSize
;
2221 PSECTION_OBJECT Section
;
2222 PMM_SECTION_SEGMENT Segment
;
2225 if (UMaximumSize
== NULL
)
2227 return(STATUS_UNSUCCESSFUL
);
2229 MaximumSize
= *UMaximumSize
;
2232 * Create the section
2234 Status
= ObCreateObject(ExGetPreviousMode(),
2235 MmSectionObjectType
,
2237 ExGetPreviousMode(),
2239 sizeof(SECTION_OBJECT
),
2242 (PVOID
*)(PVOID
)&Section
);
2243 if (!NT_SUCCESS(Status
))
2251 Section
->SectionPageProtection
= SectionPageProtection
;
2252 Section
->AllocationAttributes
= AllocationAttributes
;
2253 Section
->Segment
= NULL
;
2254 Section
->FileObject
= NULL
;
2255 Section
->MaximumSize
= MaximumSize
;
2256 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2257 TAG_MM_SECTION_SEGMENT
);
2258 if (Segment
== NULL
)
2260 ObDereferenceObject(Section
);
2261 return(STATUS_NO_MEMORY
);
2263 Section
->Segment
= Segment
;
2264 Segment
->ReferenceCount
= 1;
2265 ExInitializeFastMutex(&Segment
->Lock
);
2266 Segment
->FileOffset
= 0;
2267 Segment
->Protection
= SectionPageProtection
;
2268 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2269 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2270 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2271 Segment
->WriteCopy
= FALSE
;
2272 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2273 Segment
->VirtualAddress
= 0;
2274 Segment
->Characteristics
= 0;
2275 *SectionObject
= Section
;
2276 return(STATUS_SUCCESS
);
2282 MmCreateDataFileSection(PSECTION_OBJECT
*SectionObject
,
2283 ACCESS_MASK DesiredAccess
,
2284 POBJECT_ATTRIBUTES ObjectAttributes
,
2285 PLARGE_INTEGER UMaximumSize
,
2286 ULONG SectionPageProtection
,
2287 ULONG AllocationAttributes
,
2290 * Create a section backed by a data file
2293 PSECTION_OBJECT Section
;
2295 LARGE_INTEGER MaximumSize
;
2296 PFILE_OBJECT FileObject
;
2297 PMM_SECTION_SEGMENT Segment
;
2299 IO_STATUS_BLOCK Iosb
;
2300 LARGE_INTEGER Offset
;
2302 FILE_STANDARD_INFORMATION FileInfo
;
2305 * Create the section
2307 Status
= ObCreateObject(ExGetPreviousMode(),
2308 MmSectionObjectType
,
2310 ExGetPreviousMode(),
2312 sizeof(SECTION_OBJECT
),
2315 (PVOID
*)(PVOID
)&Section
);
2316 if (!NT_SUCCESS(Status
))
2323 Section
->SectionPageProtection
= SectionPageProtection
;
2324 Section
->AllocationAttributes
= AllocationAttributes
;
2325 Section
->Segment
= NULL
;
2328 * Check file access required
2330 if (SectionPageProtection
& PAGE_READWRITE
||
2331 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2333 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2337 FileAccess
= FILE_READ_DATA
;
2341 * Reference the file handle
2343 Status
= ObReferenceObjectByHandle(FileHandle
,
2347 (PVOID
*)(PVOID
)&FileObject
,
2349 if (!NT_SUCCESS(Status
))
2351 ObDereferenceObject(Section
);
2356 * FIXME: This is propably not entirely correct. We can't look into
2357 * the standard FCB header because it might not be initialized yet
2358 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2359 * standard file information is filled on first request).
2361 Status
= IoQueryFileInformation(FileObject
,
2362 FileStandardInformation
,
2363 sizeof(FILE_STANDARD_INFORMATION
),
2366 if (!NT_SUCCESS(Status
))
2368 ObDereferenceObject(Section
);
2369 ObDereferenceObject(FileObject
);
2374 * FIXME: Revise this once a locking order for file size changes is
2377 if (UMaximumSize
!= NULL
)
2379 MaximumSize
= *UMaximumSize
;
2383 MaximumSize
= FileInfo
.EndOfFile
;
2384 /* Mapping zero-sized files isn't allowed. */
2385 if (MaximumSize
.QuadPart
== 0)
2387 ObDereferenceObject(Section
);
2388 ObDereferenceObject(FileObject
);
2389 return STATUS_FILE_INVALID
;
2393 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2395 Status
= IoSetInformation(FileObject
,
2396 FileAllocationInformation
,
2397 sizeof(LARGE_INTEGER
),
2399 if (!NT_SUCCESS(Status
))
2401 ObDereferenceObject(Section
);
2402 ObDereferenceObject(FileObject
);
2403 return(STATUS_SECTION_NOT_EXTENDED
);
2407 if (FileObject
->SectionObjectPointer
== NULL
||
2408 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2411 * Read a bit so caching is initiated for the file object.
2412 * This is only needed because MiReadPage currently cannot
2413 * handle non-cached streams.
2415 Offset
.QuadPart
= 0;
2416 Status
= ZwReadFile(FileHandle
,
2425 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2427 ObDereferenceObject(Section
);
2428 ObDereferenceObject(FileObject
);
2431 if (FileObject
->SectionObjectPointer
== NULL
||
2432 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2434 /* FIXME: handle this situation */
2435 ObDereferenceObject(Section
);
2436 ObDereferenceObject(FileObject
);
2437 return STATUS_INVALID_PARAMETER
;
2444 Status
= MmspWaitForFileLock(FileObject
);
2445 if (Status
!= STATUS_SUCCESS
)
2447 ObDereferenceObject(Section
);
2448 ObDereferenceObject(FileObject
);
2453 * If this file hasn't been mapped as a data file before then allocate a
2454 * section segment to describe the data file mapping
2456 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2458 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2459 TAG_MM_SECTION_SEGMENT
);
2460 if (Segment
== NULL
)
2462 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2463 ObDereferenceObject(Section
);
2464 ObDereferenceObject(FileObject
);
2465 return(STATUS_NO_MEMORY
);
2467 Section
->Segment
= Segment
;
2468 Segment
->ReferenceCount
= 1;
2469 ExInitializeFastMutex(&Segment
->Lock
);
2471 * Set the lock before assigning the segment to the file object
2473 ExAcquireFastMutex(&Segment
->Lock
);
2474 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2476 Segment
->FileOffset
= 0;
2477 Segment
->Protection
= SectionPageProtection
;
2478 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2479 Segment
->Characteristics
= 0;
2480 Segment
->WriteCopy
= FALSE
;
2481 if (AllocationAttributes
& SEC_RESERVE
)
2483 Segment
->Length
= Segment
->RawLength
= 0;
2487 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2488 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2490 Segment
->VirtualAddress
= 0;
2491 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2496 * If the file is already mapped as a data file then we may need
2500 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2502 Section
->Segment
= Segment
;
2503 InterlockedIncrementUL(&Segment
->ReferenceCount
);
2504 MmLockSectionSegment(Segment
);
2506 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2507 !(AllocationAttributes
& SEC_RESERVE
))
2509 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2510 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2513 MmUnlockSectionSegment(Segment
);
2514 Section
->FileObject
= FileObject
;
2515 Section
->MaximumSize
= MaximumSize
;
2516 CcRosReferenceCache(FileObject
);
2517 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2518 *SectionObject
= Section
;
2519 return(STATUS_SUCCESS
);
2523 TODO: not that great (declaring loaders statically, having to declare all of
2524 them, having to keep them extern, etc.), will fix in the future
2526 extern NTSTATUS NTAPI PeFmtCreateSection
2528 IN CONST VOID
* FileHeader
,
2529 IN SIZE_T FileHeaderSize
,
2531 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2533 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2534 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2537 extern NTSTATUS NTAPI ElfFmtCreateSection
2539 IN CONST VOID
* FileHeader
,
2540 IN SIZE_T FileHeaderSize
,
2542 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2544 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2545 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2548 /* TODO: this is a standard DDK/PSDK macro */
2549 #ifndef RTL_NUMBER_OF
2550 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2553 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2562 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2564 SIZE_T SizeOfSegments
;
2565 PMM_SECTION_SEGMENT Segments
;
2567 /* TODO: check for integer overflow */
2568 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2570 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2572 TAG_MM_SECTION_SEGMENT
);
2575 RtlZeroMemory(Segments
, SizeOfSegments
);
2583 ExeFmtpReadFile(IN PVOID File
,
2584 IN PLARGE_INTEGER Offset
,
2587 OUT PVOID
* AllocBase
,
2588 OUT PULONG ReadSize
)
2591 LARGE_INTEGER FileOffset
;
2593 ULONG OffsetAdjustment
;
2598 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2602 KEBUGCHECK(STATUS_INVALID_PARAMETER_4
);
2605 FileOffset
= *Offset
;
2607 /* Negative/special offset: it cannot be used in this context */
2608 if(FileOffset
.u
.HighPart
< 0)
2610 KEBUGCHECK(STATUS_INVALID_PARAMETER_5
);
2613 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2614 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2615 FileOffset
.u
.LowPart
= AdjustOffset
;
2617 BufferSize
= Length
+ OffsetAdjustment
;
2618 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2621 * It's ok to use paged pool, because this is a temporary buffer only used in
2622 * the loading of executables. The assumption is that MmCreateSection is
2623 * always called at low IRQLs and that these buffers don't survive a brief
2624 * initialization phase
2626 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2628 TAG('M', 'm', 'X', 'r'));
2633 Status
= MmspPageRead(File
,
2640 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2641 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2642 * to initialize internal state is even worse. Our cache manager is in need of
2646 IO_STATUS_BLOCK Iosb
;
2648 Status
= ZwReadFile(File
,
2658 if(NT_SUCCESS(Status
))
2660 UsedSize
= Iosb
.Information
;
2665 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2667 Status
= STATUS_IN_PAGE_ERROR
;
2668 ASSERT(!NT_SUCCESS(Status
));
2671 if(NT_SUCCESS(Status
))
2673 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2674 *AllocBase
= Buffer
;
2675 *ReadSize
= UsedSize
- OffsetAdjustment
;
2686 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2687 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2688 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2693 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2697 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2699 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2700 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2707 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2711 MmspAssertSegmentsSorted(ImageSectionObject
);
2713 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2715 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2719 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2720 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2721 ImageSectionObject
->Segments
[i
- 1].Length
));
2729 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2733 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2735 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2736 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2744 MmspCompareSegments(const void * x
,
2747 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2748 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2751 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2752 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2756 * Ensures an image section's segments are sorted in memory
2761 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2764 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2766 MmspAssertSegmentsSorted(ImageSectionObject
);
2770 qsort(ImageSectionObject
->Segments
,
2771 ImageSectionObject
->NrSegments
,
2772 sizeof(ImageSectionObject
->Segments
[0]),
2773 MmspCompareSegments
);
2779 * Ensures an image section's segments don't overlap in memory and don't have
2780 * gaps and don't have a null size. We let them map to overlapping file regions,
2781 * though - that's not necessarily an error
2786 MmspCheckSegmentBounds
2788 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2794 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2796 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2800 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2802 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2804 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2812 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2813 * page could be OK (Windows seems to be OK with them), and larger gaps
2814 * could lead to image sections spanning several discontiguous regions
2815 * (NtMapViewOfSection could then refuse to map them, and they could
2816 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2818 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2819 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2820 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2831 * Merges and pads an image section's segments until they all are page-aligned
2832 * and have a size that is a multiple of the page size
2837 MmspPageAlignSegments
2839 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2845 BOOLEAN Initialized
;
2846 PMM_SECTION_SEGMENT EffectiveSegment
;
2848 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2850 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2854 Initialized
= FALSE
;
2856 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2858 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2861 * The first segment requires special handling
2865 ULONG_PTR VirtualAddress
;
2866 ULONG_PTR VirtualOffset
;
2868 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2870 /* Round down the virtual address to the nearest page */
2871 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2873 /* Round up the virtual size to the nearest page */
2874 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2875 EffectiveSegment
->VirtualAddress
;
2877 /* Adjust the raw address and size */
2878 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2880 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
2886 * Garbage in, garbage out: unaligned base addresses make the file
2887 * offset point in curious and odd places, but that's what we were
2890 EffectiveSegment
->FileOffset
-= VirtualOffset
;
2891 EffectiveSegment
->RawLength
+= VirtualOffset
;
2895 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
2896 ULONG_PTR EndOfEffectiveSegment
;
2898 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
2899 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
2902 * The current segment begins exactly where the current effective
2903 * segment ended, therefore beginning a new effective segment
2905 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
2908 ASSERT(LastSegment
<= i
);
2909 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
2911 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2913 if (LastSegment
!= i
)
2916 * Copy the current segment. If necessary, the effective segment
2917 * will be expanded later
2919 *EffectiveSegment
= *Segment
;
2923 * Page-align the virtual size. We know for sure the virtual address
2926 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
2927 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
2930 * The current segment is still part of the current effective segment:
2931 * extend the effective segment to reflect this
2933 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
2935 static const ULONG FlagsToProtection
[16] =
2943 PAGE_EXECUTE_READWRITE
,
2944 PAGE_EXECUTE_READWRITE
,
2949 PAGE_EXECUTE_WRITECOPY
,
2950 PAGE_EXECUTE_WRITECOPY
,
2951 PAGE_EXECUTE_WRITECOPY
,
2952 PAGE_EXECUTE_WRITECOPY
2955 unsigned ProtectionFlags
;
2958 * Extend the file size
2961 /* Unaligned segments must be contiguous within the file */
2962 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
2963 EffectiveSegment
->RawLength
))
2968 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
2971 * Extend the virtual size
2973 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
2975 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
2976 EffectiveSegment
->VirtualAddress
;
2979 * Merge the protection
2981 EffectiveSegment
->Protection
|= Segment
->Protection
;
2983 /* Clean up redundance */
2984 ProtectionFlags
= 0;
2986 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
2987 ProtectionFlags
|= 1 << 0;
2989 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
2990 ProtectionFlags
|= 1 << 1;
2992 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
2993 ProtectionFlags
|= 1 << 2;
2995 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2996 ProtectionFlags
|= 1 << 3;
2998 ASSERT(ProtectionFlags
< 16);
2999 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3001 /* If a segment was required to be shared and cannot, fail */
3002 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3003 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3009 * We assume no holes between segments at this point
3017 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3023 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3024 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3026 LARGE_INTEGER Offset
;
3028 PVOID FileHeaderBuffer
;
3029 ULONG FileHeaderSize
;
3031 ULONG OldNrSegments
;
3036 * Read the beginning of the file (2 pages). Should be enough to contain
3037 * all (or most) of the headers
3039 Offset
.QuadPart
= 0;
3041 /* FIXME: use FileObject instead of FileHandle */
3042 Status
= ExeFmtpReadFile (FileHandle
,
3049 if (!NT_SUCCESS(Status
))
3052 if (FileHeaderSize
== 0)
3054 ExFreePool(FileHeaderBuffer
);
3055 return STATUS_UNSUCCESSFUL
;
3059 * Look for a loader that can handle this executable
3061 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3063 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3066 /* FIXME: use FileObject instead of FileHandle */
3067 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3073 ExeFmtpAllocateSegments
);
3075 if (!NT_SUCCESS(Status
))
3077 if (ImageSectionObject
->Segments
)
3079 ExFreePool(ImageSectionObject
->Segments
);
3080 ImageSectionObject
->Segments
= NULL
;
3084 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3088 ExFreePool(FileHeaderBuffer
);
3091 * No loader handled the format
3093 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3095 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3096 ASSERT(!NT_SUCCESS(Status
));
3099 if (!NT_SUCCESS(Status
))
3102 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3107 /* FIXME? are these values platform-dependent? */
3108 if(ImageSectionObject
->StackReserve
== 0)
3109 ImageSectionObject
->StackReserve
= 0x40000;
3111 if(ImageSectionObject
->StackCommit
== 0)
3112 ImageSectionObject
->StackCommit
= 0x1000;
3114 if(ImageSectionObject
->ImageBase
== 0)
3116 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3117 ImageSectionObject
->ImageBase
= 0x10000000;
3119 ImageSectionObject
->ImageBase
= 0x00400000;
3123 * And now the fun part: fixing the segments
3126 /* Sort them by virtual address */
3127 MmspSortSegments(ImageSectionObject
, Flags
);
3129 /* Ensure they don't overlap in memory */
3130 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3131 return STATUS_INVALID_IMAGE_FORMAT
;
3133 /* Ensure they are aligned */
3134 OldNrSegments
= ImageSectionObject
->NrSegments
;
3136 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3137 return STATUS_INVALID_IMAGE_FORMAT
;
3139 /* Trim them if the alignment phase merged some of them */
3140 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3142 PMM_SECTION_SEGMENT Segments
;
3143 SIZE_T SizeOfSegments
;
3145 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3147 Segments
= ExAllocatePoolWithTag(PagedPool
,
3149 TAG_MM_SECTION_SEGMENT
);
3151 if (Segments
== NULL
)
3152 return STATUS_INSUFFICIENT_RESOURCES
;
3154 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3155 ExFreePool(ImageSectionObject
->Segments
);
3156 ImageSectionObject
->Segments
= Segments
;
3159 /* And finish their initialization */
3160 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3162 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3163 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3165 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3166 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3169 ASSERT(NT_SUCCESS(Status
));
3174 MmCreateImageSection(PSECTION_OBJECT
*SectionObject
,
3175 ACCESS_MASK DesiredAccess
,
3176 POBJECT_ATTRIBUTES ObjectAttributes
,
3177 PLARGE_INTEGER UMaximumSize
,
3178 ULONG SectionPageProtection
,
3179 ULONG AllocationAttributes
,
3182 PSECTION_OBJECT Section
;
3184 PFILE_OBJECT FileObject
;
3185 PMM_SECTION_SEGMENT SectionSegments
;
3186 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3188 ULONG FileAccess
= 0;
3191 * Specifying a maximum size is meaningless for an image section
3193 if (UMaximumSize
!= NULL
)
3195 return(STATUS_INVALID_PARAMETER_4
);
3199 * Check file access required
3201 if (SectionPageProtection
& PAGE_READWRITE
||
3202 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3204 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3208 FileAccess
= FILE_READ_DATA
;
3212 * Reference the file handle
3214 Status
= ObReferenceObjectByHandle(FileHandle
,
3218 (PVOID
*)(PVOID
)&FileObject
,
3221 if (!NT_SUCCESS(Status
))
3227 * Create the section
3229 Status
= ObCreateObject (ExGetPreviousMode(),
3230 MmSectionObjectType
,
3232 ExGetPreviousMode(),
3234 sizeof(SECTION_OBJECT
),
3237 (PVOID
*)(PVOID
)&Section
);
3238 if (!NT_SUCCESS(Status
))
3240 ObDereferenceObject(FileObject
);
3247 Section
->SectionPageProtection
= SectionPageProtection
;
3248 Section
->AllocationAttributes
= AllocationAttributes
;
3251 * Initialized caching for this file object if previously caching
3252 * was initialized for the same on disk file
3254 Status
= CcTryToInitializeFileCache(FileObject
);
3256 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3258 NTSTATUS StatusExeFmt
;
3260 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3261 if (ImageSectionObject
== NULL
)
3263 ObDereferenceObject(FileObject
);
3264 ObDereferenceObject(Section
);
3265 return(STATUS_NO_MEMORY
);
3268 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3270 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3272 if (!NT_SUCCESS(StatusExeFmt
))
3274 if(ImageSectionObject
->Segments
!= NULL
)
3275 ExFreePool(ImageSectionObject
->Segments
);
3277 ExFreePool(ImageSectionObject
);
3278 ObDereferenceObject(Section
);
3279 ObDereferenceObject(FileObject
);
3280 return(StatusExeFmt
);
3283 Section
->ImageSection
= ImageSectionObject
;
3284 ASSERT(ImageSectionObject
->Segments
);
3289 Status
= MmspWaitForFileLock(FileObject
);
3290 if (!NT_SUCCESS(Status
))
3292 ExFreePool(ImageSectionObject
->Segments
);
3293 ExFreePool(ImageSectionObject
);
3294 ObDereferenceObject(Section
);
3295 ObDereferenceObject(FileObject
);
3299 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3300 ImageSectionObject
, NULL
))
3303 * An other thread has initialized the some image in the background
3305 ExFreePool(ImageSectionObject
->Segments
);
3306 ExFreePool(ImageSectionObject
);
3307 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3308 Section
->ImageSection
= ImageSectionObject
;
3309 SectionSegments
= ImageSectionObject
->Segments
;
3311 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3313 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3317 Status
= StatusExeFmt
;
3324 Status
= MmspWaitForFileLock(FileObject
);
3325 if (Status
!= STATUS_SUCCESS
)
3327 ObDereferenceObject(Section
);
3328 ObDereferenceObject(FileObject
);
3332 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3333 Section
->ImageSection
= ImageSectionObject
;
3334 SectionSegments
= ImageSectionObject
->Segments
;
3337 * Otherwise just reference all the section segments
3339 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3341 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3344 Status
= STATUS_SUCCESS
;
3346 Section
->FileObject
= FileObject
;
3347 CcRosReferenceCache(FileObject
);
3348 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
3349 *SectionObject
= Section
;
3357 NtCreateSection (OUT PHANDLE SectionHandle
,
3358 IN ACCESS_MASK DesiredAccess
,
3359 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3360 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3361 IN ULONG SectionPageProtection OPTIONAL
,
3362 IN ULONG AllocationAttributes
,
3363 IN HANDLE FileHandle OPTIONAL
)
3365 LARGE_INTEGER SafeMaximumSize
;
3366 PSECTION_OBJECT SectionObject
;
3367 KPROCESSOR_MODE PreviousMode
;
3368 NTSTATUS Status
= STATUS_SUCCESS
;
3370 PreviousMode
= ExGetPreviousMode();
3372 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3376 /* make a copy on the stack */
3377 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3378 MaximumSize
= &SafeMaximumSize
;
3382 Status
= _SEH_GetExceptionCode();
3386 if(!NT_SUCCESS(Status
))
3392 Status
= MmCreateSection(&SectionObject
,
3396 SectionPageProtection
,
3397 AllocationAttributes
,
3401 if (NT_SUCCESS(Status
))
3403 Status
= ObInsertObject ((PVOID
)SectionObject
,
3409 ObDereferenceObject(SectionObject
);
3416 /**********************************************************************
3434 NtOpenSection(PHANDLE SectionHandle
,
3435 ACCESS_MASK DesiredAccess
,
3436 POBJECT_ATTRIBUTES ObjectAttributes
)
3439 KPROCESSOR_MODE PreviousMode
;
3440 NTSTATUS Status
= STATUS_SUCCESS
;
3442 PreviousMode
= ExGetPreviousMode();
3444 if(PreviousMode
!= KernelMode
)
3448 ProbeForWriteHandle(SectionHandle
);
3452 Status
= _SEH_GetExceptionCode();
3456 if(!NT_SUCCESS(Status
))
3462 Status
= ObOpenObjectByName(ObjectAttributes
,
3463 MmSectionObjectType
,
3470 if(NT_SUCCESS(Status
))
3474 *SectionHandle
= hSection
;
3478 Status
= _SEH_GetExceptionCode();
3487 MmMapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3488 PSECTION_OBJECT Section
,
3489 PMM_SECTION_SEGMENT Segment
,
3494 ULONG AllocationType
)
3498 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3500 BoundaryAddressMultiple
.QuadPart
= 0;
3502 Status
= MmCreateMemoryArea(AddressSpace
,
3503 MEMORY_AREA_SECTION_VIEW
,
3510 BoundaryAddressMultiple
);
3511 if (!NT_SUCCESS(Status
))
3513 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3514 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3518 ObReferenceObject((PVOID
)Section
);
3520 MArea
->Data
.SectionData
.Segment
= Segment
;
3521 MArea
->Data
.SectionData
.Section
= Section
;
3522 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3523 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3524 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3525 ViewSize
, 0, Protect
);
3527 return(STATUS_SUCCESS
);
3531 /**********************************************************************
3533 * NtMapViewOfSection
3536 * Maps a view of a section into the virtual address space of a
3541 * Handle of the section.
3544 * Handle of the process.
3547 * Desired base address (or NULL) on entry;
3548 * Actual base address of the view on exit.
3551 * Number of high order address bits that must be zero.
3554 * Size in bytes of the initially committed section of
3558 * Offset in bytes from the beginning of the section
3559 * to the beginning of the view.
3562 * Desired length of map (or zero to map all) on entry
3563 * Actual length mapped on exit.
3565 * InheritDisposition
3566 * Specified how the view is to be shared with
3570 * Type of allocation for the pages.
3573 * Protection for the committed region of the view.
3581 NtMapViewOfSection(IN HANDLE SectionHandle
,
3582 IN HANDLE ProcessHandle
,
3583 IN OUT PVOID
* BaseAddress OPTIONAL
,
3584 IN ULONG ZeroBits OPTIONAL
,
3585 IN ULONG CommitSize
,
3586 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3587 IN OUT PSIZE_T ViewSize
,
3588 IN SECTION_INHERIT InheritDisposition
,
3589 IN ULONG AllocationType OPTIONAL
,
3592 PVOID SafeBaseAddress
;
3593 LARGE_INTEGER SafeSectionOffset
;
3594 SIZE_T SafeViewSize
;
3595 PSECTION_OBJECT Section
;
3597 KPROCESSOR_MODE PreviousMode
;
3598 PMADDRESS_SPACE AddressSpace
;
3599 NTSTATUS Status
= STATUS_SUCCESS
;
3603 * Check the protection
3605 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3608 return STATUS_INVALID_PARAMETER_10
;
3611 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3612 if (tmpProtect
!= PAGE_NOACCESS
&&
3613 tmpProtect
!= PAGE_READONLY
&&
3614 tmpProtect
!= PAGE_READWRITE
&&
3615 tmpProtect
!= PAGE_WRITECOPY
&&
3616 tmpProtect
!= PAGE_EXECUTE
&&
3617 tmpProtect
!= PAGE_EXECUTE_READ
&&
3618 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3619 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3622 return STATUS_INVALID_PAGE_PROTECTION
;
3625 PreviousMode
= ExGetPreviousMode();
3627 if(PreviousMode
!= KernelMode
)
3629 SafeBaseAddress
= NULL
;
3630 SafeSectionOffset
.QuadPart
= 0;
3635 if(BaseAddress
!= NULL
)
3637 ProbeForWritePointer(BaseAddress
);
3638 SafeBaseAddress
= *BaseAddress
;
3640 if(SectionOffset
!= NULL
)
3642 ProbeForWriteLargeInteger(SectionOffset
);
3643 SafeSectionOffset
= *SectionOffset
;
3645 ProbeForWriteSize_t(ViewSize
);
3646 SafeViewSize
= *ViewSize
;
3650 Status
= _SEH_GetExceptionCode();
3654 if(!NT_SUCCESS(Status
))
3661 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3662 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3663 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3666 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3667 PROCESS_VM_OPERATION
,
3670 (PVOID
*)(PVOID
)&Process
,
3672 if (!NT_SUCCESS(Status
))
3677 AddressSpace
= &Process
->AddressSpace
;
3679 Status
= ObReferenceObjectByHandle(SectionHandle
,
3681 MmSectionObjectType
,
3683 (PVOID
*)(PVOID
)&Section
,
3685 if (!(NT_SUCCESS(Status
)))
3687 DPRINT("ObReference failed rc=%x\n",Status
);
3688 ObDereferenceObject(Process
);
3692 Status
= MmMapViewOfSection(Section
,
3694 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3697 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3698 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3703 ObDereferenceObject(Section
);
3704 ObDereferenceObject(Process
);
3706 if(NT_SUCCESS(Status
))
3708 /* copy parameters back to the caller */
3711 if(BaseAddress
!= NULL
)
3713 *BaseAddress
= SafeBaseAddress
;
3715 if(SectionOffset
!= NULL
)
3717 *SectionOffset
= SafeSectionOffset
;
3719 if(ViewSize
!= NULL
)
3721 *ViewSize
= SafeViewSize
;
3726 Status
= _SEH_GetExceptionCode();
3735 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3736 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3739 PFILE_OBJECT FileObject
;
3742 SWAPENTRY SavedSwapEntry
;
3745 PSECTION_OBJECT Section
;
3746 PMM_SECTION_SEGMENT Segment
;
3747 PMADDRESS_SPACE AddressSpace
;
3749 AddressSpace
= (PMADDRESS_SPACE
)Context
;
3751 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3753 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3754 MemoryArea
->Data
.SectionData
.ViewOffset
;
3756 Section
= MemoryArea
->Data
.SectionData
.Section
;
3757 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3759 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3763 MmUnlockSectionSegment(Segment
);
3764 MmUnlockAddressSpace(AddressSpace
);
3766 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3767 if (Status
!= STATUS_SUCCESS
)
3769 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3773 MmLockAddressSpace(AddressSpace
);
3774 MmLockSectionSegment(Segment
);
3775 MmspCompleteAndReleasePageOp(PageOp
);
3776 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3779 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3782 * For a dirty, datafile, non-private page mark it as dirty in the
3785 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3787 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3789 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3790 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3791 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3792 ASSERT(SwapEntry
== 0);
3801 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3803 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3806 MmFreeSwapPage(SwapEntry
);
3810 if (IS_SWAP_FROM_SSE(Entry
) ||
3811 Page
!= PFN_FROM_SSE(Entry
))
3816 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3818 DPRINT1("Found a private page in a pagefile section.\n");
3822 * Just dereference private pages
3824 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3825 if (SavedSwapEntry
!= 0)
3827 MmFreeSwapPage(SavedSwapEntry
);
3828 MmSetSavedSwapEntryPage(Page
, 0);
3830 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3831 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3835 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3836 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3842 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3846 PMEMORY_AREA MemoryArea
;
3847 PSECTION_OBJECT Section
;
3848 PMM_SECTION_SEGMENT Segment
;
3849 PLIST_ENTRY CurrentEntry
;
3850 PMM_REGION CurrentRegion
;
3851 PLIST_ENTRY RegionListHead
;
3853 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3855 if (MemoryArea
== NULL
)
3857 return(STATUS_UNSUCCESSFUL
);
3860 MemoryArea
->DeleteInProgress
= TRUE
;
3861 Section
= MemoryArea
->Data
.SectionData
.Section
;
3862 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3864 MmLockSectionSegment(Segment
);
3866 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3867 while (!IsListEmpty(RegionListHead
))
3869 CurrentEntry
= RemoveHeadList(RegionListHead
);
3870 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3871 ExFreePool(CurrentRegion
);
3874 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3876 Status
= MmFreeMemoryArea(AddressSpace
,
3883 Status
= MmFreeMemoryArea(AddressSpace
,
3888 MmUnlockSectionSegment(Segment
);
3889 ObDereferenceObject(Section
);
3890 return(STATUS_SUCCESS
);
3897 MmUnmapViewOfSection(PEPROCESS Process
,
3901 PMEMORY_AREA MemoryArea
;
3902 PMADDRESS_SPACE AddressSpace
;
3903 PSECTION_OBJECT Section
;
3907 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3908 Process
, BaseAddress
);
3912 AddressSpace
= &Process
->AddressSpace
;
3914 MmLockAddressSpace(AddressSpace
);
3915 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3917 if (MemoryArea
== NULL
||
3918 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
3919 MemoryArea
->DeleteInProgress
)
3921 MmUnlockAddressSpace(AddressSpace
);
3922 return STATUS_NOT_MAPPED_VIEW
;
3925 MemoryArea
->DeleteInProgress
= TRUE
;
3927 while (MemoryArea
->PageOpCount
)
3929 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
3933 Offset
-= PAGE_SIZE
;
3934 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
3935 MemoryArea
->Data
.SectionData
.Segment
,
3936 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
3939 MmUnlockAddressSpace(AddressSpace
);
3940 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3941 if (Status
!= STATUS_SUCCESS
)
3943 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3946 MmLockAddressSpace(AddressSpace
);
3947 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3949 if (MemoryArea
== NULL
||
3950 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
3952 MmUnlockAddressSpace(AddressSpace
);
3953 return STATUS_NOT_MAPPED_VIEW
;
3960 Section
= MemoryArea
->Data
.SectionData
.Section
;
3962 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3966 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3967 PMM_SECTION_SEGMENT SectionSegments
;
3968 PVOID ImageBaseAddress
= 0;
3969 PMM_SECTION_SEGMENT Segment
;
3971 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3972 ImageSectionObject
= Section
->ImageSection
;
3973 SectionSegments
= ImageSectionObject
->Segments
;
3974 NrSegments
= ImageSectionObject
->NrSegments
;
3976 /* Search for the current segment within the section segments
3977 * and calculate the image base address */
3978 for (i
= 0; i
< NrSegments
; i
++)
3980 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3982 if (Segment
== &SectionSegments
[i
])
3984 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3989 if (i
>= NrSegments
)
3994 for (i
= 0; i
< NrSegments
; i
++)
3996 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3998 PVOID SBaseAddress
= (PVOID
)
3999 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4001 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4007 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4009 MmUnlockAddressSpace(AddressSpace
);
4010 return(STATUS_SUCCESS
);
4013 /**********************************************************************
4015 * NtUnmapViewOfSection
4030 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4034 KPROCESSOR_MODE PreviousMode
;
4037 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4038 ProcessHandle
, BaseAddress
);
4040 PreviousMode
= ExGetPreviousMode();
4042 DPRINT("Referencing process\n");
4043 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4044 PROCESS_VM_OPERATION
,
4047 (PVOID
*)(PVOID
)&Process
,
4049 if (!NT_SUCCESS(Status
))
4051 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4055 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4057 ObDereferenceObject(Process
);
4064 * Queries the information of a section object.
4066 * @param SectionHandle
4067 * Handle to the section object. It must be opened with SECTION_QUERY
4069 * @param SectionInformationClass
4070 * Index to a certain information structure. Can be either
4071 * SectionBasicInformation or SectionImageInformation. The latter
4072 * is valid only for sections that were created with the SEC_IMAGE
4074 * @param SectionInformation
4075 * Caller supplies storage for resulting information.
4077 * Size of the supplied storage.
4078 * @param ResultLength
4086 NtQuerySection(IN HANDLE SectionHandle
,
4087 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4088 OUT PVOID SectionInformation
,
4089 IN ULONG SectionInformationLength
,
4090 OUT PULONG ResultLength OPTIONAL
)
4092 PSECTION_OBJECT Section
;
4093 KPROCESSOR_MODE PreviousMode
;
4094 NTSTATUS Status
= STATUS_SUCCESS
;
4096 PreviousMode
= ExGetPreviousMode();
4098 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4100 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4102 SectionInformationLength
,
4106 if(!NT_SUCCESS(Status
))
4108 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4112 Status
= ObReferenceObjectByHandle(SectionHandle
,
4114 MmSectionObjectType
,
4116 (PVOID
*)(PVOID
)&Section
,
4118 if (NT_SUCCESS(Status
))
4120 switch (SectionInformationClass
)
4122 case SectionBasicInformation
:
4124 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4128 Sbi
->Attributes
= Section
->AllocationAttributes
;
4129 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4131 Sbi
->BaseAddress
= 0;
4132 Sbi
->Size
.QuadPart
= 0;
4136 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4137 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4140 if (ResultLength
!= NULL
)
4142 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4144 Status
= STATUS_SUCCESS
;
4148 Status
= _SEH_GetExceptionCode();
4155 case SectionImageInformation
:
4157 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4161 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4162 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4164 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4165 ImageSectionObject
= Section
->ImageSection
;
4167 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4168 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4169 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4170 Sii
->SubsystemType
= ImageSectionObject
->Subsystem
;
4171 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4172 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4173 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4174 Sii
->Machine
= ImageSectionObject
->Machine
;
4175 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4178 if (ResultLength
!= NULL
)
4180 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4182 Status
= STATUS_SUCCESS
;
4186 Status
= _SEH_GetExceptionCode();
4194 ObDereferenceObject(Section
);
4202 * Extends size of file backed section.
4204 * @param SectionHandle
4205 * Handle to the section object. It must be opened with
4206 * SECTION_EXTEND_SIZE access.
4207 * @param NewMaximumSize
4208 * New maximum size of the section in bytes.
4212 * @todo Move the actual code to internal function MmExtendSection.
4216 NtExtendSection(IN HANDLE SectionHandle
,
4217 IN PLARGE_INTEGER NewMaximumSize
)
4219 LARGE_INTEGER SafeNewMaximumSize
;
4220 PSECTION_OBJECT Section
;
4221 KPROCESSOR_MODE PreviousMode
;
4222 NTSTATUS Status
= STATUS_SUCCESS
;
4224 PreviousMode
= ExGetPreviousMode();
4226 if(PreviousMode
!= KernelMode
)
4230 /* make a copy on the stack */
4231 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4232 NewMaximumSize
= &SafeNewMaximumSize
;
4236 Status
= _SEH_GetExceptionCode();
4240 if(!NT_SUCCESS(Status
))
4246 Status
= ObReferenceObjectByHandle(SectionHandle
,
4247 SECTION_EXTEND_SIZE
,
4248 MmSectionObjectType
,
4252 if (!NT_SUCCESS(Status
))
4257 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4259 ObfDereferenceObject(Section
);
4260 return STATUS_INVALID_PARAMETER
;
4264 * - Acquire file extneding resource.
4265 * - Check if we're not resizing the section below it's actual size!
4266 * - Extend segments if needed.
4267 * - Set file information (FileAllocationInformation) to the new size.
4268 * - Release file extending resource.
4271 ObDereferenceObject(Section
);
4273 return STATUS_NOT_IMPLEMENTED
;
4277 /**********************************************************************
4279 * MmAllocateSection@4
4289 * Code taken from ntoskrnl/mm/special.c.
4294 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4300 PMADDRESS_SPACE AddressSpace
;
4301 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4303 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4305 BoundaryAddressMultiple
.QuadPart
= 0;
4307 AddressSpace
= MmGetKernelAddressSpace();
4308 Result
= BaseAddress
;
4309 MmLockAddressSpace(AddressSpace
);
4310 Status
= MmCreateMemoryArea (AddressSpace
,
4318 BoundaryAddressMultiple
);
4319 MmUnlockAddressSpace(AddressSpace
);
4321 if (!NT_SUCCESS(Status
))
4325 DPRINT("Result %p\n",Result
);
4326 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
4330 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
4331 if (!NT_SUCCESS(Status
))
4333 DbgPrint("Unable to allocate page\n");
4336 Status
= MmCreateVirtualMapping (NULL
,
4337 (PVOID
)((ULONG_PTR
)Result
+ (i
* PAGE_SIZE
)),
4341 if (!NT_SUCCESS(Status
))
4343 DbgPrint("Unable to create virtual mapping\n");
4347 return ((PVOID
)Result
);
4351 /**********************************************************************
4353 * MmMapViewOfSection
4356 * Maps a view of a section into the virtual address space of a
4361 * Pointer to the section object.
4364 * Pointer to the process.
4367 * Desired base address (or NULL) on entry;
4368 * Actual base address of the view on exit.
4371 * Number of high order address bits that must be zero.
4374 * Size in bytes of the initially committed section of
4378 * Offset in bytes from the beginning of the section
4379 * to the beginning of the view.
4382 * Desired length of map (or zero to map all) on entry
4383 * Actual length mapped on exit.
4385 * InheritDisposition
4386 * Specified how the view is to be shared with
4390 * Type of allocation for the pages.
4393 * Protection for the committed region of the view.
4401 MmMapViewOfSection(IN PVOID SectionObject
,
4402 IN PEPROCESS Process
,
4403 IN OUT PVOID
*BaseAddress
,
4405 IN ULONG CommitSize
,
4406 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4407 IN OUT PSIZE_T ViewSize
,
4408 IN SECTION_INHERIT InheritDisposition
,
4409 IN ULONG AllocationType
,
4412 PSECTION_OBJECT Section
;
4413 PMADDRESS_SPACE AddressSpace
;
4415 NTSTATUS Status
= STATUS_SUCCESS
;
4419 if (Protect
!= PAGE_READONLY
&&
4420 Protect
!= PAGE_READWRITE
&&
4421 Protect
!= PAGE_WRITECOPY
&&
4422 Protect
!= PAGE_EXECUTE
&&
4423 Protect
!= PAGE_EXECUTE_READ
&&
4424 Protect
!= PAGE_EXECUTE_READWRITE
&&
4425 Protect
!= PAGE_EXECUTE_WRITECOPY
)
4428 return STATUS_INVALID_PAGE_PROTECTION
;
4432 Section
= (PSECTION_OBJECT
)SectionObject
;
4433 AddressSpace
= &Process
->AddressSpace
;
4435 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4437 MmLockAddressSpace(AddressSpace
);
4439 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4443 ULONG_PTR ImageBase
;
4445 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4446 PMM_SECTION_SEGMENT SectionSegments
;
4448 ImageSectionObject
= Section
->ImageSection
;
4449 SectionSegments
= ImageSectionObject
->Segments
;
4450 NrSegments
= ImageSectionObject
->NrSegments
;
4453 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4456 ImageBase
= ImageSectionObject
->ImageBase
;
4460 for (i
= 0; i
< NrSegments
; i
++)
4462 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4464 ULONG_PTR MaxExtent
;
4465 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4466 SectionSegments
[i
].Length
;
4467 ImageSize
= max(ImageSize
, MaxExtent
);
4471 /* Check there is enough space to map the section at that point. */
4472 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4473 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4475 /* Fail if the user requested a fixed base address. */
4476 if ((*BaseAddress
) != NULL
)
4478 MmUnlockAddressSpace(AddressSpace
);
4479 return(STATUS_UNSUCCESSFUL
);
4481 /* Otherwise find a gap to map the image. */
4482 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4485 MmUnlockAddressSpace(AddressSpace
);
4486 return(STATUS_UNSUCCESSFUL
);
4490 for (i
= 0; i
< NrSegments
; i
++)
4492 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4494 PVOID SBaseAddress
= (PVOID
)
4495 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4496 MmLockSectionSegment(&SectionSegments
[i
]);
4497 Status
= MmMapViewOfSegment(AddressSpace
,
4499 &SectionSegments
[i
],
4501 SectionSegments
[i
].Length
,
4502 SectionSegments
[i
].Protection
,
4505 MmUnlockSectionSegment(&SectionSegments
[i
]);
4506 if (!NT_SUCCESS(Status
))
4508 MmUnlockAddressSpace(AddressSpace
);
4514 *BaseAddress
= (PVOID
)ImageBase
;
4518 /* check for write access */
4519 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4520 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4523 return STATUS_SECTION_PROTECTION
;
4525 /* check for read access */
4526 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4527 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4530 return STATUS_SECTION_PROTECTION
;
4532 /* check for execute access */
4533 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4534 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4537 return STATUS_SECTION_PROTECTION
;
4540 if (ViewSize
== NULL
)
4542 /* Following this pointer would lead to us to the dark side */
4543 /* What to do? Bugcheck? Return status? Do the mambo? */
4544 KEBUGCHECK(MEMORY_MANAGEMENT
);
4547 if (SectionOffset
== NULL
)
4553 ViewOffset
= SectionOffset
->u
.LowPart
;
4556 if ((ViewOffset
% PAGE_SIZE
) != 0)
4558 MmUnlockAddressSpace(AddressSpace
);
4559 return(STATUS_MAPPED_ALIGNMENT
);
4562 if ((*ViewSize
) == 0)
4564 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4566 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4568 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4571 MmLockSectionSegment(Section
->Segment
);
4572 Status
= MmMapViewOfSegment(AddressSpace
,
4579 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4580 MmUnlockSectionSegment(Section
->Segment
);
4581 if (!NT_SUCCESS(Status
))
4583 MmUnlockAddressSpace(AddressSpace
);
4588 MmUnlockAddressSpace(AddressSpace
);
4590 return(STATUS_SUCCESS
);
4597 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4598 IN PLARGE_INTEGER NewFileSize
)
4609 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
4619 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4620 IN MMFLUSH_TYPE FlushType
)
4624 case MmFlushForDelete
:
4625 if (SectionObjectPointer
->ImageSectionObject
||
4626 SectionObjectPointer
->DataSectionObject
)
4630 CcRosSetRemoveOnClose(SectionObjectPointer
);
4632 case MmFlushForWrite
:
4642 MmForceSectionClosed (
4643 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4644 IN BOOLEAN DelayClose
)
4655 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4656 OUT PVOID
* MappedBase
,
4657 IN OUT PULONG ViewSize
)
4659 PSECTION_OBJECT Section
;
4660 PMADDRESS_SPACE AddressSpace
;
4663 DPRINT("MmMapViewInSystemSpace() called\n");
4665 Section
= (PSECTION_OBJECT
)SectionObject
;
4666 AddressSpace
= MmGetKernelAddressSpace();
4668 MmLockAddressSpace(AddressSpace
);
4671 if ((*ViewSize
) == 0)
4673 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4675 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4677 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4680 MmLockSectionSegment(Section
->Segment
);
4683 Status
= MmMapViewOfSegment(AddressSpace
,
4692 MmUnlockSectionSegment(Section
->Segment
);
4693 MmUnlockAddressSpace(AddressSpace
);
4703 MmMapViewInSessionSpace (
4705 OUT PVOID
*MappedBase
,
4706 IN OUT PSIZE_T ViewSize
4710 return STATUS_NOT_IMPLEMENTED
;
4718 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4720 PMADDRESS_SPACE AddressSpace
;
4723 DPRINT("MmUnmapViewInSystemSpace() called\n");
4725 AddressSpace
= MmGetKernelAddressSpace();
4727 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4737 MmUnmapViewInSessionSpace (
4742 return STATUS_NOT_IMPLEMENTED
;
4749 MmSetBankedSection (DWORD Unknown0
,
4757 return (STATUS_NOT_IMPLEMENTED
);
4761 /**********************************************************************
4766 * Creates a section object.
4769 * SectionObject (OUT)
4770 * Caller supplied storage for the resulting pointer
4771 * to a SECTION_OBJECT instance;
4774 * Specifies the desired access to the section can be a
4776 * STANDARD_RIGHTS_REQUIRED |
4778 * SECTION_MAP_WRITE |
4779 * SECTION_MAP_READ |
4780 * SECTION_MAP_EXECUTE
4782 * ObjectAttributes [OPTIONAL]
4783 * Initialized attributes for the object can be used
4784 * to create a named section;
4787 * Maximizes the size of the memory section. Must be
4788 * non-NULL for a page-file backed section.
4789 * If value specified for a mapped file and the file is
4790 * not large enough, file will be extended.
4792 * SectionPageProtection
4793 * Can be a combination of:
4799 * AllocationAttributes
4800 * Can be a combination of:
4805 * Handle to a file to create a section mapped to a file
4806 * instead of a memory backed section;
4817 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4818 IN ACCESS_MASK DesiredAccess
,
4819 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4820 IN PLARGE_INTEGER MaximumSize
,
4821 IN ULONG SectionPageProtection
,
4822 IN ULONG AllocationAttributes
,
4823 IN HANDLE FileHandle OPTIONAL
,
4824 IN PFILE_OBJECT File OPTIONAL
)
4829 * Check the protection
4831 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4832 if (Protection
!= PAGE_NOACCESS
&&
4833 Protection
!= PAGE_READONLY
&&
4834 Protection
!= PAGE_READWRITE
&&
4835 Protection
!= PAGE_WRITECOPY
&&
4836 Protection
!= PAGE_EXECUTE
&&
4837 Protection
!= PAGE_EXECUTE_READ
&&
4838 Protection
!= PAGE_EXECUTE_READWRITE
&&
4839 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4842 return STATUS_INVALID_PAGE_PROTECTION
;
4845 if (AllocationAttributes
& SEC_IMAGE
)
4847 return(MmCreateImageSection(SectionObject
,
4851 SectionPageProtection
,
4852 AllocationAttributes
,
4856 if (FileHandle
!= NULL
)
4858 return(MmCreateDataFileSection(SectionObject
,
4862 SectionPageProtection
,
4863 AllocationAttributes
,
4867 return(MmCreatePageFileSection(SectionObject
,
4871 SectionPageProtection
,
4872 AllocationAttributes
));