2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
50 #include <reactos/exeformat.h>
52 #if defined (ALLOC_PRAGMA)
53 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
54 #pragma alloc_text(INIT, MmInitSectionImplementation)
58 /* TYPES *********************************************************************/
62 PROS_SECTION_OBJECT Section
;
63 PMM_SECTION_SEGMENT Segment
;
68 MM_SECTION_PAGEOUT_CONTEXT
;
70 /* GLOBALS *******************************************************************/
72 POBJECT_TYPE MmSectionObjectType
= NULL
;
74 static GENERIC_MAPPING MmpSectionMapping
= {
75 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
76 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
77 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
80 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
81 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
82 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
83 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
84 #define MAX_SHARE_COUNT 0x7FF
85 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
86 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
87 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
89 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
91 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
92 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
95 /* FUNCTIONS *****************************************************************/
99 MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section
)
104 /* Return the file object */
105 return Section
->FileObject
; // Section->ControlArea->FileObject on NT
110 MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section
,
111 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
113 POBJECT_NAME_INFORMATION ObjectNameInfo
;
117 /* Make sure it's an image section */
119 if (!(Section
->AllocationAttributes
& SEC_IMAGE
))
122 return STATUS_SECTION_NOT_IMAGE
;
125 /* Allocate memory for our structure */
126 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
,
128 TAG('M', 'm', ' ', ' '));
129 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
132 Status
= ObQueryNameString(Section
->FileObject
,
136 if (!NT_SUCCESS(Status
))
138 /* Failed, free memory */
139 ExFreePool(ObjectNameInfo
);
144 *ModuleName
= ObjectNameInfo
;
145 return STATUS_SUCCESS
;
150 MmGetFileNameForAddress(IN PVOID Address
,
151 OUT PUNICODE_STRING ModuleName
)
155 * Filip says to get the MM_AVL_TABLE from EPROCESS,
156 * then use the MmMarea routines to locate the Marea that
157 * corresponds to the address. Then make sure it's a section
158 * view type (MEMORY_AREA_SECTION_VIEW) and use the marea's
159 * per-type union to get the .u.SectionView.Section pointer to
160 * the SECTION_OBJECT. Then we can use MmGetFileNameForSection
161 * to get the full filename.
163 RtlCreateUnicodeString(ModuleName
, L
"C:\\ReactOS\\system32\\ntdll.dll");
164 return STATUS_SUCCESS
;
167 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
170 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
171 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
172 * RETURNS: Status of the wait.
175 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
177 LARGE_INTEGER Timeout
;
178 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
180 Timeout
.QuadPart
= -100000000LL; // 10 sec
183 Timeout
.QuadPart
= -100000000; // 10 sec
186 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
191 * FUNCTION: Sets the page op completion event and releases the page op.
192 * ARGUMENTS: PMM_PAGEOP.
193 * RETURNS: In shorter time than it takes you to even read this
194 * description, so don't even think about geting a mug of coffee.
197 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
199 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
200 MmReleasePageOp(PageOp
);
205 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
206 * ARGUMENTS: PFILE_OBJECT to wait for.
207 * RETURNS: Status of the wait.
210 MmspWaitForFileLock(PFILE_OBJECT File
)
212 return STATUS_SUCCESS
;
213 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
218 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
221 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
223 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
225 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
227 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
235 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
237 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
239 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
240 PMM_SECTION_SEGMENT SectionSegments
;
244 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
245 NrSegments
= ImageSectionObject
->NrSegments
;
246 SectionSegments
= ImageSectionObject
->Segments
;
247 for (i
= 0; i
< NrSegments
; i
++)
249 if (SectionSegments
[i
].ReferenceCount
!= 0)
251 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
252 SectionSegments
[i
].ReferenceCount
);
255 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
257 ExFreePool(ImageSectionObject
->Segments
);
258 ExFreePool(ImageSectionObject
);
259 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
261 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
263 PMM_SECTION_SEGMENT Segment
;
265 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
268 if (Segment
->ReferenceCount
!= 0)
270 DPRINT1("Data segment still referenced\n");
273 MmFreePageTablesSectionSegment(Segment
);
275 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
281 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
283 ExAcquireFastMutex(&Segment
->Lock
);
288 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
290 ExReleaseFastMutex(&Segment
->Lock
);
295 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
299 PSECTION_PAGE_TABLE Table
;
300 ULONG DirectoryOffset
;
303 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
305 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
309 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
310 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
314 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
315 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
316 TAG_SECTION_PAGE_TABLE
);
321 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
322 DPRINT("Table %x\n", Table
);
325 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
326 Table
->Entry
[TableOffset
] = Entry
;
332 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
335 PSECTION_PAGE_TABLE Table
;
337 ULONG DirectoryOffset
;
340 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
342 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
344 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
348 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
349 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
350 DPRINT("Table %x\n", Table
);
356 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
357 Entry
= Table
->Entry
[TableOffset
];
363 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
368 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
371 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
374 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
376 DPRINT1("Maximum share count reached\n");
379 if (IS_SWAP_FROM_SSE(Entry
))
383 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
384 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
389 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
390 PMM_SECTION_SEGMENT Segment
,
396 BOOLEAN IsDirectMapped
= FALSE
;
398 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
401 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
404 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
406 DPRINT1("Zero share count for unshare\n");
409 if (IS_SWAP_FROM_SSE(Entry
))
413 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
415 * If we reducing the share count of this entry to zero then set the entry
416 * to zero and tell the cache the page is no longer mapped.
418 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
420 PFILE_OBJECT FileObject
;
422 SWAPENTRY SavedSwapEntry
;
424 BOOLEAN IsImageSection
;
427 FileOffset
= Offset
+ Segment
->FileOffset
;
429 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
431 Page
= PFN_FROM_SSE(Entry
);
432 FileObject
= Section
->FileObject
;
433 if (FileObject
!= NULL
&&
434 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
437 if ((FileOffset
% PAGE_SIZE
) == 0 &&
438 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
441 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
442 IsDirectMapped
= TRUE
;
443 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
444 if (!NT_SUCCESS(Status
))
446 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
452 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
453 if (SavedSwapEntry
== 0)
456 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
457 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
461 * Try to page out this page and set the swap entry
462 * within the section segment. There exist no rmap entry
463 * for this page. The pager thread can't page out a
464 * page without a rmap entry.
466 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
470 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
473 MmReleasePageMemoryConsumer(MC_USER
, Page
);
479 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
480 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
488 * We hold all locks. Nobody can do something with the current
489 * process and the current segment (also not within an other process).
492 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
493 if (!NT_SUCCESS(Status
))
495 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
499 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
500 MmSetSavedSwapEntryPage(Page
, 0);
502 MmReleasePageMemoryConsumer(MC_USER
, Page
);
506 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
513 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
515 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
518 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
521 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
524 PCACHE_SEGMENT CacheSeg
;
525 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
526 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
529 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
538 MiReadPage(PMEMORY_AREA MemoryArea
,
542 * FUNCTION: Read a page for a section backed memory area.
544 * MemoryArea - Memory area to read the page for.
545 * Offset - Offset of the page to read.
546 * Page - Variable that receives a page contains the read data.
553 PCACHE_SEGMENT CacheSeg
;
554 PFILE_OBJECT FileObject
;
558 BOOLEAN IsImageSection
;
561 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
562 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
563 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
564 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
565 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
569 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
572 * If the file system is letting us go directly to the cache and the
573 * memory area was mapped at an offset in the file which is page aligned
574 * then get the related cache segment.
576 if ((FileOffset
% PAGE_SIZE
) == 0 &&
577 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
578 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
582 * Get the related cache segment; we use a lower level interface than
583 * filesystems do because it is safe for us to use an offset with a
584 * alignment less than the file system block size.
586 Status
= CcRosGetCacheSegment(Bcb
,
592 if (!NT_SUCCESS(Status
))
599 * If the cache segment isn't up to date then call the file
600 * system to read in the data.
602 Status
= ReadCacheSegment(CacheSeg
);
603 if (!NT_SUCCESS(Status
))
605 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
610 * Retrieve the page from the cache segment that we actually want.
612 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
613 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
615 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
620 ULONG CacheSegOffset
;
622 * Allocate a page, this is rather complicated by the possibility
623 * we might have to move other things out of memory
625 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
626 if (!NT_SUCCESS(Status
))
630 Status
= CcRosGetCacheSegment(Bcb
,
636 if (!NT_SUCCESS(Status
))
643 * If the cache segment isn't up to date then call the file
644 * system to read in the data.
646 Status
= ReadCacheSegment(CacheSeg
);
647 if (!NT_SUCCESS(Status
))
649 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
653 PageAddr
= MmCreateHyperspaceMapping(*Page
);
654 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
655 Length
= RawLength
- SegOffset
;
656 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
658 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
660 else if (CacheSegOffset
>= PAGE_SIZE
)
662 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
666 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
667 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
668 Status
= CcRosGetCacheSegment(Bcb
,
669 FileOffset
+ CacheSegOffset
,
674 if (!NT_SUCCESS(Status
))
676 MmDeleteHyperspaceMapping(PageAddr
);
682 * If the cache segment isn't up to date then call the file
683 * system to read in the data.
685 Status
= ReadCacheSegment(CacheSeg
);
686 if (!NT_SUCCESS(Status
))
688 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
689 MmDeleteHyperspaceMapping(PageAddr
);
693 if (Length
< PAGE_SIZE
)
695 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
699 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
702 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
703 MmDeleteHyperspaceMapping(PageAddr
);
705 return(STATUS_SUCCESS
);
710 MmNotPresentFaultSectionView(PMM_AVL_TABLE AddressSpace
,
711 MEMORY_AREA
* MemoryArea
,
719 PROS_SECTION_OBJECT Section
;
720 PMM_SECTION_SEGMENT Segment
;
726 BOOLEAN HasSwapEntry
;
727 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
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(Process
, Address
))
738 MmLockPage(MmGetPfnForProcess(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(Process
, Address
))
831 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
832 HasSwapEntry
= MmIsPageSwapEntry(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(Process
,
856 if (!NT_SUCCESS(Status
))
858 DPRINT1("Unable to create virtual mapping\n");
861 MmInsertRmap(Page
, 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(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(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(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
, 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(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(Process
,
1004 if (!NT_SUCCESS(Status
))
1006 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1010 MmInsertRmap(Page
, 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(Process
,
1104 if (!NT_SUCCESS(Status
))
1106 DPRINT1("Unable to create virtual mapping\n");
1109 MmInsertRmap(Page
, 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(Process
,
1179 if (!NT_SUCCESS(Status
))
1181 DPRINT1("Unable to create virtual mapping\n");
1184 MmInsertRmap(Page
, 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(Process
,
1211 if (!NT_SUCCESS(Status
))
1213 DPRINT1("Unable to create virtual mapping\n");
1216 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1221 PageOp
->Status
= STATUS_SUCCESS
;
1222 MmspCompleteAndReleasePageOp(PageOp
);
1223 DPRINT("Address 0x%.8X\n", Address
);
1224 return(STATUS_SUCCESS
);
1230 MmAccessFaultSectionView(PMM_AVL_TABLE AddressSpace
,
1231 MEMORY_AREA
* MemoryArea
,
1235 PMM_SECTION_SEGMENT Segment
;
1236 PROS_SECTION_OBJECT Section
;
1245 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1247 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1250 * Check if the page has been paged out or has already been set readwrite
1252 if (!MmIsPagePresent(Process
, Address
) ||
1253 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1255 DPRINT("Address 0x%.8X\n", Address
);
1256 return(STATUS_SUCCESS
);
1260 * Find the offset of the page
1262 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1263 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1264 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1266 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1267 Section
= MemoryArea
->Data
.SectionData
.Section
;
1268 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1269 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1274 MmLockSectionSegment(Segment
);
1276 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1277 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1279 MmUnlockSectionSegment(Segment
);
1282 * Check if we are doing COW
1284 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1285 (Region
->Protect
== PAGE_READWRITE
||
1286 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1288 DPRINT("Address 0x%.8X\n", Address
);
1289 return(STATUS_ACCESS_VIOLATION
);
1292 if (IS_SWAP_FROM_SSE(Entry
) ||
1293 PFN_FROM_SSE(Entry
) != OldPage
)
1295 /* This is a private page. We must only change the page protection. */
1296 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1297 return(STATUS_SUCCESS
);
1301 * Get or create a pageop
1303 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1304 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1307 DPRINT1("MmGetPageOp failed\n");
1312 * Wait for any other operations to complete
1314 if (PageOp
->Thread
!= PsGetCurrentThread())
1316 MmUnlockAddressSpace(AddressSpace
);
1317 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1319 * Check for various strange conditions
1321 if (Status
== STATUS_TIMEOUT
)
1323 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1326 if (PageOp
->Status
== STATUS_PENDING
)
1328 DPRINT1("Woke for page op before completion\n");
1332 * Restart the operation
1334 MmLockAddressSpace(AddressSpace
);
1335 MmspCompleteAndReleasePageOp(PageOp
);
1336 DPRINT("Address 0x%.8X\n", Address
);
1337 return(STATUS_MM_RESTART_OPERATION
);
1341 * Release locks now we have the pageop
1343 MmUnlockAddressSpace(AddressSpace
);
1348 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1349 if (!NT_SUCCESS(Status
))
1357 MiCopyFromUserPage(NewPage
, PAddress
);
1359 MmLockAddressSpace(AddressSpace
);
1361 * Delete the old entry.
1363 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1366 * Set the PTE to point to the new page
1368 Status
= MmCreateVirtualMapping(Process
,
1373 if (!NT_SUCCESS(Status
))
1375 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1379 if (!NT_SUCCESS(Status
))
1381 DPRINT1("Unable to create virtual mapping\n");
1386 MmLockPage(NewPage
);
1387 MmUnlockPage(OldPage
);
1391 * Unshare the old page.
1393 MmDeleteRmap(OldPage
, Process
, PAddress
);
1394 MmInsertRmap(NewPage
, Process
, PAddress
);
1395 MmLockSectionSegment(Segment
);
1396 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1397 MmUnlockSectionSegment(Segment
);
1399 PageOp
->Status
= STATUS_SUCCESS
;
1400 MmspCompleteAndReleasePageOp(PageOp
);
1401 DPRINT("Address 0x%.8X\n", Address
);
1402 return(STATUS_SUCCESS
);
1406 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1408 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1412 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1415 MmLockAddressSpace(&Process
->VadRoot
);
1418 MmDeleteVirtualMapping(Process
,
1425 PageOutContext
->WasDirty
= TRUE
;
1427 if (!PageOutContext
->Private
)
1429 MmLockSectionSegment(PageOutContext
->Segment
);
1430 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1431 PageOutContext
->Segment
,
1432 PageOutContext
->Offset
,
1433 PageOutContext
->WasDirty
,
1435 MmUnlockSectionSegment(PageOutContext
->Segment
);
1439 MmUnlockAddressSpace(&Process
->VadRoot
);
1442 if (PageOutContext
->Private
)
1444 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1447 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1452 MmPageOutSectionView(PMM_AVL_TABLE AddressSpace
,
1453 MEMORY_AREA
* MemoryArea
,
1458 MM_SECTION_PAGEOUT_CONTEXT Context
;
1459 SWAPENTRY SwapEntry
;
1463 PFILE_OBJECT FileObject
;
1465 BOOLEAN DirectMapped
;
1466 BOOLEAN IsImageSection
;
1467 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1469 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1472 * Get the segment and section.
1474 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1475 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1477 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1478 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1479 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1481 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1483 FileObject
= Context
.Section
->FileObject
;
1484 DirectMapped
= FALSE
;
1485 if (FileObject
!= NULL
&&
1486 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1488 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1491 * If the file system is letting us go directly to the cache and the
1492 * memory area was mapped at an offset in the file which is page aligned
1493 * then note this is a direct mapped page.
1495 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1496 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1498 DirectMapped
= TRUE
;
1504 * This should never happen since mappings of physical memory are never
1505 * placed in the rmap lists.
1507 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1509 DPRINT1("Trying to page out from physical memory section address 0x%X "
1510 "process %d\n", Address
,
1511 Process
? Process
->UniqueProcessId
: 0);
1516 * Get the section segment entry and the physical address.
1518 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1519 if (!MmIsPagePresent(Process
, Address
))
1521 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1522 Process
? Process
->UniqueProcessId
: 0, Address
);
1525 Page
= MmGetPfnForProcess(Process
, Address
);
1526 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1529 * Prepare the context structure for the rmap delete call.
1531 Context
.WasDirty
= FALSE
;
1532 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1533 IS_SWAP_FROM_SSE(Entry
) ||
1534 PFN_FROM_SSE(Entry
) != Page
)
1536 Context
.Private
= TRUE
;
1540 Context
.Private
= FALSE
;
1544 * Take an additional reference to the page or the cache segment.
1546 if (DirectMapped
&& !Context
.Private
)
1548 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1550 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1556 MmReferencePage(Page
);
1559 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1562 * If this wasn't a private page then we should have reduced the entry to
1563 * zero by deleting all the rmaps.
1565 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1567 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1568 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1575 * If the page wasn't dirty then we can just free it as for a readonly page.
1576 * Since we unmapped all the mappings above we know it will not suddenly
1578 * If the page is from a pagefile section and has no swap entry,
1579 * we can't free the page at this point.
1581 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1582 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1584 if (Context
.Private
)
1586 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1587 Context
.WasDirty
? "dirty" : "clean", Address
);
1590 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1592 MmSetSavedSwapEntryPage(Page
, 0);
1593 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1594 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1595 PageOp
->Status
= STATUS_SUCCESS
;
1596 MmspCompleteAndReleasePageOp(PageOp
);
1597 return(STATUS_SUCCESS
);
1600 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1602 if (Context
.Private
)
1604 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1605 Context
.WasDirty
? "dirty" : "clean", Address
);
1608 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1610 MmSetSavedSwapEntryPage(Page
, 0);
1613 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1615 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1616 PageOp
->Status
= STATUS_SUCCESS
;
1617 MmspCompleteAndReleasePageOp(PageOp
);
1618 return(STATUS_SUCCESS
);
1621 else if (!Context
.Private
&& DirectMapped
)
1625 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1629 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1630 if (!NT_SUCCESS(Status
))
1632 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1635 PageOp
->Status
= STATUS_SUCCESS
;
1636 MmspCompleteAndReleasePageOp(PageOp
);
1637 return(STATUS_SUCCESS
);
1639 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1643 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1647 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1648 PageOp
->Status
= STATUS_SUCCESS
;
1649 MmspCompleteAndReleasePageOp(PageOp
);
1650 return(STATUS_SUCCESS
);
1652 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1654 MmSetSavedSwapEntryPage(Page
, 0);
1655 MmLockAddressSpace(AddressSpace
);
1656 Status
= MmCreatePageFileMapping(Process
,
1659 MmUnlockAddressSpace(AddressSpace
);
1660 if (!NT_SUCCESS(Status
))
1664 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1665 PageOp
->Status
= STATUS_SUCCESS
;
1666 MmspCompleteAndReleasePageOp(PageOp
);
1667 return(STATUS_SUCCESS
);
1671 * If necessary, allocate an entry in the paging file for this page
1675 SwapEntry
= MmAllocSwapPage();
1678 MmShowOutOfSpaceMessagePagingFile();
1679 MmLockAddressSpace(AddressSpace
);
1681 * For private pages restore the old mappings.
1683 if (Context
.Private
)
1685 Status
= MmCreateVirtualMapping(Process
,
1687 MemoryArea
->Protect
,
1690 MmSetDirtyPage(Process
, Address
);
1698 * For non-private pages if the page wasn't direct mapped then
1699 * set it back into the section segment entry so we don't loose
1700 * our copy. Otherwise it will be handled by the cache manager.
1702 Status
= MmCreateVirtualMapping(Process
,
1704 MemoryArea
->Protect
,
1707 MmSetDirtyPage(Process
, Address
);
1711 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1712 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1714 MmUnlockAddressSpace(AddressSpace
);
1715 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1716 MmspCompleteAndReleasePageOp(PageOp
);
1717 return(STATUS_PAGEFILE_QUOTA
);
1722 * Write the page to the pagefile
1724 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1725 if (!NT_SUCCESS(Status
))
1727 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1730 * As above: undo our actions.
1731 * FIXME: Also free the swap page.
1733 MmLockAddressSpace(AddressSpace
);
1734 if (Context
.Private
)
1736 Status
= MmCreateVirtualMapping(Process
,
1738 MemoryArea
->Protect
,
1741 MmSetDirtyPage(Process
, Address
);
1748 Status
= MmCreateVirtualMapping(Process
,
1750 MemoryArea
->Protect
,
1753 MmSetDirtyPage(Process
, Address
);
1757 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1758 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1760 MmUnlockAddressSpace(AddressSpace
);
1761 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1762 MmspCompleteAndReleasePageOp(PageOp
);
1763 return(STATUS_UNSUCCESSFUL
);
1767 * Otherwise we have succeeded.
1769 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1770 MmSetSavedSwapEntryPage(Page
, 0);
1771 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1772 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1774 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1778 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1781 if (Context
.Private
)
1783 MmLockAddressSpace(AddressSpace
);
1784 Status
= MmCreatePageFileMapping(Process
,
1787 MmUnlockAddressSpace(AddressSpace
);
1788 if (!NT_SUCCESS(Status
))
1795 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1796 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1799 PageOp
->Status
= STATUS_SUCCESS
;
1800 MmspCompleteAndReleasePageOp(PageOp
);
1801 return(STATUS_SUCCESS
);
1806 MmWritePageSectionView(PMM_AVL_TABLE AddressSpace
,
1807 PMEMORY_AREA MemoryArea
,
1812 PROS_SECTION_OBJECT Section
;
1813 PMM_SECTION_SEGMENT Segment
;
1815 SWAPENTRY SwapEntry
;
1819 PFILE_OBJECT FileObject
;
1821 BOOLEAN DirectMapped
;
1822 BOOLEAN IsImageSection
;
1823 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1825 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1827 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1828 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1831 * Get the segment and section.
1833 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1834 Section
= MemoryArea
->Data
.SectionData
.Section
;
1835 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1837 FileObject
= Section
->FileObject
;
1838 DirectMapped
= FALSE
;
1839 if (FileObject
!= NULL
&&
1840 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1842 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1845 * If the file system is letting us go directly to the cache and the
1846 * memory area was mapped at an offset in the file which is page aligned
1847 * then note this is a direct mapped page.
1849 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1850 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1852 DirectMapped
= TRUE
;
1857 * This should never happen since mappings of physical memory are never
1858 * placed in the rmap lists.
1860 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1862 DPRINT1("Trying to write back page from physical memory mapped at %X "
1863 "process %d\n", Address
,
1864 Process
? Process
->UniqueProcessId
: 0);
1869 * Get the section segment entry and the physical address.
1871 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1872 if (!MmIsPagePresent(Process
, Address
))
1874 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1875 Process
? Process
->UniqueProcessId
: 0, Address
);
1878 Page
= MmGetPfnForProcess(Process
, Address
);
1879 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1882 * Check for a private (COWed) page.
1884 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1885 IS_SWAP_FROM_SSE(Entry
) ||
1886 PFN_FROM_SSE(Entry
) != Page
)
1896 * Speculatively set all mappings of the page to clean.
1898 MmSetCleanAllRmaps(Page
);
1901 * If this page was direct mapped from the cache then the cache manager
1902 * will take care of writing it back to disk.
1904 if (DirectMapped
&& !Private
)
1906 ASSERT(SwapEntry
== 0);
1907 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1908 PageOp
->Status
= STATUS_SUCCESS
;
1909 MmspCompleteAndReleasePageOp(PageOp
);
1910 return(STATUS_SUCCESS
);
1914 * If necessary, allocate an entry in the paging file for this page
1918 SwapEntry
= MmAllocSwapPage();
1921 MmSetDirtyAllRmaps(Page
);
1922 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1923 MmspCompleteAndReleasePageOp(PageOp
);
1924 return(STATUS_PAGEFILE_QUOTA
);
1926 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1930 * Write the page to the pagefile
1932 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1933 if (!NT_SUCCESS(Status
))
1935 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1937 MmSetDirtyAllRmaps(Page
);
1938 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1939 MmspCompleteAndReleasePageOp(PageOp
);
1940 return(STATUS_UNSUCCESSFUL
);
1944 * Otherwise we have succeeded.
1946 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1947 PageOp
->Status
= STATUS_SUCCESS
;
1948 MmspCompleteAndReleasePageOp(PageOp
);
1949 return(STATUS_SUCCESS
);
1953 MmAlterViewAttributes(PMM_AVL_TABLE AddressSpace
,
1961 PMEMORY_AREA MemoryArea
;
1962 PMM_SECTION_SEGMENT Segment
;
1963 BOOLEAN DoCOW
= FALSE
;
1965 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1967 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1968 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1970 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1971 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
1976 if (OldProtect
!= NewProtect
)
1978 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
1980 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
1981 ULONG Protect
= NewProtect
;
1984 * If we doing COW for this segment then check if the page is
1987 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
1993 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1994 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1995 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1996 Page
= MmGetPfnForProcess(Process
, Address
);
1998 Protect
= PAGE_READONLY
;
1999 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2000 IS_SWAP_FROM_SSE(Entry
) ||
2001 PFN_FROM_SSE(Entry
) != Page
)
2003 Protect
= NewProtect
;
2007 if (MmIsPagePresent(Process
, Address
))
2009 MmSetPageProtect(Process
, Address
,
2018 MmProtectSectionView(PMM_AVL_TABLE AddressSpace
,
2019 PMEMORY_AREA MemoryArea
,
2027 ULONG_PTR MaxLength
;
2029 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2030 if (Length
> MaxLength
)
2033 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2034 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2036 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2037 Region
->Protect
!= Protect
)
2039 return STATUS_INVALID_PAGE_PROTECTION
;
2042 *OldProtect
= Region
->Protect
;
2043 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2044 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2045 BaseAddress
, Length
, Region
->Type
, Protect
,
2046 MmAlterViewAttributes
);
2052 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2054 PMEMORY_BASIC_INFORMATION Info
,
2055 PULONG ResultLength
)
2058 PVOID RegionBaseAddress
;
2059 PROS_SECTION_OBJECT Section
;
2060 PMM_SECTION_SEGMENT Segment
;
2062 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2063 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2064 Address
, &RegionBaseAddress
);
2067 return STATUS_UNSUCCESSFUL
;
2070 Section
= MemoryArea
->Data
.SectionData
.Section
;
2071 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2073 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2074 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2075 Info
->Type
= MEM_IMAGE
;
2079 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2080 Info
->Type
= MEM_MAPPED
;
2082 Info
->BaseAddress
= RegionBaseAddress
;
2083 Info
->AllocationProtect
= MemoryArea
->Protect
;
2084 Info
->RegionSize
= Region
->Length
;
2085 Info
->State
= MEM_COMMIT
;
2086 Info
->Protect
= Region
->Protect
;
2088 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2089 return(STATUS_SUCCESS
);
2094 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2099 ULONG SavedSwapEntry
;
2104 Length
= PAGE_ROUND_UP(Segment
->Length
);
2105 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2107 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2110 if (IS_SWAP_FROM_SSE(Entry
))
2112 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2116 Page
= PFN_FROM_SSE(Entry
);
2117 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2118 if (SavedSwapEntry
!= 0)
2120 MmSetSavedSwapEntryPage(Page
, 0);
2121 MmFreeSwapPage(SavedSwapEntry
);
2123 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2125 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2131 MmpDeleteSection(PVOID ObjectBody
)
2133 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2135 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2136 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2141 PMM_SECTION_SEGMENT SectionSegments
;
2144 * NOTE: Section->ImageSection can be NULL for short time
2145 * during the section creating. If we fail for some reason
2146 * until the image section is properly initialized we shouldn't
2147 * process further here.
2149 if (Section
->ImageSection
== NULL
)
2152 SectionSegments
= Section
->ImageSection
->Segments
;
2153 NrSegments
= Section
->ImageSection
->NrSegments
;
2155 for (i
= 0; i
< NrSegments
; i
++)
2157 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2159 MmLockSectionSegment(&SectionSegments
[i
]);
2161 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2162 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2166 MmpFreePageFileSegment(&SectionSegments
[i
]);
2168 MmUnlockSectionSegment(&SectionSegments
[i
]);
2175 * NOTE: Section->Segment can be NULL for short time
2176 * during the section creating.
2178 if (Section
->Segment
== NULL
)
2181 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2183 MmpFreePageFileSegment(Section
->Segment
);
2184 MmFreePageTablesSectionSegment(Section
->Segment
);
2185 ExFreePool(Section
->Segment
);
2186 Section
->Segment
= NULL
;
2190 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2193 if (Section
->FileObject
!= NULL
)
2195 CcRosDereferenceCache(Section
->FileObject
);
2196 ObDereferenceObject(Section
->FileObject
);
2197 Section
->FileObject
= NULL
;
2202 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2204 IN ACCESS_MASK GrantedAccess
,
2205 IN ULONG ProcessHandleCount
,
2206 IN ULONG SystemHandleCount
)
2208 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2209 Object
, ProcessHandleCount
);
2215 MmCreatePhysicalMemorySection(VOID
)
2217 PROS_SECTION_OBJECT PhysSection
;
2219 OBJECT_ATTRIBUTES Obj
;
2220 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2221 LARGE_INTEGER SectionSize
;
2225 * Create the section mapping physical memory
2227 SectionSize
.QuadPart
= 0xFFFFFFFF;
2228 InitializeObjectAttributes(&Obj
,
2233 Status
= MmCreateSection((PVOID
)&PhysSection
,
2237 PAGE_EXECUTE_READWRITE
,
2241 if (!NT_SUCCESS(Status
))
2243 DPRINT1("Failed to create PhysicalMemory section\n");
2246 Status
= ObInsertObject(PhysSection
,
2252 if (!NT_SUCCESS(Status
))
2254 ObDereferenceObject(PhysSection
);
2256 ObCloseHandle(Handle
, KernelMode
);
2257 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2258 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2260 return(STATUS_SUCCESS
);
2266 MmInitSectionImplementation(VOID
)
2268 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2269 UNICODE_STRING Name
;
2271 DPRINT("Creating Section Object Type\n");
2273 /* Initialize the Section object type */
2274 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2275 RtlInitUnicodeString(&Name
, L
"Section");
2276 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2277 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2278 ObjectTypeInitializer
.PoolType
= PagedPool
;
2279 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2280 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2281 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2282 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2283 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2284 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2286 return(STATUS_SUCCESS
);
2291 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2292 ACCESS_MASK DesiredAccess
,
2293 POBJECT_ATTRIBUTES ObjectAttributes
,
2294 PLARGE_INTEGER UMaximumSize
,
2295 ULONG SectionPageProtection
,
2296 ULONG AllocationAttributes
)
2298 * Create a section which is backed by the pagefile
2301 LARGE_INTEGER MaximumSize
;
2302 PROS_SECTION_OBJECT Section
;
2303 PMM_SECTION_SEGMENT Segment
;
2306 if (UMaximumSize
== NULL
)
2308 return(STATUS_UNSUCCESSFUL
);
2310 MaximumSize
= *UMaximumSize
;
2313 * Create the section
2315 Status
= ObCreateObject(ExGetPreviousMode(),
2316 MmSectionObjectType
,
2318 ExGetPreviousMode(),
2320 sizeof(ROS_SECTION_OBJECT
),
2323 (PVOID
*)(PVOID
)&Section
);
2324 if (!NT_SUCCESS(Status
))
2332 Section
->SectionPageProtection
= SectionPageProtection
;
2333 Section
->AllocationAttributes
= AllocationAttributes
;
2334 Section
->Segment
= NULL
;
2335 Section
->FileObject
= NULL
;
2336 Section
->MaximumSize
= MaximumSize
;
2337 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2338 TAG_MM_SECTION_SEGMENT
);
2339 if (Segment
== NULL
)
2341 ObDereferenceObject(Section
);
2342 return(STATUS_NO_MEMORY
);
2344 Section
->Segment
= Segment
;
2345 Segment
->ReferenceCount
= 1;
2346 ExInitializeFastMutex(&Segment
->Lock
);
2347 Segment
->FileOffset
= 0;
2348 Segment
->Protection
= SectionPageProtection
;
2349 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2350 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2351 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2352 Segment
->WriteCopy
= FALSE
;
2353 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2354 Segment
->VirtualAddress
= 0;
2355 Segment
->Characteristics
= 0;
2356 *SectionObject
= Section
;
2357 return(STATUS_SUCCESS
);
2363 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2364 ACCESS_MASK DesiredAccess
,
2365 POBJECT_ATTRIBUTES ObjectAttributes
,
2366 PLARGE_INTEGER UMaximumSize
,
2367 ULONG SectionPageProtection
,
2368 ULONG AllocationAttributes
,
2371 * Create a section backed by a data file
2374 PROS_SECTION_OBJECT Section
;
2376 LARGE_INTEGER MaximumSize
;
2377 PFILE_OBJECT FileObject
;
2378 PMM_SECTION_SEGMENT Segment
;
2380 IO_STATUS_BLOCK Iosb
;
2381 LARGE_INTEGER Offset
;
2383 FILE_STANDARD_INFORMATION FileInfo
;
2386 * Create the section
2388 Status
= ObCreateObject(ExGetPreviousMode(),
2389 MmSectionObjectType
,
2391 ExGetPreviousMode(),
2393 sizeof(ROS_SECTION_OBJECT
),
2396 (PVOID
*)(PVOID
)&Section
);
2397 if (!NT_SUCCESS(Status
))
2404 Section
->SectionPageProtection
= SectionPageProtection
;
2405 Section
->AllocationAttributes
= AllocationAttributes
;
2406 Section
->Segment
= NULL
;
2409 * Check file access required
2411 if (SectionPageProtection
& PAGE_READWRITE
||
2412 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2414 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2418 FileAccess
= FILE_READ_DATA
;
2422 * Reference the file handle
2424 Status
= ObReferenceObjectByHandle(FileHandle
,
2427 ExGetPreviousMode(),
2428 (PVOID
*)(PVOID
)&FileObject
,
2430 if (!NT_SUCCESS(Status
))
2432 ObDereferenceObject(Section
);
2437 * FIXME: This is propably not entirely correct. We can't look into
2438 * the standard FCB header because it might not be initialized yet
2439 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2440 * standard file information is filled on first request).
2442 Status
= IoQueryFileInformation(FileObject
,
2443 FileStandardInformation
,
2444 sizeof(FILE_STANDARD_INFORMATION
),
2447 if (!NT_SUCCESS(Status
))
2449 ObDereferenceObject(Section
);
2450 ObDereferenceObject(FileObject
);
2455 * FIXME: Revise this once a locking order for file size changes is
2458 if (UMaximumSize
!= NULL
)
2460 MaximumSize
= *UMaximumSize
;
2464 MaximumSize
= FileInfo
.EndOfFile
;
2465 /* Mapping zero-sized files isn't allowed. */
2466 if (MaximumSize
.QuadPart
== 0)
2468 ObDereferenceObject(Section
);
2469 ObDereferenceObject(FileObject
);
2470 return STATUS_FILE_INVALID
;
2474 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2476 Status
= IoSetInformation(FileObject
,
2477 FileAllocationInformation
,
2478 sizeof(LARGE_INTEGER
),
2480 if (!NT_SUCCESS(Status
))
2482 ObDereferenceObject(Section
);
2483 ObDereferenceObject(FileObject
);
2484 return(STATUS_SECTION_NOT_EXTENDED
);
2488 if (FileObject
->SectionObjectPointer
== NULL
||
2489 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2492 * Read a bit so caching is initiated for the file object.
2493 * This is only needed because MiReadPage currently cannot
2494 * handle non-cached streams.
2496 Offset
.QuadPart
= 0;
2497 Status
= ZwReadFile(FileHandle
,
2506 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2508 ObDereferenceObject(Section
);
2509 ObDereferenceObject(FileObject
);
2512 if (FileObject
->SectionObjectPointer
== NULL
||
2513 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2515 /* FIXME: handle this situation */
2516 ObDereferenceObject(Section
);
2517 ObDereferenceObject(FileObject
);
2518 return STATUS_INVALID_PARAMETER
;
2525 Status
= MmspWaitForFileLock(FileObject
);
2526 if (Status
!= STATUS_SUCCESS
)
2528 ObDereferenceObject(Section
);
2529 ObDereferenceObject(FileObject
);
2534 * If this file hasn't been mapped as a data file before then allocate a
2535 * section segment to describe the data file mapping
2537 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2539 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2540 TAG_MM_SECTION_SEGMENT
);
2541 if (Segment
== NULL
)
2543 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2544 ObDereferenceObject(Section
);
2545 ObDereferenceObject(FileObject
);
2546 return(STATUS_NO_MEMORY
);
2548 Section
->Segment
= Segment
;
2549 Segment
->ReferenceCount
= 1;
2550 ExInitializeFastMutex(&Segment
->Lock
);
2552 * Set the lock before assigning the segment to the file object
2554 ExAcquireFastMutex(&Segment
->Lock
);
2555 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2557 Segment
->FileOffset
= 0;
2558 Segment
->Protection
= SectionPageProtection
;
2559 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2560 Segment
->Characteristics
= 0;
2561 Segment
->WriteCopy
= FALSE
;
2562 if (AllocationAttributes
& SEC_RESERVE
)
2564 Segment
->Length
= Segment
->RawLength
= 0;
2568 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2569 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2571 Segment
->VirtualAddress
= 0;
2572 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2577 * If the file is already mapped as a data file then we may need
2581 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2583 Section
->Segment
= Segment
;
2584 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2585 MmLockSectionSegment(Segment
);
2587 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2588 !(AllocationAttributes
& SEC_RESERVE
))
2590 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2591 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2594 MmUnlockSectionSegment(Segment
);
2595 Section
->FileObject
= FileObject
;
2596 Section
->MaximumSize
= MaximumSize
;
2597 CcRosReferenceCache(FileObject
);
2598 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2599 *SectionObject
= Section
;
2600 return(STATUS_SUCCESS
);
2604 TODO: not that great (declaring loaders statically, having to declare all of
2605 them, having to keep them extern, etc.), will fix in the future
2607 extern NTSTATUS NTAPI PeFmtCreateSection
2609 IN CONST VOID
* FileHeader
,
2610 IN SIZE_T FileHeaderSize
,
2612 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2614 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2615 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2618 extern NTSTATUS NTAPI ElfFmtCreateSection
2620 IN CONST VOID
* FileHeader
,
2621 IN SIZE_T FileHeaderSize
,
2623 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2625 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2626 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2629 /* TODO: this is a standard DDK/PSDK macro */
2630 #ifndef RTL_NUMBER_OF
2631 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2634 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2645 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2647 SIZE_T SizeOfSegments
;
2648 PMM_SECTION_SEGMENT Segments
;
2650 /* TODO: check for integer overflow */
2651 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2653 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2655 TAG_MM_SECTION_SEGMENT
);
2658 RtlZeroMemory(Segments
, SizeOfSegments
);
2666 ExeFmtpReadFile(IN PVOID File
,
2667 IN PLARGE_INTEGER Offset
,
2670 OUT PVOID
* AllocBase
,
2671 OUT PULONG ReadSize
)
2674 LARGE_INTEGER FileOffset
;
2676 ULONG OffsetAdjustment
;
2681 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2688 FileOffset
= *Offset
;
2690 /* Negative/special offset: it cannot be used in this context */
2691 if(FileOffset
.u
.HighPart
< 0)
2696 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2697 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2698 FileOffset
.u
.LowPart
= AdjustOffset
;
2700 BufferSize
= Length
+ OffsetAdjustment
;
2701 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2704 * It's ok to use paged pool, because this is a temporary buffer only used in
2705 * the loading of executables. The assumption is that MmCreateSection is
2706 * always called at low IRQLs and that these buffers don't survive a brief
2707 * initialization phase
2709 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2711 TAG('M', 'm', 'X', 'r'));
2716 Status
= MmspPageRead(File
,
2723 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2724 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2725 * to initialize internal state is even worse. Our cache manager is in need of
2729 IO_STATUS_BLOCK Iosb
;
2731 Status
= ZwReadFile(File
,
2741 if(NT_SUCCESS(Status
))
2743 UsedSize
= Iosb
.Information
;
2748 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2750 Status
= STATUS_IN_PAGE_ERROR
;
2751 ASSERT(!NT_SUCCESS(Status
));
2754 if(NT_SUCCESS(Status
))
2756 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2757 *AllocBase
= Buffer
;
2758 *ReadSize
= UsedSize
- OffsetAdjustment
;
2769 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2770 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2771 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2776 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2780 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2782 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2783 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2790 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2794 MmspAssertSegmentsSorted(ImageSectionObject
);
2796 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2798 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2802 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2803 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2804 ImageSectionObject
->Segments
[i
- 1].Length
));
2812 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2816 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2818 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2819 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2827 MmspCompareSegments(const void * x
,
2830 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2831 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2834 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2835 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2839 * Ensures an image section's segments are sorted in memory
2844 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2847 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2849 MmspAssertSegmentsSorted(ImageSectionObject
);
2853 qsort(ImageSectionObject
->Segments
,
2854 ImageSectionObject
->NrSegments
,
2855 sizeof(ImageSectionObject
->Segments
[0]),
2856 MmspCompareSegments
);
2862 * Ensures an image section's segments don't overlap in memory and don't have
2863 * gaps and don't have a null size. We let them map to overlapping file regions,
2864 * though - that's not necessarily an error
2869 MmspCheckSegmentBounds
2871 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2877 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2879 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2883 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2885 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2887 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2895 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2896 * page could be OK (Windows seems to be OK with them), and larger gaps
2897 * could lead to image sections spanning several discontiguous regions
2898 * (NtMapViewOfSection could then refuse to map them, and they could
2899 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2901 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2902 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2903 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2914 * Merges and pads an image section's segments until they all are page-aligned
2915 * and have a size that is a multiple of the page size
2920 MmspPageAlignSegments
2922 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2928 BOOLEAN Initialized
;
2929 PMM_SECTION_SEGMENT EffectiveSegment
;
2931 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2933 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2937 Initialized
= FALSE
;
2939 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2941 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2944 * The first segment requires special handling
2948 ULONG_PTR VirtualAddress
;
2949 ULONG_PTR VirtualOffset
;
2951 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2953 /* Round down the virtual address to the nearest page */
2954 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2956 /* Round up the virtual size to the nearest page */
2957 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2958 EffectiveSegment
->VirtualAddress
;
2960 /* Adjust the raw address and size */
2961 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
2963 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
2969 * Garbage in, garbage out: unaligned base addresses make the file
2970 * offset point in curious and odd places, but that's what we were
2973 EffectiveSegment
->FileOffset
-= VirtualOffset
;
2974 EffectiveSegment
->RawLength
+= VirtualOffset
;
2978 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
2979 ULONG_PTR EndOfEffectiveSegment
;
2981 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
2982 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
2985 * The current segment begins exactly where the current effective
2986 * segment ended, therefore beginning a new effective segment
2988 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
2991 ASSERT(LastSegment
<= i
);
2992 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
2994 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2996 if (LastSegment
!= i
)
2999 * Copy the current segment. If necessary, the effective segment
3000 * will be expanded later
3002 *EffectiveSegment
= *Segment
;
3006 * Page-align the virtual size. We know for sure the virtual address
3009 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3010 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3013 * The current segment is still part of the current effective segment:
3014 * extend the effective segment to reflect this
3016 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3018 static const ULONG FlagsToProtection
[16] =
3026 PAGE_EXECUTE_READWRITE
,
3027 PAGE_EXECUTE_READWRITE
,
3032 PAGE_EXECUTE_WRITECOPY
,
3033 PAGE_EXECUTE_WRITECOPY
,
3034 PAGE_EXECUTE_WRITECOPY
,
3035 PAGE_EXECUTE_WRITECOPY
3038 unsigned ProtectionFlags
;
3041 * Extend the file size
3044 /* Unaligned segments must be contiguous within the file */
3045 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3046 EffectiveSegment
->RawLength
))
3051 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3054 * Extend the virtual size
3056 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3058 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3059 EffectiveSegment
->VirtualAddress
;
3062 * Merge the protection
3064 EffectiveSegment
->Protection
|= Segment
->Protection
;
3066 /* Clean up redundance */
3067 ProtectionFlags
= 0;
3069 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3070 ProtectionFlags
|= 1 << 0;
3072 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3073 ProtectionFlags
|= 1 << 1;
3075 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3076 ProtectionFlags
|= 1 << 2;
3078 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3079 ProtectionFlags
|= 1 << 3;
3081 ASSERT(ProtectionFlags
< 16);
3082 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3084 /* If a segment was required to be shared and cannot, fail */
3085 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3086 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3092 * We assume no holes between segments at this point
3100 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3106 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3107 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3109 LARGE_INTEGER Offset
;
3111 PVOID FileHeaderBuffer
;
3112 ULONG FileHeaderSize
;
3114 ULONG OldNrSegments
;
3119 * Read the beginning of the file (2 pages). Should be enough to contain
3120 * all (or most) of the headers
3122 Offset
.QuadPart
= 0;
3124 /* FIXME: use FileObject instead of FileHandle */
3125 Status
= ExeFmtpReadFile (FileHandle
,
3132 if (!NT_SUCCESS(Status
))
3135 if (FileHeaderSize
== 0)
3137 ExFreePool(FileHeaderBuffer
);
3138 return STATUS_UNSUCCESSFUL
;
3142 * Look for a loader that can handle this executable
3144 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3146 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3149 /* FIXME: use FileObject instead of FileHandle */
3150 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3156 ExeFmtpAllocateSegments
);
3158 if (!NT_SUCCESS(Status
))
3160 if (ImageSectionObject
->Segments
)
3162 ExFreePool(ImageSectionObject
->Segments
);
3163 ImageSectionObject
->Segments
= NULL
;
3167 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3171 ExFreePool(FileHeaderBuffer
);
3174 * No loader handled the format
3176 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3178 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3179 ASSERT(!NT_SUCCESS(Status
));
3182 if (!NT_SUCCESS(Status
))
3185 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3190 /* FIXME? are these values platform-dependent? */
3191 if(ImageSectionObject
->StackReserve
== 0)
3192 ImageSectionObject
->StackReserve
= 0x40000;
3194 if(ImageSectionObject
->StackCommit
== 0)
3195 ImageSectionObject
->StackCommit
= 0x1000;
3197 if(ImageSectionObject
->ImageBase
== 0)
3199 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3200 ImageSectionObject
->ImageBase
= 0x10000000;
3202 ImageSectionObject
->ImageBase
= 0x00400000;
3206 * And now the fun part: fixing the segments
3209 /* Sort them by virtual address */
3210 MmspSortSegments(ImageSectionObject
, Flags
);
3212 /* Ensure they don't overlap in memory */
3213 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3214 return STATUS_INVALID_IMAGE_FORMAT
;
3216 /* Ensure they are aligned */
3217 OldNrSegments
= ImageSectionObject
->NrSegments
;
3219 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3220 return STATUS_INVALID_IMAGE_FORMAT
;
3222 /* Trim them if the alignment phase merged some of them */
3223 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3225 PMM_SECTION_SEGMENT Segments
;
3226 SIZE_T SizeOfSegments
;
3228 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3230 Segments
= ExAllocatePoolWithTag(PagedPool
,
3232 TAG_MM_SECTION_SEGMENT
);
3234 if (Segments
== NULL
)
3235 return STATUS_INSUFFICIENT_RESOURCES
;
3237 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3238 ExFreePool(ImageSectionObject
->Segments
);
3239 ImageSectionObject
->Segments
= Segments
;
3242 /* And finish their initialization */
3243 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3245 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3246 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3248 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3249 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3252 ASSERT(NT_SUCCESS(Status
));
3257 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3258 ACCESS_MASK DesiredAccess
,
3259 POBJECT_ATTRIBUTES ObjectAttributes
,
3260 PLARGE_INTEGER UMaximumSize
,
3261 ULONG SectionPageProtection
,
3262 ULONG AllocationAttributes
,
3265 PROS_SECTION_OBJECT Section
;
3267 PFILE_OBJECT FileObject
;
3268 PMM_SECTION_SEGMENT SectionSegments
;
3269 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3271 ULONG FileAccess
= 0;
3274 * Specifying a maximum size is meaningless for an image section
3276 if (UMaximumSize
!= NULL
)
3278 return(STATUS_INVALID_PARAMETER_4
);
3282 * Check file access required
3284 if (SectionPageProtection
& PAGE_READWRITE
||
3285 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3287 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3291 FileAccess
= FILE_READ_DATA
;
3295 * Reference the file handle
3297 Status
= ObReferenceObjectByHandle(FileHandle
,
3300 ExGetPreviousMode(),
3301 (PVOID
*)(PVOID
)&FileObject
,
3304 if (!NT_SUCCESS(Status
))
3310 * Create the section
3312 Status
= ObCreateObject (ExGetPreviousMode(),
3313 MmSectionObjectType
,
3315 ExGetPreviousMode(),
3317 sizeof(ROS_SECTION_OBJECT
),
3320 (PVOID
*)(PVOID
)&Section
);
3321 if (!NT_SUCCESS(Status
))
3323 ObDereferenceObject(FileObject
);
3330 Section
->SectionPageProtection
= SectionPageProtection
;
3331 Section
->AllocationAttributes
= AllocationAttributes
;
3334 * Initialized caching for this file object if previously caching
3335 * was initialized for the same on disk file
3337 Status
= CcTryToInitializeFileCache(FileObject
);
3339 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3341 NTSTATUS StatusExeFmt
;
3343 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3344 if (ImageSectionObject
== NULL
)
3346 ObDereferenceObject(FileObject
);
3347 ObDereferenceObject(Section
);
3348 return(STATUS_NO_MEMORY
);
3351 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3353 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3355 if (!NT_SUCCESS(StatusExeFmt
))
3357 if(ImageSectionObject
->Segments
!= NULL
)
3358 ExFreePool(ImageSectionObject
->Segments
);
3360 ExFreePool(ImageSectionObject
);
3361 ObDereferenceObject(Section
);
3362 ObDereferenceObject(FileObject
);
3363 return(StatusExeFmt
);
3366 Section
->ImageSection
= ImageSectionObject
;
3367 ASSERT(ImageSectionObject
->Segments
);
3372 Status
= MmspWaitForFileLock(FileObject
);
3373 if (!NT_SUCCESS(Status
))
3375 ExFreePool(ImageSectionObject
->Segments
);
3376 ExFreePool(ImageSectionObject
);
3377 ObDereferenceObject(Section
);
3378 ObDereferenceObject(FileObject
);
3382 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3383 ImageSectionObject
, NULL
))
3386 * An other thread has initialized the some image in the background
3388 ExFreePool(ImageSectionObject
->Segments
);
3389 ExFreePool(ImageSectionObject
);
3390 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3391 Section
->ImageSection
= ImageSectionObject
;
3392 SectionSegments
= ImageSectionObject
->Segments
;
3394 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3396 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3400 Status
= StatusExeFmt
;
3407 Status
= MmspWaitForFileLock(FileObject
);
3408 if (Status
!= STATUS_SUCCESS
)
3410 ObDereferenceObject(Section
);
3411 ObDereferenceObject(FileObject
);
3415 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3416 Section
->ImageSection
= ImageSectionObject
;
3417 SectionSegments
= ImageSectionObject
->Segments
;
3420 * Otherwise just reference all the section segments
3422 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3424 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3427 Status
= STATUS_SUCCESS
;
3429 Section
->FileObject
= FileObject
;
3430 CcRosReferenceCache(FileObject
);
3431 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3432 *SectionObject
= Section
;
3440 NtCreateSection (OUT PHANDLE SectionHandle
,
3441 IN ACCESS_MASK DesiredAccess
,
3442 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3443 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3444 IN ULONG SectionPageProtection OPTIONAL
,
3445 IN ULONG AllocationAttributes
,
3446 IN HANDLE FileHandle OPTIONAL
)
3448 LARGE_INTEGER SafeMaximumSize
;
3449 PVOID SectionObject
;
3450 KPROCESSOR_MODE PreviousMode
;
3451 NTSTATUS Status
= STATUS_SUCCESS
;
3453 PreviousMode
= ExGetPreviousMode();
3455 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3459 /* make a copy on the stack */
3460 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3461 MaximumSize
= &SafeMaximumSize
;
3465 Status
= _SEH_GetExceptionCode();
3469 if(!NT_SUCCESS(Status
))
3475 Status
= MmCreateSection(&SectionObject
,
3479 SectionPageProtection
,
3480 AllocationAttributes
,
3483 if (NT_SUCCESS(Status
))
3485 Status
= ObInsertObject ((PVOID
)SectionObject
,
3497 /**********************************************************************
3515 NtOpenSection(PHANDLE SectionHandle
,
3516 ACCESS_MASK DesiredAccess
,
3517 POBJECT_ATTRIBUTES ObjectAttributes
)
3520 KPROCESSOR_MODE PreviousMode
;
3521 NTSTATUS Status
= STATUS_SUCCESS
;
3523 PreviousMode
= ExGetPreviousMode();
3525 if(PreviousMode
!= KernelMode
)
3529 ProbeForWriteHandle(SectionHandle
);
3533 Status
= _SEH_GetExceptionCode();
3537 if(!NT_SUCCESS(Status
))
3543 Status
= ObOpenObjectByName(ObjectAttributes
,
3544 MmSectionObjectType
,
3551 if(NT_SUCCESS(Status
))
3555 *SectionHandle
= hSection
;
3559 Status
= _SEH_GetExceptionCode();
3568 MmMapViewOfSegment(PMM_AVL_TABLE AddressSpace
,
3569 PROS_SECTION_OBJECT Section
,
3570 PMM_SECTION_SEGMENT Segment
,
3575 ULONG AllocationType
)
3579 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3581 BoundaryAddressMultiple
.QuadPart
= 0;
3583 Status
= MmCreateMemoryArea(AddressSpace
,
3584 MEMORY_AREA_SECTION_VIEW
,
3591 BoundaryAddressMultiple
);
3592 if (!NT_SUCCESS(Status
))
3594 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3595 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3599 ObReferenceObject((PVOID
)Section
);
3601 MArea
->Data
.SectionData
.Segment
= Segment
;
3602 MArea
->Data
.SectionData
.Section
= Section
;
3603 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3604 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3605 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3606 ViewSize
, 0, Protect
);
3608 return(STATUS_SUCCESS
);
3612 /**********************************************************************
3614 * NtMapViewOfSection
3617 * Maps a view of a section into the virtual address space of a
3622 * Handle of the section.
3625 * Handle of the process.
3628 * Desired base address (or NULL) on entry;
3629 * Actual base address of the view on exit.
3632 * Number of high order address bits that must be zero.
3635 * Size in bytes of the initially committed section of
3639 * Offset in bytes from the beginning of the section
3640 * to the beginning of the view.
3643 * Desired length of map (or zero to map all) on entry
3644 * Actual length mapped on exit.
3646 * InheritDisposition
3647 * Specified how the view is to be shared with
3651 * Type of allocation for the pages.
3654 * Protection for the committed region of the view.
3662 NtMapViewOfSection(IN HANDLE SectionHandle
,
3663 IN HANDLE ProcessHandle
,
3664 IN OUT PVOID
* BaseAddress OPTIONAL
,
3665 IN ULONG ZeroBits OPTIONAL
,
3666 IN ULONG CommitSize
,
3667 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3668 IN OUT PSIZE_T ViewSize
,
3669 IN SECTION_INHERIT InheritDisposition
,
3670 IN ULONG AllocationType OPTIONAL
,
3673 PVOID SafeBaseAddress
;
3674 LARGE_INTEGER SafeSectionOffset
;
3675 SIZE_T SafeViewSize
;
3676 PROS_SECTION_OBJECT Section
;
3678 KPROCESSOR_MODE PreviousMode
;
3679 PMM_AVL_TABLE AddressSpace
;
3680 NTSTATUS Status
= STATUS_SUCCESS
;
3684 * Check the protection
3686 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3688 return STATUS_INVALID_PARAMETER_10
;
3691 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3692 if (tmpProtect
!= PAGE_NOACCESS
&&
3693 tmpProtect
!= PAGE_READONLY
&&
3694 tmpProtect
!= PAGE_READWRITE
&&
3695 tmpProtect
!= PAGE_WRITECOPY
&&
3696 tmpProtect
!= PAGE_EXECUTE
&&
3697 tmpProtect
!= PAGE_EXECUTE_READ
&&
3698 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3699 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3701 return STATUS_INVALID_PAGE_PROTECTION
;
3704 PreviousMode
= ExGetPreviousMode();
3706 if(PreviousMode
!= KernelMode
)
3708 SafeBaseAddress
= NULL
;
3709 SafeSectionOffset
.QuadPart
= 0;
3714 if(BaseAddress
!= NULL
)
3716 ProbeForWritePointer(BaseAddress
);
3717 SafeBaseAddress
= *BaseAddress
;
3719 if(SectionOffset
!= NULL
)
3721 ProbeForWriteLargeInteger(SectionOffset
);
3722 SafeSectionOffset
= *SectionOffset
;
3724 ProbeForWriteSize_t(ViewSize
);
3725 SafeViewSize
= *ViewSize
;
3729 Status
= _SEH_GetExceptionCode();
3733 if(!NT_SUCCESS(Status
))
3740 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3741 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3742 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3745 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3747 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3748 PROCESS_VM_OPERATION
,
3751 (PVOID
*)(PVOID
)&Process
,
3753 if (!NT_SUCCESS(Status
))
3758 AddressSpace
= &Process
->VadRoot
;
3760 Status
= ObReferenceObjectByHandle(SectionHandle
,
3762 MmSectionObjectType
,
3764 (PVOID
*)(PVOID
)&Section
,
3766 if (!(NT_SUCCESS(Status
)))
3768 DPRINT("ObReference failed rc=%x\n",Status
);
3769 ObDereferenceObject(Process
);
3773 Status
= MmMapViewOfSection(Section
,
3775 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3778 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3779 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3784 /* Check if this is an image for the current process */
3785 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3786 (Process
== PsGetCurrentProcess()) &&
3787 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3789 /* Notify the debugger */
3790 DbgkMapViewOfSection(Section
,
3792 SafeSectionOffset
.LowPart
,
3796 ObDereferenceObject(Section
);
3797 ObDereferenceObject(Process
);
3799 if(NT_SUCCESS(Status
))
3801 /* copy parameters back to the caller */
3804 if(BaseAddress
!= NULL
)
3806 *BaseAddress
= SafeBaseAddress
;
3808 if(SectionOffset
!= NULL
)
3810 *SectionOffset
= SafeSectionOffset
;
3812 if(ViewSize
!= NULL
)
3814 *ViewSize
= SafeViewSize
;
3819 Status
= _SEH_GetExceptionCode();
3828 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3829 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3832 PFILE_OBJECT FileObject
;
3835 SWAPENTRY SavedSwapEntry
;
3838 PROS_SECTION_OBJECT Section
;
3839 PMM_SECTION_SEGMENT Segment
;
3840 PMM_AVL_TABLE AddressSpace
;
3843 AddressSpace
= (PMM_AVL_TABLE
)Context
;
3844 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3846 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3848 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3849 MemoryArea
->Data
.SectionData
.ViewOffset
;
3851 Section
= MemoryArea
->Data
.SectionData
.Section
;
3852 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3854 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3858 MmUnlockSectionSegment(Segment
);
3859 MmUnlockAddressSpace(AddressSpace
);
3861 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3862 if (Status
!= STATUS_SUCCESS
)
3864 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3868 MmLockAddressSpace(AddressSpace
);
3869 MmLockSectionSegment(Segment
);
3870 MmspCompleteAndReleasePageOp(PageOp
);
3871 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3874 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3877 * For a dirty, datafile, non-private page mark it as dirty in the
3880 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3882 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3884 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3885 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3886 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3887 ASSERT(SwapEntry
== 0);
3896 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3898 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3901 MmFreeSwapPage(SwapEntry
);
3905 if (IS_SWAP_FROM_SSE(Entry
) ||
3906 Page
!= PFN_FROM_SSE(Entry
))
3911 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3913 DPRINT1("Found a private page in a pagefile section.\n");
3917 * Just dereference private pages
3919 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3920 if (SavedSwapEntry
!= 0)
3922 MmFreeSwapPage(SavedSwapEntry
);
3923 MmSetSavedSwapEntryPage(Page
, 0);
3925 MmDeleteRmap(Page
, Process
, Address
);
3926 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3930 MmDeleteRmap(Page
, Process
, Address
);
3931 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3937 MmUnmapViewOfSegment(PMM_AVL_TABLE AddressSpace
,
3941 PMEMORY_AREA MemoryArea
;
3942 PROS_SECTION_OBJECT Section
;
3943 PMM_SECTION_SEGMENT Segment
;
3944 PLIST_ENTRY CurrentEntry
;
3945 PMM_REGION CurrentRegion
;
3946 PLIST_ENTRY RegionListHead
;
3948 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3950 if (MemoryArea
== NULL
)
3952 return(STATUS_UNSUCCESSFUL
);
3955 MemoryArea
->DeleteInProgress
= TRUE
;
3956 Section
= MemoryArea
->Data
.SectionData
.Section
;
3957 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3959 MmLockSectionSegment(Segment
);
3961 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3962 while (!IsListEmpty(RegionListHead
))
3964 CurrentEntry
= RemoveHeadList(RegionListHead
);
3965 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3966 ExFreePool(CurrentRegion
);
3969 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3971 Status
= MmFreeMemoryArea(AddressSpace
,
3978 Status
= MmFreeMemoryArea(AddressSpace
,
3983 MmUnlockSectionSegment(Segment
);
3984 ObDereferenceObject(Section
);
3985 return(STATUS_SUCCESS
);
3992 MmUnmapViewOfSection(PEPROCESS Process
,
3996 PMEMORY_AREA MemoryArea
;
3997 PMM_AVL_TABLE AddressSpace
;
3998 PROS_SECTION_OBJECT Section
;
4001 PVOID ImageBaseAddress
= 0;
4003 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4004 Process
, BaseAddress
);
4008 AddressSpace
= &Process
->VadRoot
;
4010 MmLockAddressSpace(AddressSpace
);
4011 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4013 if (MemoryArea
== NULL
||
4014 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4015 MemoryArea
->DeleteInProgress
)
4017 MmUnlockAddressSpace(AddressSpace
);
4018 return STATUS_NOT_MAPPED_VIEW
;
4021 MemoryArea
->DeleteInProgress
= TRUE
;
4023 while (MemoryArea
->PageOpCount
)
4025 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4029 Offset
-= PAGE_SIZE
;
4030 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4031 MemoryArea
->Data
.SectionData
.Segment
,
4032 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4035 MmUnlockAddressSpace(AddressSpace
);
4036 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4037 if (Status
!= STATUS_SUCCESS
)
4039 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4042 MmLockAddressSpace(AddressSpace
);
4043 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4045 if (MemoryArea
== NULL
||
4046 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4048 MmUnlockAddressSpace(AddressSpace
);
4049 return STATUS_NOT_MAPPED_VIEW
;
4056 Section
= MemoryArea
->Data
.SectionData
.Section
;
4058 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4062 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4063 PMM_SECTION_SEGMENT SectionSegments
;
4064 PMM_SECTION_SEGMENT Segment
;
4066 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4067 ImageSectionObject
= Section
->ImageSection
;
4068 SectionSegments
= ImageSectionObject
->Segments
;
4069 NrSegments
= ImageSectionObject
->NrSegments
;
4071 /* Search for the current segment within the section segments
4072 * and calculate the image base address */
4073 for (i
= 0; i
< NrSegments
; i
++)
4075 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4077 if (Segment
== &SectionSegments
[i
])
4079 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4084 if (i
>= NrSegments
)
4089 for (i
= 0; i
< NrSegments
; i
++)
4091 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4093 PVOID SBaseAddress
= (PVOID
)
4094 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4096 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4102 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4105 /* Notify debugger */
4106 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4108 MmUnlockAddressSpace(AddressSpace
);
4109 return(STATUS_SUCCESS
);
4112 /**********************************************************************
4114 * NtUnmapViewOfSection
4129 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4133 KPROCESSOR_MODE PreviousMode
;
4136 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4137 ProcessHandle
, BaseAddress
);
4139 PreviousMode
= ExGetPreviousMode();
4141 DPRINT("Referencing process\n");
4142 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4143 PROCESS_VM_OPERATION
,
4146 (PVOID
*)(PVOID
)&Process
,
4148 if (!NT_SUCCESS(Status
))
4150 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4154 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4156 ObDereferenceObject(Process
);
4163 * Queries the information of a section object.
4165 * @param SectionHandle
4166 * Handle to the section object. It must be opened with SECTION_QUERY
4168 * @param SectionInformationClass
4169 * Index to a certain information structure. Can be either
4170 * SectionBasicInformation or SectionImageInformation. The latter
4171 * is valid only for sections that were created with the SEC_IMAGE
4173 * @param SectionInformation
4174 * Caller supplies storage for resulting information.
4176 * Size of the supplied storage.
4177 * @param ResultLength
4185 NtQuerySection(IN HANDLE SectionHandle
,
4186 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4187 OUT PVOID SectionInformation
,
4188 IN ULONG SectionInformationLength
,
4189 OUT PULONG ResultLength OPTIONAL
)
4191 PROS_SECTION_OBJECT Section
;
4192 KPROCESSOR_MODE PreviousMode
;
4193 NTSTATUS Status
= STATUS_SUCCESS
;
4195 PreviousMode
= ExGetPreviousMode();
4197 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4199 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4201 SectionInformationLength
,
4205 if(!NT_SUCCESS(Status
))
4207 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4211 Status
= ObReferenceObjectByHandle(SectionHandle
,
4213 MmSectionObjectType
,
4215 (PVOID
*)(PVOID
)&Section
,
4217 if (NT_SUCCESS(Status
))
4219 switch (SectionInformationClass
)
4221 case SectionBasicInformation
:
4223 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4227 Sbi
->Attributes
= Section
->AllocationAttributes
;
4228 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4230 Sbi
->BaseAddress
= 0;
4231 Sbi
->Size
.QuadPart
= 0;
4235 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4236 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4239 if (ResultLength
!= NULL
)
4241 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4243 Status
= STATUS_SUCCESS
;
4247 Status
= _SEH_GetExceptionCode();
4254 case SectionImageInformation
:
4256 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4260 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4261 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4263 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4264 ImageSectionObject
= Section
->ImageSection
;
4266 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4267 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4268 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4269 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4270 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4271 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4272 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4273 Sii
->Machine
= ImageSectionObject
->Machine
;
4274 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4277 if (ResultLength
!= NULL
)
4279 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4281 Status
= STATUS_SUCCESS
;
4285 Status
= _SEH_GetExceptionCode();
4293 ObDereferenceObject(Section
);
4301 * Extends size of file backed section.
4303 * @param SectionHandle
4304 * Handle to the section object. It must be opened with
4305 * SECTION_EXTEND_SIZE access.
4306 * @param NewMaximumSize
4307 * New maximum size of the section in bytes.
4311 * @todo Move the actual code to internal function MmExtendSection.
4315 NtExtendSection(IN HANDLE SectionHandle
,
4316 IN PLARGE_INTEGER NewMaximumSize
)
4318 LARGE_INTEGER SafeNewMaximumSize
;
4319 PROS_SECTION_OBJECT Section
;
4320 KPROCESSOR_MODE PreviousMode
;
4321 NTSTATUS Status
= STATUS_SUCCESS
;
4323 PreviousMode
= ExGetPreviousMode();
4325 if(PreviousMode
!= KernelMode
)
4329 /* make a copy on the stack */
4330 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4331 NewMaximumSize
= &SafeNewMaximumSize
;
4335 Status
= _SEH_GetExceptionCode();
4339 if(!NT_SUCCESS(Status
))
4345 Status
= ObReferenceObjectByHandle(SectionHandle
,
4346 SECTION_EXTEND_SIZE
,
4347 MmSectionObjectType
,
4351 if (!NT_SUCCESS(Status
))
4356 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4358 ObfDereferenceObject(Section
);
4359 return STATUS_INVALID_PARAMETER
;
4363 * - Acquire file extneding resource.
4364 * - Check if we're not resizing the section below it's actual size!
4365 * - Extend segments if needed.
4366 * - Set file information (FileAllocationInformation) to the new size.
4367 * - Release file extending resource.
4370 ObDereferenceObject(Section
);
4372 return STATUS_NOT_IMPLEMENTED
;
4376 /**********************************************************************
4378 * MmAllocateSection@4
4388 * Code taken from ntoskrnl/mm/special.c.
4393 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4398 PMM_AVL_TABLE AddressSpace
;
4399 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4401 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4403 BoundaryAddressMultiple
.QuadPart
= 0;
4405 AddressSpace
= MmGetKernelAddressSpace();
4406 Result
= BaseAddress
;
4407 MmLockAddressSpace(AddressSpace
);
4408 Status
= MmCreateMemoryArea (AddressSpace
,
4416 BoundaryAddressMultiple
);
4417 MmUnlockAddressSpace(AddressSpace
);
4419 if (!NT_SUCCESS(Status
))
4423 DPRINT("Result %p\n",Result
);
4425 /* Create a virtual mapping for this memory area */
4426 MmMapMemoryArea(Result
, Length
, MC_NPPOOL
, PAGE_READWRITE
);
4428 return ((PVOID
)Result
);
4432 /**********************************************************************
4434 * MmMapViewOfSection
4437 * Maps a view of a section into the virtual address space of a
4442 * Pointer to the section object.
4445 * Pointer to the process.
4448 * Desired base address (or NULL) on entry;
4449 * Actual base address of the view on exit.
4452 * Number of high order address bits that must be zero.
4455 * Size in bytes of the initially committed section of
4459 * Offset in bytes from the beginning of the section
4460 * to the beginning of the view.
4463 * Desired length of map (or zero to map all) on entry
4464 * Actual length mapped on exit.
4466 * InheritDisposition
4467 * Specified how the view is to be shared with
4471 * Type of allocation for the pages.
4474 * Protection for the committed region of the view.
4482 MmMapViewOfSection(IN PVOID SectionObject
,
4483 IN PEPROCESS Process
,
4484 IN OUT PVOID
*BaseAddress
,
4486 IN ULONG CommitSize
,
4487 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4488 IN OUT PSIZE_T ViewSize
,
4489 IN SECTION_INHERIT InheritDisposition
,
4490 IN ULONG AllocationType
,
4493 PROS_SECTION_OBJECT Section
;
4494 PMM_AVL_TABLE AddressSpace
;
4496 NTSTATUS Status
= STATUS_SUCCESS
;
4500 if (Protect
!= PAGE_READONLY
&&
4501 Protect
!= PAGE_READWRITE
&&
4502 Protect
!= PAGE_WRITECOPY
&&
4503 Protect
!= PAGE_EXECUTE
&&
4504 Protect
!= PAGE_EXECUTE_READ
&&
4505 Protect
!= PAGE_EXECUTE_READWRITE
&&
4506 Protect
!= PAGE_EXECUTE_WRITECOPY
)
4508 return STATUS_INVALID_PAGE_PROTECTION
;
4512 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4513 AddressSpace
= &Process
->VadRoot
;
4515 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4517 MmLockAddressSpace(AddressSpace
);
4519 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4523 ULONG_PTR ImageBase
;
4525 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4526 PMM_SECTION_SEGMENT SectionSegments
;
4528 ImageSectionObject
= Section
->ImageSection
;
4529 SectionSegments
= ImageSectionObject
->Segments
;
4530 NrSegments
= ImageSectionObject
->NrSegments
;
4533 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4536 ImageBase
= ImageSectionObject
->ImageBase
;
4540 for (i
= 0; i
< NrSegments
; i
++)
4542 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4544 ULONG_PTR MaxExtent
;
4545 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4546 SectionSegments
[i
].Length
;
4547 ImageSize
= max(ImageSize
, MaxExtent
);
4551 ImageSectionObject
->ImageSize
= ImageSize
;
4553 /* Check there is enough space to map the section at that point. */
4554 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4555 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4557 /* Fail if the user requested a fixed base address. */
4558 if ((*BaseAddress
) != NULL
)
4560 MmUnlockAddressSpace(AddressSpace
);
4561 return(STATUS_UNSUCCESSFUL
);
4563 /* Otherwise find a gap to map the image. */
4564 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4567 MmUnlockAddressSpace(AddressSpace
);
4568 return(STATUS_UNSUCCESSFUL
);
4572 for (i
= 0; i
< NrSegments
; i
++)
4574 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4576 PVOID SBaseAddress
= (PVOID
)
4577 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4578 MmLockSectionSegment(&SectionSegments
[i
]);
4579 Status
= MmMapViewOfSegment(AddressSpace
,
4581 &SectionSegments
[i
],
4583 SectionSegments
[i
].Length
,
4584 SectionSegments
[i
].Protection
,
4587 MmUnlockSectionSegment(&SectionSegments
[i
]);
4588 if (!NT_SUCCESS(Status
))
4590 MmUnlockAddressSpace(AddressSpace
);
4596 *BaseAddress
= (PVOID
)ImageBase
;
4600 /* check for write access */
4601 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4602 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4604 return STATUS_SECTION_PROTECTION
;
4606 /* check for read access */
4607 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4608 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4610 return STATUS_SECTION_PROTECTION
;
4612 /* check for execute access */
4613 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4614 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4616 return STATUS_SECTION_PROTECTION
;
4619 if (ViewSize
== NULL
)
4621 /* Following this pointer would lead to us to the dark side */
4622 /* What to do? Bugcheck? Return status? Do the mambo? */
4623 KeBugCheck(MEMORY_MANAGEMENT
);
4626 if (SectionOffset
== NULL
)
4632 ViewOffset
= SectionOffset
->u
.LowPart
;
4635 if ((ViewOffset
% PAGE_SIZE
) != 0)
4637 MmUnlockAddressSpace(AddressSpace
);
4638 return(STATUS_MAPPED_ALIGNMENT
);
4641 if ((*ViewSize
) == 0)
4643 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4645 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4647 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4650 MmLockSectionSegment(Section
->Segment
);
4651 Status
= MmMapViewOfSegment(AddressSpace
,
4658 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4659 MmUnlockSectionSegment(Section
->Segment
);
4660 if (!NT_SUCCESS(Status
))
4662 MmUnlockAddressSpace(AddressSpace
);
4667 MmUnlockAddressSpace(AddressSpace
);
4669 return(STATUS_SUCCESS
);
4676 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4677 IN PLARGE_INTEGER NewFileSize
)
4688 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4698 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4699 IN MMFLUSH_TYPE FlushType
)
4703 case MmFlushForDelete
:
4704 if (SectionObjectPointer
->ImageSectionObject
||
4705 SectionObjectPointer
->DataSectionObject
)
4709 CcRosSetRemoveOnClose(SectionObjectPointer
);
4711 case MmFlushForWrite
:
4721 MmForceSectionClosed (
4722 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4723 IN BOOLEAN DelayClose
)
4734 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4735 OUT PVOID
* MappedBase
,
4736 IN OUT PULONG ViewSize
)
4738 PROS_SECTION_OBJECT Section
;
4739 PMM_AVL_TABLE AddressSpace
;
4742 DPRINT("MmMapViewInSystemSpace() called\n");
4744 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4745 AddressSpace
= MmGetKernelAddressSpace();
4747 MmLockAddressSpace(AddressSpace
);
4750 if ((*ViewSize
) == 0)
4752 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4754 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4756 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4759 MmLockSectionSegment(Section
->Segment
);
4762 Status
= MmMapViewOfSegment(AddressSpace
,
4771 MmUnlockSectionSegment(Section
->Segment
);
4772 MmUnlockAddressSpace(AddressSpace
);
4782 MmMapViewInSessionSpace (
4784 OUT PVOID
*MappedBase
,
4785 IN OUT PSIZE_T ViewSize
4789 return STATUS_NOT_IMPLEMENTED
;
4797 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4799 PMM_AVL_TABLE AddressSpace
;
4802 DPRINT("MmUnmapViewInSystemSpace() called\n");
4804 AddressSpace
= MmGetKernelAddressSpace();
4806 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4816 MmUnmapViewInSessionSpace (
4821 return STATUS_NOT_IMPLEMENTED
;
4828 MmSetBankedSection (ULONG Unknown0
,
4836 return (STATUS_NOT_IMPLEMENTED
);
4840 /**********************************************************************
4845 * Creates a section object.
4848 * SectionObject (OUT)
4849 * Caller supplied storage for the resulting pointer
4850 * to a SECTION_OBJECT instance;
4853 * Specifies the desired access to the section can be a
4855 * STANDARD_RIGHTS_REQUIRED |
4857 * SECTION_MAP_WRITE |
4858 * SECTION_MAP_READ |
4859 * SECTION_MAP_EXECUTE
4861 * ObjectAttributes [OPTIONAL]
4862 * Initialized attributes for the object can be used
4863 * to create a named section;
4866 * Maximizes the size of the memory section. Must be
4867 * non-NULL for a page-file backed section.
4868 * If value specified for a mapped file and the file is
4869 * not large enough, file will be extended.
4871 * SectionPageProtection
4872 * Can be a combination of:
4878 * AllocationAttributes
4879 * Can be a combination of:
4884 * Handle to a file to create a section mapped to a file
4885 * instead of a memory backed section;
4896 MmCreateSection (OUT PVOID
* Section
,
4897 IN ACCESS_MASK DesiredAccess
,
4898 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4899 IN PLARGE_INTEGER MaximumSize
,
4900 IN ULONG SectionPageProtection
,
4901 IN ULONG AllocationAttributes
,
4902 IN HANDLE FileHandle OPTIONAL
,
4903 IN PFILE_OBJECT File OPTIONAL
)
4906 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4909 * Check the protection
4911 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4912 if (Protection
!= PAGE_NOACCESS
&&
4913 Protection
!= PAGE_READONLY
&&
4914 Protection
!= PAGE_READWRITE
&&
4915 Protection
!= PAGE_WRITECOPY
&&
4916 Protection
!= PAGE_EXECUTE
&&
4917 Protection
!= PAGE_EXECUTE_READ
&&
4918 Protection
!= PAGE_EXECUTE_READWRITE
&&
4919 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4921 return STATUS_INVALID_PAGE_PROTECTION
;
4924 if (AllocationAttributes
& SEC_IMAGE
)
4926 return(MmCreateImageSection(SectionObject
,
4930 SectionPageProtection
,
4931 AllocationAttributes
,
4935 if (FileHandle
!= NULL
)
4937 return(MmCreateDataFileSection(SectionObject
,
4941 SectionPageProtection
,
4942 AllocationAttributes
,
4946 return(MmCreatePageFileSection(SectionObject
,
4950 SectionPageProtection
,
4951 AllocationAttributes
));
4956 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
4957 IN OUT PULONG NumberOfPages
,
4958 IN OUT PULONG UserPfnArray
)
4961 return STATUS_NOT_IMPLEMENTED
;
4966 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
4967 IN ULONG NumberOfPages
,
4968 IN OUT PULONG UserPfnArray
)
4971 return STATUS_NOT_IMPLEMENTED
;
4976 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
4977 IN ULONG NumberOfPages
,
4978 IN OUT PULONG UserPfnArray
)
4981 return STATUS_NOT_IMPLEMENTED
;
4986 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
4987 IN OUT PULONG NumberOfPages
,
4988 IN OUT PULONG UserPfnArray
)
4991 return STATUS_NOT_IMPLEMENTED
;
4996 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
4997 IN PVOID File2MappedAsFile
)
5000 return STATUS_NOT_IMPLEMENTED
;