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 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3743 PROCESS_VM_OPERATION
,
3746 (PVOID
*)(PVOID
)&Process
,
3748 if (!NT_SUCCESS(Status
))
3753 AddressSpace
= (PMADDRESS_SPACE
)&Process
->VadRoot
;
3755 Status
= ObReferenceObjectByHandle(SectionHandle
,
3757 MmSectionObjectType
,
3759 (PVOID
*)(PVOID
)&Section
,
3761 if (!(NT_SUCCESS(Status
)))
3763 DPRINT("ObReference failed rc=%x\n",Status
);
3764 ObDereferenceObject(Process
);
3768 Status
= MmMapViewOfSection(Section
,
3770 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3773 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3774 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3779 /* Check if this is an image for the current process */
3780 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3781 (Process
== PsGetCurrentProcess()) &&
3782 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3784 /* Notify the debugger */
3785 DbgkMapViewOfSection(Section
,
3787 SafeSectionOffset
.LowPart
,
3791 ObDereferenceObject(Section
);
3792 ObDereferenceObject(Process
);
3794 if(NT_SUCCESS(Status
))
3796 /* copy parameters back to the caller */
3799 if(BaseAddress
!= NULL
)
3801 *BaseAddress
= SafeBaseAddress
;
3803 if(SectionOffset
!= NULL
)
3805 *SectionOffset
= SafeSectionOffset
;
3807 if(ViewSize
!= NULL
)
3809 *ViewSize
= SafeViewSize
;
3814 Status
= _SEH_GetExceptionCode();
3823 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3824 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3827 PFILE_OBJECT FileObject
;
3830 SWAPENTRY SavedSwapEntry
;
3833 PROS_SECTION_OBJECT Section
;
3834 PMM_SECTION_SEGMENT Segment
;
3835 PMADDRESS_SPACE AddressSpace
;
3837 AddressSpace
= (PMADDRESS_SPACE
)Context
;
3839 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3841 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3842 MemoryArea
->Data
.SectionData
.ViewOffset
;
3844 Section
= MemoryArea
->Data
.SectionData
.Section
;
3845 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3847 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3851 MmUnlockSectionSegment(Segment
);
3852 MmUnlockAddressSpace(AddressSpace
);
3854 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3855 if (Status
!= STATUS_SUCCESS
)
3857 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3861 MmLockAddressSpace(AddressSpace
);
3862 MmLockSectionSegment(Segment
);
3863 MmspCompleteAndReleasePageOp(PageOp
);
3864 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3867 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3870 * For a dirty, datafile, non-private page mark it as dirty in the
3873 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3875 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3877 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3878 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3879 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3880 ASSERT(SwapEntry
== 0);
3889 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3891 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3894 MmFreeSwapPage(SwapEntry
);
3898 if (IS_SWAP_FROM_SSE(Entry
) ||
3899 Page
!= PFN_FROM_SSE(Entry
))
3904 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3906 DPRINT1("Found a private page in a pagefile section.\n");
3910 * Just dereference private pages
3912 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3913 if (SavedSwapEntry
!= 0)
3915 MmFreeSwapPage(SavedSwapEntry
);
3916 MmSetSavedSwapEntryPage(Page
, 0);
3918 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3919 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3923 MmDeleteRmap(Page
, AddressSpace
->Process
, Address
);
3924 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3930 MmUnmapViewOfSegment(PMADDRESS_SPACE AddressSpace
,
3934 PMEMORY_AREA MemoryArea
;
3935 PROS_SECTION_OBJECT Section
;
3936 PMM_SECTION_SEGMENT Segment
;
3937 PLIST_ENTRY CurrentEntry
;
3938 PMM_REGION CurrentRegion
;
3939 PLIST_ENTRY RegionListHead
;
3941 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3943 if (MemoryArea
== NULL
)
3945 return(STATUS_UNSUCCESSFUL
);
3948 MemoryArea
->DeleteInProgress
= TRUE
;
3949 Section
= MemoryArea
->Data
.SectionData
.Section
;
3950 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3952 MmLockSectionSegment(Segment
);
3954 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3955 while (!IsListEmpty(RegionListHead
))
3957 CurrentEntry
= RemoveHeadList(RegionListHead
);
3958 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3959 ExFreePool(CurrentRegion
);
3962 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3964 Status
= MmFreeMemoryArea(AddressSpace
,
3971 Status
= MmFreeMemoryArea(AddressSpace
,
3976 MmUnlockSectionSegment(Segment
);
3977 ObDereferenceObject(Section
);
3978 return(STATUS_SUCCESS
);
3985 MmUnmapViewOfSection(PEPROCESS Process
,
3989 PMEMORY_AREA MemoryArea
;
3990 PMADDRESS_SPACE AddressSpace
;
3991 PROS_SECTION_OBJECT Section
;
3994 PVOID ImageBaseAddress
= 0;
3996 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3997 Process
, BaseAddress
);
4001 AddressSpace
= (PMADDRESS_SPACE
)&(Process
)->VadRoot
;
4003 MmLockAddressSpace(AddressSpace
);
4004 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4006 if (MemoryArea
== NULL
||
4007 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4008 MemoryArea
->DeleteInProgress
)
4010 MmUnlockAddressSpace(AddressSpace
);
4011 return STATUS_NOT_MAPPED_VIEW
;
4014 MemoryArea
->DeleteInProgress
= TRUE
;
4016 while (MemoryArea
->PageOpCount
)
4018 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4022 Offset
-= PAGE_SIZE
;
4023 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4024 MemoryArea
->Data
.SectionData
.Segment
,
4025 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4028 MmUnlockAddressSpace(AddressSpace
);
4029 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4030 if (Status
!= STATUS_SUCCESS
)
4032 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4035 MmLockAddressSpace(AddressSpace
);
4036 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4038 if (MemoryArea
== NULL
||
4039 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4041 MmUnlockAddressSpace(AddressSpace
);
4042 return STATUS_NOT_MAPPED_VIEW
;
4049 Section
= MemoryArea
->Data
.SectionData
.Section
;
4051 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4055 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4056 PMM_SECTION_SEGMENT SectionSegments
;
4057 PMM_SECTION_SEGMENT Segment
;
4059 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4060 ImageSectionObject
= Section
->ImageSection
;
4061 SectionSegments
= ImageSectionObject
->Segments
;
4062 NrSegments
= ImageSectionObject
->NrSegments
;
4064 /* Search for the current segment within the section segments
4065 * and calculate the image base address */
4066 for (i
= 0; i
< NrSegments
; i
++)
4068 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4070 if (Segment
== &SectionSegments
[i
])
4072 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4077 if (i
>= NrSegments
)
4082 for (i
= 0; i
< NrSegments
; i
++)
4084 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4086 PVOID SBaseAddress
= (PVOID
)
4087 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4089 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4095 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4098 /* Notify debugger */
4099 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4101 MmUnlockAddressSpace(AddressSpace
);
4102 return(STATUS_SUCCESS
);
4105 /**********************************************************************
4107 * NtUnmapViewOfSection
4122 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4126 KPROCESSOR_MODE PreviousMode
;
4129 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4130 ProcessHandle
, BaseAddress
);
4132 PreviousMode
= ExGetPreviousMode();
4134 DPRINT("Referencing process\n");
4135 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4136 PROCESS_VM_OPERATION
,
4139 (PVOID
*)(PVOID
)&Process
,
4141 if (!NT_SUCCESS(Status
))
4143 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4147 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4149 ObDereferenceObject(Process
);
4156 * Queries the information of a section object.
4158 * @param SectionHandle
4159 * Handle to the section object. It must be opened with SECTION_QUERY
4161 * @param SectionInformationClass
4162 * Index to a certain information structure. Can be either
4163 * SectionBasicInformation or SectionImageInformation. The latter
4164 * is valid only for sections that were created with the SEC_IMAGE
4166 * @param SectionInformation
4167 * Caller supplies storage for resulting information.
4169 * Size of the supplied storage.
4170 * @param ResultLength
4178 NtQuerySection(IN HANDLE SectionHandle
,
4179 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4180 OUT PVOID SectionInformation
,
4181 IN ULONG SectionInformationLength
,
4182 OUT PULONG ResultLength OPTIONAL
)
4184 PROS_SECTION_OBJECT Section
;
4185 KPROCESSOR_MODE PreviousMode
;
4186 NTSTATUS Status
= STATUS_SUCCESS
;
4188 PreviousMode
= ExGetPreviousMode();
4190 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4192 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4194 SectionInformationLength
,
4198 if(!NT_SUCCESS(Status
))
4200 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4204 Status
= ObReferenceObjectByHandle(SectionHandle
,
4206 MmSectionObjectType
,
4208 (PVOID
*)(PVOID
)&Section
,
4210 if (NT_SUCCESS(Status
))
4212 switch (SectionInformationClass
)
4214 case SectionBasicInformation
:
4216 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4220 Sbi
->Attributes
= Section
->AllocationAttributes
;
4221 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4223 Sbi
->BaseAddress
= 0;
4224 Sbi
->Size
.QuadPart
= 0;
4228 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4229 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4232 if (ResultLength
!= NULL
)
4234 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4236 Status
= STATUS_SUCCESS
;
4240 Status
= _SEH_GetExceptionCode();
4247 case SectionImageInformation
:
4249 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4253 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4254 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4256 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4257 ImageSectionObject
= Section
->ImageSection
;
4259 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4260 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4261 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4262 Sii
->SubsystemType
= ImageSectionObject
->Subsystem
;
4263 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4264 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4265 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4266 Sii
->Machine
= ImageSectionObject
->Machine
;
4267 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4270 if (ResultLength
!= NULL
)
4272 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4274 Status
= STATUS_SUCCESS
;
4278 Status
= _SEH_GetExceptionCode();
4286 ObDereferenceObject(Section
);
4294 * Extends size of file backed section.
4296 * @param SectionHandle
4297 * Handle to the section object. It must be opened with
4298 * SECTION_EXTEND_SIZE access.
4299 * @param NewMaximumSize
4300 * New maximum size of the section in bytes.
4304 * @todo Move the actual code to internal function MmExtendSection.
4308 NtExtendSection(IN HANDLE SectionHandle
,
4309 IN PLARGE_INTEGER NewMaximumSize
)
4311 LARGE_INTEGER SafeNewMaximumSize
;
4312 PROS_SECTION_OBJECT Section
;
4313 KPROCESSOR_MODE PreviousMode
;
4314 NTSTATUS Status
= STATUS_SUCCESS
;
4316 PreviousMode
= ExGetPreviousMode();
4318 if(PreviousMode
!= KernelMode
)
4322 /* make a copy on the stack */
4323 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4324 NewMaximumSize
= &SafeNewMaximumSize
;
4328 Status
= _SEH_GetExceptionCode();
4332 if(!NT_SUCCESS(Status
))
4338 Status
= ObReferenceObjectByHandle(SectionHandle
,
4339 SECTION_EXTEND_SIZE
,
4340 MmSectionObjectType
,
4344 if (!NT_SUCCESS(Status
))
4349 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4351 ObfDereferenceObject(Section
);
4352 return STATUS_INVALID_PARAMETER
;
4356 * - Acquire file extneding resource.
4357 * - Check if we're not resizing the section below it's actual size!
4358 * - Extend segments if needed.
4359 * - Set file information (FileAllocationInformation) to the new size.
4360 * - Release file extending resource.
4363 ObDereferenceObject(Section
);
4365 return STATUS_NOT_IMPLEMENTED
;
4369 /**********************************************************************
4371 * MmAllocateSection@4
4381 * Code taken from ntoskrnl/mm/special.c.
4386 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4392 PMADDRESS_SPACE AddressSpace
;
4393 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4395 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4397 BoundaryAddressMultiple
.QuadPart
= 0;
4399 AddressSpace
= MmGetKernelAddressSpace();
4400 Result
= BaseAddress
;
4401 MmLockAddressSpace(AddressSpace
);
4402 Status
= MmCreateMemoryArea (AddressSpace
,
4410 BoundaryAddressMultiple
);
4411 MmUnlockAddressSpace(AddressSpace
);
4413 if (!NT_SUCCESS(Status
))
4417 DPRINT("Result %p\n",Result
);
4418 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
4422 Status
= MmRequestPageMemoryConsumer(MC_NPPOOL
, TRUE
, &Page
);
4423 if (!NT_SUCCESS(Status
))
4425 DPRINT1("Unable to allocate page\n");
4428 Status
= MmCreateVirtualMapping (NULL
,
4429 (PVOID
)((ULONG_PTR
)Result
+ (i
* PAGE_SIZE
)),
4433 if (!NT_SUCCESS(Status
))
4435 DPRINT1("Unable to create virtual mapping\n");
4439 return ((PVOID
)Result
);
4443 /**********************************************************************
4445 * MmMapViewOfSection
4448 * Maps a view of a section into the virtual address space of a
4453 * Pointer to the section object.
4456 * Pointer to the process.
4459 * Desired base address (or NULL) on entry;
4460 * Actual base address of the view on exit.
4463 * Number of high order address bits that must be zero.
4466 * Size in bytes of the initially committed section of
4470 * Offset in bytes from the beginning of the section
4471 * to the beginning of the view.
4474 * Desired length of map (or zero to map all) on entry
4475 * Actual length mapped on exit.
4477 * InheritDisposition
4478 * Specified how the view is to be shared with
4482 * Type of allocation for the pages.
4485 * Protection for the committed region of the view.
4493 MmMapViewOfSection(IN PVOID SectionObject
,
4494 IN PEPROCESS Process
,
4495 IN OUT PVOID
*BaseAddress
,
4497 IN ULONG CommitSize
,
4498 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4499 IN OUT PSIZE_T ViewSize
,
4500 IN SECTION_INHERIT InheritDisposition
,
4501 IN ULONG AllocationType
,
4504 PROS_SECTION_OBJECT Section
;
4505 PMADDRESS_SPACE AddressSpace
;
4507 NTSTATUS Status
= STATUS_SUCCESS
;
4511 if (Protect
!= PAGE_READONLY
&&
4512 Protect
!= PAGE_READWRITE
&&
4513 Protect
!= PAGE_WRITECOPY
&&
4514 Protect
!= PAGE_EXECUTE
&&
4515 Protect
!= PAGE_EXECUTE_READ
&&
4516 Protect
!= PAGE_EXECUTE_READWRITE
&&
4517 Protect
!= PAGE_EXECUTE_WRITECOPY
)
4520 return STATUS_INVALID_PAGE_PROTECTION
;
4524 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4525 AddressSpace
= (PMADDRESS_SPACE
)&(Process
)->VadRoot
;
4527 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4529 MmLockAddressSpace(AddressSpace
);
4531 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4535 ULONG_PTR ImageBase
;
4537 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4538 PMM_SECTION_SEGMENT SectionSegments
;
4540 ImageSectionObject
= Section
->ImageSection
;
4541 SectionSegments
= ImageSectionObject
->Segments
;
4542 NrSegments
= ImageSectionObject
->NrSegments
;
4545 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4548 ImageBase
= ImageSectionObject
->ImageBase
;
4552 for (i
= 0; i
< NrSegments
; i
++)
4554 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4556 ULONG_PTR MaxExtent
;
4557 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4558 SectionSegments
[i
].Length
;
4559 ImageSize
= max(ImageSize
, MaxExtent
);
4563 ImageSectionObject
->ImageSize
= ImageSize
;
4565 /* Check there is enough space to map the section at that point. */
4566 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4567 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4569 /* Fail if the user requested a fixed base address. */
4570 if ((*BaseAddress
) != NULL
)
4572 MmUnlockAddressSpace(AddressSpace
);
4573 return(STATUS_UNSUCCESSFUL
);
4575 /* Otherwise find a gap to map the image. */
4576 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4579 MmUnlockAddressSpace(AddressSpace
);
4580 return(STATUS_UNSUCCESSFUL
);
4584 for (i
= 0; i
< NrSegments
; i
++)
4586 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4588 PVOID SBaseAddress
= (PVOID
)
4589 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4590 MmLockSectionSegment(&SectionSegments
[i
]);
4591 Status
= MmMapViewOfSegment(AddressSpace
,
4593 &SectionSegments
[i
],
4595 SectionSegments
[i
].Length
,
4596 SectionSegments
[i
].Protection
,
4599 MmUnlockSectionSegment(&SectionSegments
[i
]);
4600 if (!NT_SUCCESS(Status
))
4602 MmUnlockAddressSpace(AddressSpace
);
4608 *BaseAddress
= (PVOID
)ImageBase
;
4612 /* check for write access */
4613 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4614 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4617 return STATUS_SECTION_PROTECTION
;
4619 /* check for read access */
4620 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4621 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4624 return STATUS_SECTION_PROTECTION
;
4626 /* check for execute access */
4627 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4628 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4631 return STATUS_SECTION_PROTECTION
;
4634 if (ViewSize
== NULL
)
4636 /* Following this pointer would lead to us to the dark side */
4637 /* What to do? Bugcheck? Return status? Do the mambo? */
4638 KEBUGCHECK(MEMORY_MANAGEMENT
);
4641 if (SectionOffset
== NULL
)
4647 ViewOffset
= SectionOffset
->u
.LowPart
;
4650 if ((ViewOffset
% PAGE_SIZE
) != 0)
4652 MmUnlockAddressSpace(AddressSpace
);
4653 return(STATUS_MAPPED_ALIGNMENT
);
4656 if ((*ViewSize
) == 0)
4658 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4660 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4662 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4665 MmLockSectionSegment(Section
->Segment
);
4666 Status
= MmMapViewOfSegment(AddressSpace
,
4673 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4674 MmUnlockSectionSegment(Section
->Segment
);
4675 if (!NT_SUCCESS(Status
))
4677 MmUnlockAddressSpace(AddressSpace
);
4682 MmUnlockAddressSpace(AddressSpace
);
4684 return(STATUS_SUCCESS
);
4691 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4692 IN PLARGE_INTEGER NewFileSize
)
4703 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4713 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4714 IN MMFLUSH_TYPE FlushType
)
4718 case MmFlushForDelete
:
4719 if (SectionObjectPointer
->ImageSectionObject
||
4720 SectionObjectPointer
->DataSectionObject
)
4724 CcRosSetRemoveOnClose(SectionObjectPointer
);
4726 case MmFlushForWrite
:
4736 MmForceSectionClosed (
4737 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4738 IN BOOLEAN DelayClose
)
4749 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4750 OUT PVOID
* MappedBase
,
4751 IN OUT PULONG ViewSize
)
4753 PROS_SECTION_OBJECT Section
;
4754 PMADDRESS_SPACE AddressSpace
;
4757 DPRINT("MmMapViewInSystemSpace() called\n");
4759 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4760 AddressSpace
= MmGetKernelAddressSpace();
4762 MmLockAddressSpace(AddressSpace
);
4765 if ((*ViewSize
) == 0)
4767 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4769 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4771 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4774 MmLockSectionSegment(Section
->Segment
);
4777 Status
= MmMapViewOfSegment(AddressSpace
,
4786 MmUnlockSectionSegment(Section
->Segment
);
4787 MmUnlockAddressSpace(AddressSpace
);
4797 MmMapViewInSessionSpace (
4799 OUT PVOID
*MappedBase
,
4800 IN OUT PSIZE_T ViewSize
4804 return STATUS_NOT_IMPLEMENTED
;
4812 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4814 PMADDRESS_SPACE AddressSpace
;
4817 DPRINT("MmUnmapViewInSystemSpace() called\n");
4819 AddressSpace
= MmGetKernelAddressSpace();
4821 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4831 MmUnmapViewInSessionSpace (
4836 return STATUS_NOT_IMPLEMENTED
;
4843 MmSetBankedSection (ULONG Unknown0
,
4851 return (STATUS_NOT_IMPLEMENTED
);
4855 /**********************************************************************
4860 * Creates a section object.
4863 * SectionObject (OUT)
4864 * Caller supplied storage for the resulting pointer
4865 * to a SECTION_OBJECT instance;
4868 * Specifies the desired access to the section can be a
4870 * STANDARD_RIGHTS_REQUIRED |
4872 * SECTION_MAP_WRITE |
4873 * SECTION_MAP_READ |
4874 * SECTION_MAP_EXECUTE
4876 * ObjectAttributes [OPTIONAL]
4877 * Initialized attributes for the object can be used
4878 * to create a named section;
4881 * Maximizes the size of the memory section. Must be
4882 * non-NULL for a page-file backed section.
4883 * If value specified for a mapped file and the file is
4884 * not large enough, file will be extended.
4886 * SectionPageProtection
4887 * Can be a combination of:
4893 * AllocationAttributes
4894 * Can be a combination of:
4899 * Handle to a file to create a section mapped to a file
4900 * instead of a memory backed section;
4911 MmCreateSection (OUT PVOID
* Section
,
4912 IN ACCESS_MASK DesiredAccess
,
4913 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4914 IN PLARGE_INTEGER MaximumSize
,
4915 IN ULONG SectionPageProtection
,
4916 IN ULONG AllocationAttributes
,
4917 IN HANDLE FileHandle OPTIONAL
,
4918 IN PFILE_OBJECT File OPTIONAL
)
4921 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4924 * Check the protection
4926 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4927 if (Protection
!= PAGE_NOACCESS
&&
4928 Protection
!= PAGE_READONLY
&&
4929 Protection
!= PAGE_READWRITE
&&
4930 Protection
!= PAGE_WRITECOPY
&&
4931 Protection
!= PAGE_EXECUTE
&&
4932 Protection
!= PAGE_EXECUTE_READ
&&
4933 Protection
!= PAGE_EXECUTE_READWRITE
&&
4934 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4937 return STATUS_INVALID_PAGE_PROTECTION
;
4940 if (AllocationAttributes
& SEC_IMAGE
)
4942 return(MmCreateImageSection(SectionObject
,
4946 SectionPageProtection
,
4947 AllocationAttributes
,
4951 if (FileHandle
!= NULL
)
4953 return(MmCreateDataFileSection(SectionObject
,
4957 SectionPageProtection
,
4958 AllocationAttributes
,
4962 return(MmCreatePageFileSection(SectionObject
,
4966 SectionPageProtection
,
4967 AllocationAttributes
));
4972 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
4973 IN OUT PULONG NumberOfPages
,
4974 IN OUT PULONG UserPfnArray
)
4977 return STATUS_NOT_IMPLEMENTED
;
4982 NtMapUserPhysicalPages(IN PVOID
*VirtualAddresses
,
4983 IN ULONG NumberOfPages
,
4984 IN OUT PULONG UserPfnArray
)
4987 return STATUS_NOT_IMPLEMENTED
;
4992 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
4993 IN ULONG NumberOfPages
,
4994 IN OUT PULONG UserPfnArray
)
4997 return STATUS_NOT_IMPLEMENTED
;
5002 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
5003 IN OUT PULONG NumberOfPages
,
5004 IN OUT PULONG UserPfnArray
)
5007 return STATUS_NOT_IMPLEMENTED
;
5012 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
5013 IN PVOID File2MappedAsFile
)
5016 return STATUS_NOT_IMPLEMENTED
;