3 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/mm/section.c
22 * PURPOSE: Implements section objects
24 * PROGRAMMERS: Rex Jolliff
37 * Thomas Weidenmueller
38 * Gunnar Andre' Dalsnes
46 /* INCLUDES *****************************************************************/
50 #include <internal/debug.h>
51 #include <reactos/exeformat.h>
53 #if defined (ALLOC_PRAGMA)
54 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
55 #pragma alloc_text(INIT, MmInitSectionImplementation)
59 /* TYPES *********************************************************************/
63 PROS_SECTION_OBJECT Section
;
64 PMM_SECTION_SEGMENT Segment
;
69 MM_SECTION_PAGEOUT_CONTEXT
;
71 /* GLOBALS *******************************************************************/
73 POBJECT_TYPE MmSectionObjectType
= NULL
;
75 static GENERIC_MAPPING MmpSectionMapping
= {
76 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
77 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
78 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
81 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
82 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
83 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
84 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
85 #define MAX_SHARE_COUNT 0x7FF
86 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
87 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
88 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
90 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
92 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
93 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
96 /* FUNCTIONS *****************************************************************/
100 MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section
)
105 /* Return the file object */
106 return Section
->FileObject
; // Section->ControlArea->FileObject on NT
111 MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section
,
112 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
114 POBJECT_NAME_INFORMATION ObjectNameInfo
;
118 /* Make sure it's an image section */
120 if (!(Section
->AllocationAttributes
& SEC_IMAGE
))
123 return STATUS_SECTION_NOT_IMAGE
;
126 /* Allocate memory for our structure */
127 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
,
129 TAG('M', 'm', ' ', ' '));
130 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
133 Status
= ObQueryNameString(Section
->FileObject
,
137 if (!NT_SUCCESS(Status
))
139 /* Failed, free memory */
140 ExFreePool(ObjectNameInfo
);
145 *ModuleName
= ObjectNameInfo
;
146 return STATUS_SUCCESS
;
151 MmGetFileNameForAddress(IN PVOID Address
,
152 OUT PUNICODE_STRING ModuleName
)
156 * Filip says to get the MADDRESS_SPACE from EPROCESS,
157 * then use the MmMarea routines to locate the Marea that
158 * corresponds to the address. Then make sure it's a section
159 * view type (MEMORY_AREA_SECTION_VIEW) and use the marea's
160 * per-type union to get the .u.SectionView.Section pointer to
161 * the SECTION_OBJECT. Then we can use MmGetFileNameForSection
162 * to get the full filename.
164 RtlCreateUnicodeString(ModuleName
, L
"C:\\ReactOS\\system32\\ntdll.dll");
165 return STATUS_SUCCESS
;
168 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
171 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
172 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
173 * RETURNS: Status of the wait.
176 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
178 LARGE_INTEGER Timeout
;
179 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
181 Timeout
.QuadPart
= -100000000LL; // 10 sec
184 Timeout
.QuadPart
= -100000000; // 10 sec
187 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
192 * FUNCTION: Sets the page op completion event and releases the page op.
193 * ARGUMENTS: PMM_PAGEOP.
194 * RETURNS: In shorter time than it takes you to even read this
195 * description, so don't even think about geting a mug of coffee.
198 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
200 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
201 MmReleasePageOp(PageOp
);
206 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
207 * ARGUMENTS: PFILE_OBJECT to wait for.
208 * RETURNS: Status of the wait.
211 MmspWaitForFileLock(PFILE_OBJECT File
)
213 return STATUS_SUCCESS
;
214 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
219 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
222 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
224 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
226 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
228 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
236 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
238 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
240 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
241 PMM_SECTION_SEGMENT SectionSegments
;
245 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
246 NrSegments
= ImageSectionObject
->NrSegments
;
247 SectionSegments
= ImageSectionObject
->Segments
;
248 for (i
= 0; i
< NrSegments
; i
++)
250 if (SectionSegments
[i
].ReferenceCount
!= 0)
252 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
253 SectionSegments
[i
].ReferenceCount
);
256 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
258 ExFreePool(ImageSectionObject
->Segments
);
259 ExFreePool(ImageSectionObject
);
260 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
262 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
264 PMM_SECTION_SEGMENT Segment
;
266 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
269 if (Segment
->ReferenceCount
!= 0)
271 DPRINT1("Data segment still referenced\n");
274 MmFreePageTablesSectionSegment(Segment
);
276 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
282 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
284 ExAcquireFastMutex(&Segment
->Lock
);
289 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
291 ExReleaseFastMutex(&Segment
->Lock
);
296 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
300 PSECTION_PAGE_TABLE Table
;
301 ULONG DirectoryOffset
;
304 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
306 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
310 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
311 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
315 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
316 ExAllocatePoolWithTag(PagedPool
, sizeof(SECTION_PAGE_TABLE
),
317 TAG_SECTION_PAGE_TABLE
);
322 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
323 DPRINT("Table %x\n", Table
);
326 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
327 Table
->Entry
[TableOffset
] = Entry
;
333 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
336 PSECTION_PAGE_TABLE Table
;
338 ULONG DirectoryOffset
;
341 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
343 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
345 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
349 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
350 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
351 DPRINT("Table %x\n", Table
);
357 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
358 Entry
= Table
->Entry
[TableOffset
];
364 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
369 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
372 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
375 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
377 DPRINT1("Maximum share count reached\n");
380 if (IS_SWAP_FROM_SSE(Entry
))
384 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
385 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
390 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
391 PMM_SECTION_SEGMENT Segment
,
397 BOOLEAN IsDirectMapped
= FALSE
;
399 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
402 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
405 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
407 DPRINT1("Zero share count for unshare\n");
410 if (IS_SWAP_FROM_SSE(Entry
))
414 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
416 * If we reducing the share count of this entry to zero then set the entry
417 * to zero and tell the cache the page is no longer mapped.
419 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
421 PFILE_OBJECT FileObject
;
423 SWAPENTRY SavedSwapEntry
;
425 BOOLEAN IsImageSection
;
428 FileOffset
= Offset
+ Segment
->FileOffset
;
430 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
432 Page
= PFN_FROM_SSE(Entry
);
433 FileObject
= Section
->FileObject
;
434 if (FileObject
!= NULL
&&
435 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
438 if ((FileOffset
% PAGE_SIZE
) == 0 &&
439 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
442 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
443 IsDirectMapped
= TRUE
;
444 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
445 if (!NT_SUCCESS(Status
))
447 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
453 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
454 if (SavedSwapEntry
== 0)
457 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
458 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
462 * Try to page out this page and set the swap entry
463 * within the section segment. There exist no rmap entry
464 * for this page. The pager thread can't page out a
465 * page without a rmap entry.
467 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
471 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
474 MmReleasePageMemoryConsumer(MC_USER
, Page
);
480 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
481 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
489 * We hold all locks. Nobody can do something with the current
490 * process and the current segment (also not within an other process).
493 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
494 if (!NT_SUCCESS(Status
))
496 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
500 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
501 MmSetSavedSwapEntryPage(Page
, 0);
503 MmReleasePageMemoryConsumer(MC_USER
, Page
);
507 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
514 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
516 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
519 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
522 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
525 PCACHE_SEGMENT CacheSeg
;
526 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
527 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
530 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
539 MiReadPage(PMEMORY_AREA MemoryArea
,
543 * FUNCTION: Read a page for a section backed memory area.
545 * MemoryArea - Memory area to read the page for.
546 * Offset - Offset of the page to read.
547 * Page - Variable that receives a page contains the read data.
554 PCACHE_SEGMENT CacheSeg
;
555 PFILE_OBJECT FileObject
;
559 BOOLEAN IsImageSection
;
562 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
563 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
564 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
565 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
566 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
570 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
573 * If the file system is letting us go directly to the cache and the
574 * memory area was mapped at an offset in the file which is page aligned
575 * then get the related cache segment.
577 if ((FileOffset
% PAGE_SIZE
) == 0 &&
578 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
579 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
583 * Get the related cache segment; we use a lower level interface than
584 * filesystems do because it is safe for us to use an offset with a
585 * alignment less than the file system block size.
587 Status
= CcRosGetCacheSegment(Bcb
,
593 if (!NT_SUCCESS(Status
))
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
);
611 * Retrieve the page from the cache segment that we actually want.
613 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
614 FileOffset
- BaseOffset
).QuadPart
>> PAGE_SHIFT
;
616 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
621 ULONG CacheSegOffset
;
623 * Allocate a page, this is rather complicated by the possibility
624 * we might have to move other things out of memory
626 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
627 if (!NT_SUCCESS(Status
))
631 Status
= CcRosGetCacheSegment(Bcb
,
637 if (!NT_SUCCESS(Status
))
644 * If the cache segment isn't up to date then call the file
645 * system to read in the data.
647 Status
= ReadCacheSegment(CacheSeg
);
648 if (!NT_SUCCESS(Status
))
650 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
654 PageAddr
= MmCreateHyperspaceMapping(*Page
);
655 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
656 Length
= RawLength
- SegOffset
;
657 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
659 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
661 else if (CacheSegOffset
>= PAGE_SIZE
)
663 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
667 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
668 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
669 Status
= CcRosGetCacheSegment(Bcb
,
670 FileOffset
+ CacheSegOffset
,
675 if (!NT_SUCCESS(Status
))
677 MmDeleteHyperspaceMapping(PageAddr
);
683 * If the cache segment isn't up to date then call the file
684 * system to read in the data.
686 Status
= ReadCacheSegment(CacheSeg
);
687 if (!NT_SUCCESS(Status
))
689 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
690 MmDeleteHyperspaceMapping(PageAddr
);
694 if (Length
< PAGE_SIZE
)
696 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
700 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
703 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
704 MmDeleteHyperspaceMapping(PageAddr
);
706 return(STATUS_SUCCESS
);
711 MmNotPresentFaultSectionView(PMADDRESS_SPACE AddressSpace
,
712 MEMORY_AREA
* MemoryArea
,
720 PROS_SECTION_OBJECT Section
;
721 PMM_SECTION_SEGMENT Segment
;
727 BOOLEAN HasSwapEntry
;
730 * There is a window between taking the page fault and locking the
731 * address space when another thread could load the page so we check
734 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
738 MmLockPage(MmGetPfnForProcess(AddressSpace
->Process
, Address
));
740 return(STATUS_SUCCESS
);
743 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
744 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
745 + MemoryArea
->Data
.SectionData
.ViewOffset
;
747 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
748 Section
= MemoryArea
->Data
.SectionData
.Section
;
749 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
750 &MemoryArea
->Data
.SectionData
.RegionListHead
,
755 MmLockSectionSegment(Segment
);
758 * Check if this page needs to be mapped COW
760 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
761 (Region
->Protect
== PAGE_READWRITE
||
762 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
764 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
768 Attributes
= Region
->Protect
;
772 * Get or create a page operation descriptor
774 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
777 DPRINT1("MmGetPageOp failed\n");
782 * Check if someone else is already handling this fault, if so wait
785 if (PageOp
->Thread
!= PsGetCurrentThread())
787 MmUnlockSectionSegment(Segment
);
788 MmUnlockAddressSpace(AddressSpace
);
789 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
791 * Check for various strange conditions
793 if (Status
!= STATUS_SUCCESS
)
795 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
798 if (PageOp
->Status
== STATUS_PENDING
)
800 DPRINT1("Woke for page op before completion\n");
803 MmLockAddressSpace(AddressSpace
);
805 * If this wasn't a pagein then restart the operation
807 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
809 MmspCompleteAndReleasePageOp(PageOp
);
810 DPRINT("Address 0x%.8X\n", Address
);
811 return(STATUS_MM_RESTART_OPERATION
);
815 * If the thread handling this fault has failed then we don't retry
817 if (!NT_SUCCESS(PageOp
->Status
))
819 Status
= PageOp
->Status
;
820 MmspCompleteAndReleasePageOp(PageOp
);
821 DPRINT("Address 0x%.8X\n", Address
);
824 MmLockSectionSegment(Segment
);
826 * If the completed fault was for another address space then set the
829 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
831 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
832 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
834 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
837 * The page was a private page in another or in our address space
839 MmUnlockSectionSegment(Segment
);
840 MmspCompleteAndReleasePageOp(PageOp
);
841 return(STATUS_MM_RESTART_OPERATION
);
844 Page
= PFN_FROM_SSE(Entry
);
846 MmSharePageEntrySectionSegment(Segment
, Offset
);
848 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
849 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
851 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
856 if (!NT_SUCCESS(Status
))
858 DPRINT1("Unable to create virtual mapping\n");
861 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
867 MmUnlockSectionSegment(Segment
);
868 PageOp
->Status
= STATUS_SUCCESS
;
869 MmspCompleteAndReleasePageOp(PageOp
);
870 DPRINT("Address 0x%.8X\n", Address
);
871 return(STATUS_SUCCESS
);
874 HasSwapEntry
= MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)PAddress
);
878 * Must be private page we have swapped out.
885 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
887 DPRINT1("Found a swaped out private page in a pagefile section.\n");
891 MmUnlockSectionSegment(Segment
);
892 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)PAddress
, &SwapEntry
);
894 MmUnlockAddressSpace(AddressSpace
);
895 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
896 if (!NT_SUCCESS(Status
))
901 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
902 if (!NT_SUCCESS(Status
))
904 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
907 MmLockAddressSpace(AddressSpace
);
908 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
913 if (!NT_SUCCESS(Status
))
915 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
921 * Store the swap entry for later use.
923 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
926 * Add the page to the process's working set
928 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
931 * Finish the operation
937 PageOp
->Status
= STATUS_SUCCESS
;
938 MmspCompleteAndReleasePageOp(PageOp
);
939 DPRINT("Address 0x%.8X\n", Address
);
940 return(STATUS_SUCCESS
);
944 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
946 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
948 MmUnlockSectionSegment(Segment
);
950 * Just map the desired physical page
952 Page
= Offset
>> PAGE_SHIFT
;
953 Status
= MmCreateVirtualMappingUnsafe(AddressSpace
->Process
,
958 if (!NT_SUCCESS(Status
))
960 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
965 * Don't add an rmap entry since the page mapped could be for
970 MmLockPageUnsafe(Page
);
974 * Cleanup and release locks
976 PageOp
->Status
= STATUS_SUCCESS
;
977 MmspCompleteAndReleasePageOp(PageOp
);
978 DPRINT("Address 0x%.8X\n", Address
);
979 return(STATUS_SUCCESS
);
983 * Map anonymous memory for BSS sections
985 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
987 MmUnlockSectionSegment(Segment
);
988 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
989 if (!NT_SUCCESS(Status
))
991 MmUnlockAddressSpace(AddressSpace
);
992 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
993 MmLockAddressSpace(AddressSpace
);
995 if (!NT_SUCCESS(Status
))
999 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1004 if (!NT_SUCCESS(Status
))
1006 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1010 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1017 * Cleanup and release locks
1019 PageOp
->Status
= STATUS_SUCCESS
;
1020 MmspCompleteAndReleasePageOp(PageOp
);
1021 DPRINT("Address 0x%.8X\n", Address
);
1022 return(STATUS_SUCCESS
);
1026 * Get the entry corresponding to the offset within the section
1028 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1033 * If the entry is zero (and it can't change because we have
1034 * locked the segment) then we need to load the page.
1038 * Release all our locks and read in the page from disk
1040 MmUnlockSectionSegment(Segment
);
1041 MmUnlockAddressSpace(AddressSpace
);
1043 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1044 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1046 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1047 if (!NT_SUCCESS(Status
))
1049 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1054 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1055 if (!NT_SUCCESS(Status
))
1057 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1060 if (!NT_SUCCESS(Status
))
1063 * FIXME: What do we know in this case?
1066 * Cleanup and release locks
1068 MmLockAddressSpace(AddressSpace
);
1069 PageOp
->Status
= Status
;
1070 MmspCompleteAndReleasePageOp(PageOp
);
1071 DPRINT("Address 0x%.8X\n", Address
);
1075 * Relock the address space and segment
1077 MmLockAddressSpace(AddressSpace
);
1078 MmLockSectionSegment(Segment
);
1081 * Check the entry. No one should change the status of a page
1082 * that has a pending page-in.
1084 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1085 if (Entry
!= Entry1
)
1087 DPRINT1("Someone changed ppte entry while we slept\n");
1092 * Mark the offset within the section as having valid, in-memory
1095 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1096 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1097 MmUnlockSectionSegment(Segment
);
1099 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1104 if (!NT_SUCCESS(Status
))
1106 DPRINT1("Unable to create virtual mapping\n");
1109 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1115 PageOp
->Status
= STATUS_SUCCESS
;
1116 MmspCompleteAndReleasePageOp(PageOp
);
1117 DPRINT("Address 0x%.8X\n", Address
);
1118 return(STATUS_SUCCESS
);
1120 else if (IS_SWAP_FROM_SSE(Entry
))
1122 SWAPENTRY SwapEntry
;
1124 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1127 * Release all our locks and read in the page from disk
1129 MmUnlockSectionSegment(Segment
);
1131 MmUnlockAddressSpace(AddressSpace
);
1133 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1134 if (!NT_SUCCESS(Status
))
1139 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1140 if (!NT_SUCCESS(Status
))
1146 * Relock the address space and segment
1148 MmLockAddressSpace(AddressSpace
);
1149 MmLockSectionSegment(Segment
);
1152 * Check the entry. No one should change the status of a page
1153 * that has a pending page-in.
1155 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1156 if (Entry
!= Entry1
)
1158 DPRINT1("Someone changed ppte entry while we slept\n");
1163 * Mark the offset within the section as having valid, in-memory
1166 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1167 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1168 MmUnlockSectionSegment(Segment
);
1171 * Save the swap entry.
1173 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1174 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1179 if (!NT_SUCCESS(Status
))
1181 DPRINT1("Unable to create virtual mapping\n");
1184 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1189 PageOp
->Status
= STATUS_SUCCESS
;
1190 MmspCompleteAndReleasePageOp(PageOp
);
1191 DPRINT("Address 0x%.8X\n", Address
);
1192 return(STATUS_SUCCESS
);
1197 * If the section offset is already in-memory and valid then just
1198 * take another reference to the page
1201 Page
= PFN_FROM_SSE(Entry
);
1203 MmSharePageEntrySectionSegment(Segment
, Offset
);
1204 MmUnlockSectionSegment(Segment
);
1206 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1211 if (!NT_SUCCESS(Status
))
1213 DPRINT1("Unable to create virtual mapping\n");
1216 MmInsertRmap(Page
, AddressSpace
->Process
, (PVOID
)PAddress
);
1221 PageOp
->Status
= STATUS_SUCCESS
;
1222 MmspCompleteAndReleasePageOp(PageOp
);
1223 DPRINT("Address 0x%.8X\n", Address
);
1224 return(STATUS_SUCCESS
);
1230 MmAccessFaultSectionView(PMADDRESS_SPACE AddressSpace
,
1231 MEMORY_AREA
* MemoryArea
,
1235 PMM_SECTION_SEGMENT Segment
;
1236 PROS_SECTION_OBJECT Section
;
1246 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1249 * Check if the page has been paged out or has already been set readwrite
1251 if (!MmIsPagePresent(AddressSpace
->Process
, Address
) ||
1252 MmGetPageProtect(AddressSpace
->Process
, Address
) & PAGE_READWRITE
)
1254 DPRINT("Address 0x%.8X\n", Address
);
1255 return(STATUS_SUCCESS
);
1259 * Find the offset of the page
1261 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1262 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1263 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1265 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1266 Section
= MemoryArea
->Data
.SectionData
.Section
;
1267 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1268 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1273 MmLockSectionSegment(Segment
);
1275 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1276 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1278 MmUnlockSectionSegment(Segment
);
1281 * Check if we are doing COW
1283 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1284 (Region
->Protect
== PAGE_READWRITE
||
1285 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1287 DPRINT("Address 0x%.8X\n", Address
);
1288 return(STATUS_UNSUCCESSFUL
);
1291 if (IS_SWAP_FROM_SSE(Entry
) ||
1292 PFN_FROM_SSE(Entry
) != OldPage
)
1294 /* This is a private page. We must only change the page protection. */
1295 MmSetPageProtect(AddressSpace
->Process
, PAddress
, Region
->Protect
);
1296 return(STATUS_SUCCESS
);
1300 * Get or create a pageop
1302 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1303 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1306 DPRINT1("MmGetPageOp failed\n");
1311 * Wait for any other operations to complete
1313 if (PageOp
->Thread
!= PsGetCurrentThread())
1315 MmUnlockAddressSpace(AddressSpace
);
1316 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1318 * Check for various strange conditions
1320 if (Status
== STATUS_TIMEOUT
)
1322 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1325 if (PageOp
->Status
== STATUS_PENDING
)
1327 DPRINT1("Woke for page op before completion\n");
1331 * Restart the operation
1333 MmLockAddressSpace(AddressSpace
);
1334 MmspCompleteAndReleasePageOp(PageOp
);
1335 DPRINT("Address 0x%.8X\n", Address
);
1336 return(STATUS_MM_RESTART_OPERATION
);
1340 * Release locks now we have the pageop
1342 MmUnlockAddressSpace(AddressSpace
);
1347 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1348 if (!NT_SUCCESS(Status
))
1356 MiCopyFromUserPage(NewPage
, PAddress
);
1358 MmLockAddressSpace(AddressSpace
);
1360 * Delete the old entry.
1362 MmDeleteVirtualMapping(AddressSpace
->Process
, Address
, FALSE
, NULL
, NULL
);
1365 * Set the PTE to point to the new page
1367 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1372 if (!NT_SUCCESS(Status
))
1374 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1378 if (!NT_SUCCESS(Status
))
1380 DPRINT1("Unable to create virtual mapping\n");
1385 MmLockPage(NewPage
);
1386 MmUnlockPage(OldPage
);
1390 * Unshare the old page.
1392 MmDeleteRmap(OldPage
, AddressSpace
->Process
, PAddress
);
1393 MmInsertRmap(NewPage
, AddressSpace
->Process
, PAddress
);
1394 MmLockSectionSegment(Segment
);
1395 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1396 MmUnlockSectionSegment(Segment
);
1398 PageOp
->Status
= STATUS_SUCCESS
;
1399 MmspCompleteAndReleasePageOp(PageOp
);
1400 DPRINT("Address 0x%.8X\n", Address
);
1401 return(STATUS_SUCCESS
);
1405 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1407 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1411 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1414 MmLockAddressSpace((PMADDRESS_SPACE
)&Process
->VadRoot
);
1417 MmDeleteVirtualMapping(Process
,
1424 PageOutContext
->WasDirty
= TRUE
;
1426 if (!PageOutContext
->Private
)
1428 MmLockSectionSegment(PageOutContext
->Segment
);
1429 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1430 PageOutContext
->Segment
,
1431 PageOutContext
->Offset
,
1432 PageOutContext
->WasDirty
,
1434 MmUnlockSectionSegment(PageOutContext
->Segment
);
1438 MmUnlockAddressSpace((PMADDRESS_SPACE
)&Process
->VadRoot
);
1441 if (PageOutContext
->Private
)
1443 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1446 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1451 MmPageOutSectionView(PMADDRESS_SPACE AddressSpace
,
1452 MEMORY_AREA
* MemoryArea
,
1457 MM_SECTION_PAGEOUT_CONTEXT Context
;
1458 SWAPENTRY SwapEntry
;
1462 PFILE_OBJECT FileObject
;
1464 BOOLEAN DirectMapped
;
1465 BOOLEAN IsImageSection
;
1467 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1470 * Get the segment and section.
1472 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1473 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1475 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1476 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1477 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1479 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1481 FileObject
= Context
.Section
->FileObject
;
1482 DirectMapped
= FALSE
;
1483 if (FileObject
!= NULL
&&
1484 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1486 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1489 * If the file system is letting us go directly to the cache and the
1490 * memory area was mapped at an offset in the file which is page aligned
1491 * then note this is a direct mapped page.
1493 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1494 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1496 DirectMapped
= TRUE
;
1502 * This should never happen since mappings of physical memory are never
1503 * placed in the rmap lists.
1505 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1507 DPRINT1("Trying to page out from physical memory section address 0x%X "
1508 "process %d\n", Address
,
1509 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1514 * Get the section segment entry and the physical address.
1516 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1517 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1519 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1520 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1523 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1524 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1527 * Prepare the context structure for the rmap delete call.
1529 Context
.WasDirty
= FALSE
;
1530 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1531 IS_SWAP_FROM_SSE(Entry
) ||
1532 PFN_FROM_SSE(Entry
) != Page
)
1534 Context
.Private
= TRUE
;
1538 Context
.Private
= FALSE
;
1542 * Take an additional reference to the page or the cache segment.
1544 if (DirectMapped
&& !Context
.Private
)
1546 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1548 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1554 MmReferencePage(Page
);
1557 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1560 * If this wasn't a private page then we should have reduced the entry to
1561 * zero by deleting all the rmaps.
1563 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1565 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1566 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1573 * If the page wasn't dirty then we can just free it as for a readonly page.
1574 * Since we unmapped all the mappings above we know it will not suddenly
1576 * If the page is from a pagefile section and has no swap entry,
1577 * we can't free the page at this point.
1579 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1580 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1582 if (Context
.Private
)
1584 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1585 Context
.WasDirty
? "dirty" : "clean", Address
);
1588 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1590 MmSetSavedSwapEntryPage(Page
, 0);
1591 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1592 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1593 PageOp
->Status
= STATUS_SUCCESS
;
1594 MmspCompleteAndReleasePageOp(PageOp
);
1595 return(STATUS_SUCCESS
);
1598 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1600 if (Context
.Private
)
1602 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1603 Context
.WasDirty
? "dirty" : "clean", Address
);
1606 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1608 MmSetSavedSwapEntryPage(Page
, 0);
1611 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1613 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1614 PageOp
->Status
= STATUS_SUCCESS
;
1615 MmspCompleteAndReleasePageOp(PageOp
);
1616 return(STATUS_SUCCESS
);
1619 else if (!Context
.Private
&& DirectMapped
)
1623 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1627 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1628 if (!NT_SUCCESS(Status
))
1630 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1633 PageOp
->Status
= STATUS_SUCCESS
;
1634 MmspCompleteAndReleasePageOp(PageOp
);
1635 return(STATUS_SUCCESS
);
1637 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1641 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1645 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1646 PageOp
->Status
= STATUS_SUCCESS
;
1647 MmspCompleteAndReleasePageOp(PageOp
);
1648 return(STATUS_SUCCESS
);
1650 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1652 MmSetSavedSwapEntryPage(Page
, 0);
1653 MmLockAddressSpace(AddressSpace
);
1654 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1657 MmUnlockAddressSpace(AddressSpace
);
1658 if (!NT_SUCCESS(Status
))
1662 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1663 PageOp
->Status
= STATUS_SUCCESS
;
1664 MmspCompleteAndReleasePageOp(PageOp
);
1665 return(STATUS_SUCCESS
);
1669 * If necessary, allocate an entry in the paging file for this page
1673 SwapEntry
= MmAllocSwapPage();
1676 MmShowOutOfSpaceMessagePagingFile();
1677 MmLockAddressSpace(AddressSpace
);
1679 * For private pages restore the old mappings.
1681 if (Context
.Private
)
1683 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1685 MemoryArea
->Protect
,
1688 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1690 AddressSpace
->Process
,
1696 * For non-private pages if the page wasn't direct mapped then
1697 * set it back into the section segment entry so we don't loose
1698 * our copy. Otherwise it will be handled by the cache manager.
1700 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1702 MemoryArea
->Protect
,
1705 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1707 AddressSpace
->Process
,
1709 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1710 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1712 MmUnlockAddressSpace(AddressSpace
);
1713 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1714 MmspCompleteAndReleasePageOp(PageOp
);
1715 return(STATUS_PAGEFILE_QUOTA
);
1720 * Write the page to the pagefile
1722 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1723 if (!NT_SUCCESS(Status
))
1725 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1728 * As above: undo our actions.
1729 * FIXME: Also free the swap page.
1731 MmLockAddressSpace(AddressSpace
);
1732 if (Context
.Private
)
1734 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1736 MemoryArea
->Protect
,
1739 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1741 AddressSpace
->Process
,
1746 Status
= MmCreateVirtualMapping(AddressSpace
->Process
,
1748 MemoryArea
->Protect
,
1751 MmSetDirtyPage(AddressSpace
->Process
, Address
);
1753 AddressSpace
->Process
,
1755 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1756 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1758 MmUnlockAddressSpace(AddressSpace
);
1759 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1760 MmspCompleteAndReleasePageOp(PageOp
);
1761 return(STATUS_UNSUCCESSFUL
);
1765 * Otherwise we have succeeded.
1767 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1768 MmSetSavedSwapEntryPage(Page
, 0);
1769 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1770 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1772 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1776 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1779 if (Context
.Private
)
1781 MmLockAddressSpace(AddressSpace
);
1782 Status
= MmCreatePageFileMapping(AddressSpace
->Process
,
1785 MmUnlockAddressSpace(AddressSpace
);
1786 if (!NT_SUCCESS(Status
))
1793 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1794 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1797 PageOp
->Status
= STATUS_SUCCESS
;
1798 MmspCompleteAndReleasePageOp(PageOp
);
1799 return(STATUS_SUCCESS
);
1804 MmWritePageSectionView(PMADDRESS_SPACE AddressSpace
,
1805 PMEMORY_AREA MemoryArea
,
1810 PROS_SECTION_OBJECT Section
;
1811 PMM_SECTION_SEGMENT Segment
;
1813 SWAPENTRY SwapEntry
;
1817 PFILE_OBJECT FileObject
;
1819 BOOLEAN DirectMapped
;
1820 BOOLEAN IsImageSection
;
1822 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1824 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1825 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1828 * Get the segment and section.
1830 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1831 Section
= MemoryArea
->Data
.SectionData
.Section
;
1832 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1834 FileObject
= Section
->FileObject
;
1835 DirectMapped
= FALSE
;
1836 if (FileObject
!= NULL
&&
1837 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1839 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1842 * If the file system is letting us go directly to the cache and the
1843 * memory area was mapped at an offset in the file which is page aligned
1844 * then note this is a direct mapped page.
1846 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1847 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1849 DirectMapped
= TRUE
;
1854 * This should never happen since mappings of physical memory are never
1855 * placed in the rmap lists.
1857 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1859 DPRINT1("Trying to write back page from physical memory mapped at %X "
1860 "process %d\n", Address
,
1861 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0);
1866 * Get the section segment entry and the physical address.
1868 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1869 if (!MmIsPagePresent(AddressSpace
->Process
, Address
))
1871 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1872 AddressSpace
->Process
? AddressSpace
->Process
->UniqueProcessId
: 0, Address
);
1875 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1876 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1879 * Check for a private (COWed) page.
1881 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1882 IS_SWAP_FROM_SSE(Entry
) ||
1883 PFN_FROM_SSE(Entry
) != Page
)
1893 * Speculatively set all mappings of the page to clean.
1895 MmSetCleanAllRmaps(Page
);
1898 * If this page was direct mapped from the cache then the cache manager
1899 * will take care of writing it back to disk.
1901 if (DirectMapped
&& !Private
)
1903 ASSERT(SwapEntry
== 0);
1904 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1905 PageOp
->Status
= STATUS_SUCCESS
;
1906 MmspCompleteAndReleasePageOp(PageOp
);
1907 return(STATUS_SUCCESS
);
1911 * If necessary, allocate an entry in the paging file for this page
1915 SwapEntry
= MmAllocSwapPage();
1918 MmSetDirtyAllRmaps(Page
);
1919 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1920 MmspCompleteAndReleasePageOp(PageOp
);
1921 return(STATUS_PAGEFILE_QUOTA
);
1923 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1927 * Write the page to the pagefile
1929 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1930 if (!NT_SUCCESS(Status
))
1932 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1934 MmSetDirtyAllRmaps(Page
);
1935 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1936 MmspCompleteAndReleasePageOp(PageOp
);
1937 return(STATUS_UNSUCCESSFUL
);
1941 * Otherwise we have succeeded.
1943 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1944 PageOp
->Status
= STATUS_SUCCESS
;
1945 MmspCompleteAndReleasePageOp(PageOp
);
1946 return(STATUS_SUCCESS
);
1950 MmAlterViewAttributes(PMADDRESS_SPACE AddressSpace
,
1958 PMEMORY_AREA MemoryArea
;
1959 PMM_SECTION_SEGMENT Segment
;
1960 BOOLEAN DoCOW
= FALSE
;
1963 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1964 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1966 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1967 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1972 if (OldProtect
!= NewProtect
)
1974 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1976 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1977 ULONG Protect
= NewProtect
;
1980 * If we doing COW for this segment then check if the page is
1983 if (DoCOW
&& MmIsPagePresent(AddressSpace
->Process
, Address
))
1989 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1990 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1991 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1992 Page
= MmGetPfnForProcess(AddressSpace
->Process
, Address
);
1994 Protect
= PAGE_READONLY
;
1995 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1996 IS_SWAP_FROM_SSE(Entry
) ||
1997 PFN_FROM_SSE(Entry
) != Page
)
1999 Protect
= NewProtect
;
2003 if (MmIsPagePresent(AddressSpace
->Process
, Address
))
2005 MmSetPageProtect(AddressSpace
->Process
, Address
,
2014 MmProtectSectionView(PMADDRESS_SPACE AddressSpace
,
2015 PMEMORY_AREA MemoryArea
,
2023 ULONG_PTR MaxLength
;
2025 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2026 if (Length
> MaxLength
)
2029 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2030 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2032 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2033 Region
->Protect
!= Protect
)
2036 return STATUS_INVALID_PAGE_PROTECTION
;
2039 *OldProtect
= Region
->Protect
;
2040 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2041 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2042 BaseAddress
, Length
, Region
->Type
, Protect
,
2043 MmAlterViewAttributes
);
2049 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2051 PMEMORY_BASIC_INFORMATION Info
,
2052 PULONG ResultLength
)
2055 PVOID RegionBaseAddress
;
2056 PROS_SECTION_OBJECT Section
;
2057 PMM_SECTION_SEGMENT Segment
;
2059 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2060 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2061 Address
, &RegionBaseAddress
);
2064 return STATUS_UNSUCCESSFUL
;
2067 Section
= MemoryArea
->Data
.SectionData
.Section
;
2068 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2070 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2071 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2072 Info
->Type
= MEM_IMAGE
;
2076 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2077 Info
->Type
= MEM_MAPPED
;
2079 Info
->BaseAddress
= RegionBaseAddress
;
2080 Info
->AllocationProtect
= MemoryArea
->Protect
;
2081 Info
->RegionSize
= Region
->Length
;
2082 Info
->State
= MEM_COMMIT
;
2083 Info
->Protect
= Region
->Protect
;
2085 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2086 return(STATUS_SUCCESS
);
2091 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2096 ULONG SavedSwapEntry
;
2101 Length
= PAGE_ROUND_UP(Segment
->Length
);
2102 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2104 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2107 if (IS_SWAP_FROM_SSE(Entry
))
2109 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2113 Page
= PFN_FROM_SSE(Entry
);
2114 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2115 if (SavedSwapEntry
!= 0)
2117 MmSetSavedSwapEntryPage(Page
, 0);
2118 MmFreeSwapPage(SavedSwapEntry
);
2120 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2122 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2128 MmpDeleteSection(PVOID ObjectBody
)
2130 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2132 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2133 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2138 PMM_SECTION_SEGMENT SectionSegments
;
2141 * NOTE: Section->ImageSection can be NULL for short time
2142 * during the section creating. If we fail for some reason
2143 * until the image section is properly initialized we shouldn't
2144 * process further here.
2146 if (Section
->ImageSection
== NULL
)
2149 SectionSegments
= Section
->ImageSection
->Segments
;
2150 NrSegments
= Section
->ImageSection
->NrSegments
;
2152 for (i
= 0; i
< NrSegments
; i
++)
2154 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2156 MmLockSectionSegment(&SectionSegments
[i
]);
2158 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2159 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2163 MmpFreePageFileSegment(&SectionSegments
[i
]);
2165 MmUnlockSectionSegment(&SectionSegments
[i
]);
2172 * NOTE: Section->Segment can be NULL for short time
2173 * during the section creating.
2175 if (Section
->Segment
== NULL
)
2178 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2180 MmpFreePageFileSegment(Section
->Segment
);
2181 MmFreePageTablesSectionSegment(Section
->Segment
);
2182 ExFreePool(Section
->Segment
);
2183 Section
->Segment
= NULL
;
2187 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2190 if (Section
->FileObject
!= NULL
)
2192 CcRosDereferenceCache(Section
->FileObject
);
2193 ObDereferenceObject(Section
->FileObject
);
2194 Section
->FileObject
= NULL
;
2199 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2201 IN ACCESS_MASK GrantedAccess
,
2202 IN ULONG ProcessHandleCount
,
2203 IN ULONG SystemHandleCount
)
2205 DPRINT("MmpCloseSection(OB %x, HC %d) RC %d\n",
2206 Object
, ProcessHandleCount
, ObGetObjectPointerCount(Object
));
2212 MmCreatePhysicalMemorySection(VOID
)
2214 PROS_SECTION_OBJECT PhysSection
;
2216 OBJECT_ATTRIBUTES Obj
;
2217 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2218 LARGE_INTEGER SectionSize
;
2222 * Create the section mapping physical memory
2224 SectionSize
.QuadPart
= 0xFFFFFFFF;
2225 InitializeObjectAttributes(&Obj
,
2230 Status
= MmCreateSection((PVOID
)&PhysSection
,
2234 PAGE_EXECUTE_READWRITE
,
2238 if (!NT_SUCCESS(Status
))
2240 DPRINT1("Failed to create PhysicalMemory section\n");
2243 Status
= ObInsertObject(PhysSection
,
2249 if (!NT_SUCCESS(Status
))
2251 ObDereferenceObject(PhysSection
);
2253 ObCloseHandle(Handle
, KernelMode
);
2254 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2255 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2257 return(STATUS_SUCCESS
);
2263 MmInitSectionImplementation(VOID
)
2265 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2266 UNICODE_STRING Name
;
2268 DPRINT("Creating Section Object Type\n");
2270 /* Initialize the Section object type */
2271 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2272 RtlInitUnicodeString(&Name
, L
"Section");
2273 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2274 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2275 ObjectTypeInitializer
.PoolType
= PagedPool
;
2276 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2277 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2278 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2279 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2280 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2281 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2283 return(STATUS_SUCCESS
);
2288 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2289 ACCESS_MASK DesiredAccess
,
2290 POBJECT_ATTRIBUTES ObjectAttributes
,
2291 PLARGE_INTEGER UMaximumSize
,
2292 ULONG SectionPageProtection
,
2293 ULONG AllocationAttributes
)
2295 * Create a section which is backed by the pagefile
2298 LARGE_INTEGER MaximumSize
;
2299 PROS_SECTION_OBJECT Section
;
2300 PMM_SECTION_SEGMENT Segment
;
2303 if (UMaximumSize
== NULL
)
2305 return(STATUS_UNSUCCESSFUL
);
2307 MaximumSize
= *UMaximumSize
;
2310 * Create the section
2312 Status
= ObCreateObject(ExGetPreviousMode(),
2313 MmSectionObjectType
,
2315 ExGetPreviousMode(),
2317 sizeof(ROS_SECTION_OBJECT
),
2320 (PVOID
*)(PVOID
)&Section
);
2321 if (!NT_SUCCESS(Status
))
2329 Section
->SectionPageProtection
= SectionPageProtection
;
2330 Section
->AllocationAttributes
= AllocationAttributes
;
2331 Section
->Segment
= NULL
;
2332 Section
->FileObject
= NULL
;
2333 Section
->MaximumSize
= MaximumSize
;
2334 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2335 TAG_MM_SECTION_SEGMENT
);
2336 if (Segment
== NULL
)
2338 ObDereferenceObject(Section
);
2339 return(STATUS_NO_MEMORY
);
2341 Section
->Segment
= Segment
;
2342 Segment
->ReferenceCount
= 1;
2343 ExInitializeFastMutex(&Segment
->Lock
);
2344 Segment
->FileOffset
= 0;
2345 Segment
->Protection
= SectionPageProtection
;
2346 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2347 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2348 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2349 Segment
->WriteCopy
= FALSE
;
2350 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2351 Segment
->VirtualAddress
= 0;
2352 Segment
->Characteristics
= 0;
2353 *SectionObject
= Section
;
2354 return(STATUS_SUCCESS
);
2360 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2361 ACCESS_MASK DesiredAccess
,
2362 POBJECT_ATTRIBUTES ObjectAttributes
,
2363 PLARGE_INTEGER UMaximumSize
,
2364 ULONG SectionPageProtection
,
2365 ULONG AllocationAttributes
,
2368 * Create a section backed by a data file
2371 PROS_SECTION_OBJECT Section
;
2373 LARGE_INTEGER MaximumSize
;
2374 PFILE_OBJECT FileObject
;
2375 PMM_SECTION_SEGMENT Segment
;
2377 IO_STATUS_BLOCK Iosb
;
2378 LARGE_INTEGER Offset
;
2380 FILE_STANDARD_INFORMATION FileInfo
;
2383 * Create the section
2385 Status
= ObCreateObject(ExGetPreviousMode(),
2386 MmSectionObjectType
,
2388 ExGetPreviousMode(),
2390 sizeof(ROS_SECTION_OBJECT
),
2393 (PVOID
*)(PVOID
)&Section
);
2394 if (!NT_SUCCESS(Status
))
2401 Section
->SectionPageProtection
= SectionPageProtection
;
2402 Section
->AllocationAttributes
= AllocationAttributes
;
2403 Section
->Segment
= NULL
;
2406 * Check file access required
2408 if (SectionPageProtection
& PAGE_READWRITE
||
2409 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2411 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2415 FileAccess
= FILE_READ_DATA
;
2419 * Reference the file handle
2421 Status
= ObReferenceObjectByHandle(FileHandle
,
2425 (PVOID
*)(PVOID
)&FileObject
,
2427 if (!NT_SUCCESS(Status
))
2429 ObDereferenceObject(Section
);
2434 * FIXME: This is propably not entirely correct. We can't look into
2435 * the standard FCB header because it might not be initialized yet
2436 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2437 * standard file information is filled on first request).
2439 Status
= IoQueryFileInformation(FileObject
,
2440 FileStandardInformation
,
2441 sizeof(FILE_STANDARD_INFORMATION
),
2444 if (!NT_SUCCESS(Status
))
2446 ObDereferenceObject(Section
);
2447 ObDereferenceObject(FileObject
);
2452 * FIXME: Revise this once a locking order for file size changes is
2455 if (UMaximumSize
!= NULL
)
2457 MaximumSize
= *UMaximumSize
;
2461 MaximumSize
= FileInfo
.EndOfFile
;
2462 /* Mapping zero-sized files isn't allowed. */
2463 if (MaximumSize
.QuadPart
== 0)
2465 ObDereferenceObject(Section
);
2466 ObDereferenceObject(FileObject
);
2467 return STATUS_FILE_INVALID
;
2471 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2473 Status
= IoSetInformation(FileObject
,
2474 FileAllocationInformation
,
2475 sizeof(LARGE_INTEGER
),
2477 if (!NT_SUCCESS(Status
))
2479 ObDereferenceObject(Section
);
2480 ObDereferenceObject(FileObject
);
2481 return(STATUS_SECTION_NOT_EXTENDED
);
2485 if (FileObject
->SectionObjectPointer
== NULL
||
2486 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2489 * Read a bit so caching is initiated for the file object.
2490 * This is only needed because MiReadPage currently cannot
2491 * handle non-cached streams.
2493 Offset
.QuadPart
= 0;
2494 Status
= ZwReadFile(FileHandle
,
2503 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2505 ObDereferenceObject(Section
);
2506 ObDereferenceObject(FileObject
);
2509 if (FileObject
->SectionObjectPointer
== NULL
||
2510 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2512 /* FIXME: handle this situation */
2513 ObDereferenceObject(Section
);
2514 ObDereferenceObject(FileObject
);
2515 return STATUS_INVALID_PARAMETER
;
2522 Status
= MmspWaitForFileLock(FileObject
);
2523 if (Status
!= STATUS_SUCCESS
)
2525 ObDereferenceObject(Section
);
2526 ObDereferenceObject(FileObject
);
2531 * If this file hasn't been mapped as a data file before then allocate a
2532 * section segment to describe the data file mapping
2534 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2536 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2537 TAG_MM_SECTION_SEGMENT
);
2538 if (Segment
== NULL
)
2540 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2541 ObDereferenceObject(Section
);
2542 ObDereferenceObject(FileObject
);
2543 return(STATUS_NO_MEMORY
);
2545 Section
->Segment
= Segment
;
2546 Segment
->ReferenceCount
= 1;
2547 ExInitializeFastMutex(&Segment
->Lock
);
2549 * Set the lock before assigning the segment to the file object
2551 ExAcquireFastMutex(&Segment
->Lock
);
2552 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2554 Segment
->FileOffset
= 0;
2555 Segment
->Protection
= SectionPageProtection
;
2556 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2557 Segment
->Characteristics
= 0;
2558 Segment
->WriteCopy
= FALSE
;
2559 if (AllocationAttributes
& SEC_RESERVE
)
2561 Segment
->Length
= Segment
->RawLength
= 0;
2565 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2566 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2568 Segment
->VirtualAddress
= 0;
2569 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2574 * If the file is already mapped as a data file then we may need
2578 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2580 Section
->Segment
= Segment
;
2581 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2582 MmLockSectionSegment(Segment
);
2584 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2585 !(AllocationAttributes
& SEC_RESERVE
))
2587 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2588 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2591 MmUnlockSectionSegment(Segment
);
2592 Section
->FileObject
= FileObject
;
2593 Section
->MaximumSize
= MaximumSize
;
2594 CcRosReferenceCache(FileObject
);
2595 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2596 *SectionObject
= Section
;
2597 return(STATUS_SUCCESS
);
2601 TODO: not that great (declaring loaders statically, having to declare all of
2602 them, having to keep them extern, etc.), will fix in the future
2604 extern NTSTATUS NTAPI PeFmtCreateSection
2606 IN CONST VOID
* FileHeader
,
2607 IN SIZE_T FileHeaderSize
,
2609 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2611 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2612 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2615 extern NTSTATUS NTAPI ElfFmtCreateSection
2617 IN CONST VOID
* FileHeader
,
2618 IN SIZE_T FileHeaderSize
,
2620 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2622 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2623 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2626 /* TODO: this is a standard DDK/PSDK macro */
2627 #ifndef RTL_NUMBER_OF
2628 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2631 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2640 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2642 SIZE_T SizeOfSegments
;
2643 PMM_SECTION_SEGMENT Segments
;
2645 /* TODO: check for integer overflow */
2646 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2648 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2650 TAG_MM_SECTION_SEGMENT
);
2653 RtlZeroMemory(Segments
, SizeOfSegments
);
2661 ExeFmtpReadFile(IN PVOID File
,
2662 IN PLARGE_INTEGER Offset
,
2665 OUT PVOID
* AllocBase
,
2666 OUT PULONG ReadSize
)
2669 LARGE_INTEGER FileOffset
;
2671 ULONG OffsetAdjustment
;
2676 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2680 KEBUGCHECK(STATUS_INVALID_PARAMETER_4
);
2683 FileOffset
= *Offset
;
2685 /* Negative/special offset: it cannot be used in this context */
2686 if(FileOffset
.u
.HighPart
< 0)
2688 KEBUGCHECK(STATUS_INVALID_PARAMETER_5
);
2691 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2692 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2693 FileOffset
.u
.LowPart
= AdjustOffset
;
2695 BufferSize
= Length
+ OffsetAdjustment
;
2696 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2699 * It's ok to use paged pool, because this is a temporary buffer only used in
2700 * the loading of executables. The assumption is that MmCreateSection is
2701 * always called at low IRQLs and that these buffers don't survive a brief
2702 * initialization phase
2704 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2706 TAG('M', 'm', 'X', 'r'));
2711 Status
= MmspPageRead(File
,
2718 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2719 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2720 * to initialize internal state is even worse. Our cache manager is in need of
2724 IO_STATUS_BLOCK Iosb
;
2726 Status
= ZwReadFile(File
,
2736 if(NT_SUCCESS(Status
))
2738 UsedSize
= Iosb
.Information
;
2743 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2745 Status
= STATUS_IN_PAGE_ERROR
;
2746 ASSERT(!NT_SUCCESS(Status
));
2749 if(NT_SUCCESS(Status
))
2751 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2752 *AllocBase
= Buffer
;
2753 *ReadSize
= UsedSize
- OffsetAdjustment
;
2764 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2765 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2766 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2771 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2775 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2777 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2778 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2785 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2789 MmspAssertSegmentsSorted(ImageSectionObject
);
2791 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2793 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2797 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2798 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2799 ImageSectionObject
->Segments
[i
- 1].Length
));
2807 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2811 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2813 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2814 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2822 MmspCompareSegments(const void * x
,
2825 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2826 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2829 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2830 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2834 * Ensures an image section's segments are sorted in memory
2839 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2842 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2844 MmspAssertSegmentsSorted(ImageSectionObject
);
2848 qsort(ImageSectionObject
->Segments
,
2849 ImageSectionObject
->NrSegments
,
2850 sizeof(ImageSectionObject
->Segments
[0]),
2851 MmspCompareSegments
);
2857 * Ensures an image section's segments don't overlap in memory and don't have
2858 * gaps and don't have a null size. We let them map to overlapping file regions,
2859 * though - that's not necessarily an error
2864 MmspCheckSegmentBounds
2866 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2872 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2874 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2878 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2880 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2882 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2890 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2891 * page could be OK (Windows seems to be OK with them), and larger gaps
2892 * could lead to image sections spanning several discontiguous regions
2893 * (NtMapViewOfSection could then refuse to map them, and they could
2894 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2896 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2897 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2898 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2909 * Merges and pads an image section's segments until they all are page-aligned
2910 * and have a size that is a multiple of the page size
2915 MmspPageAlignSegments
2917 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2923 BOOLEAN Initialized
;
2924 PMM_SECTION_SEGMENT EffectiveSegment
;
2926 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2928 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2932 Initialized
= FALSE
;
2934 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2936 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2939 * The first segment requires special handling
2943 ULONG_PTR VirtualAddress
;
2944 ULONG_PTR VirtualOffset
;
2946 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2948 /* Round down the virtual address to the nearest page */
2949 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2951 /* Round up the virtual size to the nearest page */
2952 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2953 EffectiveSegment
->VirtualAddress
;
2955 /* Adjust the raw address and size */
2956 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2958 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
2964 * Garbage in, garbage out: unaligned base addresses make the file
2965 * offset point in curious and odd places, but that's what we were
2968 EffectiveSegment
->FileOffset
-= VirtualOffset
;
2969 EffectiveSegment
->RawLength
+= VirtualOffset
;
2973 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
2974 ULONG_PTR EndOfEffectiveSegment
;
2976 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
2977 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
2980 * The current segment begins exactly where the current effective
2981 * segment ended, therefore beginning a new effective segment
2983 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
2986 ASSERT(LastSegment
<= i
);
2987 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
2989 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2991 if (LastSegment
!= i
)
2994 * Copy the current segment. If necessary, the effective segment
2995 * will be expanded later
2997 *EffectiveSegment
= *Segment
;
3001 * Page-align the virtual size. We know for sure the virtual address
3004 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3005 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3008 * The current segment is still part of the current effective segment:
3009 * extend the effective segment to reflect this
3011 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3013 static const ULONG FlagsToProtection
[16] =
3021 PAGE_EXECUTE_READWRITE
,
3022 PAGE_EXECUTE_READWRITE
,
3027 PAGE_EXECUTE_WRITECOPY
,
3028 PAGE_EXECUTE_WRITECOPY
,
3029 PAGE_EXECUTE_WRITECOPY
,
3030 PAGE_EXECUTE_WRITECOPY
3033 unsigned ProtectionFlags
;
3036 * Extend the file size
3039 /* Unaligned segments must be contiguous within the file */
3040 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3041 EffectiveSegment
->RawLength
))
3046 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3049 * Extend the virtual size
3051 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3053 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3054 EffectiveSegment
->VirtualAddress
;
3057 * Merge the protection
3059 EffectiveSegment
->Protection
|= Segment
->Protection
;
3061 /* Clean up redundance */
3062 ProtectionFlags
= 0;
3064 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3065 ProtectionFlags
|= 1 << 0;
3067 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3068 ProtectionFlags
|= 1 << 1;
3070 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3071 ProtectionFlags
|= 1 << 2;
3073 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3074 ProtectionFlags
|= 1 << 3;
3076 ASSERT(ProtectionFlags
< 16);
3077 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3079 /* If a segment was required to be shared and cannot, fail */
3080 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3081 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3087 * We assume no holes between segments at this point
3095 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3101 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3102 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3104 LARGE_INTEGER Offset
;
3106 PVOID FileHeaderBuffer
;
3107 ULONG FileHeaderSize
;
3109 ULONG OldNrSegments
;
3114 * Read the beginning of the file (2 pages). Should be enough to contain
3115 * all (or most) of the headers
3117 Offset
.QuadPart
= 0;
3119 /* FIXME: use FileObject instead of FileHandle */
3120 Status
= ExeFmtpReadFile (FileHandle
,
3127 if (!NT_SUCCESS(Status
))
3130 if (FileHeaderSize
== 0)
3132 ExFreePool(FileHeaderBuffer
);
3133 return STATUS_UNSUCCESSFUL
;
3137 * Look for a loader that can handle this executable
3139 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3141 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3144 /* FIXME: use FileObject instead of FileHandle */
3145 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3151 ExeFmtpAllocateSegments
);
3153 if (!NT_SUCCESS(Status
))
3155 if (ImageSectionObject
->Segments
)
3157 ExFreePool(ImageSectionObject
->Segments
);
3158 ImageSectionObject
->Segments
= NULL
;
3162 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3166 ExFreePool(FileHeaderBuffer
);
3169 * No loader handled the format
3171 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3173 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3174 ASSERT(!NT_SUCCESS(Status
));
3177 if (!NT_SUCCESS(Status
))
3180 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3185 /* FIXME? are these values platform-dependent? */
3186 if(ImageSectionObject
->StackReserve
== 0)
3187 ImageSectionObject
->StackReserve
= 0x40000;
3189 if(ImageSectionObject
->StackCommit
== 0)
3190 ImageSectionObject
->StackCommit
= 0x1000;
3192 if(ImageSectionObject
->ImageBase
== 0)
3194 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3195 ImageSectionObject
->ImageBase
= 0x10000000;
3197 ImageSectionObject
->ImageBase
= 0x00400000;
3201 * And now the fun part: fixing the segments
3204 /* Sort them by virtual address */
3205 MmspSortSegments(ImageSectionObject
, Flags
);
3207 /* Ensure they don't overlap in memory */
3208 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3209 return STATUS_INVALID_IMAGE_FORMAT
;
3211 /* Ensure they are aligned */
3212 OldNrSegments
= ImageSectionObject
->NrSegments
;
3214 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3215 return STATUS_INVALID_IMAGE_FORMAT
;
3217 /* Trim them if the alignment phase merged some of them */
3218 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3220 PMM_SECTION_SEGMENT Segments
;
3221 SIZE_T SizeOfSegments
;
3223 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3225 Segments
= ExAllocatePoolWithTag(PagedPool
,
3227 TAG_MM_SECTION_SEGMENT
);
3229 if (Segments
== NULL
)
3230 return STATUS_INSUFFICIENT_RESOURCES
;
3232 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3233 ExFreePool(ImageSectionObject
->Segments
);
3234 ImageSectionObject
->Segments
= Segments
;
3237 /* And finish their initialization */
3238 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3240 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3241 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3243 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3244 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3247 ASSERT(NT_SUCCESS(Status
));
3252 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3253 ACCESS_MASK DesiredAccess
,
3254 POBJECT_ATTRIBUTES ObjectAttributes
,
3255 PLARGE_INTEGER UMaximumSize
,
3256 ULONG SectionPageProtection
,
3257 ULONG AllocationAttributes
,
3260 PROS_SECTION_OBJECT Section
;
3262 PFILE_OBJECT FileObject
;
3263 PMM_SECTION_SEGMENT SectionSegments
;
3264 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3266 ULONG FileAccess
= 0;
3269 * Specifying a maximum size is meaningless for an image section
3271 if (UMaximumSize
!= NULL
)
3273 return(STATUS_INVALID_PARAMETER_4
);
3277 * Check file access required
3279 if (SectionPageProtection
& PAGE_READWRITE
||
3280 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3282 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3286 FileAccess
= FILE_READ_DATA
;
3290 * Reference the file handle
3292 Status
= ObReferenceObjectByHandle(FileHandle
,
3295 ExGetPreviousMode(),
3296 (PVOID
*)(PVOID
)&FileObject
,
3299 if (!NT_SUCCESS(Status
))
3305 * Create the section
3307 Status
= ObCreateObject (ExGetPreviousMode(),
3308 MmSectionObjectType
,
3310 ExGetPreviousMode(),
3312 sizeof(ROS_SECTION_OBJECT
),
3315 (PVOID
*)(PVOID
)&Section
);
3316 if (!NT_SUCCESS(Status
))
3318 ObDereferenceObject(FileObject
);
3325 Section
->SectionPageProtection
= SectionPageProtection
;
3326 Section
->AllocationAttributes
= AllocationAttributes
;
3329 * Initialized caching for this file object if previously caching
3330 * was initialized for the same on disk file
3332 Status
= CcTryToInitializeFileCache(FileObject
);
3334 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3336 NTSTATUS StatusExeFmt
;
3338 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3339 if (ImageSectionObject
== NULL
)
3341 ObDereferenceObject(FileObject
);
3342 ObDereferenceObject(Section
);
3343 return(STATUS_NO_MEMORY
);
3346 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3348 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3350 if (!NT_SUCCESS(StatusExeFmt
))
3352 if(ImageSectionObject
->Segments
!= NULL
)
3353 ExFreePool(ImageSectionObject
->Segments
);
3355 ExFreePool(ImageSectionObject
);
3356 ObDereferenceObject(Section
);
3357 ObDereferenceObject(FileObject
);
3358 return(StatusExeFmt
);
3361 Section
->ImageSection
= ImageSectionObject
;
3362 ASSERT(ImageSectionObject
->Segments
);
3367 Status
= MmspWaitForFileLock(FileObject
);
3368 if (!NT_SUCCESS(Status
))
3370 ExFreePool(ImageSectionObject
->Segments
);
3371 ExFreePool(ImageSectionObject
);
3372 ObDereferenceObject(Section
);
3373 ObDereferenceObject(FileObject
);
3377 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3378 ImageSectionObject
, NULL
))
3381 * An other thread has initialized the some image in the background
3383 ExFreePool(ImageSectionObject
->Segments
);
3384 ExFreePool(ImageSectionObject
);
3385 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3386 Section
->ImageSection
= ImageSectionObject
;
3387 SectionSegments
= ImageSectionObject
->Segments
;
3389 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3391 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3395 Status
= StatusExeFmt
;
3402 Status
= MmspWaitForFileLock(FileObject
);
3403 if (Status
!= STATUS_SUCCESS
)
3405 ObDereferenceObject(Section
);
3406 ObDereferenceObject(FileObject
);
3410 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3411 Section
->ImageSection
= ImageSectionObject
;
3412 SectionSegments
= ImageSectionObject
->Segments
;
3415 * Otherwise just reference all the section segments
3417 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3419 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3422 Status
= STATUS_SUCCESS
;
3424 Section
->FileObject
= FileObject
;
3425 CcRosReferenceCache(FileObject
);
3426 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3427 *SectionObject
= Section
;
3435 NtCreateSection (OUT PHANDLE SectionHandle
,
3436 IN ACCESS_MASK DesiredAccess
,
3437 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3438 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3439 IN ULONG SectionPageProtection OPTIONAL
,
3440 IN ULONG AllocationAttributes
,
3441 IN HANDLE FileHandle OPTIONAL
)
3443 LARGE_INTEGER SafeMaximumSize
;
3444 PVOID SectionObject
;
3445 KPROCESSOR_MODE PreviousMode
;
3446 NTSTATUS Status
= STATUS_SUCCESS
;
3448 PreviousMode
= ExGetPreviousMode();
3450 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3454 /* make a copy on the stack */
3455 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3456 MaximumSize
= &SafeMaximumSize
;
3460 Status
= _SEH_GetExceptionCode();
3464 if(!NT_SUCCESS(Status
))
3470 Status
= MmCreateSection(&SectionObject
,
3474 SectionPageProtection
,
3475 AllocationAttributes
,
3478 if (NT_SUCCESS(Status
))
3480 Status
= ObInsertObject ((PVOID
)SectionObject
,
3492 /**********************************************************************
3510 NtOpenSection(PHANDLE SectionHandle
,
3511 ACCESS_MASK DesiredAccess
,
3512 POBJECT_ATTRIBUTES ObjectAttributes
)
3515 KPROCESSOR_MODE PreviousMode
;
3516 NTSTATUS Status
= STATUS_SUCCESS
;
3518 PreviousMode
= ExGetPreviousMode();
3520 if(PreviousMode
!= KernelMode
)
3524 ProbeForWriteHandle(SectionHandle
);
3528 Status
= _SEH_GetExceptionCode();
3532 if(!NT_SUCCESS(Status
))
3538 Status
= ObOpenObjectByName(ObjectAttributes
,
3539 MmSectionObjectType
,
3546 if(NT_SUCCESS(Status
))
3550 *SectionHandle
= hSection
;
3554 Status
= _SEH_GetExceptionCode();
3563 MmMapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3564 PROS_SECTION_OBJECT Section
,
3565 PMM_SECTION_SEGMENT Segment
,
3570 ULONG AllocationType
)
3574 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3576 BoundaryAddressMultiple
.QuadPart
= 0;
3578 Status
= MmCreateMemoryArea(AddressSpace
,
3579 MEMORY_AREA_SECTION_VIEW
,
3586 BoundaryAddressMultiple
);
3587 if (!NT_SUCCESS(Status
))
3589 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3590 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3594 ObReferenceObject((PVOID
)Section
);
3596 MArea
->Data
.SectionData
.Segment
= Segment
;
3597 MArea
->Data
.SectionData
.Section
= Section
;
3598 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3599 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3600 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3601 ViewSize
, 0, Protect
);
3603 return(STATUS_SUCCESS
);
3607 /**********************************************************************
3609 * NtMapViewOfSection
3612 * Maps a view of a section into the virtual address space of a
3617 * Handle of the section.
3620 * Handle of the process.
3623 * Desired base address (or NULL) on entry;
3624 * Actual base address of the view on exit.
3627 * Number of high order address bits that must be zero.
3630 * Size in bytes of the initially committed section of
3634 * Offset in bytes from the beginning of the section
3635 * to the beginning of the view.
3638 * Desired length of map (or zero to map all) on entry
3639 * Actual length mapped on exit.
3641 * InheritDisposition
3642 * Specified how the view is to be shared with
3646 * Type of allocation for the pages.
3649 * Protection for the committed region of the view.
3657 NtMapViewOfSection(IN HANDLE SectionHandle
,
3658 IN HANDLE ProcessHandle
,
3659 IN OUT PVOID
* BaseAddress OPTIONAL
,
3660 IN ULONG ZeroBits OPTIONAL
,
3661 IN ULONG CommitSize
,
3662 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3663 IN OUT PSIZE_T ViewSize
,
3664 IN SECTION_INHERIT InheritDisposition
,
3665 IN ULONG AllocationType OPTIONAL
,
3668 PVOID SafeBaseAddress
;
3669 LARGE_INTEGER SafeSectionOffset
;
3670 SIZE_T SafeViewSize
;
3671 PROS_SECTION_OBJECT Section
;
3673 KPROCESSOR_MODE PreviousMode
;
3674 PMADDRESS_SPACE AddressSpace
;
3675 NTSTATUS Status
= STATUS_SUCCESS
;
3679 * Check the protection
3681 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3684 return STATUS_INVALID_PARAMETER_10
;
3687 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3688 if (tmpProtect
!= PAGE_NOACCESS
&&
3689 tmpProtect
!= PAGE_READONLY
&&
3690 tmpProtect
!= PAGE_READWRITE
&&
3691 tmpProtect
!= PAGE_WRITECOPY
&&
3692 tmpProtect
!= PAGE_EXECUTE
&&
3693 tmpProtect
!= PAGE_EXECUTE_READ
&&
3694 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3695 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3698 return STATUS_INVALID_PAGE_PROTECTION
;
3701 PreviousMode
= ExGetPreviousMode();
3703 if(PreviousMode
!= KernelMode
)
3705 SafeBaseAddress
= NULL
;
3706 SafeSectionOffset
.QuadPart
= 0;
3711 if(BaseAddress
!= NULL
)
3713 ProbeForWritePointer(BaseAddress
);
3714 SafeBaseAddress
= *BaseAddress
;
3716 if(SectionOffset
!= NULL
)
3718 ProbeForWriteLargeInteger(SectionOffset
);
3719 SafeSectionOffset
= *SectionOffset
;
3721 ProbeForWriteSize_t(ViewSize
);
3722 SafeViewSize
= *ViewSize
;
3726 Status
= _SEH_GetExceptionCode();
3730 if(!NT_SUCCESS(Status
))
3737 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3738 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3739 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3742 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3744 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3745 PROCESS_VM_OPERATION
,
3748 (PVOID
*)(PVOID
)&Process
,
3750 if (!NT_SUCCESS(Status
))
3755 AddressSpace
= (PMADDRESS_SPACE
)&Process
->VadRoot
;
3757 Status
= ObReferenceObjectByHandle(SectionHandle
,
3759 MmSectionObjectType
,
3761 (PVOID
*)(PVOID
)&Section
,
3763 if (!(NT_SUCCESS(Status
)))
3765 DPRINT("ObReference failed rc=%x\n",Status
);
3766 ObDereferenceObject(Process
);
3770 Status
= MmMapViewOfSection(Section
,
3772 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3775 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3776 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3781 /* Check if this is an image for the current process */
3782 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3783 (Process
== PsGetCurrentProcess()) &&
3784 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3786 /* Notify the debugger */
3787 DbgkMapViewOfSection(Section
,
3789 SafeSectionOffset
.LowPart
,
3793 ObDereferenceObject(Section
);
3794 ObDereferenceObject(Process
);
3796 if(NT_SUCCESS(Status
))
3798 /* copy parameters back to the caller */
3801 if(BaseAddress
!= NULL
)
3803 *BaseAddress
= SafeBaseAddress
;
3805 if(SectionOffset
!= NULL
)
3807 *SectionOffset
= SafeSectionOffset
;
3809 if(ViewSize
!= NULL
)
3811 *ViewSize
= SafeViewSize
;
3816 Status
= _SEH_GetExceptionCode();
3825 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3826 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3829 PFILE_OBJECT FileObject
;
3832 SWAPENTRY SavedSwapEntry
;
3835 PROS_SECTION_OBJECT Section
;
3836 PMM_SECTION_SEGMENT Segment
;
3837 PMADDRESS_SPACE AddressSpace
;
3839 AddressSpace
= (PMADDRESS_SPACE
)Context
;
3841 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3843 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3844 MemoryArea
->Data
.SectionData
.ViewOffset
;
3846 Section
= MemoryArea
->Data
.SectionData
.Section
;
3847 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3849 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3853 MmUnlockSectionSegment(Segment
);
3854 MmUnlockAddressSpace(AddressSpace
);
3856 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3857 if (Status
!= STATUS_SUCCESS
)
3859 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3863 MmLockAddressSpace(AddressSpace
);
3864 MmLockSectionSegment(Segment
);
3865 MmspCompleteAndReleasePageOp(PageOp
);
3866 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3869 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3872 * For a dirty, datafile, non-private page mark it as dirty in the
3875 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3877 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3879 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3880 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3881 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3882 ASSERT(SwapEntry
== 0);
3891 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3893 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3896 MmFreeSwapPage(SwapEntry
);
3900 if (IS_SWAP_FROM_SSE(Entry
) ||
3901 Page
!= PFN_FROM_SSE(Entry
))
3906 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3908 DPRINT1("Found a private page in a pagefile section.\n");
3912 * Just dereference private pages
3914 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3915 if (SavedSwapEntry
!= 0)
3917 MmFreeSwapPage(SavedSwapEntry
);
3918 MmSetSavedSwapEntryPage(Page
, 0);
3920 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3921 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3925 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3926 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3932 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3936 PMEMORY_AREA MemoryArea
;
3937 PROS_SECTION_OBJECT Section
;
3938 PMM_SECTION_SEGMENT Segment
;
3939 PLIST_ENTRY CurrentEntry
;
3940 PMM_REGION CurrentRegion
;
3941 PLIST_ENTRY RegionListHead
;
3943 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3945 if (MemoryArea
== NULL
)
3947 return(STATUS_UNSUCCESSFUL
);
3950 MemoryArea
->DeleteInProgress
= TRUE
;
3951 Section
= MemoryArea
->Data
.SectionData
.Section
;
3952 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3954 MmLockSectionSegment(Segment
);
3956 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3957 while (!IsListEmpty(RegionListHead
))
3959 CurrentEntry
= RemoveHeadList(RegionListHead
);
3960 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3961 ExFreePool(CurrentRegion
);
3964 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3966 Status
= MmFreeMemoryArea(AddressSpace
,
3973 Status
= MmFreeMemoryArea(AddressSpace
,
3978 MmUnlockSectionSegment(Segment
);
3979 ObDereferenceObject(Section
);
3980 return(STATUS_SUCCESS
);
3987 MmUnmapViewOfSection(PEPROCESS Process
,
3991 PMEMORY_AREA MemoryArea
;
3992 PMADDRESS_SPACE AddressSpace
;
3993 PROS_SECTION_OBJECT Section
;
3996 PVOID ImageBaseAddress
= 0;
3998 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3999 Process
, BaseAddress
);
4003 AddressSpace
= (PMADDRESS_SPACE
)&(Process
)->VadRoot
;
4005 MmLockAddressSpace(AddressSpace
);
4006 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4008 if (MemoryArea
== NULL
||
4009 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4010 MemoryArea
->DeleteInProgress
)
4012 MmUnlockAddressSpace(AddressSpace
);
4013 return STATUS_NOT_MAPPED_VIEW
;
4016 MemoryArea
->DeleteInProgress
= TRUE
;
4018 while (MemoryArea
->PageOpCount
)
4020 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4024 Offset
-= PAGE_SIZE
;
4025 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4026 MemoryArea
->Data
.SectionData
.Segment
,
4027 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4030 MmUnlockAddressSpace(AddressSpace
);
4031 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4032 if (Status
!= STATUS_SUCCESS
)
4034 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4037 MmLockAddressSpace(AddressSpace
);
4038 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4040 if (MemoryArea
== NULL
||
4041 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4043 MmUnlockAddressSpace(AddressSpace
);
4044 return STATUS_NOT_MAPPED_VIEW
;
4051 Section
= MemoryArea
->Data
.SectionData
.Section
;
4053 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4057 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4058 PMM_SECTION_SEGMENT SectionSegments
;
4059 PMM_SECTION_SEGMENT Segment
;
4061 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4062 ImageSectionObject
= Section
->ImageSection
;
4063 SectionSegments
= ImageSectionObject
->Segments
;
4064 NrSegments
= ImageSectionObject
->NrSegments
;
4066 /* Search for the current segment within the section segments
4067 * and calculate the image base address */
4068 for (i
= 0; i
< NrSegments
; i
++)
4070 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4072 if (Segment
== &SectionSegments
[i
])
4074 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4079 if (i
>= NrSegments
)
4084 for (i
= 0; i
< NrSegments
; i
++)
4086 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4088 PVOID SBaseAddress
= (PVOID
)
4089 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4091 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4097 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4100 /* Notify debugger */
4101 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4103 MmUnlockAddressSpace(AddressSpace
);
4104 return(STATUS_SUCCESS
);
4107 /**********************************************************************
4109 * NtUnmapViewOfSection
4124 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4128 KPROCESSOR_MODE PreviousMode
;
4131 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4132 ProcessHandle
, BaseAddress
);
4134 PreviousMode
= ExGetPreviousMode();
4136 DPRINT("Referencing process\n");
4137 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4138 PROCESS_VM_OPERATION
,
4141 (PVOID
*)(PVOID
)&Process
,
4143 if (!NT_SUCCESS(Status
))
4145 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4149 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4151 ObDereferenceObject(Process
);
4158 * Queries the information of a section object.
4160 * @param SectionHandle
4161 * Handle to the section object. It must be opened with SECTION_QUERY
4163 * @param SectionInformationClass
4164 * Index to a certain information structure. Can be either
4165 * SectionBasicInformation or SectionImageInformation. The latter
4166 * is valid only for sections that were created with the SEC_IMAGE
4168 * @param SectionInformation
4169 * Caller supplies storage for resulting information.
4171 * Size of the supplied storage.
4172 * @param ResultLength
4180 NtQuerySection(IN HANDLE SectionHandle
,
4181 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4182 OUT PVOID SectionInformation
,
4183 IN ULONG SectionInformationLength
,
4184 OUT PULONG ResultLength OPTIONAL
)
4186 PROS_SECTION_OBJECT Section
;
4187 KPROCESSOR_MODE PreviousMode
;
4188 NTSTATUS Status
= STATUS_SUCCESS
;
4190 PreviousMode
= ExGetPreviousMode();
4192 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4194 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4196 SectionInformationLength
,
4200 if(!NT_SUCCESS(Status
))
4202 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4206 Status
= ObReferenceObjectByHandle(SectionHandle
,
4208 MmSectionObjectType
,
4210 (PVOID
*)(PVOID
)&Section
,
4212 if (NT_SUCCESS(Status
))
4214 switch (SectionInformationClass
)
4216 case SectionBasicInformation
:
4218 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4222 Sbi
->Attributes
= Section
->AllocationAttributes
;
4223 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4225 Sbi
->BaseAddress
= 0;
4226 Sbi
->Size
.QuadPart
= 0;
4230 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4231 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4234 if (ResultLength
!= NULL
)
4236 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4238 Status
= STATUS_SUCCESS
;
4242 Status
= _SEH_GetExceptionCode();
4249 case SectionImageInformation
:
4251 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4255 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4256 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4258 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4259 ImageSectionObject
= Section
->ImageSection
;
4261 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4262 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4263 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4264 Sii
->SubsystemType
= ImageSectionObject
->Subsystem
;
4265 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4266 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4267 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4268 Sii
->Machine
= ImageSectionObject
->Machine
;
4269 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4272 if (ResultLength
!= NULL
)
4274 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4276 Status
= STATUS_SUCCESS
;
4280 Status
= _SEH_GetExceptionCode();
4288 ObDereferenceObject(Section
);
4296 * Extends size of file backed section.
4298 * @param SectionHandle
4299 * Handle to the section object. It must be opened with
4300 * SECTION_EXTEND_SIZE access.
4301 * @param NewMaximumSize
4302 * New maximum size of the section in bytes.
4306 * @todo Move the actual code to internal function MmExtendSection.
4310 NtExtendSection(IN HANDLE SectionHandle
,
4311 IN PLARGE_INTEGER NewMaximumSize
)
4313 LARGE_INTEGER SafeNewMaximumSize
;
4314 PROS_SECTION_OBJECT Section
;
4315 KPROCESSOR_MODE PreviousMode
;
4316 NTSTATUS Status
= STATUS_SUCCESS
;
4318 PreviousMode
= ExGetPreviousMode();
4320 if(PreviousMode
!= KernelMode
)
4324 /* make a copy on the stack */
4325 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4326 NewMaximumSize
= &SafeNewMaximumSize
;
4330 Status
= _SEH_GetExceptionCode();
4334 if(!NT_SUCCESS(Status
))
4340 Status
= ObReferenceObjectByHandle(SectionHandle
,
4341 SECTION_EXTEND_SIZE
,
4342 MmSectionObjectType
,
4346 if (!NT_SUCCESS(Status
))
4351 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4353 ObfDereferenceObject(Section
);
4354 return STATUS_INVALID_PARAMETER
;
4358 * - Acquire file extneding resource.
4359 * - Check if we're not resizing the section below it's actual size!
4360 * - Extend segments if needed.
4361 * - Set file information (FileAllocationInformation) to the new size.
4362 * - Release file extending resource.
4365 ObDereferenceObject(Section
);
4367 return STATUS_NOT_IMPLEMENTED
;
4371 /**********************************************************************
4373 * MmAllocateSection@4
4383 * Code taken from ntoskrnl/mm/special.c.
4388 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4394 PMADDRESS_SPACE AddressSpace
;
4395 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4397 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4399 BoundaryAddressMultiple
.QuadPart
= 0;
4401 AddressSpace
= MmGetKernelAddressSpace();
4402 Result
= BaseAddress
;
4403 MmLockAddressSpace(AddressSpace
);
4404 Status
= MmCreateMemoryArea (AddressSpace
,
4412 BoundaryAddressMultiple
);
4413 MmUnlockAddressSpace(AddressSpace
);
4415 if (!NT_SUCCESS(Status
))
4419 DPRINT("Result %p\n",Result
);
4420 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
4424 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
4425 if (!NT_SUCCESS(Status
))
4427 DPRINT1("Unable to allocate page\n");
4430 Status
= MmCreateVirtualMapping (NULL
,
4431 (PVOID
)((ULONG_PTR
)Result
+ (i
* PAGE_SIZE
)),
4435 if (!NT_SUCCESS(Status
))
4437 DPRINT1("Unable to create virtual mapping\n");
4441 return ((PVOID
)Result
);
4445 /**********************************************************************
4447 * MmMapViewOfSection
4450 * Maps a view of a section into the virtual address space of a
4455 * Pointer to the section object.
4458 * Pointer to the process.
4461 * Desired base address (or NULL) on entry;
4462 * Actual base address of the view on exit.
4465 * Number of high order address bits that must be zero.
4468 * Size in bytes of the initially committed section of
4472 * Offset in bytes from the beginning of the section
4473 * to the beginning of the view.
4476 * Desired length of map (or zero to map all) on entry
4477 * Actual length mapped on exit.
4479 * InheritDisposition
4480 * Specified how the view is to be shared with
4484 * Type of allocation for the pages.
4487 * Protection for the committed region of the view.
4495 MmMapViewOfSection(IN PVOID SectionObject
,
4496 IN PEPROCESS Process
,
4497 IN OUT PVOID
*BaseAddress
,
4499 IN ULONG CommitSize
,
4500 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4501 IN OUT PSIZE_T ViewSize
,
4502 IN SECTION_INHERIT InheritDisposition
,
4503 IN ULONG AllocationType
,
4506 PROS_SECTION_OBJECT Section
;
4507 PMADDRESS_SPACE AddressSpace
;
4509 NTSTATUS Status
= STATUS_SUCCESS
;
4513 if (Protect
!= PAGE_READONLY
&&
4514 Protect
!= PAGE_READWRITE
&&
4515 Protect
!= PAGE_WRITECOPY
&&
4516 Protect
!= PAGE_EXECUTE
&&
4517 Protect
!= PAGE_EXECUTE_READ
&&
4518 Protect
!= PAGE_EXECUTE_READWRITE
&&
4519 Protect
!= PAGE_EXECUTE_WRITECOPY
)
4522 return STATUS_INVALID_PAGE_PROTECTION
;
4526 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4527 AddressSpace
= (PMADDRESS_SPACE
)&(Process
)->VadRoot
;
4529 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4531 MmLockAddressSpace(AddressSpace
);
4533 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4537 ULONG_PTR ImageBase
;
4539 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4540 PMM_SECTION_SEGMENT SectionSegments
;
4542 ImageSectionObject
= Section
->ImageSection
;
4543 SectionSegments
= ImageSectionObject
->Segments
;
4544 NrSegments
= ImageSectionObject
->NrSegments
;
4547 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4550 ImageBase
= ImageSectionObject
->ImageBase
;
4554 for (i
= 0; i
< NrSegments
; i
++)
4556 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4558 ULONG_PTR MaxExtent
;
4559 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4560 SectionSegments
[i
].Length
;
4561 ImageSize
= max(ImageSize
, MaxExtent
);
4565 ImageSectionObject
->ImageSize
= ImageSize
;
4567 /* Check there is enough space to map the section at that point. */
4568 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4569 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4571 /* Fail if the user requested a fixed base address. */
4572 if ((*BaseAddress
) != NULL
)
4574 MmUnlockAddressSpace(AddressSpace
);
4575 return(STATUS_UNSUCCESSFUL
);
4577 /* Otherwise find a gap to map the image. */
4578 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4581 MmUnlockAddressSpace(AddressSpace
);
4582 return(STATUS_UNSUCCESSFUL
);
4586 for (i
= 0; i
< NrSegments
; i
++)
4588 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4590 PVOID SBaseAddress
= (PVOID
)
4591 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4592 MmLockSectionSegment(&SectionSegments
[i
]);
4593 Status
= MmMapViewOfSegment(AddressSpace
,
4595 &SectionSegments
[i
],
4597 SectionSegments
[i
].Length
,
4598 SectionSegments
[i
].Protection
,
4601 MmUnlockSectionSegment(&SectionSegments
[i
]);
4602 if (!NT_SUCCESS(Status
))
4604 MmUnlockAddressSpace(AddressSpace
);
4610 *BaseAddress
= (PVOID
)ImageBase
;
4614 /* check for write access */
4615 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4616 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4619 return STATUS_SECTION_PROTECTION
;
4621 /* check for read access */
4622 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4623 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4626 return STATUS_SECTION_PROTECTION
;
4628 /* check for execute access */
4629 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4630 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4633 return STATUS_SECTION_PROTECTION
;
4636 if (ViewSize
== NULL
)
4638 /* Following this pointer would lead to us to the dark side */
4639 /* What to do? Bugcheck? Return status? Do the mambo? */
4640 KEBUGCHECK(MEMORY_MANAGEMENT
);
4643 if (SectionOffset
== NULL
)
4649 ViewOffset
= SectionOffset
->u
.LowPart
;
4652 if ((ViewOffset
% PAGE_SIZE
) != 0)
4654 MmUnlockAddressSpace(AddressSpace
);
4655 return(STATUS_MAPPED_ALIGNMENT
);
4658 if ((*ViewSize
) == 0)
4660 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4662 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4664 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4667 MmLockSectionSegment(Section
->Segment
);
4668 Status
= MmMapViewOfSegment(AddressSpace
,
4675 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4676 MmUnlockSectionSegment(Section
->Segment
);
4677 if (!NT_SUCCESS(Status
))
4679 MmUnlockAddressSpace(AddressSpace
);
4684 MmUnlockAddressSpace(AddressSpace
);
4686 return(STATUS_SUCCESS
);
4693 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4694 IN PLARGE_INTEGER NewFileSize
)
4705 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4715 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4716 IN MMFLUSH_TYPE FlushType
)
4720 case MmFlushForDelete
:
4721 if (SectionObjectPointer
->ImageSectionObject
||
4722 SectionObjectPointer
->DataSectionObject
)
4726 CcRosSetRemoveOnClose(SectionObjectPointer
);
4728 case MmFlushForWrite
:
4738 MmForceSectionClosed (
4739 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4740 IN BOOLEAN DelayClose
)
4751 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4752 OUT PVOID
* MappedBase
,
4753 IN OUT PULONG ViewSize
)
4755 PROS_SECTION_OBJECT Section
;
4756 PMADDRESS_SPACE AddressSpace
;
4759 DPRINT("MmMapViewInSystemSpace() called\n");
4761 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4762 AddressSpace
= MmGetKernelAddressSpace();
4764 MmLockAddressSpace(AddressSpace
);
4767 if ((*ViewSize
) == 0)
4769 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4771 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4773 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4776 MmLockSectionSegment(Section
->Segment
);
4779 Status
= MmMapViewOfSegment(AddressSpace
,
4788 MmUnlockSectionSegment(Section
->Segment
);
4789 MmUnlockAddressSpace(AddressSpace
);
4799 MmMapViewInSessionSpace (
4801 OUT PVOID
*MappedBase
,
4802 IN OUT PSIZE_T ViewSize
4806 return STATUS_NOT_IMPLEMENTED
;
4814 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4816 PMADDRESS_SPACE AddressSpace
;
4819 DPRINT("MmUnmapViewInSystemSpace() called\n");
4821 AddressSpace
= MmGetKernelAddressSpace();
4823 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4833 MmUnmapViewInSessionSpace (
4838 return STATUS_NOT_IMPLEMENTED
;
4845 MmSetBankedSection (ULONG Unknown0
,
4853 return (STATUS_NOT_IMPLEMENTED
);
4857 /**********************************************************************
4862 * Creates a section object.
4865 * SectionObject (OUT)
4866 * Caller supplied storage for the resulting pointer
4867 * to a SECTION_OBJECT instance;
4870 * Specifies the desired access to the section can be a
4872 * STANDARD_RIGHTS_REQUIRED |
4874 * SECTION_MAP_WRITE |
4875 * SECTION_MAP_READ |
4876 * SECTION_MAP_EXECUTE
4878 * ObjectAttributes [OPTIONAL]
4879 * Initialized attributes for the object can be used
4880 * to create a named section;
4883 * Maximizes the size of the memory section. Must be
4884 * non-NULL for a page-file backed section.
4885 * If value specified for a mapped file and the file is
4886 * not large enough, file will be extended.
4888 * SectionPageProtection
4889 * Can be a combination of:
4895 * AllocationAttributes
4896 * Can be a combination of:
4901 * Handle to a file to create a section mapped to a file
4902 * instead of a memory backed section;
4913 MmCreateSection (OUT PVOID
* Section
,
4914 IN ACCESS_MASK DesiredAccess
,
4915 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4916 IN PLARGE_INTEGER MaximumSize
,
4917 IN ULONG SectionPageProtection
,
4918 IN ULONG AllocationAttributes
,
4919 IN HANDLE FileHandle OPTIONAL
,
4920 IN PFILE_OBJECT File OPTIONAL
)
4923 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4926 * Check the protection
4928 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4929 if (Protection
!= PAGE_NOACCESS
&&
4930 Protection
!= PAGE_READONLY
&&
4931 Protection
!= PAGE_READWRITE
&&
4932 Protection
!= PAGE_WRITECOPY
&&
4933 Protection
!= PAGE_EXECUTE
&&
4934 Protection
!= PAGE_EXECUTE_READ
&&
4935 Protection
!= PAGE_EXECUTE_READWRITE
&&
4936 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4939 return STATUS_INVALID_PAGE_PROTECTION
;
4942 if (AllocationAttributes
& SEC_IMAGE
)
4944 return(MmCreateImageSection(SectionObject
,
4948 SectionPageProtection
,
4949 AllocationAttributes
,
4953 if (FileHandle
!= NULL
)
4955 return(MmCreateDataFileSection(SectionObject
,
4959 SectionPageProtection
,
4960 AllocationAttributes
,
4964 return(MmCreatePageFileSection(SectionObject
,
4968 SectionPageProtection
,
4969 AllocationAttributes
));
4974 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
4975 IN OUT PULONG NumberOfPages
,
4976 IN OUT PULONG UserPfnArray
)
4979 return STATUS_NOT_IMPLEMENTED
;
4984 NtMapUserPhysicalPages(IN PVOID
*VirtualAddresses
,
4985 IN ULONG NumberOfPages
,
4986 IN OUT PULONG UserPfnArray
)
4989 return STATUS_NOT_IMPLEMENTED
;
4994 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
4995 IN ULONG NumberOfPages
,
4996 IN OUT PULONG UserPfnArray
)
4999 return STATUS_NOT_IMPLEMENTED
;
5004 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
5005 IN OUT PULONG NumberOfPages
,
5006 IN OUT PULONG UserPfnArray
)
5009 return STATUS_NOT_IMPLEMENTED
;
5014 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
5015 IN PVOID File2MappedAsFile
)
5018 return STATUS_NOT_IMPLEMENTED
;