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)
59 MiMapViewInSystemSpace(IN PVOID Section
,
61 OUT PVOID
*MappedBase
,
62 IN OUT PSIZE_T ViewSize
);
66 MmCreateArm3Section(OUT PVOID
*SectionObject
,
67 IN ACCESS_MASK DesiredAccess
,
68 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
69 IN PLARGE_INTEGER InputMaximumSize
,
70 IN ULONG SectionPageProtection
,
71 IN ULONG AllocationAttributes
,
72 IN HANDLE FileHandle OPTIONAL
,
73 IN PFILE_OBJECT FileObject OPTIONAL
);
75 /* TYPES *********************************************************************/
79 PROS_SECTION_OBJECT Section
;
80 PMM_SECTION_SEGMENT Segment
;
85 MM_SECTION_PAGEOUT_CONTEXT
;
87 /* GLOBALS *******************************************************************/
89 POBJECT_TYPE MmSectionObjectType
= NULL
;
91 SIZE_T MmAllocationFragment
;
93 ULONG_PTR MmSubsectionBase
;
95 static GENERIC_MAPPING MmpSectionMapping
= {
96 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
97 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
98 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
101 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
102 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
103 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
104 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
105 #define MAX_SHARE_COUNT 0x7FF
106 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
107 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
108 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
110 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
112 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
113 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
116 /* FUNCTIONS *****************************************************************/
120 MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section
)
125 /* Return the file object */
126 return Section
->FileObject
; // Section->ControlArea->FileObject on NT
131 MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section
,
132 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
134 POBJECT_NAME_INFORMATION ObjectNameInfo
;
138 /* Make sure it's an image section */
140 if (!(Section
->AllocationAttributes
& SEC_IMAGE
))
143 return STATUS_SECTION_NOT_IMAGE
;
146 /* Allocate memory for our structure */
147 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
,
150 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
153 Status
= ObQueryNameString(Section
->FileObject
,
157 if (!NT_SUCCESS(Status
))
159 /* Failed, free memory */
160 ExFreePoolWithTag(ObjectNameInfo
, ' mM');
165 *ModuleName
= ObjectNameInfo
;
166 return STATUS_SUCCESS
;
171 MmGetFileNameForAddress(IN PVOID Address
,
172 OUT PUNICODE_STRING ModuleName
)
174 PROS_SECTION_OBJECT Section
;
175 PMEMORY_AREA MemoryArea
;
176 PMMSUPPORT AddressSpace
;
177 POBJECT_NAME_INFORMATION ModuleNameInformation
;
178 NTSTATUS Status
= STATUS_ADDRESS_NOT_ASSOCIATED
;
180 /* Get the MM_AVL_TABLE from EPROCESS */
181 if (Address
>= MmSystemRangeStart
)
183 AddressSpace
= MmGetKernelAddressSpace();
187 AddressSpace
= &PsGetCurrentProcess()->Vm
;
190 /* Lock address space */
191 MmLockAddressSpace(AddressSpace
);
193 /* Locate the memory area for the process by address */
194 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
196 /* Make sure it's a section view type */
197 if ((MemoryArea
!= NULL
) && (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
))
199 /* Get the section pointer to the SECTION_OBJECT */
200 Section
= MemoryArea
->Data
.SectionData
.Section
;
202 /* Unlock address space */
203 MmUnlockAddressSpace(AddressSpace
);
205 /* Get the filename of the section */
206 Status
= MmGetFileNameForSection(Section
,&ModuleNameInformation
);
208 if (NT_SUCCESS(Status
))
210 /* Init modulename */
211 RtlCreateUnicodeString(ModuleName
,
212 ModuleNameInformation
->Name
.Buffer
);
214 /* Free temp taged buffer from MmGetFileNameForSection() */
215 ExFreePoolWithTag(ModuleNameInformation
, ' mM');
216 DPRINT("Found ModuleName %S by address %p\n",
217 ModuleName
->Buffer
,Address
);
222 /* Unlock address space */
223 MmUnlockAddressSpace(AddressSpace
);
229 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
232 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
233 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
234 * RETURNS: Status of the wait.
237 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
239 LARGE_INTEGER Timeout
;
240 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
242 Timeout
.QuadPart
= -100000000LL; // 10 sec
245 Timeout
.QuadPart
= -100000000; // 10 sec
248 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
253 * FUNCTION: Sets the page op completion event and releases the page op.
254 * ARGUMENTS: PMM_PAGEOP.
255 * RETURNS: In shorter time than it takes you to even read this
256 * description, so don't even think about geting a mug of coffee.
259 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
261 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
262 MmReleasePageOp(PageOp
);
267 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
268 * ARGUMENTS: PFILE_OBJECT to wait for.
269 * RETURNS: Status of the wait.
272 MmspWaitForFileLock(PFILE_OBJECT File
)
274 return STATUS_SUCCESS
;
275 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
280 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
283 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
285 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
287 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
289 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
297 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
299 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
301 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
302 PMM_SECTION_SEGMENT SectionSegments
;
306 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
307 NrSegments
= ImageSectionObject
->NrSegments
;
308 SectionSegments
= ImageSectionObject
->Segments
;
309 for (i
= 0; i
< NrSegments
; i
++)
311 if (SectionSegments
[i
].ReferenceCount
!= 0)
313 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
314 SectionSegments
[i
].ReferenceCount
);
315 KeBugCheck(MEMORY_MANAGEMENT
);
317 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
319 ExFreePool(ImageSectionObject
->Segments
);
320 ExFreePool(ImageSectionObject
);
321 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
323 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
325 PMM_SECTION_SEGMENT Segment
;
327 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
330 if (Segment
->ReferenceCount
!= 0)
332 DPRINT1("Data segment still referenced\n");
333 KeBugCheck(MEMORY_MANAGEMENT
);
335 MmFreePageTablesSectionSegment(Segment
);
337 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
343 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
345 ExAcquireFastMutex(&Segment
->Lock
);
350 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
352 ExReleaseFastMutex(&Segment
->Lock
);
357 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
361 PSECTION_PAGE_TABLE Table
;
362 ULONG DirectoryOffset
;
365 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
367 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
371 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
372 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
376 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
377 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
378 TAG_SECTION_PAGE_TABLE
);
381 KeBugCheck(MEMORY_MANAGEMENT
);
383 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
384 DPRINT("Table %x\n", Table
);
387 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
388 Table
->Entry
[TableOffset
] = Entry
;
394 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
397 PSECTION_PAGE_TABLE Table
;
399 ULONG DirectoryOffset
;
402 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
404 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
406 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
410 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
411 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
412 DPRINT("Table %x\n", Table
);
418 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
419 Entry
= Table
->Entry
[TableOffset
];
425 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
430 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
433 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
434 KeBugCheck(MEMORY_MANAGEMENT
);
436 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
438 DPRINT1("Maximum share count reached\n");
439 KeBugCheck(MEMORY_MANAGEMENT
);
441 if (IS_SWAP_FROM_SSE(Entry
))
443 KeBugCheck(MEMORY_MANAGEMENT
);
445 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
446 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
451 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
452 PMM_SECTION_SEGMENT Segment
,
458 BOOLEAN IsDirectMapped
= FALSE
;
460 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
463 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
464 KeBugCheck(MEMORY_MANAGEMENT
);
466 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
468 DPRINT1("Zero share count for unshare\n");
469 KeBugCheck(MEMORY_MANAGEMENT
);
471 if (IS_SWAP_FROM_SSE(Entry
))
473 KeBugCheck(MEMORY_MANAGEMENT
);
475 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
477 * If we reducing the share count of this entry to zero then set the entry
478 * to zero and tell the cache the page is no longer mapped.
480 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
482 PFILE_OBJECT FileObject
;
484 SWAPENTRY SavedSwapEntry
;
486 BOOLEAN IsImageSection
;
489 FileOffset
= Offset
+ Segment
->FileOffset
;
491 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
493 Page
= PFN_FROM_SSE(Entry
);
494 FileObject
= Section
->FileObject
;
495 if (FileObject
!= NULL
&&
496 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
499 if ((FileOffset
% PAGE_SIZE
) == 0 &&
500 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
503 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
504 IsDirectMapped
= TRUE
;
505 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
506 if (!NT_SUCCESS(Status
))
508 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
509 KeBugCheck(MEMORY_MANAGEMENT
);
514 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
515 if (SavedSwapEntry
== 0)
518 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
519 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
523 * Try to page out this page and set the swap entry
524 * within the section segment. There exist no rmap entry
525 * for this page. The pager thread can't page out a
526 * page without a rmap entry.
528 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
532 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
535 MmReleasePageMemoryConsumer(MC_USER
, Page
);
541 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
542 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
550 * We hold all locks. Nobody can do something with the current
551 * process and the current segment (also not within an other process).
554 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
555 if (!NT_SUCCESS(Status
))
557 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
558 KeBugCheck(MEMORY_MANAGEMENT
);
561 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
562 MmSetSavedSwapEntryPage(Page
, 0);
564 MmReleasePageMemoryConsumer(MC_USER
, Page
);
568 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
569 KeBugCheck(MEMORY_MANAGEMENT
);
575 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
577 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
580 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
583 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
586 PCACHE_SEGMENT CacheSeg
;
587 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
588 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
591 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
600 MiCopyFromUserPage(PFN_NUMBER DestPage
, PVOID SourceAddress
)
606 Process
= PsGetCurrentProcess();
607 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
608 if (TempAddress
== NULL
)
610 return(STATUS_NO_MEMORY
);
612 memcpy(TempAddress
, SourceAddress
, PAGE_SIZE
);
613 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
614 return(STATUS_SUCCESS
);
619 MiReadPage(PMEMORY_AREA MemoryArea
,
623 * FUNCTION: Read a page for a section backed memory area.
625 * MemoryArea - Memory area to read the page for.
626 * Offset - Offset of the page to read.
627 * Page - Variable that receives a page contains the read data.
634 PCACHE_SEGMENT CacheSeg
;
635 PFILE_OBJECT FileObject
;
639 BOOLEAN IsImageSection
;
642 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
643 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
644 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
645 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
646 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
650 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
653 * If the file system is letting us go directly to the cache and the
654 * memory area was mapped at an offset in the file which is page aligned
655 * then get the related cache segment.
657 if ((FileOffset
% PAGE_SIZE
) == 0 &&
658 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
659 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
663 * Get the related cache segment; we use a lower level interface than
664 * filesystems do because it is safe for us to use an offset with a
665 * alignment less than the file system block size.
667 Status
= CcRosGetCacheSegment(Bcb
,
673 if (!NT_SUCCESS(Status
))
680 * If the cache segment isn't up to date then call the file
681 * system to read in the data.
683 Status
= ReadCacheSegment(CacheSeg
);
684 if (!NT_SUCCESS(Status
))
686 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
691 * Retrieve the page from the cache segment that we actually want.
693 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
694 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
696 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
703 ULONG CacheSegOffset
;
706 * Allocate a page, this is rather complicated by the possibility
707 * we might have to move other things out of memory
709 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
710 if (!NT_SUCCESS(Status
))
714 Status
= CcRosGetCacheSegment(Bcb
,
720 if (!NT_SUCCESS(Status
))
727 * If the cache segment isn't up to date then call the file
728 * system to read in the data.
730 Status
= ReadCacheSegment(CacheSeg
);
731 if (!NT_SUCCESS(Status
))
733 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
738 Process
= PsGetCurrentProcess();
739 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
740 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
741 Length
= RawLength
- SegOffset
;
742 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
744 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
746 else if (CacheSegOffset
>= PAGE_SIZE
)
748 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
752 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
753 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
754 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
755 Status
= CcRosGetCacheSegment(Bcb
,
756 FileOffset
+ CacheSegOffset
,
761 if (!NT_SUCCESS(Status
))
768 * If the cache segment isn't up to date then call the file
769 * system to read in the data.
771 Status
= ReadCacheSegment(CacheSeg
);
772 if (!NT_SUCCESS(Status
))
774 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
778 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
779 if (Length
< PAGE_SIZE
)
781 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
785 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
788 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
789 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
791 return(STATUS_SUCCESS
);
796 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
797 MEMORY_AREA
* MemoryArea
,
805 PROS_SECTION_OBJECT Section
;
806 PMM_SECTION_SEGMENT Segment
;
812 BOOLEAN HasSwapEntry
;
813 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
816 * There is a window between taking the page fault and locking the
817 * address space when another thread could load the page so we check
820 if (MmIsPagePresent(Process
, Address
))
822 return(STATUS_SUCCESS
);
825 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
826 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
827 + MemoryArea
->Data
.SectionData
.ViewOffset
;
829 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
830 Section
= MemoryArea
->Data
.SectionData
.Section
;
831 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
832 &MemoryArea
->Data
.SectionData
.RegionListHead
,
837 MmLockSectionSegment(Segment
);
840 * Check if this page needs to be mapped COW
842 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
843 (Region
->Protect
== PAGE_READWRITE
||
844 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
846 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
850 Attributes
= Region
->Protect
;
854 * Get or create a page operation descriptor
856 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
859 DPRINT1("MmGetPageOp failed\n");
860 KeBugCheck(MEMORY_MANAGEMENT
);
864 * Check if someone else is already handling this fault, if so wait
867 if (PageOp
->Thread
!= PsGetCurrentThread())
869 MmUnlockSectionSegment(Segment
);
870 MmUnlockAddressSpace(AddressSpace
);
871 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
873 * Check for various strange conditions
875 if (Status
!= STATUS_SUCCESS
)
877 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
878 KeBugCheck(MEMORY_MANAGEMENT
);
880 if (PageOp
->Status
== STATUS_PENDING
)
882 DPRINT1("Woke for page op before completion\n");
883 KeBugCheck(MEMORY_MANAGEMENT
);
885 MmLockAddressSpace(AddressSpace
);
887 * If this wasn't a pagein then restart the operation
889 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
891 MmspCompleteAndReleasePageOp(PageOp
);
892 DPRINT("Address 0x%.8X\n", Address
);
893 return(STATUS_MM_RESTART_OPERATION
);
897 * If the thread handling this fault has failed then we don't retry
899 if (!NT_SUCCESS(PageOp
->Status
))
901 Status
= PageOp
->Status
;
902 MmspCompleteAndReleasePageOp(PageOp
);
903 DPRINT("Address 0x%.8X\n", Address
);
906 MmLockSectionSegment(Segment
);
908 * If the completed fault was for another address space then set the
911 if (!MmIsPagePresent(Process
, Address
))
913 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
914 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
916 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
919 * The page was a private page in another or in our address space
921 MmUnlockSectionSegment(Segment
);
922 MmspCompleteAndReleasePageOp(PageOp
);
923 return(STATUS_MM_RESTART_OPERATION
);
926 Page
= PFN_FROM_SSE(Entry
);
928 MmSharePageEntrySectionSegment(Segment
, Offset
);
930 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
931 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
933 Status
= MmCreateVirtualMapping(Process
,
938 if (!NT_SUCCESS(Status
))
940 DPRINT1("Unable to create virtual mapping\n");
941 KeBugCheck(MEMORY_MANAGEMENT
);
943 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
945 MmUnlockSectionSegment(Segment
);
946 PageOp
->Status
= STATUS_SUCCESS
;
947 MmspCompleteAndReleasePageOp(PageOp
);
948 DPRINT("Address 0x%.8X\n", Address
);
949 return(STATUS_SUCCESS
);
952 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
956 * Must be private page we have swapped out.
963 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
965 DPRINT1("Found a swaped out private page in a pagefile section.\n");
966 KeBugCheck(MEMORY_MANAGEMENT
);
969 MmUnlockSectionSegment(Segment
);
970 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
972 MmUnlockAddressSpace(AddressSpace
);
973 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
974 if (!NT_SUCCESS(Status
))
976 KeBugCheck(MEMORY_MANAGEMENT
);
979 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
980 if (!NT_SUCCESS(Status
))
982 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
983 KeBugCheck(MEMORY_MANAGEMENT
);
985 MmLockAddressSpace(AddressSpace
);
986 Status
= MmCreateVirtualMapping(Process
,
991 if (!NT_SUCCESS(Status
))
993 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
994 KeBugCheck(MEMORY_MANAGEMENT
);
999 * Store the swap entry for later use.
1001 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1004 * Add the page to the process's working set
1006 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1009 * Finish the operation
1011 PageOp
->Status
= STATUS_SUCCESS
;
1012 MmspCompleteAndReleasePageOp(PageOp
);
1013 DPRINT("Address 0x%.8X\n", Address
);
1014 return(STATUS_SUCCESS
);
1018 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1020 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1022 MmUnlockSectionSegment(Segment
);
1024 * Just map the desired physical page
1026 Page
= Offset
>> PAGE_SHIFT
;
1027 Status
= MmCreateVirtualMappingUnsafe(Process
,
1032 if (!NT_SUCCESS(Status
))
1034 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1035 KeBugCheck(MEMORY_MANAGEMENT
);
1040 * Cleanup and release locks
1042 PageOp
->Status
= STATUS_SUCCESS
;
1043 MmspCompleteAndReleasePageOp(PageOp
);
1044 DPRINT("Address 0x%.8X\n", Address
);
1045 return(STATUS_SUCCESS
);
1049 * Map anonymous memory for BSS sections
1051 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1053 MmUnlockSectionSegment(Segment
);
1054 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1055 if (!NT_SUCCESS(Status
))
1057 MmUnlockAddressSpace(AddressSpace
);
1058 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1059 MmLockAddressSpace(AddressSpace
);
1061 if (!NT_SUCCESS(Status
))
1063 KeBugCheck(MEMORY_MANAGEMENT
);
1065 Status
= MmCreateVirtualMapping(Process
,
1070 if (!NT_SUCCESS(Status
))
1072 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1073 KeBugCheck(MEMORY_MANAGEMENT
);
1076 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1079 * Cleanup and release locks
1081 PageOp
->Status
= STATUS_SUCCESS
;
1082 MmspCompleteAndReleasePageOp(PageOp
);
1083 DPRINT("Address 0x%.8X\n", Address
);
1084 return(STATUS_SUCCESS
);
1088 * Get the entry corresponding to the offset within the section
1090 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1095 * If the entry is zero (and it can't change because we have
1096 * locked the segment) then we need to load the page.
1100 * Release all our locks and read in the page from disk
1102 MmUnlockSectionSegment(Segment
);
1103 MmUnlockAddressSpace(AddressSpace
);
1105 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1106 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1108 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1109 if (!NT_SUCCESS(Status
))
1111 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1116 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1117 if (!NT_SUCCESS(Status
))
1119 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1122 if (!NT_SUCCESS(Status
))
1125 * FIXME: What do we know in this case?
1128 * Cleanup and release locks
1130 MmLockAddressSpace(AddressSpace
);
1131 PageOp
->Status
= Status
;
1132 MmspCompleteAndReleasePageOp(PageOp
);
1133 DPRINT("Address 0x%.8X\n", Address
);
1137 * Relock the address space and segment
1139 MmLockAddressSpace(AddressSpace
);
1140 MmLockSectionSegment(Segment
);
1143 * Check the entry. No one should change the status of a page
1144 * that has a pending page-in.
1146 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1147 if (Entry
!= Entry1
)
1149 DPRINT1("Someone changed ppte entry while we slept\n");
1150 KeBugCheck(MEMORY_MANAGEMENT
);
1154 * Mark the offset within the section as having valid, in-memory
1157 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1158 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1159 MmUnlockSectionSegment(Segment
);
1161 Status
= MmCreateVirtualMapping(Process
,
1166 if (!NT_SUCCESS(Status
))
1168 DPRINT1("Unable to create virtual mapping\n");
1169 KeBugCheck(MEMORY_MANAGEMENT
);
1171 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1173 PageOp
->Status
= STATUS_SUCCESS
;
1174 MmspCompleteAndReleasePageOp(PageOp
);
1175 DPRINT("Address 0x%.8X\n", Address
);
1176 return(STATUS_SUCCESS
);
1178 else if (IS_SWAP_FROM_SSE(Entry
))
1180 SWAPENTRY SwapEntry
;
1182 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1185 * Release all our locks and read in the page from disk
1187 MmUnlockSectionSegment(Segment
);
1189 MmUnlockAddressSpace(AddressSpace
);
1191 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1192 if (!NT_SUCCESS(Status
))
1194 KeBugCheck(MEMORY_MANAGEMENT
);
1197 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1198 if (!NT_SUCCESS(Status
))
1200 KeBugCheck(MEMORY_MANAGEMENT
);
1204 * Relock the address space and segment
1206 MmLockAddressSpace(AddressSpace
);
1207 MmLockSectionSegment(Segment
);
1210 * Check the entry. No one should change the status of a page
1211 * that has a pending page-in.
1213 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1214 if (Entry
!= Entry1
)
1216 DPRINT1("Someone changed ppte entry while we slept\n");
1217 KeBugCheck(MEMORY_MANAGEMENT
);
1221 * Mark the offset within the section as having valid, in-memory
1224 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1225 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1226 MmUnlockSectionSegment(Segment
);
1229 * Save the swap entry.
1231 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1232 Status
= MmCreateVirtualMapping(Process
,
1237 if (!NT_SUCCESS(Status
))
1239 DPRINT1("Unable to create virtual mapping\n");
1240 KeBugCheck(MEMORY_MANAGEMENT
);
1242 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1243 PageOp
->Status
= STATUS_SUCCESS
;
1244 MmspCompleteAndReleasePageOp(PageOp
);
1245 DPRINT("Address 0x%.8X\n", Address
);
1246 return(STATUS_SUCCESS
);
1251 * If the section offset is already in-memory and valid then just
1252 * take another reference to the page
1255 Page
= PFN_FROM_SSE(Entry
);
1257 MmSharePageEntrySectionSegment(Segment
, Offset
);
1258 MmUnlockSectionSegment(Segment
);
1260 Status
= MmCreateVirtualMapping(Process
,
1265 if (!NT_SUCCESS(Status
))
1267 DPRINT1("Unable to create virtual mapping\n");
1268 KeBugCheck(MEMORY_MANAGEMENT
);
1270 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1271 PageOp
->Status
= STATUS_SUCCESS
;
1272 MmspCompleteAndReleasePageOp(PageOp
);
1273 DPRINT("Address 0x%.8X\n", Address
);
1274 return(STATUS_SUCCESS
);
1280 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1281 MEMORY_AREA
* MemoryArea
,
1285 PMM_SECTION_SEGMENT Segment
;
1286 PROS_SECTION_OBJECT Section
;
1295 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1297 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1300 * Check if the page has been paged out or has already been set readwrite
1302 if (!MmIsPagePresent(Process
, Address
) ||
1303 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1305 DPRINT("Address 0x%.8X\n", Address
);
1306 return(STATUS_SUCCESS
);
1310 * Find the offset of the page
1312 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1313 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1314 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1316 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1317 Section
= MemoryArea
->Data
.SectionData
.Section
;
1318 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1319 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1324 MmLockSectionSegment(Segment
);
1326 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1327 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1329 MmUnlockSectionSegment(Segment
);
1332 * Check if we are doing COW
1334 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1335 (Region
->Protect
== PAGE_READWRITE
||
1336 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1338 DPRINT("Address 0x%.8X\n", Address
);
1339 return(STATUS_ACCESS_VIOLATION
);
1342 if (IS_SWAP_FROM_SSE(Entry
) ||
1343 PFN_FROM_SSE(Entry
) != OldPage
)
1345 /* This is a private page. We must only change the page protection. */
1346 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1347 return(STATUS_SUCCESS
);
1351 * Get or create a pageop
1353 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1354 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1357 DPRINT1("MmGetPageOp failed\n");
1358 KeBugCheck(MEMORY_MANAGEMENT
);
1362 * Wait for any other operations to complete
1364 if (PageOp
->Thread
!= PsGetCurrentThread())
1366 MmUnlockAddressSpace(AddressSpace
);
1367 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1369 * Check for various strange conditions
1371 if (Status
== STATUS_TIMEOUT
)
1373 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1374 KeBugCheck(MEMORY_MANAGEMENT
);
1376 if (PageOp
->Status
== STATUS_PENDING
)
1378 DPRINT1("Woke for page op before completion\n");
1379 KeBugCheck(MEMORY_MANAGEMENT
);
1382 * Restart the operation
1384 MmLockAddressSpace(AddressSpace
);
1385 MmspCompleteAndReleasePageOp(PageOp
);
1386 DPRINT("Address 0x%.8X\n", Address
);
1387 return(STATUS_MM_RESTART_OPERATION
);
1391 * Release locks now we have the pageop
1393 MmUnlockAddressSpace(AddressSpace
);
1398 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1399 if (!NT_SUCCESS(Status
))
1401 KeBugCheck(MEMORY_MANAGEMENT
);
1407 MiCopyFromUserPage(NewPage
, PAddress
);
1409 MmLockAddressSpace(AddressSpace
);
1411 * Delete the old entry.
1413 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1416 * Set the PTE to point to the new page
1418 Status
= MmCreateVirtualMapping(Process
,
1423 if (!NT_SUCCESS(Status
))
1425 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1426 KeBugCheck(MEMORY_MANAGEMENT
);
1429 if (!NT_SUCCESS(Status
))
1431 DPRINT1("Unable to create virtual mapping\n");
1432 KeBugCheck(MEMORY_MANAGEMENT
);
1436 * Unshare the old page.
1438 MmDeleteRmap(OldPage
, Process
, PAddress
);
1439 MmInsertRmap(NewPage
, Process
, PAddress
);
1440 MmLockSectionSegment(Segment
);
1441 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1442 MmUnlockSectionSegment(Segment
);
1444 PageOp
->Status
= STATUS_SUCCESS
;
1445 MmspCompleteAndReleasePageOp(PageOp
);
1446 DPRINT("Address 0x%.8X\n", Address
);
1447 return(STATUS_SUCCESS
);
1451 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1453 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1457 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1460 MmLockAddressSpace(&Process
->Vm
);
1463 MmDeleteVirtualMapping(Process
,
1470 PageOutContext
->WasDirty
= TRUE
;
1472 if (!PageOutContext
->Private
)
1474 MmLockSectionSegment(PageOutContext
->Segment
);
1475 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1476 PageOutContext
->Segment
,
1477 PageOutContext
->Offset
,
1478 PageOutContext
->WasDirty
,
1480 MmUnlockSectionSegment(PageOutContext
->Segment
);
1484 MmUnlockAddressSpace(&Process
->Vm
);
1487 if (PageOutContext
->Private
)
1489 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1492 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1497 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1498 MEMORY_AREA
* MemoryArea
,
1503 MM_SECTION_PAGEOUT_CONTEXT Context
;
1504 SWAPENTRY SwapEntry
;
1508 PFILE_OBJECT FileObject
;
1510 BOOLEAN DirectMapped
;
1511 BOOLEAN IsImageSection
;
1512 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1515 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1518 * Get the segment and section.
1520 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1521 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1523 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1524 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1525 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1527 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1529 FileObject
= Context
.Section
->FileObject
;
1530 DirectMapped
= FALSE
;
1531 if (FileObject
!= NULL
&&
1532 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1534 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1537 * If the file system is letting us go directly to the cache and the
1538 * memory area was mapped at an offset in the file which is page aligned
1539 * then note this is a direct mapped page.
1541 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1542 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1544 DirectMapped
= TRUE
;
1550 * This should never happen since mappings of physical memory are never
1551 * placed in the rmap lists.
1553 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1555 DPRINT1("Trying to page out from physical memory section address 0x%X "
1556 "process %d\n", Address
,
1557 Process
? Process
->UniqueProcessId
: 0);
1558 KeBugCheck(MEMORY_MANAGEMENT
);
1562 * Get the section segment entry and the physical address.
1564 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1565 if (!MmIsPagePresent(Process
, Address
))
1567 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1568 Process
? Process
->UniqueProcessId
: 0, Address
);
1569 KeBugCheck(MEMORY_MANAGEMENT
);
1571 Page
= MmGetPfnForProcess(Process
, Address
);
1572 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1575 * Prepare the context structure for the rmap delete call.
1577 Context
.WasDirty
= FALSE
;
1578 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1579 IS_SWAP_FROM_SSE(Entry
) ||
1580 PFN_FROM_SSE(Entry
) != Page
)
1582 Context
.Private
= TRUE
;
1586 Context
.Private
= FALSE
;
1590 * Take an additional reference to the page or the cache segment.
1592 if (DirectMapped
&& !Context
.Private
)
1594 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1596 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1597 KeBugCheck(MEMORY_MANAGEMENT
);
1602 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1603 MmReferencePage(Page
);
1604 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1607 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1610 * If this wasn't a private page then we should have reduced the entry to
1611 * zero by deleting all the rmaps.
1613 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1615 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1616 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1618 KeBugCheck(MEMORY_MANAGEMENT
);
1623 * If the page wasn't dirty then we can just free it as for a readonly page.
1624 * Since we unmapped all the mappings above we know it will not suddenly
1626 * If the page is from a pagefile section and has no swap entry,
1627 * we can't free the page at this point.
1629 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1630 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1632 if (Context
.Private
)
1634 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1635 Context
.WasDirty
? "dirty" : "clean", Address
);
1636 KeBugCheck(MEMORY_MANAGEMENT
);
1638 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1640 MmSetSavedSwapEntryPage(Page
, 0);
1641 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1642 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1643 PageOp
->Status
= STATUS_SUCCESS
;
1644 MmspCompleteAndReleasePageOp(PageOp
);
1645 return(STATUS_SUCCESS
);
1648 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1650 if (Context
.Private
)
1652 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1653 Context
.WasDirty
? "dirty" : "clean", Address
);
1654 KeBugCheck(MEMORY_MANAGEMENT
);
1656 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1658 MmSetSavedSwapEntryPage(Page
, 0);
1661 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1663 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1664 PageOp
->Status
= STATUS_SUCCESS
;
1665 MmspCompleteAndReleasePageOp(PageOp
);
1666 return(STATUS_SUCCESS
);
1669 else if (!Context
.Private
&& DirectMapped
)
1673 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1675 KeBugCheck(MEMORY_MANAGEMENT
);
1677 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1678 if (!NT_SUCCESS(Status
))
1680 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1681 KeBugCheck(MEMORY_MANAGEMENT
);
1683 PageOp
->Status
= STATUS_SUCCESS
;
1684 MmspCompleteAndReleasePageOp(PageOp
);
1685 return(STATUS_SUCCESS
);
1687 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1691 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1693 KeBugCheck(MEMORY_MANAGEMENT
);
1695 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1696 PageOp
->Status
= STATUS_SUCCESS
;
1697 MmspCompleteAndReleasePageOp(PageOp
);
1698 return(STATUS_SUCCESS
);
1700 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1702 MmSetSavedSwapEntryPage(Page
, 0);
1703 MmLockAddressSpace(AddressSpace
);
1704 Status
= MmCreatePageFileMapping(Process
,
1707 MmUnlockAddressSpace(AddressSpace
);
1708 if (!NT_SUCCESS(Status
))
1710 KeBugCheck(MEMORY_MANAGEMENT
);
1712 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1713 PageOp
->Status
= STATUS_SUCCESS
;
1714 MmspCompleteAndReleasePageOp(PageOp
);
1715 return(STATUS_SUCCESS
);
1719 * If necessary, allocate an entry in the paging file for this page
1723 SwapEntry
= MmAllocSwapPage();
1726 MmShowOutOfSpaceMessagePagingFile();
1727 MmLockAddressSpace(AddressSpace
);
1729 * For private pages restore the old mappings.
1731 if (Context
.Private
)
1733 Status
= MmCreateVirtualMapping(Process
,
1735 MemoryArea
->Protect
,
1738 MmSetDirtyPage(Process
, Address
);
1746 * For non-private pages if the page wasn't direct mapped then
1747 * set it back into the section segment entry so we don't loose
1748 * our copy. Otherwise it will be handled by the cache manager.
1750 Status
= MmCreateVirtualMapping(Process
,
1752 MemoryArea
->Protect
,
1755 MmSetDirtyPage(Process
, Address
);
1759 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1760 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1762 MmUnlockAddressSpace(AddressSpace
);
1763 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1764 MmspCompleteAndReleasePageOp(PageOp
);
1765 return(STATUS_PAGEFILE_QUOTA
);
1770 * Write the page to the pagefile
1772 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1773 if (!NT_SUCCESS(Status
))
1775 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1778 * As above: undo our actions.
1779 * FIXME: Also free the swap page.
1781 MmLockAddressSpace(AddressSpace
);
1782 if (Context
.Private
)
1784 Status
= MmCreateVirtualMapping(Process
,
1786 MemoryArea
->Protect
,
1789 MmSetDirtyPage(Process
, Address
);
1796 Status
= MmCreateVirtualMapping(Process
,
1798 MemoryArea
->Protect
,
1801 MmSetDirtyPage(Process
, Address
);
1805 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1806 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1808 MmUnlockAddressSpace(AddressSpace
);
1809 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1810 MmspCompleteAndReleasePageOp(PageOp
);
1811 return(STATUS_UNSUCCESSFUL
);
1815 * Otherwise we have succeeded.
1817 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1818 MmSetSavedSwapEntryPage(Page
, 0);
1819 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1820 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1822 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1826 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1829 if (Context
.Private
)
1831 MmLockAddressSpace(AddressSpace
);
1832 Status
= MmCreatePageFileMapping(Process
,
1835 MmUnlockAddressSpace(AddressSpace
);
1836 if (!NT_SUCCESS(Status
))
1838 KeBugCheck(MEMORY_MANAGEMENT
);
1843 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1844 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1847 PageOp
->Status
= STATUS_SUCCESS
;
1848 MmspCompleteAndReleasePageOp(PageOp
);
1849 return(STATUS_SUCCESS
);
1854 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
1855 PMEMORY_AREA MemoryArea
,
1860 PROS_SECTION_OBJECT Section
;
1861 PMM_SECTION_SEGMENT Segment
;
1863 SWAPENTRY SwapEntry
;
1867 PFILE_OBJECT FileObject
;
1869 BOOLEAN DirectMapped
;
1870 BOOLEAN IsImageSection
;
1871 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1873 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1875 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1876 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1879 * Get the segment and section.
1881 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1882 Section
= MemoryArea
->Data
.SectionData
.Section
;
1883 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1885 FileObject
= Section
->FileObject
;
1886 DirectMapped
= FALSE
;
1887 if (FileObject
!= NULL
&&
1888 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1890 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1893 * If the file system is letting us go directly to the cache and the
1894 * memory area was mapped at an offset in the file which is page aligned
1895 * then note this is a direct mapped page.
1897 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1898 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1900 DirectMapped
= TRUE
;
1905 * This should never happen since mappings of physical memory are never
1906 * placed in the rmap lists.
1908 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1910 DPRINT1("Trying to write back page from physical memory mapped at %X "
1911 "process %d\n", Address
,
1912 Process
? Process
->UniqueProcessId
: 0);
1913 KeBugCheck(MEMORY_MANAGEMENT
);
1917 * Get the section segment entry and the physical address.
1919 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1920 if (!MmIsPagePresent(Process
, Address
))
1922 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1923 Process
? Process
->UniqueProcessId
: 0, Address
);
1924 KeBugCheck(MEMORY_MANAGEMENT
);
1926 Page
= MmGetPfnForProcess(Process
, Address
);
1927 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1930 * Check for a private (COWed) page.
1932 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1933 IS_SWAP_FROM_SSE(Entry
) ||
1934 PFN_FROM_SSE(Entry
) != Page
)
1944 * Speculatively set all mappings of the page to clean.
1946 MmSetCleanAllRmaps(Page
);
1949 * If this page was direct mapped from the cache then the cache manager
1950 * will take care of writing it back to disk.
1952 if (DirectMapped
&& !Private
)
1954 ASSERT(SwapEntry
== 0);
1955 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1956 PageOp
->Status
= STATUS_SUCCESS
;
1957 MmspCompleteAndReleasePageOp(PageOp
);
1958 return(STATUS_SUCCESS
);
1962 * If necessary, allocate an entry in the paging file for this page
1966 SwapEntry
= MmAllocSwapPage();
1969 MmSetDirtyAllRmaps(Page
);
1970 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1971 MmspCompleteAndReleasePageOp(PageOp
);
1972 return(STATUS_PAGEFILE_QUOTA
);
1974 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1978 * Write the page to the pagefile
1980 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1981 if (!NT_SUCCESS(Status
))
1983 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1985 MmSetDirtyAllRmaps(Page
);
1986 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1987 MmspCompleteAndReleasePageOp(PageOp
);
1988 return(STATUS_UNSUCCESSFUL
);
1992 * Otherwise we have succeeded.
1994 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1995 PageOp
->Status
= STATUS_SUCCESS
;
1996 MmspCompleteAndReleasePageOp(PageOp
);
1997 return(STATUS_SUCCESS
);
2001 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2009 PMEMORY_AREA MemoryArea
;
2010 PMM_SECTION_SEGMENT Segment
;
2011 BOOLEAN DoCOW
= FALSE
;
2013 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2015 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2016 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2018 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
2019 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2024 if (OldProtect
!= NewProtect
)
2026 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2028 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2029 ULONG Protect
= NewProtect
;
2032 * If we doing COW for this segment then check if the page is
2035 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2041 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2042 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2043 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2044 Page
= MmGetPfnForProcess(Process
, Address
);
2046 Protect
= PAGE_READONLY
;
2047 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2048 IS_SWAP_FROM_SSE(Entry
) ||
2049 PFN_FROM_SSE(Entry
) != Page
)
2051 Protect
= NewProtect
;
2055 if (MmIsPagePresent(Process
, Address
))
2057 MmSetPageProtect(Process
, Address
,
2066 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2067 PMEMORY_AREA MemoryArea
,
2075 ULONG_PTR MaxLength
;
2077 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2078 if (Length
> MaxLength
)
2081 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2082 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2084 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2085 Region
->Protect
!= Protect
)
2087 return STATUS_INVALID_PAGE_PROTECTION
;
2090 *OldProtect
= Region
->Protect
;
2091 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2092 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2093 BaseAddress
, Length
, Region
->Type
, Protect
,
2094 MmAlterViewAttributes
);
2100 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2102 PMEMORY_BASIC_INFORMATION Info
,
2103 PSIZE_T ResultLength
)
2106 PVOID RegionBaseAddress
;
2107 PROS_SECTION_OBJECT Section
;
2108 PMM_SECTION_SEGMENT Segment
;
2110 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2111 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2112 Address
, &RegionBaseAddress
);
2115 return STATUS_UNSUCCESSFUL
;
2118 Section
= MemoryArea
->Data
.SectionData
.Section
;
2119 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2121 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2122 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2123 Info
->Type
= MEM_IMAGE
;
2127 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2128 Info
->Type
= MEM_MAPPED
;
2130 Info
->BaseAddress
= RegionBaseAddress
;
2131 Info
->AllocationProtect
= MemoryArea
->Protect
;
2132 Info
->RegionSize
= Region
->Length
;
2133 Info
->State
= MEM_COMMIT
;
2134 Info
->Protect
= Region
->Protect
;
2136 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2137 return(STATUS_SUCCESS
);
2142 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2147 ULONG SavedSwapEntry
;
2152 Length
= PAGE_ROUND_UP(Segment
->Length
);
2153 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2155 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2158 if (IS_SWAP_FROM_SSE(Entry
))
2160 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2164 Page
= PFN_FROM_SSE(Entry
);
2165 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2166 if (SavedSwapEntry
!= 0)
2168 MmSetSavedSwapEntryPage(Page
, 0);
2169 MmFreeSwapPage(SavedSwapEntry
);
2171 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2173 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2179 MmpDeleteSection(PVOID ObjectBody
)
2181 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2183 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2184 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2189 PMM_SECTION_SEGMENT SectionSegments
;
2192 * NOTE: Section->ImageSection can be NULL for short time
2193 * during the section creating. If we fail for some reason
2194 * until the image section is properly initialized we shouldn't
2195 * process further here.
2197 if (Section
->ImageSection
== NULL
)
2200 SectionSegments
= Section
->ImageSection
->Segments
;
2201 NrSegments
= Section
->ImageSection
->NrSegments
;
2203 for (i
= 0; i
< NrSegments
; i
++)
2205 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2207 MmLockSectionSegment(&SectionSegments
[i
]);
2209 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2210 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2214 MmpFreePageFileSegment(&SectionSegments
[i
]);
2216 MmUnlockSectionSegment(&SectionSegments
[i
]);
2223 * NOTE: Section->Segment can be NULL for short time
2224 * during the section creating.
2226 if (Section
->Segment
== NULL
)
2229 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2231 MmpFreePageFileSegment(Section
->Segment
);
2232 MmFreePageTablesSectionSegment(Section
->Segment
);
2233 ExFreePool(Section
->Segment
);
2234 Section
->Segment
= NULL
;
2238 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2241 if (Section
->FileObject
!= NULL
)
2243 CcRosDereferenceCache(Section
->FileObject
);
2244 ObDereferenceObject(Section
->FileObject
);
2245 Section
->FileObject
= NULL
;
2250 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2252 IN ACCESS_MASK GrantedAccess
,
2253 IN ULONG ProcessHandleCount
,
2254 IN ULONG SystemHandleCount
)
2256 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2257 Object
, ProcessHandleCount
);
2263 MmCreatePhysicalMemorySection(VOID
)
2265 PROS_SECTION_OBJECT PhysSection
;
2267 OBJECT_ATTRIBUTES Obj
;
2268 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2269 LARGE_INTEGER SectionSize
;
2273 * Create the section mapping physical memory
2275 SectionSize
.QuadPart
= 0xFFFFFFFF;
2276 InitializeObjectAttributes(&Obj
,
2281 Status
= MmCreateSection((PVOID
)&PhysSection
,
2285 PAGE_EXECUTE_READWRITE
,
2289 if (!NT_SUCCESS(Status
))
2291 DPRINT1("Failed to create PhysicalMemory section\n");
2292 KeBugCheck(MEMORY_MANAGEMENT
);
2294 Status
= ObInsertObject(PhysSection
,
2300 if (!NT_SUCCESS(Status
))
2302 ObDereferenceObject(PhysSection
);
2304 ObCloseHandle(Handle
, KernelMode
);
2305 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2306 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2308 return(STATUS_SUCCESS
);
2314 MmInitSectionImplementation(VOID
)
2316 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2317 UNICODE_STRING Name
;
2319 DPRINT("Creating Section Object Type\n");
2321 /* Initialize the Section object type */
2322 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2323 RtlInitUnicodeString(&Name
, L
"Section");
2324 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2325 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2326 ObjectTypeInitializer
.PoolType
= PagedPool
;
2327 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2328 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2329 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2330 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2331 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2332 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2334 MmCreatePhysicalMemorySection();
2336 return(STATUS_SUCCESS
);
2341 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2342 ACCESS_MASK DesiredAccess
,
2343 POBJECT_ATTRIBUTES ObjectAttributes
,
2344 PLARGE_INTEGER UMaximumSize
,
2345 ULONG SectionPageProtection
,
2346 ULONG AllocationAttributes
)
2348 * Create a section which is backed by the pagefile
2351 LARGE_INTEGER MaximumSize
;
2352 PROS_SECTION_OBJECT Section
;
2353 PMM_SECTION_SEGMENT Segment
;
2356 if (UMaximumSize
== NULL
)
2358 return(STATUS_UNSUCCESSFUL
);
2360 MaximumSize
= *UMaximumSize
;
2363 * Create the section
2365 Status
= ObCreateObject(ExGetPreviousMode(),
2366 MmSectionObjectType
,
2368 ExGetPreviousMode(),
2370 sizeof(ROS_SECTION_OBJECT
),
2373 (PVOID
*)(PVOID
)&Section
);
2374 if (!NT_SUCCESS(Status
))
2382 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2383 Section
->SectionPageProtection
= SectionPageProtection
;
2384 Section
->AllocationAttributes
= AllocationAttributes
;
2385 Section
->MaximumSize
= MaximumSize
;
2386 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2387 TAG_MM_SECTION_SEGMENT
);
2388 if (Segment
== NULL
)
2390 ObDereferenceObject(Section
);
2391 return(STATUS_NO_MEMORY
);
2393 Section
->Segment
= Segment
;
2394 Segment
->ReferenceCount
= 1;
2395 ExInitializeFastMutex(&Segment
->Lock
);
2396 Segment
->FileOffset
= 0;
2397 Segment
->Protection
= SectionPageProtection
;
2398 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2399 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2400 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2401 Segment
->WriteCopy
= FALSE
;
2402 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2403 Segment
->VirtualAddress
= 0;
2404 Segment
->Characteristics
= 0;
2405 *SectionObject
= Section
;
2406 return(STATUS_SUCCESS
);
2412 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2413 ACCESS_MASK DesiredAccess
,
2414 POBJECT_ATTRIBUTES ObjectAttributes
,
2415 PLARGE_INTEGER UMaximumSize
,
2416 ULONG SectionPageProtection
,
2417 ULONG AllocationAttributes
,
2420 * Create a section backed by a data file
2423 PROS_SECTION_OBJECT Section
;
2425 LARGE_INTEGER MaximumSize
;
2426 PFILE_OBJECT FileObject
;
2427 PMM_SECTION_SEGMENT Segment
;
2429 IO_STATUS_BLOCK Iosb
;
2430 LARGE_INTEGER Offset
;
2432 FILE_STANDARD_INFORMATION FileInfo
;
2436 * Create the section
2438 Status
= ObCreateObject(ExGetPreviousMode(),
2439 MmSectionObjectType
,
2441 ExGetPreviousMode(),
2443 sizeof(ROS_SECTION_OBJECT
),
2446 (PVOID
*)(PVOID
)&Section
);
2447 if (!NT_SUCCESS(Status
))
2454 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2455 Section
->SectionPageProtection
= SectionPageProtection
;
2456 Section
->AllocationAttributes
= AllocationAttributes
;
2459 * Check file access required
2461 if (SectionPageProtection
& PAGE_READWRITE
||
2462 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2464 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2468 FileAccess
= FILE_READ_DATA
;
2472 * Reference the file handle
2474 Status
= ObReferenceObjectByHandle(FileHandle
,
2477 ExGetPreviousMode(),
2478 (PVOID
*)(PVOID
)&FileObject
,
2480 if (!NT_SUCCESS(Status
))
2482 ObDereferenceObject(Section
);
2487 * FIXME: This is propably not entirely correct. We can't look into
2488 * the standard FCB header because it might not be initialized yet
2489 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2490 * standard file information is filled on first request).
2492 Status
= IoQueryFileInformation(FileObject
,
2493 FileStandardInformation
,
2494 sizeof(FILE_STANDARD_INFORMATION
),
2497 Iosb
.Information
= Length
;
2498 if (!NT_SUCCESS(Status
))
2500 ObDereferenceObject(Section
);
2501 ObDereferenceObject(FileObject
);
2506 * FIXME: Revise this once a locking order for file size changes is
2509 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2511 MaximumSize
= *UMaximumSize
;
2515 MaximumSize
= FileInfo
.EndOfFile
;
2516 /* Mapping zero-sized files isn't allowed. */
2517 if (MaximumSize
.QuadPart
== 0)
2519 ObDereferenceObject(Section
);
2520 ObDereferenceObject(FileObject
);
2521 return STATUS_FILE_INVALID
;
2525 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2527 Status
= IoSetInformation(FileObject
,
2528 FileAllocationInformation
,
2529 sizeof(LARGE_INTEGER
),
2531 if (!NT_SUCCESS(Status
))
2533 ObDereferenceObject(Section
);
2534 ObDereferenceObject(FileObject
);
2535 return(STATUS_SECTION_NOT_EXTENDED
);
2539 if (FileObject
->SectionObjectPointer
== NULL
||
2540 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2543 * Read a bit so caching is initiated for the file object.
2544 * This is only needed because MiReadPage currently cannot
2545 * handle non-cached streams.
2547 Offset
.QuadPart
= 0;
2548 Status
= ZwReadFile(FileHandle
,
2557 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2559 ObDereferenceObject(Section
);
2560 ObDereferenceObject(FileObject
);
2563 if (FileObject
->SectionObjectPointer
== NULL
||
2564 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2566 /* FIXME: handle this situation */
2567 ObDereferenceObject(Section
);
2568 ObDereferenceObject(FileObject
);
2569 return STATUS_INVALID_PARAMETER
;
2576 Status
= MmspWaitForFileLock(FileObject
);
2577 if (Status
!= STATUS_SUCCESS
)
2579 ObDereferenceObject(Section
);
2580 ObDereferenceObject(FileObject
);
2585 * If this file hasn't been mapped as a data file before then allocate a
2586 * section segment to describe the data file mapping
2588 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2590 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2591 TAG_MM_SECTION_SEGMENT
);
2592 if (Segment
== NULL
)
2594 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2595 ObDereferenceObject(Section
);
2596 ObDereferenceObject(FileObject
);
2597 return(STATUS_NO_MEMORY
);
2599 Section
->Segment
= Segment
;
2600 Segment
->ReferenceCount
= 1;
2601 ExInitializeFastMutex(&Segment
->Lock
);
2603 * Set the lock before assigning the segment to the file object
2605 ExAcquireFastMutex(&Segment
->Lock
);
2606 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2608 Segment
->FileOffset
= 0;
2609 Segment
->Protection
= SectionPageProtection
;
2610 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2611 Segment
->Characteristics
= 0;
2612 Segment
->WriteCopy
= FALSE
;
2613 if (AllocationAttributes
& SEC_RESERVE
)
2615 Segment
->Length
= Segment
->RawLength
= 0;
2619 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2620 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2622 Segment
->VirtualAddress
= 0;
2623 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2628 * If the file is already mapped as a data file then we may need
2632 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2634 Section
->Segment
= Segment
;
2635 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2636 MmLockSectionSegment(Segment
);
2638 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2639 !(AllocationAttributes
& SEC_RESERVE
))
2641 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2642 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2645 MmUnlockSectionSegment(Segment
);
2646 Section
->FileObject
= FileObject
;
2647 Section
->MaximumSize
= MaximumSize
;
2648 CcRosReferenceCache(FileObject
);
2649 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2650 *SectionObject
= Section
;
2651 return(STATUS_SUCCESS
);
2655 TODO: not that great (declaring loaders statically, having to declare all of
2656 them, having to keep them extern, etc.), will fix in the future
2658 extern NTSTATUS NTAPI PeFmtCreateSection
2660 IN CONST VOID
* FileHeader
,
2661 IN SIZE_T FileHeaderSize
,
2663 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2665 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2666 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2669 extern NTSTATUS NTAPI ElfFmtCreateSection
2671 IN CONST VOID
* FileHeader
,
2672 IN SIZE_T FileHeaderSize
,
2674 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2676 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2677 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2680 /* TODO: this is a standard DDK/PSDK macro */
2681 #ifndef RTL_NUMBER_OF
2682 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2685 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2696 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2698 SIZE_T SizeOfSegments
;
2699 PMM_SECTION_SEGMENT Segments
;
2701 /* TODO: check for integer overflow */
2702 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2704 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2706 TAG_MM_SECTION_SEGMENT
);
2709 RtlZeroMemory(Segments
, SizeOfSegments
);
2717 ExeFmtpReadFile(IN PVOID File
,
2718 IN PLARGE_INTEGER Offset
,
2721 OUT PVOID
* AllocBase
,
2722 OUT PULONG ReadSize
)
2725 LARGE_INTEGER FileOffset
;
2727 ULONG OffsetAdjustment
;
2732 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2736 KeBugCheck(MEMORY_MANAGEMENT
);
2739 FileOffset
= *Offset
;
2741 /* Negative/special offset: it cannot be used in this context */
2742 if(FileOffset
.u
.HighPart
< 0)
2744 KeBugCheck(MEMORY_MANAGEMENT
);
2747 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2748 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2749 FileOffset
.u
.LowPart
= AdjustOffset
;
2751 BufferSize
= Length
+ OffsetAdjustment
;
2752 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2755 * It's ok to use paged pool, because this is a temporary buffer only used in
2756 * the loading of executables. The assumption is that MmCreateSection is
2757 * always called at low IRQLs and that these buffers don't survive a brief
2758 * initialization phase
2760 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2765 KeBugCheck(MEMORY_MANAGEMENT
);
2771 Status
= MmspPageRead(File
,
2778 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2779 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2780 * to initialize internal state is even worse. Our cache manager is in need of
2784 IO_STATUS_BLOCK Iosb
;
2786 Status
= ZwReadFile(File
,
2796 if(NT_SUCCESS(Status
))
2798 UsedSize
= Iosb
.Information
;
2803 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2805 Status
= STATUS_IN_PAGE_ERROR
;
2806 ASSERT(!NT_SUCCESS(Status
));
2809 if(NT_SUCCESS(Status
))
2811 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2812 *AllocBase
= Buffer
;
2813 *ReadSize
= UsedSize
- OffsetAdjustment
;
2817 ExFreePoolWithTag(Buffer
, 'rXmM');
2824 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2825 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2826 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2831 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2835 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2837 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2838 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2845 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2849 MmspAssertSegmentsSorted(ImageSectionObject
);
2851 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2853 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2857 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2858 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2859 ImageSectionObject
->Segments
[i
- 1].Length
));
2867 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2871 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2873 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2874 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2882 MmspCompareSegments(const void * x
,
2885 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2886 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2889 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2890 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2894 * Ensures an image section's segments are sorted in memory
2899 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2902 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2904 MmspAssertSegmentsSorted(ImageSectionObject
);
2908 qsort(ImageSectionObject
->Segments
,
2909 ImageSectionObject
->NrSegments
,
2910 sizeof(ImageSectionObject
->Segments
[0]),
2911 MmspCompareSegments
);
2917 * Ensures an image section's segments don't overlap in memory and don't have
2918 * gaps and don't have a null size. We let them map to overlapping file regions,
2919 * though - that's not necessarily an error
2924 MmspCheckSegmentBounds
2926 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2932 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2934 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2938 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2940 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2942 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2950 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2951 * page could be OK (Windows seems to be OK with them), and larger gaps
2952 * could lead to image sections spanning several discontiguous regions
2953 * (NtMapViewOfSection could then refuse to map them, and they could
2954 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2956 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2957 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2958 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2969 * Merges and pads an image section's segments until they all are page-aligned
2970 * and have a size that is a multiple of the page size
2975 MmspPageAlignSegments
2977 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2983 PMM_SECTION_SEGMENT EffectiveSegment
;
2985 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2987 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2992 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2994 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2997 * The first segment requires special handling
3001 ULONG_PTR VirtualAddress
;
3002 ULONG_PTR VirtualOffset
;
3004 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
3006 /* Round down the virtual address to the nearest page */
3007 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3009 /* Round up the virtual size to the nearest page */
3010 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3011 EffectiveSegment
->VirtualAddress
;
3013 /* Adjust the raw address and size */
3014 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3016 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3022 * Garbage in, garbage out: unaligned base addresses make the file
3023 * offset point in curious and odd places, but that's what we were
3026 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3027 EffectiveSegment
->RawLength
+= VirtualOffset
;
3031 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3032 ULONG_PTR EndOfEffectiveSegment
;
3034 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3035 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3038 * The current segment begins exactly where the current effective
3039 * segment ended, therefore beginning a new effective segment
3041 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3044 ASSERT(LastSegment
<= i
);
3045 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3047 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3049 if (LastSegment
!= i
)
3052 * Copy the current segment. If necessary, the effective segment
3053 * will be expanded later
3055 *EffectiveSegment
= *Segment
;
3059 * Page-align the virtual size. We know for sure the virtual address
3062 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3063 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3066 * The current segment is still part of the current effective segment:
3067 * extend the effective segment to reflect this
3069 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3071 static const ULONG FlagsToProtection
[16] =
3079 PAGE_EXECUTE_READWRITE
,
3080 PAGE_EXECUTE_READWRITE
,
3085 PAGE_EXECUTE_WRITECOPY
,
3086 PAGE_EXECUTE_WRITECOPY
,
3087 PAGE_EXECUTE_WRITECOPY
,
3088 PAGE_EXECUTE_WRITECOPY
3091 unsigned ProtectionFlags
;
3094 * Extend the file size
3097 /* Unaligned segments must be contiguous within the file */
3098 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3099 EffectiveSegment
->RawLength
))
3104 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3107 * Extend the virtual size
3109 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3111 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3112 EffectiveSegment
->VirtualAddress
;
3115 * Merge the protection
3117 EffectiveSegment
->Protection
|= Segment
->Protection
;
3119 /* Clean up redundance */
3120 ProtectionFlags
= 0;
3122 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3123 ProtectionFlags
|= 1 << 0;
3125 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3126 ProtectionFlags
|= 1 << 1;
3128 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3129 ProtectionFlags
|= 1 << 2;
3131 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3132 ProtectionFlags
|= 1 << 3;
3134 ASSERT(ProtectionFlags
< 16);
3135 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3137 /* If a segment was required to be shared and cannot, fail */
3138 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3139 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3145 * We assume no holes between segments at this point
3149 KeBugCheck(MEMORY_MANAGEMENT
);
3153 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3159 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3160 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3162 LARGE_INTEGER Offset
;
3164 PVOID FileHeaderBuffer
;
3165 ULONG FileHeaderSize
;
3167 ULONG OldNrSegments
;
3172 * Read the beginning of the file (2 pages). Should be enough to contain
3173 * all (or most) of the headers
3175 Offset
.QuadPart
= 0;
3177 /* FIXME: use FileObject instead of FileHandle */
3178 Status
= ExeFmtpReadFile (FileHandle
,
3185 if (!NT_SUCCESS(Status
))
3188 if (FileHeaderSize
== 0)
3190 ExFreePool(FileHeaderBuffer
);
3191 return STATUS_UNSUCCESSFUL
;
3195 * Look for a loader that can handle this executable
3197 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3199 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3202 /* FIXME: use FileObject instead of FileHandle */
3203 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3209 ExeFmtpAllocateSegments
);
3211 if (!NT_SUCCESS(Status
))
3213 if (ImageSectionObject
->Segments
)
3215 ExFreePool(ImageSectionObject
->Segments
);
3216 ImageSectionObject
->Segments
= NULL
;
3220 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3224 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3227 * No loader handled the format
3229 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3231 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3232 ASSERT(!NT_SUCCESS(Status
));
3235 if (!NT_SUCCESS(Status
))
3238 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3243 /* FIXME? are these values platform-dependent? */
3244 if(ImageSectionObject
->StackReserve
== 0)
3245 ImageSectionObject
->StackReserve
= 0x40000;
3247 if(ImageSectionObject
->StackCommit
== 0)
3248 ImageSectionObject
->StackCommit
= 0x1000;
3250 if(ImageSectionObject
->ImageBase
== 0)
3252 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3253 ImageSectionObject
->ImageBase
= 0x10000000;
3255 ImageSectionObject
->ImageBase
= 0x00400000;
3259 * And now the fun part: fixing the segments
3262 /* Sort them by virtual address */
3263 MmspSortSegments(ImageSectionObject
, Flags
);
3265 /* Ensure they don't overlap in memory */
3266 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3267 return STATUS_INVALID_IMAGE_FORMAT
;
3269 /* Ensure they are aligned */
3270 OldNrSegments
= ImageSectionObject
->NrSegments
;
3272 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3273 return STATUS_INVALID_IMAGE_FORMAT
;
3275 /* Trim them if the alignment phase merged some of them */
3276 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3278 PMM_SECTION_SEGMENT Segments
;
3279 SIZE_T SizeOfSegments
;
3281 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3283 Segments
= ExAllocatePoolWithTag(PagedPool
,
3285 TAG_MM_SECTION_SEGMENT
);
3287 if (Segments
== NULL
)
3288 return STATUS_INSUFFICIENT_RESOURCES
;
3290 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3291 ExFreePool(ImageSectionObject
->Segments
);
3292 ImageSectionObject
->Segments
= Segments
;
3295 /* And finish their initialization */
3296 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3298 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3299 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3301 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3302 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3305 ASSERT(NT_SUCCESS(Status
));
3310 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3311 ACCESS_MASK DesiredAccess
,
3312 POBJECT_ATTRIBUTES ObjectAttributes
,
3313 PLARGE_INTEGER UMaximumSize
,
3314 ULONG SectionPageProtection
,
3315 ULONG AllocationAttributes
,
3318 PROS_SECTION_OBJECT Section
;
3320 PFILE_OBJECT FileObject
;
3321 PMM_SECTION_SEGMENT SectionSegments
;
3322 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3324 ULONG FileAccess
= 0;
3327 * Check file access required
3329 if (SectionPageProtection
& PAGE_READWRITE
||
3330 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3332 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3336 FileAccess
= FILE_READ_DATA
;
3340 * Reference the file handle
3342 Status
= ObReferenceObjectByHandle(FileHandle
,
3345 ExGetPreviousMode(),
3346 (PVOID
*)(PVOID
)&FileObject
,
3349 if (!NT_SUCCESS(Status
))
3355 * Create the section
3357 Status
= ObCreateObject (ExGetPreviousMode(),
3358 MmSectionObjectType
,
3360 ExGetPreviousMode(),
3362 sizeof(ROS_SECTION_OBJECT
),
3365 (PVOID
*)(PVOID
)&Section
);
3366 if (!NT_SUCCESS(Status
))
3368 ObDereferenceObject(FileObject
);
3375 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3376 Section
->SectionPageProtection
= SectionPageProtection
;
3377 Section
->AllocationAttributes
= AllocationAttributes
;
3380 * Initialized caching for this file object if previously caching
3381 * was initialized for the same on disk file
3383 Status
= CcTryToInitializeFileCache(FileObject
);
3385 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3387 NTSTATUS StatusExeFmt
;
3389 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3390 if (ImageSectionObject
== NULL
)
3392 ObDereferenceObject(FileObject
);
3393 ObDereferenceObject(Section
);
3394 return(STATUS_NO_MEMORY
);
3397 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3399 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3401 if (!NT_SUCCESS(StatusExeFmt
))
3403 if(ImageSectionObject
->Segments
!= NULL
)
3404 ExFreePool(ImageSectionObject
->Segments
);
3406 ExFreePool(ImageSectionObject
);
3407 ObDereferenceObject(Section
);
3408 ObDereferenceObject(FileObject
);
3409 return(StatusExeFmt
);
3412 Section
->ImageSection
= ImageSectionObject
;
3413 ASSERT(ImageSectionObject
->Segments
);
3418 Status
= MmspWaitForFileLock(FileObject
);
3419 if (!NT_SUCCESS(Status
))
3421 ExFreePool(ImageSectionObject
->Segments
);
3422 ExFreePool(ImageSectionObject
);
3423 ObDereferenceObject(Section
);
3424 ObDereferenceObject(FileObject
);
3428 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3429 ImageSectionObject
, NULL
))
3432 * An other thread has initialized the same image in the background
3434 ExFreePool(ImageSectionObject
->Segments
);
3435 ExFreePool(ImageSectionObject
);
3436 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3437 Section
->ImageSection
= ImageSectionObject
;
3438 SectionSegments
= ImageSectionObject
->Segments
;
3440 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3442 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3446 Status
= StatusExeFmt
;
3453 Status
= MmspWaitForFileLock(FileObject
);
3454 if (Status
!= STATUS_SUCCESS
)
3456 ObDereferenceObject(Section
);
3457 ObDereferenceObject(FileObject
);
3461 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3462 Section
->ImageSection
= ImageSectionObject
;
3463 SectionSegments
= ImageSectionObject
->Segments
;
3466 * Otherwise just reference all the section segments
3468 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3470 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3473 Status
= STATUS_SUCCESS
;
3475 Section
->FileObject
= FileObject
;
3476 CcRosReferenceCache(FileObject
);
3477 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3478 *SectionObject
= Section
;
3485 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3486 PROS_SECTION_OBJECT Section
,
3487 PMM_SECTION_SEGMENT Segment
,
3492 ULONG AllocationType
)
3496 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3498 BoundaryAddressMultiple
.QuadPart
= 0;
3500 Status
= MmCreateMemoryArea(AddressSpace
,
3501 MEMORY_AREA_SECTION_VIEW
,
3508 BoundaryAddressMultiple
);
3509 if (!NT_SUCCESS(Status
))
3511 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3512 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3516 ObReferenceObject((PVOID
)Section
);
3518 MArea
->Data
.SectionData
.Segment
= Segment
;
3519 MArea
->Data
.SectionData
.Section
= Section
;
3520 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3521 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3522 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3523 ViewSize
, 0, Protect
);
3525 return(STATUS_SUCCESS
);
3531 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3532 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3535 PFILE_OBJECT FileObject
;
3538 SWAPENTRY SavedSwapEntry
;
3541 PROS_SECTION_OBJECT Section
;
3542 PMM_SECTION_SEGMENT Segment
;
3543 PMMSUPPORT AddressSpace
;
3546 AddressSpace
= (PMMSUPPORT
)Context
;
3547 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3549 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3551 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3552 MemoryArea
->Data
.SectionData
.ViewOffset
;
3554 Section
= MemoryArea
->Data
.SectionData
.Section
;
3555 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3557 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3561 MmUnlockSectionSegment(Segment
);
3562 MmUnlockAddressSpace(AddressSpace
);
3564 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3565 if (Status
!= STATUS_SUCCESS
)
3567 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3568 KeBugCheck(MEMORY_MANAGEMENT
);
3571 MmLockAddressSpace(AddressSpace
);
3572 MmLockSectionSegment(Segment
);
3573 MmspCompleteAndReleasePageOp(PageOp
);
3574 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3577 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3580 * For a dirty, datafile, non-private page mark it as dirty in the
3583 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3585 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3587 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3588 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3589 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3590 ASSERT(SwapEntry
== 0);
3599 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3601 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3602 KeBugCheck(MEMORY_MANAGEMENT
);
3604 MmFreeSwapPage(SwapEntry
);
3608 if (IS_SWAP_FROM_SSE(Entry
) ||
3609 Page
!= PFN_FROM_SSE(Entry
))
3614 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3616 DPRINT1("Found a private page in a pagefile section.\n");
3617 KeBugCheck(MEMORY_MANAGEMENT
);
3620 * Just dereference private pages
3622 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3623 if (SavedSwapEntry
!= 0)
3625 MmFreeSwapPage(SavedSwapEntry
);
3626 MmSetSavedSwapEntryPage(Page
, 0);
3628 MmDeleteRmap(Page
, Process
, Address
);
3629 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3633 MmDeleteRmap(Page
, Process
, Address
);
3634 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3640 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
3644 PMEMORY_AREA MemoryArea
;
3645 PROS_SECTION_OBJECT Section
;
3646 PMM_SECTION_SEGMENT Segment
;
3647 PLIST_ENTRY CurrentEntry
;
3648 PMM_REGION CurrentRegion
;
3649 PLIST_ENTRY RegionListHead
;
3651 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3653 if (MemoryArea
== NULL
)
3655 return(STATUS_UNSUCCESSFUL
);
3658 MemoryArea
->DeleteInProgress
= TRUE
;
3659 Section
= MemoryArea
->Data
.SectionData
.Section
;
3660 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3662 MmLockSectionSegment(Segment
);
3664 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
3665 while (!IsListEmpty(RegionListHead
))
3667 CurrentEntry
= RemoveHeadList(RegionListHead
);
3668 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
3669 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
3672 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
3674 Status
= MmFreeMemoryArea(AddressSpace
,
3681 Status
= MmFreeMemoryArea(AddressSpace
,
3686 MmUnlockSectionSegment(Segment
);
3687 ObDereferenceObject(Section
);
3695 MmUnmapViewOfSection(PEPROCESS Process
,
3699 PMEMORY_AREA MemoryArea
;
3700 PMMSUPPORT AddressSpace
;
3701 PROS_SECTION_OBJECT Section
;
3704 PVOID ImageBaseAddress
= 0;
3706 DPRINT("Opening memory area Process %x BaseAddress %x\n",
3707 Process
, BaseAddress
);
3711 AddressSpace
= &Process
->Vm
;
3713 MmLockAddressSpace(AddressSpace
);
3714 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3716 if (MemoryArea
== NULL
||
3717 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
3718 MemoryArea
->DeleteInProgress
)
3720 MmUnlockAddressSpace(AddressSpace
);
3721 return STATUS_NOT_MAPPED_VIEW
;
3724 MemoryArea
->DeleteInProgress
= TRUE
;
3726 while (MemoryArea
->PageOpCount
)
3728 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
3732 Offset
-= PAGE_SIZE
;
3733 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
3734 MemoryArea
->Data
.SectionData
.Segment
,
3735 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
3738 MmUnlockAddressSpace(AddressSpace
);
3739 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3740 if (Status
!= STATUS_SUCCESS
)
3742 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3743 KeBugCheck(MEMORY_MANAGEMENT
);
3745 MmLockAddressSpace(AddressSpace
);
3746 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3748 if (MemoryArea
== NULL
||
3749 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
3751 MmUnlockAddressSpace(AddressSpace
);
3752 return STATUS_NOT_MAPPED_VIEW
;
3759 Section
= MemoryArea
->Data
.SectionData
.Section
;
3761 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3765 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3766 PMM_SECTION_SEGMENT SectionSegments
;
3767 PMM_SECTION_SEGMENT Segment
;
3769 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3770 ImageSectionObject
= Section
->ImageSection
;
3771 SectionSegments
= ImageSectionObject
->Segments
;
3772 NrSegments
= ImageSectionObject
->NrSegments
;
3774 /* Search for the current segment within the section segments
3775 * and calculate the image base address */
3776 for (i
= 0; i
< NrSegments
; i
++)
3778 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3780 if (Segment
== &SectionSegments
[i
])
3782 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
3787 if (i
>= NrSegments
)
3789 KeBugCheck(MEMORY_MANAGEMENT
);
3792 for (i
= 0; i
< NrSegments
; i
++)
3794 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
3796 PVOID SBaseAddress
= (PVOID
)
3797 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
3799 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
3805 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
3808 MmUnlockAddressSpace(AddressSpace
);
3810 /* Notify debugger */
3811 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
3813 return(STATUS_SUCCESS
);
3820 * Queries the information of a section object.
3822 * @param SectionHandle
3823 * Handle to the section object. It must be opened with SECTION_QUERY
3825 * @param SectionInformationClass
3826 * Index to a certain information structure. Can be either
3827 * SectionBasicInformation or SectionImageInformation. The latter
3828 * is valid only for sections that were created with the SEC_IMAGE
3830 * @param SectionInformation
3831 * Caller supplies storage for resulting information.
3833 * Size of the supplied storage.
3834 * @param ResultLength
3842 NtQuerySection(IN HANDLE SectionHandle
,
3843 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
3844 OUT PVOID SectionInformation
,
3845 IN SIZE_T SectionInformationLength
,
3846 OUT PSIZE_T ResultLength OPTIONAL
)
3848 PROS_SECTION_OBJECT Section
;
3849 KPROCESSOR_MODE PreviousMode
;
3853 PreviousMode
= ExGetPreviousMode();
3855 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
3857 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
3859 SectionInformationLength
,
3864 if(!NT_SUCCESS(Status
))
3866 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
3870 Status
= ObReferenceObjectByHandle(SectionHandle
,
3872 MmSectionObjectType
,
3874 (PVOID
*)(PVOID
)&Section
,
3876 if (NT_SUCCESS(Status
))
3878 switch (SectionInformationClass
)
3880 case SectionBasicInformation
:
3882 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
3886 Sbi
->Attributes
= Section
->AllocationAttributes
;
3887 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3889 Sbi
->BaseAddress
= 0;
3890 Sbi
->Size
.QuadPart
= 0;
3894 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
3895 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
3898 if (ResultLength
!= NULL
)
3900 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
3902 Status
= STATUS_SUCCESS
;
3904 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3906 Status
= _SEH2_GetExceptionCode();
3913 case SectionImageInformation
:
3915 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
3919 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
3920 if (Section
->AllocationAttributes
& SEC_IMAGE
)
3922 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3923 ImageSectionObject
= Section
->ImageSection
;
3925 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
3926 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
3927 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
3928 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
3929 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
3930 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
3931 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
3932 Sii
->Machine
= ImageSectionObject
->Machine
;
3933 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
3936 if (ResultLength
!= NULL
)
3938 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
3940 Status
= STATUS_SUCCESS
;
3942 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3944 Status
= _SEH2_GetExceptionCode();
3952 ObDereferenceObject(Section
);
3961 /**********************************************************************
3963 * MmMapViewOfSection
3966 * Maps a view of a section into the virtual address space of a
3971 * Pointer to the section object.
3974 * Pointer to the process.
3977 * Desired base address (or NULL) on entry;
3978 * Actual base address of the view on exit.
3981 * Number of high order address bits that must be zero.
3984 * Size in bytes of the initially committed section of
3988 * Offset in bytes from the beginning of the section
3989 * to the beginning of the view.
3992 * Desired length of map (or zero to map all) on entry
3993 * Actual length mapped on exit.
3995 * InheritDisposition
3996 * Specified how the view is to be shared with
4000 * Type of allocation for the pages.
4003 * Protection for the committed region of the view.
4011 MmMapViewOfSection(IN PVOID SectionObject
,
4012 IN PEPROCESS Process
,
4013 IN OUT PVOID
*BaseAddress
,
4014 IN ULONG_PTR ZeroBits
,
4015 IN SIZE_T CommitSize
,
4016 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4017 IN OUT PSIZE_T ViewSize
,
4018 IN SECTION_INHERIT InheritDisposition
,
4019 IN ULONG AllocationType
,
4022 PROS_SECTION_OBJECT Section
;
4023 PMMSUPPORT AddressSpace
;
4025 NTSTATUS Status
= STATUS_SUCCESS
;
4029 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4031 return STATUS_INVALID_PAGE_PROTECTION
;
4035 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4036 AddressSpace
= &Process
->Vm
;
4038 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4040 MmLockAddressSpace(AddressSpace
);
4042 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4046 ULONG_PTR ImageBase
;
4048 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4049 PMM_SECTION_SEGMENT SectionSegments
;
4051 ImageSectionObject
= Section
->ImageSection
;
4052 SectionSegments
= ImageSectionObject
->Segments
;
4053 NrSegments
= ImageSectionObject
->NrSegments
;
4056 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4059 ImageBase
= ImageSectionObject
->ImageBase
;
4063 for (i
= 0; i
< NrSegments
; i
++)
4065 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4067 ULONG_PTR MaxExtent
;
4068 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4069 SectionSegments
[i
].Length
;
4070 ImageSize
= max(ImageSize
, MaxExtent
);
4074 ImageSectionObject
->ImageSize
= ImageSize
;
4076 /* Check there is enough space to map the section at that point. */
4077 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4078 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4080 /* Fail if the user requested a fixed base address. */
4081 if ((*BaseAddress
) != NULL
)
4083 MmUnlockAddressSpace(AddressSpace
);
4084 return(STATUS_UNSUCCESSFUL
);
4086 /* Otherwise find a gap to map the image. */
4087 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4090 MmUnlockAddressSpace(AddressSpace
);
4091 return(STATUS_UNSUCCESSFUL
);
4095 for (i
= 0; i
< NrSegments
; i
++)
4097 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4099 PVOID SBaseAddress
= (PVOID
)
4100 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4101 MmLockSectionSegment(&SectionSegments
[i
]);
4102 Status
= MmMapViewOfSegment(AddressSpace
,
4104 &SectionSegments
[i
],
4106 SectionSegments
[i
].Length
,
4107 SectionSegments
[i
].Protection
,
4110 MmUnlockSectionSegment(&SectionSegments
[i
]);
4111 if (!NT_SUCCESS(Status
))
4113 MmUnlockAddressSpace(AddressSpace
);
4119 *BaseAddress
= (PVOID
)ImageBase
;
4123 /* check for write access */
4124 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4125 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4127 MmUnlockAddressSpace(AddressSpace
);
4128 return STATUS_SECTION_PROTECTION
;
4130 /* check for read access */
4131 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4132 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4134 MmUnlockAddressSpace(AddressSpace
);
4135 return STATUS_SECTION_PROTECTION
;
4137 /* check for execute access */
4138 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4139 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4141 MmUnlockAddressSpace(AddressSpace
);
4142 return STATUS_SECTION_PROTECTION
;
4145 if (ViewSize
== NULL
)
4147 /* Following this pointer would lead to us to the dark side */
4148 /* What to do? Bugcheck? Return status? Do the mambo? */
4149 KeBugCheck(MEMORY_MANAGEMENT
);
4152 if (SectionOffset
== NULL
)
4158 ViewOffset
= SectionOffset
->u
.LowPart
;
4161 if ((ViewOffset
% PAGE_SIZE
) != 0)
4163 MmUnlockAddressSpace(AddressSpace
);
4164 return(STATUS_MAPPED_ALIGNMENT
);
4167 if ((*ViewSize
) == 0)
4169 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4171 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4173 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4176 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4178 MmLockSectionSegment(Section
->Segment
);
4179 Status
= MmMapViewOfSegment(AddressSpace
,
4186 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4187 MmUnlockSectionSegment(Section
->Segment
);
4188 if (!NT_SUCCESS(Status
))
4190 MmUnlockAddressSpace(AddressSpace
);
4195 MmUnlockAddressSpace(AddressSpace
);
4197 return(STATUS_SUCCESS
);
4204 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4205 IN PLARGE_INTEGER NewFileSize
)
4207 /* Check whether an ImageSectionObject exists */
4208 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4210 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4214 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4216 PMM_SECTION_SEGMENT Segment
;
4218 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4221 if (Segment
->ReferenceCount
!= 0)
4223 /* Check size of file */
4224 if (SectionObjectPointer
->SharedCacheMap
)
4226 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4227 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4235 /* Something must gone wrong
4236 * how can we have a Section but no
4238 DPRINT("ERROR: DataSectionObject without reference!\n");
4242 DPRINT("FIXME: didn't check for outstanding write probes\n");
4254 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4255 IN MMFLUSH_TYPE FlushType
)
4259 case MmFlushForDelete
:
4260 if (SectionObjectPointer
->ImageSectionObject
||
4261 SectionObjectPointer
->DataSectionObject
)
4265 CcRosSetRemoveOnClose(SectionObjectPointer
);
4267 case MmFlushForWrite
:
4277 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4278 OUT PVOID
* MappedBase
,
4279 IN OUT PSIZE_T ViewSize
)
4281 PROS_SECTION_OBJECT Section
;
4282 PMMSUPPORT AddressSpace
;
4285 if ((ULONG_PTR
)SectionObject
& 1)
4288 extern PVOID MmSession
;
4289 return MiMapViewInSystemSpace((PVOID
)((ULONG_PTR
)SectionObject
& ~1),
4295 DPRINT("MmMapViewInSystemSpace() called\n");
4297 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4298 AddressSpace
= MmGetKernelAddressSpace();
4300 MmLockAddressSpace(AddressSpace
);
4303 if ((*ViewSize
) == 0)
4305 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4307 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4309 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4312 MmLockSectionSegment(Section
->Segment
);
4315 Status
= MmMapViewOfSegment(AddressSpace
,
4324 MmUnlockSectionSegment(Section
->Segment
);
4325 MmUnlockAddressSpace(AddressSpace
);
4334 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4336 PMMSUPPORT AddressSpace
;
4339 DPRINT("MmUnmapViewInSystemSpace() called\n");
4341 AddressSpace
= MmGetKernelAddressSpace();
4343 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4349 /**********************************************************************
4354 * Creates a section object.
4357 * SectionObject (OUT)
4358 * Caller supplied storage for the resulting pointer
4359 * to a SECTION_OBJECT instance;
4362 * Specifies the desired access to the section can be a
4364 * STANDARD_RIGHTS_REQUIRED |
4366 * SECTION_MAP_WRITE |
4367 * SECTION_MAP_READ |
4368 * SECTION_MAP_EXECUTE
4370 * ObjectAttributes [OPTIONAL]
4371 * Initialized attributes for the object can be used
4372 * to create a named section;
4375 * Maximizes the size of the memory section. Must be
4376 * non-NULL for a page-file backed section.
4377 * If value specified for a mapped file and the file is
4378 * not large enough, file will be extended.
4380 * SectionPageProtection
4381 * Can be a combination of:
4387 * AllocationAttributes
4388 * Can be a combination of:
4393 * Handle to a file to create a section mapped to a file
4394 * instead of a memory backed section;
4405 MmCreateSection (OUT PVOID
* Section
,
4406 IN ACCESS_MASK DesiredAccess
,
4407 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4408 IN PLARGE_INTEGER MaximumSize
,
4409 IN ULONG SectionPageProtection
,
4410 IN ULONG AllocationAttributes
,
4411 IN HANDLE FileHandle OPTIONAL
,
4412 IN PFILE_OBJECT File OPTIONAL
)
4415 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4417 /* Check if an ARM3 section is being created instead */
4418 if (AllocationAttributes
& 0xC0000000)
4420 DPRINT1("arm 3 path\n");
4421 return MmCreateArm3Section(Section
,
4425 SectionPageProtection
,
4426 AllocationAttributes
&~ 0xC0000000,
4432 * Check the protection
4434 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4435 if (Protection
!= PAGE_READONLY
&&
4436 Protection
!= PAGE_READWRITE
&&
4437 Protection
!= PAGE_WRITECOPY
&&
4438 Protection
!= PAGE_EXECUTE
&&
4439 Protection
!= PAGE_EXECUTE_READ
&&
4440 Protection
!= PAGE_EXECUTE_READWRITE
&&
4441 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4443 return STATUS_INVALID_PAGE_PROTECTION
;
4446 if (AllocationAttributes
& SEC_IMAGE
)
4448 return(MmCreateImageSection(SectionObject
,
4452 SectionPageProtection
,
4453 AllocationAttributes
,
4457 if (FileHandle
!= NULL
)
4459 return(MmCreateDataFileSection(SectionObject
,
4463 SectionPageProtection
,
4464 AllocationAttributes
,
4468 return(MmCreatePageFileSection(SectionObject
,
4472 SectionPageProtection
,
4473 AllocationAttributes
));