3 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library 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 GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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>
53 #include <reactos/exeformat.h>
55 /* TYPES *********************************************************************/
59 PSECTION_OBJECT Section
;
60 PMM_SECTION_SEGMENT Segment
;
65 MM_SECTION_PAGEOUT_CONTEXT
;
67 /* GLOBALS *******************************************************************/
69 POBJECT_TYPE EXPORTED MmSectionObjectType
= NULL
;
71 static GENERIC_MAPPING MmpSectionMapping
= {
72 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
73 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
74 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
77 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
78 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
79 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
80 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
81 #define MAX_SHARE_COUNT 0x7FF
82 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
83 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
84 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
86 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
88 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
89 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
92 /* FUNCTIONS *****************************************************************/
94 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
97 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
98 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
99 * RETURNS: Status of the wait.
102 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
104 LARGE_INTEGER Timeout
;
105 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
107 Timeout
.QuadPart
= -100000000LL; // 10 sec
110 Timeout
.QuadPart
= -100000000; // 10 sec
113 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
118 * FUNCTION: Sets the page op completion event and releases the page op.
119 * ARGUMENTS: PMM_PAGEOP.
120 * RETURNS: In shorter time than it takes you to even read this
121 * description, so don't even think about geting a mug of coffee.
124 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
126 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
127 MmReleasePageOp(PageOp
);
132 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
133 * ARGUMENTS: PFILE_OBJECT to wait for.
134 * RETURNS: Status of the wait.
137 MmspWaitForFileLock(PFILE_OBJECT File
)
139 return KeWaitForSingleObject(&File
->Lock
, 0, KernelMode
, FALSE
, NULL
);
144 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
147 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
149 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
151 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
153 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
160 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
162 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
164 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
165 PMM_SECTION_SEGMENT SectionSegments
;
169 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
170 NrSegments
= ImageSectionObject
->NrSegments
;
171 SectionSegments
= ImageSectionObject
->Segments
;
172 for (i
= 0; i
< NrSegments
; i
++)
174 if (SectionSegments
[i
].ReferenceCount
!= 0)
176 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
177 SectionSegments
[i
].ReferenceCount
);
180 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
182 ExFreePool(ImageSectionObject
->Segments
);
183 ExFreePool(ImageSectionObject
);
184 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
186 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
188 PMM_SECTION_SEGMENT Segment
;
190 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
193 if (Segment
->ReferenceCount
!= 0)
195 DPRINT1("Data segment still referenced\n");
198 MmFreePageTablesSectionSegment(Segment
);
200 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
205 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
207 ExAcquireFastMutex(&Segment
->Lock
);
211 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
213 ExReleaseFastMutex(&Segment
->Lock
);
217 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
221 PSECTION_PAGE_TABLE Table
;
222 ULONG DirectoryOffset
;
225 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
227 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
231 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
232 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
236 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
237 ExAllocatePoolWithTag(PagedPool
, sizeof(SECTION_PAGE_TABLE
),
238 TAG_SECTION_PAGE_TABLE
);
243 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
244 DPRINT("Table %x\n", Table
);
247 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
248 Table
->Entry
[TableOffset
] = Entry
;
253 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
256 PSECTION_PAGE_TABLE Table
;
258 ULONG DirectoryOffset
;
261 DPRINT("MmGetPageEntrySection(Offset %x)\n", Offset
);
263 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
265 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
269 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
270 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
271 DPRINT("Table %x\n", Table
);
277 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
278 Entry
= Table
->Entry
[TableOffset
];
283 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
288 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
291 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
294 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
296 DPRINT1("Maximum share count reached\n");
299 if (IS_SWAP_FROM_SSE(Entry
))
303 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
304 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
308 MmUnsharePageEntrySectionSegment(PSECTION_OBJECT Section
,
309 PMM_SECTION_SEGMENT Segment
,
315 BOOLEAN IsDirectMapped
= FALSE
;
317 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
320 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
323 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
325 DPRINT1("Zero share count for unshare\n");
328 if (IS_SWAP_FROM_SSE(Entry
))
332 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
334 * If we reducing the share count of this entry to zero then set the entry
335 * to zero and tell the cache the page is no longer mapped.
337 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
339 PFILE_OBJECT FileObject
;
341 SWAPENTRY SavedSwapEntry
;
343 BOOLEAN IsImageSection
;
346 FileOffset
= Offset
+ Segment
->FileOffset
;
348 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
350 Page
= PFN_FROM_SSE(Entry
);
351 FileObject
= Section
->FileObject
;
352 if (FileObject
!= NULL
&&
353 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
356 if ((FileOffset
% PAGE_SIZE
) == 0 &&
357 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
360 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
361 IsDirectMapped
= TRUE
;
362 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
363 if (!NT_SUCCESS(Status
))
365 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
371 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
372 if (SavedSwapEntry
== 0)
375 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
376 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
380 * Try to page out this page and set the swap entry
381 * within the section segment. There exist no rmap entry
382 * for this page. The pager thread can't page out a
383 * page without a rmap entry.
385 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
389 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
392 MmReleasePageMemoryConsumer(MC_USER
, Page
);
398 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
399 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
407 * We hold all locks. Nobody can do something with the current
408 * process and the current segment (also not within an other process).
411 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
412 if (!NT_SUCCESS(Status
))
414 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
418 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
419 MmSetSavedSwapEntryPage(Page
, 0);
421 MmReleasePageMemoryConsumer(MC_USER
, Page
);
425 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
432 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
434 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
437 BOOL
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
440 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
443 PCACHE_SEGMENT CacheSeg
;
444 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
445 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
448 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
456 MiReadPage(PMEMORY_AREA MemoryArea
,
460 * FUNCTION: Read a page for a section backed memory area.
462 * MemoryArea - Memory area to read the page for.
463 * Offset - Offset of the page to read.
464 * Page - Variable that receives a page contains the read data.
471 PCACHE_SEGMENT CacheSeg
;
472 PFILE_OBJECT FileObject
;
476 BOOLEAN IsImageSection
;
479 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
480 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
481 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
482 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
483 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
487 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
490 * If the file system is letting us go directly to the cache and the
491 * memory area was mapped at an offset in the file which is page aligned
492 * then get the related cache segment.
494 if ((FileOffset
% PAGE_SIZE
) == 0 &&
495 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
496 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
500 * Get the related cache segment; we use a lower level interface than
501 * filesystems do because it is safe for us to use an offset with a
502 * alignment less than the file system block size.
504 Status
= CcRosGetCacheSegment(Bcb
,
510 if (!NT_SUCCESS(Status
))
517 * If the cache segment isn't up to date then call the file
518 * system to read in the data.
520 Status
= ReadCacheSegment(CacheSeg
);
521 if (!NT_SUCCESS(Status
))
523 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
528 * Retrieve the page from the cache segment that we actually want.
530 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
531 FileOffset
- BaseOffset
).QuadPart
>> PAGE_SHIFT
;
533 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
538 ULONG CacheSegOffset
;
540 * Allocate a page, this is rather complicated by the possibility
541 * we might have to move other things out of memory
543 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
544 if (!NT_SUCCESS(Status
))
548 Status
= CcRosGetCacheSegment(Bcb
,
554 if (!NT_SUCCESS(Status
))
561 * If the cache segment isn't up to date then call the file
562 * system to read in the data.
564 Status
= ReadCacheSegment(CacheSeg
);
565 if (!NT_SUCCESS(Status
))
567 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
571 PageAddr
= MmCreateHyperspaceMapping(*Page
);
572 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
573 Length
= RawLength
- SegOffset
;
574 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
576 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
578 else if (CacheSegOffset
>= PAGE_SIZE
)
580 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
584 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
585 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
586 Status
= CcRosGetCacheSegment(Bcb
,
587 FileOffset
+ CacheSegOffset
,
592 if (!NT_SUCCESS(Status
))
594 MmDeleteHyperspaceMapping(PageAddr
);
600 * If the cache segment isn't up to date then call the file
601 * system to read in the data.
603 Status
= ReadCacheSegment(CacheSeg
);
604 if (!NT_SUCCESS(Status
))
606 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
607 MmDeleteHyperspaceMapping(PageAddr
);
611 if (Length
< PAGE_SIZE
)
613 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
617 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
620 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
621 MmDeleteHyperspaceMapping(PageAddr
);
623 return(STATUS_SUCCESS
);
627 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
628 MEMORY_AREA
* MemoryArea
,
636 PSECTION_OBJECT Section
;
637 PMM_SECTION_SEGMENT Segment
;
646 * There is a window between taking the page fault and locking the
647 * address space when another thread could load the page so we check
650 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
654 MmLockPage(MmGetPfnForProcess(AddressSpace
->Process
, Address
));
656 return(STATUS_SUCCESS
);
659 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
660 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
662 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
663 Section
= MemoryArea
->Data
.SectionData
.Section
;
664 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
665 &MemoryArea
->Data
.SectionData
.RegionListHead
,
670 MmLockSectionSegment(Segment
);
673 * Check if this page needs to be mapped COW
675 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
676 (Region
->Protect
== PAGE_READWRITE
||
677 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
679 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
683 Attributes
= Region
->Protect
;
687 * Get or create a page operation descriptor
689 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
692 DPRINT1("MmGetPageOp failed\n");
697 * Check if someone else is already handling this fault, if so wait
700 if (PageOp
->Thread
!= PsGetCurrentThread())
702 MmUnlockSectionSegment(Segment
);
703 MmUnlockAddressSpace(AddressSpace
);
704 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
706 * Check for various strange conditions
708 if (Status
!= STATUS_SUCCESS
)
710 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
713 if (PageOp
->Status
== STATUS_PENDING
)
715 DPRINT1("Woke for page op before completion\n");
718 MmLockAddressSpace(AddressSpace
);
720 * If this wasn't a pagein then restart the operation
722 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
724 MmspCompleteAndReleasePageOp(PageOp
);
725 DPRINT("Address 0x%.8X\n", Address
);
726 return(STATUS_MM_RESTART_OPERATION
);
730 * If the thread handling this fault has failed then we don't retry
732 if (!NT_SUCCESS(PageOp
->Status
))
734 Status
= PageOp
->Status
;
735 MmspCompleteAndReleasePageOp(PageOp
);
736 DPRINT("Address 0x%.8X\n", Address
);
739 MmLockSectionSegment(Segment
);
741 * If the completed fault was for another address space then set the
744 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
746 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
747 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
749 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
752 * The page was a private page in another or in our address space
754 MmUnlockSectionSegment(Segment
);
755 MmspCompleteAndReleasePageOp(PageOp
);
756 return(STATUS_MM_RESTART_OPERATION
);
759 Page
= PFN_FROM_SSE(Entry
);
761 MmSharePageEntrySectionSegment(Segment
, Offset
);
763 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
764 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
766 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
771 if (!NT_SUCCESS(Status
))
773 DbgPrint("Unable to create virtual mapping\n");
776 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
782 MmUnlockSectionSegment(Segment
);
783 PageOp
->Status
= STATUS_SUCCESS
;
784 MmspCompleteAndReleasePageOp(PageOp
);
785 DPRINT("Address 0x%.8X\n", Address
);
786 return(STATUS_SUCCESS
);
789 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
793 * Must be private page we have swapped out.
800 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
802 DPRINT1("Found a swaped out private page in a pagefile section.\n");
806 MmUnlockSectionSegment(Segment
);
807 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
809 MmUnlockAddressSpace(AddressSpace
);
810 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
811 if (!NT_SUCCESS(Status
))
816 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
817 if (!NT_SUCCESS(Status
))
819 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
822 MmLockAddressSpace(AddressSpace
);
823 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
828 if (!NT_SUCCESS(Status
))
830 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
836 * Store the swap entry for later use.
838 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
841 * Add the page to the process's working set
843 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
846 * Finish the operation
852 PageOp
->Status
= STATUS_SUCCESS
;
853 MmspCompleteAndReleasePageOp(PageOp
);
854 DPRINT("Address 0x%.8X\n", Address
);
855 return(STATUS_SUCCESS
);
859 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
861 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
863 MmUnlockSectionSegment(Segment
);
865 * Just map the desired physical page
867 Page
= (Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
) >> PAGE_SHIFT
;
868 Status
= MmCreateVirtualMappingUnsafe(AddressSpace
->Process
,
873 if (!NT_SUCCESS(Status
))
875 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
880 * Don't add an rmap entry since the page mapped could be for
885 MmLockPageUnsafe(Page
);
889 * Cleanup and release locks
891 PageOp
->Status
= STATUS_SUCCESS
;
892 MmspCompleteAndReleasePageOp(PageOp
);
893 DPRINT("Address 0x%.8X\n", Address
);
894 return(STATUS_SUCCESS
);
898 * Map anonymous memory for BSS sections
900 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
902 MmUnlockSectionSegment(Segment
);
903 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
904 if (!NT_SUCCESS(Status
))
906 MmUnlockAddressSpace(AddressSpace
);
907 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
908 MmLockAddressSpace(AddressSpace
);
910 if (!NT_SUCCESS(Status
))
914 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
919 if (!NT_SUCCESS(Status
))
921 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
925 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
932 * Cleanup and release locks
934 PageOp
->Status
= STATUS_SUCCESS
;
935 MmspCompleteAndReleasePageOp(PageOp
);
936 DPRINT("Address 0x%.8X\n", Address
);
937 return(STATUS_SUCCESS
);
941 * Get the entry corresponding to the offset within the section
943 Offset
+= MemoryArea
->Data
.SectionData
.ViewOffset
;
944 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
949 * If the entry is zero (and it can't change because we have
950 * locked the segment) then we need to load the page.
954 * Release all our locks and read in the page from disk
956 MmUnlockSectionSegment(Segment
);
957 MmUnlockAddressSpace(AddressSpace
);
959 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
960 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
962 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
963 if (!NT_SUCCESS(Status
))
965 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
970 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
971 if (!NT_SUCCESS(Status
))
973 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
976 if (!NT_SUCCESS(Status
))
979 * FIXME: What do we know in this case?
982 * Cleanup and release locks
984 MmLockAddressSpace(AddressSpace
);
985 PageOp
->Status
= Status
;
986 MmspCompleteAndReleasePageOp(PageOp
);
987 DPRINT("Address 0x%.8X\n", Address
);
991 * Relock the address space and segment
993 MmLockAddressSpace(AddressSpace
);
994 MmLockSectionSegment(Segment
);
997 * Check the entry. No one should change the status of a page
998 * that has a pending page-in.
1000 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1001 if (Entry
!= Entry1
)
1003 DbgPrint("Someone changed ppte entry while we slept\n");
1008 * Mark the offset within the section as having valid, in-memory
1011 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1012 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1013 MmUnlockSectionSegment(Segment
);
1015 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1020 if (!NT_SUCCESS(Status
))
1022 DbgPrint("Unable to create virtual mapping\n");
1025 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1031 PageOp
->Status
= STATUS_SUCCESS
;
1032 MmspCompleteAndReleasePageOp(PageOp
);
1033 DPRINT("Address 0x%.8X\n", Address
);
1034 return(STATUS_SUCCESS
);
1036 else if (IS_SWAP_FROM_SSE(Entry
))
1038 SWAPENTRY SwapEntry
;
1040 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1043 * Release all our locks and read in the page from disk
1045 MmUnlockSectionSegment(Segment
);
1047 MmUnlockAddressSpace(AddressSpace
);
1049 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1050 if (!NT_SUCCESS(Status
))
1055 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1056 if (!NT_SUCCESS(Status
))
1062 * Relock the address space and segment
1064 MmLockAddressSpace(AddressSpace
);
1065 MmLockSectionSegment(Segment
);
1068 * Check the entry. No one should change the status of a page
1069 * that has a pending page-in.
1071 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1072 if (Entry
!= Entry1
)
1074 DbgPrint("Someone changed ppte entry while we slept\n");
1079 * Mark the offset within the section as having valid, in-memory
1082 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1083 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1084 MmUnlockSectionSegment(Segment
);
1087 * Save the swap entry.
1089 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1090 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1095 if (!NT_SUCCESS(Status
))
1097 DbgPrint("Unable to create virtual mapping\n");
1100 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1105 PageOp
->Status
= STATUS_SUCCESS
;
1106 MmspCompleteAndReleasePageOp(PageOp
);
1107 DPRINT("Address 0x%.8X\n", Address
);
1108 return(STATUS_SUCCESS
);
1113 * If the section offset is already in-memory and valid then just
1114 * take another reference to the page
1117 Page
= PFN_FROM_SSE(Entry
);
1119 MmSharePageEntrySectionSegment(Segment
, Offset
);
1120 MmUnlockSectionSegment(Segment
);
1122 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1127 if (!NT_SUCCESS(Status
))
1129 DbgPrint("Unable to create virtual mapping\n");
1132 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1137 PageOp
->Status
= STATUS_SUCCESS
;
1138 MmspCompleteAndReleasePageOp(PageOp
);
1139 DPRINT("Address 0x%.8X\n", Address
);
1140 return(STATUS_SUCCESS
);
1145 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1146 MEMORY_AREA
* MemoryArea
,
1150 PMM_SECTION_SEGMENT Segment
;
1151 PSECTION_OBJECT Section
;
1162 * Check if the page has been paged out or has already been set readwrite
1164 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1165 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1167 DPRINT("Address 0x%.8X\n", Address
);
1168 return(STATUS_SUCCESS
);
1172 * Find the offset of the page
1174 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1175 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1177 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1178 Section
= MemoryArea
->Data
.SectionData
.Section
;
1179 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1180 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1185 MmLockSectionSegment(Segment
);
1187 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1188 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1190 MmUnlockSectionSegment(Segment
);
1193 * Check if we are doing COW
1195 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1196 (Region
->Protect
== PAGE_READWRITE
||
1197 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1199 DPRINT("Address 0x%.8X\n", Address
);
1200 return(STATUS_UNSUCCESSFUL
);
1203 if (IS_SWAP_FROM_SSE(Entry
) ||
1204 PFN_FROM_SSE(Entry
) != OldPage
)
1206 /* This is a private page. We must only change the page protection. */
1207 MmSetPageProtect(AddressSpace
->Process
, PAddress
, Region
->Protect
);
1208 return(STATUS_SUCCESS
);
1212 * Get or create a pageop
1214 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1215 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1218 DPRINT1("MmGetPageOp failed\n");
1223 * Wait for any other operations to complete
1225 if (PageOp
->Thread
!= PsGetCurrentThread())
1227 MmUnlockAddressSpace(AddressSpace
);
1228 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1230 * Check for various strange conditions
1232 if (Status
== STATUS_TIMEOUT
)
1234 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1237 if (PageOp
->Status
== STATUS_PENDING
)
1239 DPRINT1("Woke for page op before completion\n");
1243 * Restart the operation
1245 MmLockAddressSpace(AddressSpace
);
1246 MmspCompleteAndReleasePageOp(PageOp
);
1247 DPRINT("Address 0x%.8X\n", Address
);
1248 return(STATUS_MM_RESTART_OPERATION
);
1252 * Release locks now we have the pageop
1254 MmUnlockAddressSpace(AddressSpace
);
1259 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1260 if (!NT_SUCCESS(Status
))
1268 MiCopyFromUserPage(NewPage
, PAddress
);
1271 * Delete the old entry.
1273 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1276 * Set the PTE to point to the new page
1278 MmLockAddressSpace(AddressSpace
);
1279 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1284 if (!NT_SUCCESS(Status
))
1286 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1290 MmInsertRmap(NewPage
, AddressSpace
->Process
, PAddress
);
1291 if (!NT_SUCCESS(Status
))
1293 DbgPrint("Unable to create virtual mapping\n");
1298 MmLockPage(NewPage
);
1299 MmUnlockPage(OldPage
);
1303 * Unshare the old page.
1305 MmDeleteRmap(OldPage
, AddressSpace
->Process
, PAddress
);
1306 MmLockSectionSegment(Segment
);
1307 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1308 MmUnlockSectionSegment(Segment
);
1310 PageOp
->Status
= STATUS_SUCCESS
;
1311 MmspCompleteAndReleasePageOp(PageOp
);
1312 DPRINT("Address 0x%.8X\n", Address
);
1313 return(STATUS_SUCCESS
);
1317 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1319 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1323 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1324 MmDeleteVirtualMapping(Process
,
1331 PageOutContext
->WasDirty
= TRUE
;
1333 if (!PageOutContext
->Private
)
1335 MmUnsharePageEntrySectionSegment(PageOutContext
->Section
,
1336 PageOutContext
->Segment
,
1337 PageOutContext
->Offset
,
1338 PageOutContext
->WasDirty
,
1343 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1346 DPRINT("PhysicalAddress %I64x, Address %x\n", Page
, Address
);
1350 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1351 MEMORY_AREA
* MemoryArea
,
1356 MM_SECTION_PAGEOUT_CONTEXT Context
;
1357 SWAPENTRY SwapEntry
;
1361 PFILE_OBJECT FileObject
;
1363 BOOLEAN DirectMapped
;
1364 BOOLEAN IsImageSection
;
1366 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1369 * Get the segment and section.
1371 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1372 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1374 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1375 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1377 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1379 FileObject
= Context
.Section
->FileObject
;
1380 DirectMapped
= FALSE
;
1381 if (FileObject
!= NULL
&&
1382 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1384 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1387 * If the file system is letting us go directly to the cache and the
1388 * memory area was mapped at an offset in the file which is page aligned
1389 * then note this is a direct mapped page.
1391 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1392 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1394 DirectMapped
= TRUE
;
1400 * This should never happen since mappings of physical memory are never
1401 * placed in the rmap lists.
1403 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1405 DPRINT1("Trying to page out from physical memory section address 0x%X "
1406 "process %d\n", Address
,
1407 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1412 * Get the section segment entry and the physical address.
1414 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1415 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1417 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1418 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1421 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1422 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1425 * Prepare the context structure for the rmap delete call.
1427 Context
.WasDirty
= FALSE
;
1428 if (Context
.Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
||
1429 IS_SWAP_FROM_SSE(Entry
) ||
1430 PFN_FROM_SSE(Entry
) != Page
)
1432 Context
.Private
= TRUE
;
1436 Context
.Private
= FALSE
;
1440 * Take an additional reference to the page or the cache segment.
1442 if (DirectMapped
&& !Context
.Private
)
1444 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1446 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1452 MmReferencePage(Page
);
1455 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1458 * If this wasn't a private page then we should have reduced the entry to
1459 * zero by deleting all the rmaps.
1461 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1463 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1464 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1471 * If the page wasn't dirty then we can just free it as for a readonly page.
1472 * Since we unmapped all the mappings above we know it will not suddenly
1474 * If the page is from a pagefile section and has no swap entry,
1475 * we can't free the page at this point.
1477 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1478 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1480 if (Context
.Private
)
1482 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1483 Context
.WasDirty
? "dirty" : "clean", Address
);
1486 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1488 MmSetSavedSwapEntryPage(Page
, 0);
1489 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1490 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1491 PageOp
->Status
= STATUS_SUCCESS
;
1492 MmspCompleteAndReleasePageOp(PageOp
);
1493 return(STATUS_SUCCESS
);
1496 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1498 if (Context
.Private
)
1500 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1501 Context
.WasDirty
? "dirty" : "clean", Address
);
1504 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1506 MmSetSavedSwapEntryPage(Page
, 0);
1509 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1511 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1512 PageOp
->Status
= STATUS_SUCCESS
;
1513 MmspCompleteAndReleasePageOp(PageOp
);
1514 return(STATUS_SUCCESS
);
1517 else if (!Context
.Private
&& DirectMapped
)
1521 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1525 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1526 if (!NT_SUCCESS(Status
))
1528 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1531 PageOp
->Status
= STATUS_SUCCESS
;
1532 MmspCompleteAndReleasePageOp(PageOp
);
1533 return(STATUS_SUCCESS
);
1535 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1539 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1543 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1544 PageOp
->Status
= STATUS_SUCCESS
;
1545 MmspCompleteAndReleasePageOp(PageOp
);
1546 return(STATUS_SUCCESS
);
1548 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1550 MmSetSavedSwapEntryPage(Page
, 0);
1551 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1554 if (!NT_SUCCESS(Status
))
1558 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1559 PageOp
->Status
= STATUS_SUCCESS
;
1560 MmspCompleteAndReleasePageOp(PageOp
);
1561 return(STATUS_SUCCESS
);
1565 * If necessary, allocate an entry in the paging file for this page
1569 SwapEntry
= MmAllocSwapPage();
1572 MmShowOutOfSpaceMessagePagingFile();
1575 * For private pages restore the old mappings.
1577 if (Context
.Private
)
1579 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1581 MemoryArea
->Attributes
,
1584 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1586 AddressSpace
->Process
,
1592 * For non-private pages if the page wasn't direct mapped then
1593 * set it back into the section segment entry so we don't loose
1594 * our copy. Otherwise it will be handled by the cache manager.
1596 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1598 MemoryArea
->Attributes
,
1601 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1603 AddressSpace
->Process
,
1605 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1606 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1608 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1609 MmspCompleteAndReleasePageOp(PageOp
);
1610 return(STATUS_PAGEFILE_QUOTA
);
1615 * Write the page to the pagefile
1617 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1618 if (!NT_SUCCESS(Status
))
1620 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1623 * As above: undo our actions.
1624 * FIXME: Also free the swap page.
1626 if (Context
.Private
)
1628 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1630 MemoryArea
->Attributes
,
1633 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1635 AddressSpace
->Process
,
1640 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1642 MemoryArea
->Attributes
,
1645 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1647 AddressSpace
->Process
,
1649 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1650 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1652 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1653 MmspCompleteAndReleasePageOp(PageOp
);
1654 return(STATUS_UNSUCCESSFUL
);
1658 * Otherwise we have succeeded.
1660 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1661 MmSetSavedSwapEntryPage(Page
, 0);
1662 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1663 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1665 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1669 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1672 if (Context
.Private
)
1674 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1677 if (!NT_SUCCESS(Status
))
1684 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1685 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1688 PageOp
->Status
= STATUS_SUCCESS
;
1689 MmspCompleteAndReleasePageOp(PageOp
);
1690 return(STATUS_SUCCESS
);
1694 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1695 PMEMORY_AREA MemoryArea
,
1700 PSECTION_OBJECT Section
;
1701 PMM_SECTION_SEGMENT Segment
;
1703 SWAPENTRY SwapEntry
;
1707 PFILE_OBJECT FileObject
;
1709 BOOLEAN DirectMapped
;
1710 BOOLEAN IsImageSection
;
1712 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1714 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1717 * Get the segment and section.
1719 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1720 Section
= MemoryArea
->Data
.SectionData
.Section
;
1721 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1723 FileObject
= Section
->FileObject
;
1724 DirectMapped
= FALSE
;
1725 if (FileObject
!= NULL
&&
1726 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1728 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1731 * If the file system is letting us go directly to the cache and the
1732 * memory area was mapped at an offset in the file which is page aligned
1733 * then note this is a direct mapped page.
1735 if ((Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
% PAGE_SIZE
) == 0 &&
1736 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1738 DirectMapped
= TRUE
;
1743 * This should never happen since mappings of physical memory are never
1744 * placed in the rmap lists.
1746 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1748 DPRINT1("Trying to write back page from physical memory mapped at %X "
1749 "process %d\n", Address
,
1750 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1755 * Get the section segment entry and the physical address.
1757 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1758 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1760 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1761 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1764 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1765 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1768 * Check for a private (COWed) page.
1770 if (Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
||
1771 IS_SWAP_FROM_SSE(Entry
) ||
1772 PFN_FROM_SSE(Entry
) != Page
)
1782 * Speculatively set all mappings of the page to clean.
1784 MmSetCleanAllRmaps(Page
);
1787 * If this page was direct mapped from the cache then the cache manager
1788 * will take care of writing it back to disk.
1790 if (DirectMapped
&& !Private
)
1792 ASSERT(SwapEntry
== 0);
1793 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
1794 PageOp
->Status
= STATUS_SUCCESS
;
1795 MmspCompleteAndReleasePageOp(PageOp
);
1796 return(STATUS_SUCCESS
);
1800 * If necessary, allocate an entry in the paging file for this page
1804 SwapEntry
= MmAllocSwapPage();
1807 MmSetDirtyAllRmaps(Page
);
1808 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1809 MmspCompleteAndReleasePageOp(PageOp
);
1810 return(STATUS_PAGEFILE_QUOTA
);
1812 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1816 * Write the page to the pagefile
1818 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1819 if (!NT_SUCCESS(Status
))
1821 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1823 MmSetDirtyAllRmaps(Page
);
1824 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1825 MmspCompleteAndReleasePageOp(PageOp
);
1826 return(STATUS_UNSUCCESSFUL
);
1830 * Otherwise we have succeeded.
1832 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1833 PageOp
->Status
= STATUS_SUCCESS
;
1834 MmspCompleteAndReleasePageOp(PageOp
);
1835 return(STATUS_SUCCESS
);
1839 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1847 PMEMORY_AREA MemoryArea
;
1848 PMM_SECTION_SEGMENT Segment
;
1852 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1853 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1855 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1856 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1861 if (OldProtect
!= NewProtect
)
1863 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1865 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1866 ULONG Protect
= NewProtect
;
1869 * If we doing COW for this segment then check if the page is
1872 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1878 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
;
1879 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1880 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1882 Protect
= PAGE_READONLY
;
1883 if (Segment
->Characteristics
& IMAGE_SCN_LNK_OTHER
||
1884 IS_SWAP_FROM_SSE(Entry
) ||
1885 PFN_FROM_SSE(Entry
) != Page
)
1887 Protect
= NewProtect
;
1891 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
1893 MmSetPageProtect(AddressSpace
->Process
, Address
,
1901 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
1902 PMEMORY_AREA MemoryArea
,
1910 ULONG_PTR MaxLength
;
1912 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
1913 if (Length
> MaxLength
)
1916 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1917 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1919 *OldProtect
= Region
->Protect
;
1920 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
1921 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1922 BaseAddress
, Length
, Region
->Type
, Protect
,
1923 MmAlterViewAttributes
);
1929 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
1931 PMEMORY_BASIC_INFORMATION Info
,
1932 PULONG ResultLength
)
1935 PVOID RegionBaseAddress
;
1936 PSECTION_OBJECT Section
;
1937 PMM_SECTION_SEGMENT Segment
;
1939 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
1940 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1941 Address
, &RegionBaseAddress
);
1944 return STATUS_UNSUCCESSFUL
;
1947 Section
= MemoryArea
->Data
.SectionData
.Section
;
1948 if (Section
->AllocationAttributes
& SEC_IMAGE
)
1950 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1951 Info
->AllocationBase
= MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
1952 Info
->Type
= MEM_IMAGE
;
1956 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
1957 Info
->Type
= MEM_MAPPED
;
1959 Info
->BaseAddress
= RegionBaseAddress
;
1960 Info
->AllocationProtect
= MemoryArea
->Attributes
;
1961 Info
->RegionSize
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
-
1962 (ULONG_PTR
)MemoryArea
->StartingAddress
);
1963 Info
->State
= MEM_COMMIT
;
1964 Info
->Protect
= Region
->Protect
;
1966 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
1967 return(STATUS_SUCCESS
);
1971 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
1976 ULONG SavedSwapEntry
;
1981 Length
= PAGE_ROUND_UP(Segment
->Length
);
1982 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
1984 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1987 if (IS_SWAP_FROM_SSE(Entry
))
1989 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
1993 Page
= PFN_FROM_SSE(Entry
);
1994 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
1995 if (SavedSwapEntry
!= 0)
1997 MmSetSavedSwapEntryPage(Page
, 0);
1998 MmFreeSwapPage(SavedSwapEntry
);
2000 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2002 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2008 MmpDeleteSection(PVOID ObjectBody
)
2010 PSECTION_OBJECT Section
= (PSECTION_OBJECT
)ObjectBody
;
2012 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2013 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2018 PMM_SECTION_SEGMENT SectionSegments
;
2021 * NOTE: Section->ImageSection can be NULL for short time
2022 * during the section creating. If we fail for some reason
2023 * until the image section is properly initialized we shouldn't
2024 * process further here.
2026 if (Section
->ImageSection
== NULL
)
2029 SectionSegments
= Section
->ImageSection
->Segments
;
2030 NrSegments
= Section
->ImageSection
->NrSegments
;
2032 for (i
= 0; i
< NrSegments
; i
++)
2034 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2036 MmLockSectionSegment(&SectionSegments
[i
]);
2038 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2039 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2043 MmpFreePageFileSegment(&SectionSegments
[i
]);
2045 MmUnlockSectionSegment(&SectionSegments
[i
]);
2052 * NOTE: Section->Segment can be NULL for short time
2053 * during the section creating.
2055 if (Section
->Segment
== NULL
)
2058 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2060 MmpFreePageFileSegment(Section
->Segment
);
2061 MmFreePageTablesSectionSegment(Section
->Segment
);
2062 ExFreePool(Section
->Segment
);
2063 Section
->Segment
= NULL
;
2067 InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2070 if (Section
->FileObject
!= NULL
)
2072 CcRosDereferenceCache(Section
->FileObject
);
2073 ObDereferenceObject(Section
->FileObject
);
2074 Section
->FileObject
= NULL
;
2079 MmpCloseSection(PVOID ObjectBody
,
2082 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2083 ObjectBody
, HandleCount
, ObGetObjectPointerCount(ObjectBody
));
2086 NTSTATUS INIT_FUNCTION
2087 MmCreatePhysicalMemorySection(VOID
)
2089 PSECTION_OBJECT PhysSection
;
2091 OBJECT_ATTRIBUTES Obj
;
2092 UNICODE_STRING Name
= ROS_STRING_INITIALIZER(L
"\\Device\\PhysicalMemory");
2093 LARGE_INTEGER SectionSize
;
2096 * Create the section mapping physical memory
2098 SectionSize
.QuadPart
= 0xFFFFFFFF;
2099 InitializeObjectAttributes(&Obj
,
2104 Status
= MmCreateSection(&PhysSection
,
2108 PAGE_EXECUTE_READWRITE
,
2112 if (!NT_SUCCESS(Status
))
2114 DbgPrint("Failed to create PhysicalMemory section\n");
2117 Status
= ObInsertObject(PhysSection
,
2123 if (!NT_SUCCESS(Status
))
2125 ObDereferenceObject(PhysSection
);
2127 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2129 return(STATUS_SUCCESS
);
2132 NTSTATUS INIT_FUNCTION
2133 MmInitSectionImplementation(VOID
)
2135 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2136 UNICODE_STRING Name
;
2138 DPRINT("Creating Section Object Type\n");
2140 /* Initialize the Section object type */
2141 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2142 RtlInitUnicodeString(&Name
, L
"Section");
2143 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2144 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(SECTION_OBJECT
);
2145 ObjectTypeInitializer
.PoolType
= PagedPool
;
2146 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2147 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2148 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2149 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2150 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &MmSectionObjectType
);
2152 return(STATUS_SUCCESS
);
2156 MmCreatePageFileSection(PSECTION_OBJECT
*SectionObject
,
2157 ACCESS_MASK DesiredAccess
,
2158 POBJECT_ATTRIBUTES ObjectAttributes
,
2159 PLARGE_INTEGER UMaximumSize
,
2160 ULONG SectionPageProtection
,
2161 ULONG AllocationAttributes
)
2163 * Create a section which is backed by the pagefile
2166 LARGE_INTEGER MaximumSize
;
2167 PSECTION_OBJECT Section
;
2168 PMM_SECTION_SEGMENT Segment
;
2171 if (UMaximumSize
== NULL
)
2173 return(STATUS_UNSUCCESSFUL
);
2175 MaximumSize
= *UMaximumSize
;
2178 * Create the section
2180 Status
= ObCreateObject(ExGetPreviousMode(),
2181 MmSectionObjectType
,
2183 ExGetPreviousMode(),
2185 sizeof(SECTION_OBJECT
),
2188 (PVOID
*)(PVOID
)&Section
);
2189 if (!NT_SUCCESS(Status
))
2197 Section
->SectionPageProtection
= SectionPageProtection
;
2198 Section
->AllocationAttributes
= AllocationAttributes
;
2199 Section
->Segment
= NULL
;
2200 Section
->FileObject
= NULL
;
2201 Section
->MaximumSize
= MaximumSize
;
2202 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2203 TAG_MM_SECTION_SEGMENT
);
2204 if (Segment
== NULL
)
2206 ObDereferenceObject(Section
);
2207 return(STATUS_NO_MEMORY
);
2209 Section
->Segment
= Segment
;
2210 Segment
->ReferenceCount
= 1;
2211 ExInitializeFastMutex(&Segment
->Lock
);
2212 Segment
->FileOffset
= 0;
2213 Segment
->Protection
= SectionPageProtection
;
2214 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2215 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2216 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2217 Segment
->WriteCopy
= FALSE
;
2218 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2219 Segment
->VirtualAddress
= 0;
2220 Segment
->Characteristics
= 0;
2221 *SectionObject
= Section
;
2222 return(STATUS_SUCCESS
);
2227 MmCreateDataFileSection(PSECTION_OBJECT
*SectionObject
,
2228 ACCESS_MASK DesiredAccess
,
2229 POBJECT_ATTRIBUTES ObjectAttributes
,
2230 PLARGE_INTEGER UMaximumSize
,
2231 ULONG SectionPageProtection
,
2232 ULONG AllocationAttributes
,
2235 * Create a section backed by a data file
2238 PSECTION_OBJECT Section
;
2240 LARGE_INTEGER MaximumSize
;
2241 PFILE_OBJECT FileObject
;
2242 PMM_SECTION_SEGMENT Segment
;
2244 IO_STATUS_BLOCK Iosb
;
2245 LARGE_INTEGER Offset
;
2247 FILE_STANDARD_INFORMATION FileInfo
;
2250 * Create the section
2252 Status
= ObCreateObject(ExGetPreviousMode(),
2253 MmSectionObjectType
,
2255 ExGetPreviousMode(),
2257 sizeof(SECTION_OBJECT
),
2260 (PVOID
*)(PVOID
)&Section
);
2261 if (!NT_SUCCESS(Status
))
2268 Section
->SectionPageProtection
= SectionPageProtection
;
2269 Section
->AllocationAttributes
= AllocationAttributes
;
2270 Section
->Segment
= NULL
;
2273 * Check file access required
2275 if (SectionPageProtection
& PAGE_READWRITE
||
2276 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2278 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2282 FileAccess
= FILE_READ_DATA
;
2286 * Reference the file handle
2288 Status
= ObReferenceObjectByHandle(FileHandle
,
2292 (PVOID
*)(PVOID
)&FileObject
,
2294 if (!NT_SUCCESS(Status
))
2296 ObDereferenceObject(Section
);
2301 * FIXME: This is propably not entirely correct. We can't look into
2302 * the standard FCB header because it might not be initialized yet
2303 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2304 * standard file information is filled on first request).
2306 Status
= NtQueryInformationFile(FileHandle
,
2309 sizeof(FILE_STANDARD_INFORMATION
),
2310 FileStandardInformation
);
2311 if (!NT_SUCCESS(Status
))
2313 ObDereferenceObject(Section
);
2314 ObDereferenceObject(FileObject
);
2319 * FIXME: Revise this once a locking order for file size changes is
2322 if (UMaximumSize
!= NULL
)
2324 MaximumSize
= *UMaximumSize
;
2328 MaximumSize
= FileInfo
.EndOfFile
;
2329 /* Mapping zero-sized files isn't allowed. */
2330 if (MaximumSize
.QuadPart
== 0)
2332 ObDereferenceObject(Section
);
2333 ObDereferenceObject(FileObject
);
2334 return STATUS_FILE_INVALID
;
2338 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2340 Status
= NtSetInformationFile(FileHandle
,
2343 sizeof(LARGE_INTEGER
),
2344 FileAllocationInformation
);
2345 if (!NT_SUCCESS(Status
))
2347 ObDereferenceObject(Section
);
2348 ObDereferenceObject(FileObject
);
2349 return(STATUS_SECTION_NOT_EXTENDED
);
2353 if (FileObject
->SectionObjectPointer
== NULL
||
2354 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2357 * Read a bit so caching is initiated for the file object.
2358 * This is only needed because MiReadPage currently cannot
2359 * handle non-cached streams.
2361 Offset
.QuadPart
= 0;
2362 Status
= ZwReadFile(FileHandle
,
2371 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2373 ObDereferenceObject(Section
);
2374 ObDereferenceObject(FileObject
);
2377 if (FileObject
->SectionObjectPointer
== NULL
||
2378 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2380 /* FIXME: handle this situation */
2381 ObDereferenceObject(Section
);
2382 ObDereferenceObject(FileObject
);
2383 return STATUS_INVALID_PARAMETER
;
2390 Status
= MmspWaitForFileLock(FileObject
);
2391 if (Status
!= STATUS_SUCCESS
)
2393 ObDereferenceObject(Section
);
2394 ObDereferenceObject(FileObject
);
2399 * If this file hasn't been mapped as a data file before then allocate a
2400 * section segment to describe the data file mapping
2402 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2404 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2405 TAG_MM_SECTION_SEGMENT
);
2406 if (Segment
== NULL
)
2408 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2409 ObDereferenceObject(Section
);
2410 ObDereferenceObject(FileObject
);
2411 return(STATUS_NO_MEMORY
);
2413 Section
->Segment
= Segment
;
2414 Segment
->ReferenceCount
= 1;
2415 ExInitializeFastMutex(&Segment
->Lock
);
2417 * Set the lock before assigning the segment to the file object
2419 ExAcquireFastMutex(&Segment
->Lock
);
2420 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2422 Segment
->FileOffset
= 0;
2423 Segment
->Protection
= SectionPageProtection
;
2424 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2425 Segment
->Characteristics
= 0;
2426 Segment
->WriteCopy
= FALSE
;
2427 if (AllocationAttributes
& SEC_RESERVE
)
2429 Segment
->Length
= Segment
->RawLength
= 0;
2433 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2434 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2436 Segment
->VirtualAddress
= 0;
2437 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2442 * If the file is already mapped as a data file then we may need
2446 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2448 Section
->Segment
= Segment
;
2449 InterlockedIncrementUL(&Segment
->ReferenceCount
);
2450 MmLockSectionSegment(Segment
);
2452 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2453 !(AllocationAttributes
& SEC_RESERVE
))
2455 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2456 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2459 MmUnlockSectionSegment(Segment
);
2460 Section
->FileObject
= FileObject
;
2461 Section
->MaximumSize
= MaximumSize
;
2462 CcRosReferenceCache(FileObject
);
2463 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
2464 *SectionObject
= Section
;
2465 return(STATUS_SUCCESS
);
2469 TODO: not that great (declaring loaders statically, having to declare all of
2470 them, having to keep them extern, etc.), will fix in the future
2472 extern NTSTATUS NTAPI PeFmtCreateSection
2474 IN CONST VOID
* FileHeader
,
2475 IN SIZE_T FileHeaderSize
,
2477 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2479 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2480 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2483 extern NTSTATUS NTAPI ElfFmtCreateSection
2485 IN CONST VOID
* FileHeader
,
2486 IN SIZE_T FileHeaderSize
,
2488 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2490 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2491 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2494 /* TODO: this is a standard DDK/PSDK macro */
2495 #ifndef RTL_NUMBER_OF
2496 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2499 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2508 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2510 SIZE_T SizeOfSegments
;
2511 PMM_SECTION_SEGMENT Segments
;
2513 /* TODO: check for integer overflow */
2514 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2516 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2518 TAG_MM_SECTION_SEGMENT
);
2521 RtlZeroMemory(Segments
, SizeOfSegments
);
2529 ExeFmtpReadFile(IN PVOID File
,
2530 IN PLARGE_INTEGER Offset
,
2533 OUT PVOID
* AllocBase
,
2534 OUT PULONG ReadSize
)
2537 LARGE_INTEGER FileOffset
;
2539 ULONG OffsetAdjustment
;
2544 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2548 KEBUGCHECK(STATUS_INVALID_PARAMETER_4
);
2551 FileOffset
= *Offset
;
2553 /* Negative/special offset: it cannot be used in this context */
2554 if(FileOffset
.u
.HighPart
< 0)
2556 KEBUGCHECK(STATUS_INVALID_PARAMETER_5
);
2559 ASSERT(PAGE_SIZE
<= MAXULONG
);
2560 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2561 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2562 FileOffset
.u
.LowPart
= AdjustOffset
;
2564 BufferSize
= Length
+ OffsetAdjustment
;
2565 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2568 * It's ok to use paged pool, because this is a temporary buffer only used in
2569 * the loading of executables. The assumption is that MmCreateSection is
2570 * always called at low IRQLs and that these buffers don't survive a brief
2571 * initialization phase
2573 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2575 TAG('M', 'm', 'X', 'r'));
2580 Status
= MmspPageRead(File
,
2587 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2588 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2589 * to initialize internal state is even worse. Our cache manager is in need of
2593 IO_STATUS_BLOCK Iosb
;
2595 Status
= ZwReadFile(File
,
2605 if(NT_SUCCESS(Status
))
2607 UsedSize
= Iosb
.Information
;
2612 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2614 Status
= STATUS_IN_PAGE_ERROR
;
2615 ASSERT(!NT_SUCCESS(Status
));
2618 if(NT_SUCCESS(Status
))
2620 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2621 *AllocBase
= Buffer
;
2622 *ReadSize
= UsedSize
- OffsetAdjustment
;
2633 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2634 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2635 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2640 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2644 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2646 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2647 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2654 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2658 MmspAssertSegmentsSorted(ImageSectionObject
);
2660 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2662 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2666 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2667 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2668 ImageSectionObject
->Segments
[i
- 1].Length
));
2676 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2680 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2682 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2683 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2691 MmspCompareSegments(const void * x
,
2694 PMM_SECTION_SEGMENT Segment1
= (PMM_SECTION_SEGMENT
)x
;
2695 PMM_SECTION_SEGMENT Segment2
= (PMM_SECTION_SEGMENT
)y
;
2698 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2699 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2703 * Ensures an image section's segments are sorted in memory
2708 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2711 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2713 MmspAssertSegmentsSorted(ImageSectionObject
);
2717 qsort(ImageSectionObject
->Segments
,
2718 ImageSectionObject
->NrSegments
,
2719 sizeof(ImageSectionObject
->Segments
[0]),
2720 MmspCompareSegments
);
2726 * Ensures an image section's segments don't overlap in memory and don't have
2727 * gaps and don't have a null size. We let them map to overlapping file regions,
2728 * though - that's not necessarily an error
2733 MmspCheckSegmentBounds
2735 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2741 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2743 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2747 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2749 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2751 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2759 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2760 * page could be OK (Windows seems to be OK with them), and larger gaps
2761 * could lead to image sections spanning several discontiguous regions
2762 * (NtMapViewOfSection could then refuse to map them, and they could
2763 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2765 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2766 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2767 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2778 * Merges and pads an image section's segments until they all are page-aligned
2779 * and have a size that is a multiple of the page size
2784 MmspPageAlignSegments
2786 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2792 BOOLEAN Initialized
;
2794 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2796 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2800 Initialized
= FALSE
;
2803 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2805 PMM_SECTION_SEGMENT EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2808 * The first segment requires special handling
2812 ULONG_PTR VirtualAddress
;
2813 ULONG_PTR VirtualOffset
;
2815 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2817 /* Round down the virtual address to the nearest page */
2818 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2820 /* Round up the virtual size to the nearest page */
2821 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2822 EffectiveSegment
->VirtualAddress
;
2824 /* Adjust the raw address and size */
2825 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2827 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
2833 * Garbage in, garbage out: unaligned base addresses make the file
2834 * offset point in curious and odd places, but that's what we were
2837 EffectiveSegment
->FileOffset
-= VirtualOffset
;
2838 EffectiveSegment
->RawLength
+= VirtualOffset
;
2842 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
2843 ULONG_PTR EndOfEffectiveSegment
;
2845 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
2846 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
2849 * The current segment begins exactly where the current effective
2850 * segment ended, therefore beginning a new effective segment
2852 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
2855 ASSERT(LastSegment
<= i
);
2856 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
2858 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2861 * Copy the current segment. If necessary, the effective segment
2862 * will be expanded later
2864 *EffectiveSegment
= *Segment
;
2867 * Page-align the virtual size. We know for sure the virtual address
2870 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
2871 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
2874 * The current segment is still part of the current effective segment:
2875 * extend the effective segment to reflect this
2877 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
2879 static const ULONG FlagsToProtection
[16] =
2887 PAGE_EXECUTE_READWRITE
,
2888 PAGE_EXECUTE_READWRITE
,
2893 PAGE_EXECUTE_WRITECOPY
,
2894 PAGE_EXECUTE_WRITECOPY
,
2895 PAGE_EXECUTE_WRITECOPY
,
2896 PAGE_EXECUTE_WRITECOPY
2899 unsigned ProtectionFlags
;
2902 * Extend the file size
2905 /* Unaligned segments must be contiguous within the file */
2906 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
2907 EffectiveSegment
->RawLength
))
2912 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
2915 * Extend the virtual size
2917 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) > EndOfEffectiveSegment
);
2919 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
2920 EffectiveSegment
->VirtualAddress
;
2923 * Merge the protection
2925 EffectiveSegment
->Protection
|= Segment
->Protection
;
2927 /* Clean up redundance */
2928 ProtectionFlags
= 0;
2930 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
2931 ProtectionFlags
|= 1 << 0;
2933 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
2934 ProtectionFlags
|= 1 << 1;
2936 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
2937 ProtectionFlags
|= 1 << 2;
2939 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2940 ProtectionFlags
|= 1 << 3;
2942 ASSERT(ProtectionFlags
< 16);
2943 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
2945 /* If a segment was required to be shared and cannot, fail */
2946 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
2947 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
2953 * We assume no holes between segments at this point
2966 ExeFmtpCreateImageSection(HANDLE FileHandle
,
2967 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2969 LARGE_INTEGER Offset
;
2971 PVOID FileHeaderBuffer
;
2972 ULONG FileHeaderSize
;
2974 ULONG OldNrSegments
;
2979 * Read the beginning of the file (2 pages). Should be enough to contain
2980 * all (or most) of the headers
2982 Offset
.QuadPart
= 0;
2984 /* FIXME: use FileObject instead of FileHandle */
2985 Status
= ExeFmtpReadFile (FileHandle
,
2992 if (!NT_SUCCESS(Status
))
2995 if (FileHeaderSize
== 0)
2997 ExFreePool(FileHeaderBuffer
);
2998 return STATUS_UNSUCCESSFUL
;
3002 * Look for a loader that can handle this executable
3004 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3006 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3009 /* FIXME: use FileObject instead of FileHandle */
3010 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3016 ExeFmtpAllocateSegments
);
3018 if (!NT_SUCCESS(Status
))
3020 if (ImageSectionObject
->Segments
)
3022 ExFreePool(ImageSectionObject
->Segments
);
3023 ImageSectionObject
->Segments
= NULL
;
3027 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3031 ExFreePool(FileHeaderBuffer
);
3034 * No loader handled the format
3036 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3038 Status
= STATUS_INVALID_IMAGE_FORMAT
;
3039 ASSERT(!NT_SUCCESS(Status
));
3042 if (!NT_SUCCESS(Status
))
3045 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3050 /* FIXME? are these values platform-dependent? */
3051 if(ImageSectionObject
->StackReserve
== 0)
3052 ImageSectionObject
->StackReserve
= 0x40000;
3054 if(ImageSectionObject
->StackCommit
== 0)
3055 ImageSectionObject
->StackCommit
= 0x1000;
3057 if(ImageSectionObject
->ImageBase
== 0)
3059 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3060 ImageSectionObject
->ImageBase
= 0x10000000;
3062 ImageSectionObject
->ImageBase
= 0x00400000;
3066 * And now the fun part: fixing the segments
3069 /* Sort them by virtual address */
3070 MmspSortSegments(ImageSectionObject
, Flags
);
3072 /* Ensure they don't overlap in memory */
3073 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3074 return STATUS_INVALID_IMAGE_FORMAT
;
3076 /* Ensure they are aligned */
3077 OldNrSegments
= ImageSectionObject
->NrSegments
;
3079 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3080 return STATUS_INVALID_IMAGE_FORMAT
;
3082 /* Trim them if the alignment phase merged some of them */
3083 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3085 PMM_SECTION_SEGMENT Segments
;
3086 SIZE_T SizeOfSegments
;
3088 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3090 Segments
= ExAllocatePoolWithTag(PagedPool
,
3092 TAG_MM_SECTION_SEGMENT
);
3094 if (Segments
== NULL
)
3095 return STATUS_INSUFFICIENT_RESOURCES
;
3097 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3098 ExFreePool(ImageSectionObject
->Segments
);
3099 ImageSectionObject
->Segments
= Segments
;
3102 /* And finish their initialization */
3103 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3105 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3106 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3108 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3109 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3112 ASSERT(NT_SUCCESS(Status
));
3117 MmCreateImageSection(PSECTION_OBJECT
*SectionObject
,
3118 ACCESS_MASK DesiredAccess
,
3119 POBJECT_ATTRIBUTES ObjectAttributes
,
3120 PLARGE_INTEGER UMaximumSize
,
3121 ULONG SectionPageProtection
,
3122 ULONG AllocationAttributes
,
3125 PSECTION_OBJECT Section
;
3127 PFILE_OBJECT FileObject
;
3128 PMM_SECTION_SEGMENT SectionSegments
;
3129 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3131 ULONG FileAccess
= 0;
3134 * Specifying a maximum size is meaningless for an image section
3136 if (UMaximumSize
!= NULL
)
3138 return(STATUS_INVALID_PARAMETER_4
);
3142 * Check file access required
3144 if (SectionPageProtection
& PAGE_READWRITE
||
3145 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3147 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3151 FileAccess
= FILE_READ_DATA
;
3155 * Reference the file handle
3157 Status
= ObReferenceObjectByHandle(FileHandle
,
3161 (PVOID
*)(PVOID
)&FileObject
,
3164 if (!NT_SUCCESS(Status
))
3170 * Create the section
3172 Status
= ObCreateObject (ExGetPreviousMode(),
3173 MmSectionObjectType
,
3175 ExGetPreviousMode(),
3177 sizeof(SECTION_OBJECT
),
3180 (PVOID
*)(PVOID
)&Section
);
3181 if (!NT_SUCCESS(Status
))
3183 ObDereferenceObject(FileObject
);
3190 Section
->SectionPageProtection
= SectionPageProtection
;
3191 Section
->AllocationAttributes
= AllocationAttributes
;
3194 * Initialized caching for this file object if previously caching
3195 * was initialized for the same on disk file
3197 Status
= CcTryToInitializeFileCache(FileObject
);
3199 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3201 NTSTATUS StatusExeFmt
;
3203 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3204 if (ImageSectionObject
== NULL
)
3206 ObDereferenceObject(FileObject
);
3207 ObDereferenceObject(Section
);
3208 return(STATUS_NO_MEMORY
);
3211 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3213 if (!NT_SUCCESS(StatusExeFmt
))
3215 if(ImageSectionObject
->Segments
!= NULL
)
3216 ExFreePool(ImageSectionObject
->Segments
);
3218 ExFreePool(ImageSectionObject
);
3219 ObDereferenceObject(Section
);
3220 ObDereferenceObject(FileObject
);
3221 return(StatusExeFmt
);
3224 Section
->ImageSection
= ImageSectionObject
;
3225 ASSERT(ImageSectionObject
->Segments
);
3230 Status
= MmspWaitForFileLock(FileObject
);
3231 if (!NT_SUCCESS(Status
))
3233 ExFreePool(ImageSectionObject
->Segments
);
3234 ExFreePool(ImageSectionObject
);
3235 ObDereferenceObject(Section
);
3236 ObDereferenceObject(FileObject
);
3240 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3241 ImageSectionObject
, NULL
))
3244 * An other thread has initialized the some image in the background
3246 ExFreePool(ImageSectionObject
->Segments
);
3247 ExFreePool(ImageSectionObject
);
3248 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3249 Section
->ImageSection
= ImageSectionObject
;
3250 SectionSegments
= ImageSectionObject
->Segments
;
3252 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3254 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3258 Status
= StatusExeFmt
;
3265 Status
= MmspWaitForFileLock(FileObject
);
3266 if (Status
!= STATUS_SUCCESS
)
3268 ObDereferenceObject(Section
);
3269 ObDereferenceObject(FileObject
);
3273 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3274 Section
->ImageSection
= ImageSectionObject
;
3275 SectionSegments
= ImageSectionObject
->Segments
;
3278 * Otherwise just reference all the section segments
3280 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3282 InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3285 Status
= STATUS_SUCCESS
;
3287 Section
->FileObject
= FileObject
;
3288 CcRosReferenceCache(FileObject
);
3289 KeSetEvent((PVOID
)&FileObject
->Lock
, IO_NO_INCREMENT
, FALSE
);
3290 *SectionObject
= Section
;
3298 NtCreateSection (OUT PHANDLE SectionHandle
,
3299 IN ACCESS_MASK DesiredAccess
,
3300 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3301 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3302 IN ULONG SectionPageProtection OPTIONAL
,
3303 IN ULONG AllocationAttributes
,
3304 IN HANDLE FileHandle OPTIONAL
)
3306 LARGE_INTEGER SafeMaximumSize
;
3307 PSECTION_OBJECT SectionObject
;
3308 KPROCESSOR_MODE PreviousMode
;
3309 NTSTATUS Status
= STATUS_SUCCESS
;
3311 PreviousMode
= ExGetPreviousMode();
3313 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3317 ProbeForRead(MaximumSize
,
3318 sizeof(LARGE_INTEGER
),
3320 /* make a copy on the stack */
3321 SafeMaximumSize
= *MaximumSize
;
3322 MaximumSize
= &SafeMaximumSize
;
3326 Status
= _SEH_GetExceptionCode();
3330 if(!NT_SUCCESS(Status
))
3337 * Check the protection
3339 if ((SectionPageProtection
& PAGE_FLAGS_VALID_FROM_USER_MODE
) !=
3340 SectionPageProtection
)
3342 return(STATUS_INVALID_PAGE_PROTECTION
);
3345 Status
= MmCreateSection(&SectionObject
,
3349 SectionPageProtection
,
3350 AllocationAttributes
,
3354 if (NT_SUCCESS(Status
))
3356 Status
= ObInsertObject ((PVOID
)SectionObject
,
3362 ObDereferenceObject(SectionObject
);
3369 /**********************************************************************
3387 NtOpenSection(PHANDLE SectionHandle
,
3388 ACCESS_MASK DesiredAccess
,
3389 POBJECT_ATTRIBUTES ObjectAttributes
)
3392 KPROCESSOR_MODE PreviousMode
;
3393 NTSTATUS Status
= STATUS_SUCCESS
;
3395 PreviousMode
= ExGetPreviousMode();
3397 if(PreviousMode
!= KernelMode
)
3401 ProbeForWrite(SectionHandle
,
3407 Status
= _SEH_GetExceptionCode();
3411 if(!NT_SUCCESS(Status
))
3417 Status
= ObOpenObjectByName(ObjectAttributes
,
3418 MmSectionObjectType
,
3425 if(NT_SUCCESS(Status
))
3429 *SectionHandle
= hSection
;
3433 Status
= _SEH_GetExceptionCode();
3442 MmMapViewOfSegment(PEPROCESS Process
,
3443 PMADDRESS_SPACE AddressSpace
,
3444 PSECTION_OBJECT Section
,
3445 PMM_SECTION_SEGMENT Segment
,
3454 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3456 BoundaryAddressMultiple
.QuadPart
= 0;
3458 Status
= MmCreateMemoryArea(Process
,
3460 MEMORY_AREA_SECTION_VIEW
,
3467 BoundaryAddressMultiple
);
3468 if (!NT_SUCCESS(Status
))
3470 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3471 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3476 ObReferenceObjectByPointer((PVOID
)Section
,
3479 ExGetPreviousMode());
3480 MArea
->Data
.SectionData
.Segment
= Segment
;
3481 MArea
->Data
.SectionData
.Section
= Section
;
3482 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3483 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3484 MmInitialiseRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3485 ViewSize
, 0, Protect
);
3487 return(STATUS_SUCCESS
);
3491 /**********************************************************************
3493 * NtMapViewOfSection
3496 * Maps a view of a section into the virtual address space of a
3501 * Handle of the section.
3504 * Handle of the process.
3507 * Desired base address (or NULL) on entry;
3508 * Actual base address of the view on exit.
3511 * Number of high order address bits that must be zero.
3514 * Size in bytes of the initially committed section of
3518 * Offset in bytes from the beginning of the section
3519 * to the beginning of the view.
3522 * Desired length of map (or zero to map all) on entry
3523 * Actual length mapped on exit.
3525 * InheritDisposition
3526 * Specified how the view is to be shared with
3530 * Type of allocation for the pages.
3533 * Protection for the committed region of the view.
3541 NtMapViewOfSection(IN HANDLE SectionHandle
,
3542 IN HANDLE ProcessHandle
,
3543 IN OUT PVOID
* BaseAddress OPTIONAL
,
3544 IN ULONG ZeroBits OPTIONAL
,
3545 IN ULONG CommitSize
,
3546 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3547 IN OUT PULONG ViewSize
,
3548 IN SECTION_INHERIT InheritDisposition
,
3549 IN ULONG AllocationType OPTIONAL
,
3552 PVOID SafeBaseAddress
;
3553 LARGE_INTEGER SafeSectionOffset
;
3555 PSECTION_OBJECT Section
;
3557 KPROCESSOR_MODE PreviousMode
;
3558 PMADDRESS_SPACE AddressSpace
;
3559 NTSTATUS Status
= STATUS_SUCCESS
;
3561 PreviousMode
= ExGetPreviousMode();
3563 if(PreviousMode
!= KernelMode
)
3565 SafeBaseAddress
= NULL
;
3566 SafeSectionOffset
.QuadPart
= 0;
3571 if(BaseAddress
!= NULL
)
3573 ProbeForWrite(BaseAddress
,
3576 SafeBaseAddress
= *BaseAddress
;
3578 if(SectionOffset
!= NULL
)
3580 ProbeForWrite(SectionOffset
,
3581 sizeof(LARGE_INTEGER
),
3583 SafeSectionOffset
= *SectionOffset
;
3585 ProbeForWrite(ViewSize
,
3588 SafeViewSize
= *ViewSize
;
3592 Status
= _SEH_GetExceptionCode();
3596 if(!NT_SUCCESS(Status
))
3603 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3604 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3605 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3608 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3609 PROCESS_VM_OPERATION
,
3612 (PVOID
*)(PVOID
)&Process
,
3614 if (!NT_SUCCESS(Status
))
3619 AddressSpace
= &Process
->AddressSpace
;
3621 Status
= ObReferenceObjectByHandle(SectionHandle
,
3623 MmSectionObjectType
,
3625 (PVOID
*)(PVOID
)&Section
,
3627 if (!(NT_SUCCESS(Status
)))
3629 DPRINT("ObReference failed rc=%x\n",Status
);
3630 ObDereferenceObject(Process
);
3634 Status
= MmMapViewOfSection(Section
,
3636 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3639 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3640 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3645 ObDereferenceObject(Section
);
3646 ObDereferenceObject(Process
);
3648 if(NT_SUCCESS(Status
))
3650 /* copy parameters back to the caller */
3653 if(BaseAddress
!= NULL
)
3655 *BaseAddress
= SafeBaseAddress
;
3657 if(SectionOffset
!= NULL
)
3659 *SectionOffset
= SafeSectionOffset
;
3661 if(ViewSize
!= NULL
)
3663 *ViewSize
= SafeViewSize
;
3668 Status
= _SEH_GetExceptionCode();
3677 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3678 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3681 PFILE_OBJECT FileObject
;
3684 SWAPENTRY SavedSwapEntry
;
3687 PSECTION_OBJECT Section
;
3688 PMM_SECTION_SEGMENT Segment
;
3689 PMADDRESS_SPACE AddressSpace
;
3691 AddressSpace
= (PMADDRESS_SPACE
)Context
;
3693 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3695 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3696 MemoryArea
->Data
.SectionData
.ViewOffset
;
3698 Section
= MemoryArea
->Data
.SectionData
.Section
;
3699 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3701 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3705 MmUnlockSectionSegment(Segment
);
3706 MmUnlockAddressSpace(AddressSpace
);
3708 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3709 if (Status
!= STATUS_SUCCESS
)
3711 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3715 MmLockAddressSpace(AddressSpace
);
3716 MmLockSectionSegment(Segment
);
3717 MmspCompleteAndReleasePageOp(PageOp
);
3718 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3721 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3724 * For a dirty, datafile, non-private page mark it as dirty in the
3727 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3729 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3731 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3732 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3733 CcRosMarkDirtyCacheSegment(Bcb
, Offset
);
3734 ASSERT(SwapEntry
== 0);
3743 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3745 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3748 MmFreeSwapPage(SwapEntry
);
3752 if (IS_SWAP_FROM_SSE(Entry
) ||
3753 Page
!= PFN_FROM_SSE(Entry
))
3758 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3760 DPRINT1("Found a private page in a pagefile section.\n");
3764 * Just dereference private pages
3766 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3767 if (SavedSwapEntry
!= 0)
3769 MmFreeSwapPage(SavedSwapEntry
);
3770 MmSetSavedSwapEntryPage(Page
, 0);
3772 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3773 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3777 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3778 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3784 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3788 PMEMORY_AREA MemoryArea
;
3789 PSECTION_OBJECT Section
;
3790 PMM_SECTION_SEGMENT Segment
;
3791 PLIST_ENTRY CurrentEntry
;
3792 PMM_REGION CurrentRegion
;
3793 PLIST_ENTRY RegionListHead
;
3795 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3797 if (MemoryArea
== NULL
)
3799 return(STATUS_UNSUCCESSFUL
);
3802 MemoryArea
->DeleteInProgress
= TRUE
;
3803 Section
= MemoryArea
->Data
.SectionData
.Section
;
3804 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3806 MmLockSectionSegment(Segment
);
3808 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3809 while (!IsListEmpty(RegionListHead
))
3811 CurrentEntry
= RemoveHeadList(RegionListHead
);
3812 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3813 ExFreePool(CurrentRegion
);
3816 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3818 Status
= MmFreeMemoryArea(AddressSpace
,
3825 Status
= MmFreeMemoryArea(AddressSpace
,
3830 MmUnlockSectionSegment(Segment
);
3831 ObDereferenceObject(Section
);
3832 return(STATUS_SUCCESS
);
3839 MmUnmapViewOfSection(PEPROCESS Process
,
3843 PMEMORY_AREA MemoryArea
;
3844 PMADDRESS_SPACE AddressSpace
;
3845 PSECTION_OBJECT Section
;
3847 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3848 Process
, BaseAddress
);
3852 AddressSpace
= &Process
->AddressSpace
;
3853 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3855 if (MemoryArea
== NULL
||
3856 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
3857 MemoryArea
->DeleteInProgress
)
3859 return STATUS_NOT_MAPPED_VIEW
;
3862 Section
= MemoryArea
->Data
.SectionData
.Section
;
3864 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3868 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3869 PMM_SECTION_SEGMENT SectionSegments
;
3870 PVOID ImageBaseAddress
= 0;
3871 PMM_SECTION_SEGMENT Segment
;
3873 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3874 ImageSectionObject
= Section
->ImageSection
;
3875 SectionSegments
= ImageSectionObject
->Segments
;
3876 NrSegments
= ImageSectionObject
->NrSegments
;
3878 /* Search for the current segment within the section segments
3879 * and calculate the image base address */
3880 for (i
= 0; i
< NrSegments
; i
++)
3882 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3884 if (Segment
== &SectionSegments
[i
])
3886 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3891 if (i
>= NrSegments
)
3896 for (i
= 0; i
< NrSegments
; i
++)
3898 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3900 PVOID SBaseAddress
= (PVOID
)
3901 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3903 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
3909 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
3911 return(STATUS_SUCCESS
);
3914 /**********************************************************************
3916 * NtUnmapViewOfSection
3931 NtUnmapViewOfSection (HANDLE ProcessHandle
,
3935 KPROCESSOR_MODE PreviousMode
;
3938 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
3939 ProcessHandle
, BaseAddress
);
3941 PreviousMode
= ExGetPreviousMode();
3943 DPRINT("Referencing process\n");
3944 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3945 PROCESS_VM_OPERATION
,
3948 (PVOID
*)(PVOID
)&Process
,
3950 if (!NT_SUCCESS(Status
))
3952 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
3956 MmLockAddressSpace(&Process
->AddressSpace
);
3957 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
3958 MmUnlockAddressSpace(&Process
->AddressSpace
);
3960 ObDereferenceObject(Process
);
3967 * Queries the information of a section object.
3969 * @param SectionHandle
3970 * Handle to the section object. It must be opened with SECTION_QUERY
3972 * @param SectionInformationClass
3973 * Index to a certain information structure. Can be either
3974 * SectionBasicInformation or SectionImageInformation. The latter
3975 * is valid only for sections that were created with the SEC_IMAGE
3977 * @param SectionInformation
3978 * Caller supplies storage for resulting information.
3980 * Size of the supplied storage.
3981 * @param ResultLength
3989 NtQuerySection(IN HANDLE SectionHandle
,
3990 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
3991 OUT PVOID SectionInformation
,
3992 IN ULONG SectionInformationLength
,
3993 OUT PULONG ResultLength OPTIONAL
)
3995 PSECTION_OBJECT Section
;
3996 KPROCESSOR_MODE PreviousMode
;
3997 NTSTATUS Status
= STATUS_SUCCESS
;
3999 PreviousMode
= ExGetPreviousMode();
4001 DefaultQueryInfoBufferCheck(SectionInformationClass
,
4004 SectionInformationLength
,
4009 if(!NT_SUCCESS(Status
))
4011 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4015 Status
= ObReferenceObjectByHandle(SectionHandle
,
4017 MmSectionObjectType
,
4019 (PVOID
*)(PVOID
)&Section
,
4021 if (NT_SUCCESS(Status
))
4023 switch (SectionInformationClass
)
4025 case SectionBasicInformation
:
4027 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4031 Sbi
->Attributes
= Section
->AllocationAttributes
;
4032 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4034 Sbi
->BaseAddress
= 0;
4035 Sbi
->Size
.QuadPart
= 0;
4039 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4040 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4043 if (ResultLength
!= NULL
)
4045 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4047 Status
= STATUS_SUCCESS
;
4051 Status
= _SEH_GetExceptionCode();
4058 case SectionImageInformation
:
4060 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4064 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4065 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4067 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4068 ImageSectionObject
= Section
->ImageSection
;
4070 Sii
->EntryPoint
= ImageSectionObject
->EntryPoint
;
4071 Sii
->StackReserve
= ImageSectionObject
->StackReserve
;
4072 Sii
->StackCommit
= ImageSectionObject
->StackCommit
;
4073 Sii
->Subsystem
= ImageSectionObject
->Subsystem
;
4074 Sii
->MinorSubsystemVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4075 Sii
->MajorSubsystemVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4076 Sii
->Characteristics
= ImageSectionObject
->ImageCharacteristics
;
4077 Sii
->ImageNumber
= ImageSectionObject
->Machine
;
4078 Sii
->Executable
= ImageSectionObject
->Executable
;
4081 if (ResultLength
!= NULL
)
4083 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4085 Status
= STATUS_SUCCESS
;
4089 Status
= _SEH_GetExceptionCode();
4097 ObDereferenceObject(Section
);
4105 * Extends size of file backed section.
4107 * @param SectionHandle
4108 * Handle to the section object. It must be opened with
4109 * SECTION_EXTEND_SIZE access.
4110 * @param NewMaximumSize
4111 * New maximum size of the section in bytes.
4115 * @todo Move the actual code to internal function MmExtendSection.
4119 NtExtendSection(IN HANDLE SectionHandle
,
4120 IN PLARGE_INTEGER NewMaximumSize
)
4122 LARGE_INTEGER SafeNewMaximumSize
;
4123 PSECTION_OBJECT Section
;
4124 KPROCESSOR_MODE PreviousMode
;
4125 NTSTATUS Status
= STATUS_SUCCESS
;
4127 PreviousMode
= ExGetPreviousMode();
4129 if(PreviousMode
!= KernelMode
)
4133 ProbeForRead(NewMaximumSize
,
4134 sizeof(LARGE_INTEGER
),
4136 /* make a copy on the stack */
4137 SafeNewMaximumSize
= *NewMaximumSize
;
4138 NewMaximumSize
= &SafeNewMaximumSize
;
4142 Status
= _SEH_GetExceptionCode();
4146 if(!NT_SUCCESS(Status
))
4152 Status
= ObReferenceObjectByHandle(SectionHandle
,
4153 SECTION_EXTEND_SIZE
,
4154 MmSectionObjectType
,
4158 if (!NT_SUCCESS(Status
))
4163 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4165 ObfDereferenceObject(Section
);
4166 return STATUS_INVALID_PARAMETER
;
4170 * - Acquire file extneding resource.
4171 * - Check if we're not resizing the section below it's actual size!
4172 * - Extend segments if needed.
4173 * - Set file information (FileAllocationInformation) to the new size.
4174 * - Release file extending resource.
4177 ObDereferenceObject(Section
);
4179 return STATUS_NOT_IMPLEMENTED
;
4183 /**********************************************************************
4185 * MmAllocateSection@4
4195 * Code taken from ntoskrnl/mm/special.c.
4200 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4206 PMADDRESS_SPACE AddressSpace
;
4207 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4209 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4211 BoundaryAddressMultiple
.QuadPart
= 0;
4213 AddressSpace
= MmGetKernelAddressSpace();
4214 Result
= BaseAddress
;
4215 MmLockAddressSpace(AddressSpace
);
4216 Status
= MmCreateMemoryArea (NULL
,
4225 BoundaryAddressMultiple
);
4226 MmUnlockAddressSpace(AddressSpace
);
4228 if (!NT_SUCCESS(Status
))
4232 DPRINT("Result %p\n",Result
);
4233 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
4237 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
4238 if (!NT_SUCCESS(Status
))
4240 DbgPrint("Unable to allocate page\n");
4243 Status
= MmCreateVirtualMapping (NULL
,
4244 (PVOID
)((ULONG_PTR
)Result
+ (i
* PAGE_SIZE
)),
4248 if (!NT_SUCCESS(Status
))
4250 DbgPrint("Unable to create virtual mapping\n");
4254 return ((PVOID
)Result
);
4258 /**********************************************************************
4260 * MmMapViewOfSection
4263 * Maps a view of a section into the virtual address space of a
4268 * Pointer to the section object.
4271 * Pointer to the process.
4274 * Desired base address (or NULL) on entry;
4275 * Actual base address of the view on exit.
4278 * Number of high order address bits that must be zero.
4281 * Size in bytes of the initially committed section of
4285 * Offset in bytes from the beginning of the section
4286 * to the beginning of the view.
4289 * Desired length of map (or zero to map all) on entry
4290 * Actual length mapped on exit.
4292 * InheritDisposition
4293 * Specified how the view is to be shared with
4297 * Type of allocation for the pages.
4300 * Protection for the committed region of the view.
4308 MmMapViewOfSection(IN PVOID SectionObject
,
4309 IN PEPROCESS Process
,
4310 IN OUT PVOID
*BaseAddress
,
4312 IN ULONG CommitSize
,
4313 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4314 IN OUT PULONG ViewSize
,
4315 IN SECTION_INHERIT InheritDisposition
,
4316 IN ULONG AllocationType
,
4319 PSECTION_OBJECT Section
;
4320 PMADDRESS_SPACE AddressSpace
;
4322 NTSTATUS Status
= STATUS_SUCCESS
;
4326 Section
= (PSECTION_OBJECT
)SectionObject
;
4327 AddressSpace
= &Process
->AddressSpace
;
4329 MmLockAddressSpace(AddressSpace
);
4331 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4335 ULONG_PTR ImageBase
;
4337 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4338 PMM_SECTION_SEGMENT SectionSegments
;
4340 ImageSectionObject
= Section
->ImageSection
;
4341 SectionSegments
= ImageSectionObject
->Segments
;
4342 NrSegments
= ImageSectionObject
->NrSegments
;
4345 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4348 ImageBase
= ImageSectionObject
->ImageBase
;
4352 for (i
= 0; i
< NrSegments
; i
++)
4354 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4356 ULONG_PTR MaxExtent
;
4357 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4358 SectionSegments
[i
].Length
;
4359 ImageSize
= max(ImageSize
, MaxExtent
);
4363 /* Check there is enough space to map the section at that point. */
4364 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4365 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4367 /* Fail if the user requested a fixed base address. */
4368 if ((*BaseAddress
) != NULL
)
4370 MmUnlockAddressSpace(AddressSpace
);
4371 return(STATUS_UNSUCCESSFUL
);
4373 /* Otherwise find a gap to map the image. */
4374 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4377 MmUnlockAddressSpace(AddressSpace
);
4378 return(STATUS_UNSUCCESSFUL
);
4382 for (i
= 0; i
< NrSegments
; i
++)
4384 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4386 PVOID SBaseAddress
= (PVOID
)
4387 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4388 MmLockSectionSegment(&SectionSegments
[i
]);
4389 Status
= MmMapViewOfSegment(Process
,
4392 &SectionSegments
[i
],
4394 SectionSegments
[i
].Length
,
4395 SectionSegments
[i
].Protection
,
4398 MmUnlockSectionSegment(&SectionSegments
[i
]);
4399 if (!NT_SUCCESS(Status
))
4401 MmUnlockAddressSpace(AddressSpace
);
4407 *BaseAddress
= (PVOID
)ImageBase
;
4411 if (ViewSize
== NULL
)
4413 /* Following this pointer would lead to us to the dark side */
4414 /* What to do? Bugcheck? Return status? Do the mambo? */
4415 KEBUGCHECK(MEMORY_MANAGEMENT
);
4418 if (SectionOffset
== NULL
)
4424 ViewOffset
= SectionOffset
->u
.LowPart
;
4427 if ((ViewOffset
% PAGE_SIZE
) != 0)
4429 MmUnlockAddressSpace(AddressSpace
);
4430 return(STATUS_MAPPED_ALIGNMENT
);
4433 if ((*ViewSize
) == 0)
4435 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4437 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4439 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4442 MmLockSectionSegment(Section
->Segment
);
4443 Status
= MmMapViewOfSegment(Process
,
4451 (AllocationType
& MEM_TOP_DOWN
));
4452 MmUnlockSectionSegment(Section
->Segment
);
4453 if (!NT_SUCCESS(Status
))
4455 MmUnlockAddressSpace(AddressSpace
);
4460 MmUnlockAddressSpace(AddressSpace
);
4462 return(STATUS_SUCCESS
);
4469 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4470 IN PLARGE_INTEGER NewFileSize
)
4481 MmDisableModifiedWriteOfSection (DWORD Unknown0
)
4491 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4492 IN MMFLUSH_TYPE FlushType
)
4496 case MmFlushForDelete
:
4497 if (SectionObjectPointer
->ImageSectionObject
||
4498 SectionObjectPointer
->DataSectionObject
)
4502 CcRosSetRemoveOnClose(SectionObjectPointer
);
4504 case MmFlushForWrite
:
4514 MmForceSectionClosed (
4515 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4516 IN BOOLEAN DelayClose
)
4527 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4528 OUT PVOID
* MappedBase
,
4529 IN OUT PULONG ViewSize
)
4531 PSECTION_OBJECT Section
;
4532 PMADDRESS_SPACE AddressSpace
;
4535 DPRINT("MmMapViewInSystemSpace() called\n");
4537 Section
= (PSECTION_OBJECT
)SectionObject
;
4538 AddressSpace
= MmGetKernelAddressSpace();
4540 MmLockAddressSpace(AddressSpace
);
4543 if ((*ViewSize
) == 0)
4545 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4547 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4549 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4552 MmLockSectionSegment(Section
->Segment
);
4555 Status
= MmMapViewOfSegment(NULL
,
4565 MmUnlockSectionSegment(Section
->Segment
);
4566 MmUnlockAddressSpace(AddressSpace
);
4576 MmMapViewInSessionSpace (
4578 OUT PVOID
*MappedBase
,
4579 IN OUT PSIZE_T ViewSize
4583 return STATUS_NOT_IMPLEMENTED
;
4591 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4593 PMADDRESS_SPACE AddressSpace
;
4596 DPRINT("MmUnmapViewInSystemSpace() called\n");
4598 AddressSpace
= MmGetKernelAddressSpace();
4600 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4610 MmUnmapViewInSessionSpace (
4615 return STATUS_NOT_IMPLEMENTED
;
4622 MmSetBankedSection (DWORD Unknown0
,
4630 return (STATUS_NOT_IMPLEMENTED
);
4634 /**********************************************************************
4639 * Creates a section object.
4642 * SectionObject (OUT)
4643 * Caller supplied storage for the resulting pointer
4644 * to a SECTION_OBJECT instance;
4647 * Specifies the desired access to the section can be a
4649 * STANDARD_RIGHTS_REQUIRED |
4651 * SECTION_MAP_WRITE |
4652 * SECTION_MAP_READ |
4653 * SECTION_MAP_EXECUTE
4655 * ObjectAttributes [OPTIONAL]
4656 * Initialized attributes for the object can be used
4657 * to create a named section;
4660 * Maximizes the size of the memory section. Must be
4661 * non-NULL for a page-file backed section.
4662 * If value specified for a mapped file and the file is
4663 * not large enough, file will be extended.
4665 * SectionPageProtection
4666 * Can be a combination of:
4672 * AllocationAttributes
4673 * Can be a combination of:
4678 * Handle to a file to create a section mapped to a file
4679 * instead of a memory backed section;
4690 MmCreateSection (OUT PSECTION_OBJECT
* SectionObject
,
4691 IN ACCESS_MASK DesiredAccess
,
4692 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4693 IN PLARGE_INTEGER MaximumSize
,
4694 IN ULONG SectionPageProtection
,
4695 IN ULONG AllocationAttributes
,
4696 IN HANDLE FileHandle OPTIONAL
,
4697 IN PFILE_OBJECT File OPTIONAL
)
4699 if (AllocationAttributes
& SEC_IMAGE
)
4701 return(MmCreateImageSection(SectionObject
,
4705 SectionPageProtection
,
4706 AllocationAttributes
,
4710 if (FileHandle
!= NULL
)
4712 return(MmCreateDataFileSection(SectionObject
,
4716 SectionPageProtection
,
4717 AllocationAttributes
,
4721 return(MmCreatePageFileSection(SectionObject
,
4725 SectionPageProtection
,
4726 AllocationAttributes
));