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>
51 #include "ARM3/miarm.h"
53 #if defined (ALLOC_PRAGMA)
54 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
55 #pragma alloc_text(INIT, MmInitSectionImplementation)
59 /* TYPES *********************************************************************/
63 PROS_SECTION_OBJECT Section
;
64 PMM_SECTION_SEGMENT Segment
;
69 MM_SECTION_PAGEOUT_CONTEXT
;
71 /* GLOBALS *******************************************************************/
73 POBJECT_TYPE MmSectionObjectType
= NULL
;
75 ULONG_PTR MmSubsectionBase
;
77 static GENERIC_MAPPING MmpSectionMapping
= {
78 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
79 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
80 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
83 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
84 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
85 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
86 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
87 #define MAX_SHARE_COUNT 0x7FF
88 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
89 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
90 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
92 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
94 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
95 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
98 /* FUNCTIONS *****************************************************************/
102 MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section
)
107 /* Return the file object */
108 return Section
->FileObject
; // Section->ControlArea->FileObject on NT
113 MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section
,
114 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
116 POBJECT_NAME_INFORMATION ObjectNameInfo
;
120 /* Make sure it's an image section */
122 if (!(Section
->AllocationAttributes
& SEC_IMAGE
))
125 return STATUS_SECTION_NOT_IMAGE
;
128 /* Allocate memory for our structure */
129 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
,
132 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
135 Status
= ObQueryNameString(Section
->FileObject
,
139 if (!NT_SUCCESS(Status
))
141 /* Failed, free memory */
142 ExFreePoolWithTag(ObjectNameInfo
, ' mM');
147 *ModuleName
= ObjectNameInfo
;
148 return STATUS_SUCCESS
;
153 MmGetFileNameForAddress(IN PVOID Address
,
154 OUT PUNICODE_STRING ModuleName
)
156 PROS_SECTION_OBJECT Section
;
157 PMEMORY_AREA MemoryArea
;
158 PMMSUPPORT AddressSpace
;
159 POBJECT_NAME_INFORMATION ModuleNameInformation
;
160 NTSTATUS Status
= STATUS_ADDRESS_NOT_ASSOCIATED
;
162 /* Get the MM_AVL_TABLE from EPROCESS */
163 if (Address
>= MmSystemRangeStart
)
165 AddressSpace
= MmGetKernelAddressSpace();
169 AddressSpace
= &PsGetCurrentProcess()->Vm
;
172 /* Lock address space */
173 MmLockAddressSpace(AddressSpace
);
175 /* Locate the memory area for the process by address */
176 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
178 /* Make sure it's a section view type */
179 if ((MemoryArea
!= NULL
) && (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
))
181 /* Get the section pointer to the SECTION_OBJECT */
182 Section
= MemoryArea
->Data
.SectionData
.Section
;
184 /* Unlock address space */
185 MmUnlockAddressSpace(AddressSpace
);
187 /* Get the filename of the section */
188 Status
= MmGetFileNameForSection(Section
,&ModuleNameInformation
);
190 if (NT_SUCCESS(Status
))
192 /* Init modulename */
193 RtlCreateUnicodeString(ModuleName
,
194 ModuleNameInformation
->Name
.Buffer
);
196 /* Free temp taged buffer from MmGetFileNameForSection() */
197 ExFreePoolWithTag(ModuleNameInformation
, ' mM');
198 DPRINT("Found ModuleName %S by address %p\n",
199 ModuleName
->Buffer
,Address
);
204 /* Unlock address space */
205 MmUnlockAddressSpace(AddressSpace
);
211 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
214 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
215 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
216 * RETURNS: Status of the wait.
219 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
221 LARGE_INTEGER Timeout
;
222 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
224 Timeout
.QuadPart
= -100000000LL; // 10 sec
227 Timeout
.QuadPart
= -100000000; // 10 sec
230 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
235 * FUNCTION: Sets the page op completion event and releases the page op.
236 * ARGUMENTS: PMM_PAGEOP.
237 * RETURNS: In shorter time than it takes you to even read this
238 * description, so don't even think about geting a mug of coffee.
241 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
243 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
244 MmReleasePageOp(PageOp
);
249 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
250 * ARGUMENTS: PFILE_OBJECT to wait for.
251 * RETURNS: Status of the wait.
254 MmspWaitForFileLock(PFILE_OBJECT File
)
256 return STATUS_SUCCESS
;
257 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
262 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
265 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
267 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
269 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
271 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
279 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
281 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
283 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
284 PMM_SECTION_SEGMENT SectionSegments
;
288 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
289 NrSegments
= ImageSectionObject
->NrSegments
;
290 SectionSegments
= ImageSectionObject
->Segments
;
291 for (i
= 0; i
< NrSegments
; i
++)
293 if (SectionSegments
[i
].ReferenceCount
!= 0)
295 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
296 SectionSegments
[i
].ReferenceCount
);
297 KeBugCheck(MEMORY_MANAGEMENT
);
299 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
301 ExFreePool(ImageSectionObject
->Segments
);
302 ExFreePool(ImageSectionObject
);
303 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
305 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
307 PMM_SECTION_SEGMENT Segment
;
309 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
312 if (Segment
->ReferenceCount
!= 0)
314 DPRINT1("Data segment still referenced\n");
315 KeBugCheck(MEMORY_MANAGEMENT
);
317 MmFreePageTablesSectionSegment(Segment
);
319 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
325 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
327 ExAcquireFastMutex(&Segment
->Lock
);
332 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
334 ExReleaseFastMutex(&Segment
->Lock
);
339 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
343 PSECTION_PAGE_TABLE Table
;
344 ULONG DirectoryOffset
;
347 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
349 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
353 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
354 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
358 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
359 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
360 TAG_SECTION_PAGE_TABLE
);
363 KeBugCheck(MEMORY_MANAGEMENT
);
365 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
366 DPRINT("Table %x\n", Table
);
369 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
370 Table
->Entry
[TableOffset
] = Entry
;
376 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
379 PSECTION_PAGE_TABLE Table
;
381 ULONG DirectoryOffset
;
384 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
386 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
388 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
392 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
393 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
394 DPRINT("Table %x\n", Table
);
400 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
401 Entry
= Table
->Entry
[TableOffset
];
407 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
412 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
415 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
416 KeBugCheck(MEMORY_MANAGEMENT
);
418 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
420 DPRINT1("Maximum share count reached\n");
421 KeBugCheck(MEMORY_MANAGEMENT
);
423 if (IS_SWAP_FROM_SSE(Entry
))
425 KeBugCheck(MEMORY_MANAGEMENT
);
427 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
428 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
433 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
434 PMM_SECTION_SEGMENT Segment
,
440 BOOLEAN IsDirectMapped
= FALSE
;
442 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
445 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
446 KeBugCheck(MEMORY_MANAGEMENT
);
448 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
450 DPRINT1("Zero share count for unshare\n");
451 KeBugCheck(MEMORY_MANAGEMENT
);
453 if (IS_SWAP_FROM_SSE(Entry
))
455 KeBugCheck(MEMORY_MANAGEMENT
);
457 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
459 * If we reducing the share count of this entry to zero then set the entry
460 * to zero and tell the cache the page is no longer mapped.
462 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
464 PFILE_OBJECT FileObject
;
466 SWAPENTRY SavedSwapEntry
;
468 BOOLEAN IsImageSection
;
471 FileOffset
= Offset
+ Segment
->FileOffset
;
473 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
475 Page
= PFN_FROM_SSE(Entry
);
476 FileObject
= Section
->FileObject
;
477 if (FileObject
!= NULL
&&
478 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
481 if ((FileOffset
% PAGE_SIZE
) == 0 &&
482 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
485 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
486 IsDirectMapped
= TRUE
;
487 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
488 if (!NT_SUCCESS(Status
))
490 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
491 KeBugCheck(MEMORY_MANAGEMENT
);
496 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
497 if (SavedSwapEntry
== 0)
500 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
501 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
505 * Try to page out this page and set the swap entry
506 * within the section segment. There exist no rmap entry
507 * for this page. The pager thread can't page out a
508 * page without a rmap entry.
510 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
514 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
517 MmReleasePageMemoryConsumer(MC_USER
, Page
);
523 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
524 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
532 * We hold all locks. Nobody can do something with the current
533 * process and the current segment (also not within an other process).
536 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
537 if (!NT_SUCCESS(Status
))
539 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
540 KeBugCheck(MEMORY_MANAGEMENT
);
543 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
544 MmSetSavedSwapEntryPage(Page
, 0);
546 MmReleasePageMemoryConsumer(MC_USER
, Page
);
550 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
551 KeBugCheck(MEMORY_MANAGEMENT
);
557 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
559 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
562 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
565 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
568 PCACHE_SEGMENT CacheSeg
;
569 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
570 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
573 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
582 MiCopyFromUserPage(PFN_NUMBER DestPage
, PVOID SourceAddress
)
588 Process
= PsGetCurrentProcess();
589 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
590 if (TempAddress
== NULL
)
592 return(STATUS_NO_MEMORY
);
594 memcpy(TempAddress
, SourceAddress
, PAGE_SIZE
);
595 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
596 return(STATUS_SUCCESS
);
601 MiReadPage(PMEMORY_AREA MemoryArea
,
605 * FUNCTION: Read a page for a section backed memory area.
607 * MemoryArea - Memory area to read the page for.
608 * Offset - Offset of the page to read.
609 * Page - Variable that receives a page contains the read data.
616 PCACHE_SEGMENT CacheSeg
;
617 PFILE_OBJECT FileObject
;
621 BOOLEAN IsImageSection
;
624 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
625 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
626 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
627 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
628 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
632 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
635 * If the file system is letting us go directly to the cache and the
636 * memory area was mapped at an offset in the file which is page aligned
637 * then get the related cache segment.
639 if ((FileOffset
% PAGE_SIZE
) == 0 &&
640 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
641 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
645 * Get the related cache segment; we use a lower level interface than
646 * filesystems do because it is safe for us to use an offset with a
647 * alignment less than the file system block size.
649 Status
= CcRosGetCacheSegment(Bcb
,
655 if (!NT_SUCCESS(Status
))
662 * If the cache segment isn't up to date then call the file
663 * system to read in the data.
665 Status
= ReadCacheSegment(CacheSeg
);
666 if (!NT_SUCCESS(Status
))
668 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
673 * Retrieve the page from the cache segment that we actually want.
675 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
676 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
678 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
685 ULONG CacheSegOffset
;
688 * Allocate a page, this is rather complicated by the possibility
689 * we might have to move other things out of memory
691 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
692 if (!NT_SUCCESS(Status
))
696 Status
= CcRosGetCacheSegment(Bcb
,
702 if (!NT_SUCCESS(Status
))
709 * If the cache segment isn't up to date then call the file
710 * system to read in the data.
712 Status
= ReadCacheSegment(CacheSeg
);
713 if (!NT_SUCCESS(Status
))
715 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
720 Process
= PsGetCurrentProcess();
721 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
722 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
723 Length
= RawLength
- SegOffset
;
724 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
726 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
728 else if (CacheSegOffset
>= PAGE_SIZE
)
730 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
734 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
735 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
736 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
737 Status
= CcRosGetCacheSegment(Bcb
,
738 FileOffset
+ CacheSegOffset
,
743 if (!NT_SUCCESS(Status
))
750 * If the cache segment isn't up to date then call the file
751 * system to read in the data.
753 Status
= ReadCacheSegment(CacheSeg
);
754 if (!NT_SUCCESS(Status
))
756 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
760 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
761 if (Length
< PAGE_SIZE
)
763 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
767 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
770 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
771 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
773 return(STATUS_SUCCESS
);
778 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
779 MEMORY_AREA
* MemoryArea
,
787 PROS_SECTION_OBJECT Section
;
788 PMM_SECTION_SEGMENT Segment
;
794 BOOLEAN HasSwapEntry
;
795 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
799 * There is a window between taking the page fault and locking the
800 * address space when another thread could load the page so we check
803 if (MmIsPagePresent(Process
, Address
))
807 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
808 MmLockPage(MmGetPfnForProcess(Process
, Address
));
809 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
811 return(STATUS_SUCCESS
);
814 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
815 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
816 + MemoryArea
->Data
.SectionData
.ViewOffset
;
818 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
819 Section
= MemoryArea
->Data
.SectionData
.Section
;
820 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
821 &MemoryArea
->Data
.SectionData
.RegionListHead
,
826 MmLockSectionSegment(Segment
);
829 * Check if this page needs to be mapped COW
831 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
832 (Region
->Protect
== PAGE_READWRITE
||
833 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
835 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
839 Attributes
= Region
->Protect
;
843 * Get or create a page operation descriptor
845 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
848 DPRINT1("MmGetPageOp failed\n");
849 KeBugCheck(MEMORY_MANAGEMENT
);
853 * Check if someone else is already handling this fault, if so wait
856 if (PageOp
->Thread
!= PsGetCurrentThread())
858 MmUnlockSectionSegment(Segment
);
859 MmUnlockAddressSpace(AddressSpace
);
860 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
862 * Check for various strange conditions
864 if (Status
!= STATUS_SUCCESS
)
866 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
867 KeBugCheck(MEMORY_MANAGEMENT
);
869 if (PageOp
->Status
== STATUS_PENDING
)
871 DPRINT1("Woke for page op before completion\n");
872 KeBugCheck(MEMORY_MANAGEMENT
);
874 MmLockAddressSpace(AddressSpace
);
876 * If this wasn't a pagein then restart the operation
878 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
880 MmspCompleteAndReleasePageOp(PageOp
);
881 DPRINT("Address 0x%.8X\n", Address
);
882 return(STATUS_MM_RESTART_OPERATION
);
886 * If the thread handling this fault has failed then we don't retry
888 if (!NT_SUCCESS(PageOp
->Status
))
890 Status
= PageOp
->Status
;
891 MmspCompleteAndReleasePageOp(PageOp
);
892 DPRINT("Address 0x%.8X\n", Address
);
895 MmLockSectionSegment(Segment
);
897 * If the completed fault was for another address space then set the
900 if (!MmIsPagePresent(Process
, Address
))
902 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
903 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
905 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
908 * The page was a private page in another or in our address space
910 MmUnlockSectionSegment(Segment
);
911 MmspCompleteAndReleasePageOp(PageOp
);
912 return(STATUS_MM_RESTART_OPERATION
);
915 Page
= PFN_FROM_SSE(Entry
);
917 MmSharePageEntrySectionSegment(Segment
, Offset
);
919 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
920 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
922 Status
= MmCreateVirtualMapping(Process
,
927 if (!NT_SUCCESS(Status
))
929 DPRINT1("Unable to create virtual mapping\n");
930 KeBugCheck(MEMORY_MANAGEMENT
);
932 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
936 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
938 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
940 MmUnlockSectionSegment(Segment
);
941 PageOp
->Status
= STATUS_SUCCESS
;
942 MmspCompleteAndReleasePageOp(PageOp
);
943 DPRINT("Address 0x%.8X\n", Address
);
944 return(STATUS_SUCCESS
);
947 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
951 * Must be private page we have swapped out.
958 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
960 DPRINT1("Found a swaped out private page in a pagefile section.\n");
961 KeBugCheck(MEMORY_MANAGEMENT
);
964 MmUnlockSectionSegment(Segment
);
965 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
967 MmUnlockAddressSpace(AddressSpace
);
968 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
969 if (!NT_SUCCESS(Status
))
971 KeBugCheck(MEMORY_MANAGEMENT
);
974 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
975 if (!NT_SUCCESS(Status
))
977 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
978 KeBugCheck(MEMORY_MANAGEMENT
);
980 MmLockAddressSpace(AddressSpace
);
981 Status
= MmCreateVirtualMapping(Process
,
986 if (!NT_SUCCESS(Status
))
988 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
989 KeBugCheck(MEMORY_MANAGEMENT
);
994 * Store the swap entry for later use.
996 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
999 * Add the page to the process's working set
1001 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1004 * Finish the operation
1008 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1010 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1012 PageOp
->Status
= STATUS_SUCCESS
;
1013 MmspCompleteAndReleasePageOp(PageOp
);
1014 DPRINT("Address 0x%.8X\n", Address
);
1015 return(STATUS_SUCCESS
);
1019 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1021 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1023 MmUnlockSectionSegment(Segment
);
1025 * Just map the desired physical page
1027 Page
= Offset
>> PAGE_SHIFT
;
1028 Status
= MmCreateVirtualMappingUnsafe(Process
,
1033 if (!NT_SUCCESS(Status
))
1035 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1036 KeBugCheck(MEMORY_MANAGEMENT
);
1040 * Don't add an rmap entry since the page mapped could be for
1045 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1047 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1051 * Cleanup and release locks
1053 PageOp
->Status
= STATUS_SUCCESS
;
1054 MmspCompleteAndReleasePageOp(PageOp
);
1055 DPRINT("Address 0x%.8X\n", Address
);
1056 return(STATUS_SUCCESS
);
1060 * Map anonymous memory for BSS sections
1062 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1064 MmUnlockSectionSegment(Segment
);
1065 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1066 if (!NT_SUCCESS(Status
))
1068 MmUnlockAddressSpace(AddressSpace
);
1069 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1070 MmLockAddressSpace(AddressSpace
);
1072 if (!NT_SUCCESS(Status
))
1074 KeBugCheck(MEMORY_MANAGEMENT
);
1076 Status
= MmCreateVirtualMapping(Process
,
1081 if (!NT_SUCCESS(Status
))
1083 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1084 KeBugCheck(MEMORY_MANAGEMENT
);
1087 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1090 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1092 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1096 * Cleanup and release locks
1098 PageOp
->Status
= STATUS_SUCCESS
;
1099 MmspCompleteAndReleasePageOp(PageOp
);
1100 DPRINT("Address 0x%.8X\n", Address
);
1101 return(STATUS_SUCCESS
);
1105 * Get the entry corresponding to the offset within the section
1107 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1112 * If the entry is zero (and it can't change because we have
1113 * locked the segment) then we need to load the page.
1117 * Release all our locks and read in the page from disk
1119 MmUnlockSectionSegment(Segment
);
1120 MmUnlockAddressSpace(AddressSpace
);
1122 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1123 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1125 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1126 if (!NT_SUCCESS(Status
))
1128 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1133 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1134 if (!NT_SUCCESS(Status
))
1136 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1139 if (!NT_SUCCESS(Status
))
1142 * FIXME: What do we know in this case?
1145 * Cleanup and release locks
1147 MmLockAddressSpace(AddressSpace
);
1148 PageOp
->Status
= Status
;
1149 MmspCompleteAndReleasePageOp(PageOp
);
1150 DPRINT("Address 0x%.8X\n", Address
);
1154 * Relock the address space and segment
1156 MmLockAddressSpace(AddressSpace
);
1157 MmLockSectionSegment(Segment
);
1160 * Check the entry. No one should change the status of a page
1161 * that has a pending page-in.
1163 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1164 if (Entry
!= Entry1
)
1166 DPRINT1("Someone changed ppte entry while we slept\n");
1167 KeBugCheck(MEMORY_MANAGEMENT
);
1171 * Mark the offset within the section as having valid, in-memory
1174 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1175 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1176 MmUnlockSectionSegment(Segment
);
1178 Status
= MmCreateVirtualMapping(Process
,
1183 if (!NT_SUCCESS(Status
))
1185 DPRINT1("Unable to create virtual mapping\n");
1186 KeBugCheck(MEMORY_MANAGEMENT
);
1188 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1192 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1194 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1196 PageOp
->Status
= STATUS_SUCCESS
;
1197 MmspCompleteAndReleasePageOp(PageOp
);
1198 DPRINT("Address 0x%.8X\n", Address
);
1199 return(STATUS_SUCCESS
);
1201 else if (IS_SWAP_FROM_SSE(Entry
))
1203 SWAPENTRY SwapEntry
;
1205 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1208 * Release all our locks and read in the page from disk
1210 MmUnlockSectionSegment(Segment
);
1212 MmUnlockAddressSpace(AddressSpace
);
1214 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1215 if (!NT_SUCCESS(Status
))
1217 KeBugCheck(MEMORY_MANAGEMENT
);
1220 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1221 if (!NT_SUCCESS(Status
))
1223 KeBugCheck(MEMORY_MANAGEMENT
);
1227 * Relock the address space and segment
1229 MmLockAddressSpace(AddressSpace
);
1230 MmLockSectionSegment(Segment
);
1233 * Check the entry. No one should change the status of a page
1234 * that has a pending page-in.
1236 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1237 if (Entry
!= Entry1
)
1239 DPRINT1("Someone changed ppte entry while we slept\n");
1240 KeBugCheck(MEMORY_MANAGEMENT
);
1244 * Mark the offset within the section as having valid, in-memory
1247 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1248 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1249 MmUnlockSectionSegment(Segment
);
1252 * Save the swap entry.
1254 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1255 Status
= MmCreateVirtualMapping(Process
,
1260 if (!NT_SUCCESS(Status
))
1262 DPRINT1("Unable to create virtual mapping\n");
1263 KeBugCheck(MEMORY_MANAGEMENT
);
1265 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1268 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1270 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1272 PageOp
->Status
= STATUS_SUCCESS
;
1273 MmspCompleteAndReleasePageOp(PageOp
);
1274 DPRINT("Address 0x%.8X\n", Address
);
1275 return(STATUS_SUCCESS
);
1280 * If the section offset is already in-memory and valid then just
1281 * take another reference to the page
1284 Page
= PFN_FROM_SSE(Entry
);
1286 MmSharePageEntrySectionSegment(Segment
, Offset
);
1287 MmUnlockSectionSegment(Segment
);
1289 Status
= MmCreateVirtualMapping(Process
,
1294 if (!NT_SUCCESS(Status
))
1296 DPRINT1("Unable to create virtual mapping\n");
1297 KeBugCheck(MEMORY_MANAGEMENT
);
1299 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1302 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1304 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1306 PageOp
->Status
= STATUS_SUCCESS
;
1307 MmspCompleteAndReleasePageOp(PageOp
);
1308 DPRINT("Address 0x%.8X\n", Address
);
1309 return(STATUS_SUCCESS
);
1315 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1316 MEMORY_AREA
* MemoryArea
,
1320 PMM_SECTION_SEGMENT Segment
;
1321 PROS_SECTION_OBJECT Section
;
1330 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1333 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1336 * Check if the page has been paged out or has already been set readwrite
1338 if (!MmIsPagePresent(Process
, Address
) ||
1339 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1341 DPRINT("Address 0x%.8X\n", Address
);
1342 return(STATUS_SUCCESS
);
1346 * Find the offset of the page
1348 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1349 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1350 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1352 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1353 Section
= MemoryArea
->Data
.SectionData
.Section
;
1354 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1355 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1360 MmLockSectionSegment(Segment
);
1362 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1363 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1365 MmUnlockSectionSegment(Segment
);
1368 * Check if we are doing COW
1370 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1371 (Region
->Protect
== PAGE_READWRITE
||
1372 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1374 DPRINT("Address 0x%.8X\n", Address
);
1375 return(STATUS_ACCESS_VIOLATION
);
1378 if (IS_SWAP_FROM_SSE(Entry
) ||
1379 PFN_FROM_SSE(Entry
) != OldPage
)
1381 /* This is a private page. We must only change the page protection. */
1382 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1383 return(STATUS_SUCCESS
);
1387 * Get or create a pageop
1389 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1390 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1393 DPRINT1("MmGetPageOp failed\n");
1394 KeBugCheck(MEMORY_MANAGEMENT
);
1398 * Wait for any other operations to complete
1400 if (PageOp
->Thread
!= PsGetCurrentThread())
1402 MmUnlockAddressSpace(AddressSpace
);
1403 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1405 * Check for various strange conditions
1407 if (Status
== STATUS_TIMEOUT
)
1409 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1410 KeBugCheck(MEMORY_MANAGEMENT
);
1412 if (PageOp
->Status
== STATUS_PENDING
)
1414 DPRINT1("Woke for page op before completion\n");
1415 KeBugCheck(MEMORY_MANAGEMENT
);
1418 * Restart the operation
1420 MmLockAddressSpace(AddressSpace
);
1421 MmspCompleteAndReleasePageOp(PageOp
);
1422 DPRINT("Address 0x%.8X\n", Address
);
1423 return(STATUS_MM_RESTART_OPERATION
);
1427 * Release locks now we have the pageop
1429 MmUnlockAddressSpace(AddressSpace
);
1434 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1435 if (!NT_SUCCESS(Status
))
1437 KeBugCheck(MEMORY_MANAGEMENT
);
1443 MiCopyFromUserPage(NewPage
, PAddress
);
1445 MmLockAddressSpace(AddressSpace
);
1447 * Delete the old entry.
1449 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1452 * Set the PTE to point to the new page
1454 Status
= MmCreateVirtualMapping(Process
,
1459 if (!NT_SUCCESS(Status
))
1461 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1462 KeBugCheck(MEMORY_MANAGEMENT
);
1465 if (!NT_SUCCESS(Status
))
1467 DPRINT1("Unable to create virtual mapping\n");
1468 KeBugCheck(MEMORY_MANAGEMENT
);
1472 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1473 MmLockPage(NewPage
);
1474 MmUnlockPage(OldPage
);
1475 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1479 * Unshare the old page.
1481 MmDeleteRmap(OldPage
, Process
, PAddress
);
1482 MmInsertRmap(NewPage
, Process
, PAddress
);
1483 MmLockSectionSegment(Segment
);
1484 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1485 MmUnlockSectionSegment(Segment
);
1487 PageOp
->Status
= STATUS_SUCCESS
;
1488 MmspCompleteAndReleasePageOp(PageOp
);
1489 DPRINT("Address 0x%.8X\n", Address
);
1490 return(STATUS_SUCCESS
);
1494 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1496 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1500 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1503 MmLockAddressSpace(&Process
->Vm
);
1506 MmDeleteVirtualMapping(Process
,
1513 PageOutContext
->WasDirty
= TRUE
;
1515 if (!PageOutContext
->Private
)
1517 MmLockSectionSegment(PageOutContext
->Segment
);
1518 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1519 PageOutContext
->Segment
,
1520 PageOutContext
->Offset
,
1521 PageOutContext
->WasDirty
,
1523 MmUnlockSectionSegment(PageOutContext
->Segment
);
1527 MmUnlockAddressSpace(&Process
->Vm
);
1530 if (PageOutContext
->Private
)
1532 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1535 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1540 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1541 MEMORY_AREA
* MemoryArea
,
1546 MM_SECTION_PAGEOUT_CONTEXT Context
;
1547 SWAPENTRY SwapEntry
;
1551 PFILE_OBJECT FileObject
;
1553 BOOLEAN DirectMapped
;
1554 BOOLEAN IsImageSection
;
1555 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1558 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1561 * Get the segment and section.
1563 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1564 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1566 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1567 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1568 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1570 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1572 FileObject
= Context
.Section
->FileObject
;
1573 DirectMapped
= FALSE
;
1574 if (FileObject
!= NULL
&&
1575 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1577 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1580 * If the file system is letting us go directly to the cache and the
1581 * memory area was mapped at an offset in the file which is page aligned
1582 * then note this is a direct mapped page.
1584 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1585 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1587 DirectMapped
= TRUE
;
1593 * This should never happen since mappings of physical memory are never
1594 * placed in the rmap lists.
1596 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1598 DPRINT1("Trying to page out from physical memory section address 0x%X "
1599 "process %d\n", Address
,
1600 Process
? Process
->UniqueProcessId
: 0);
1601 KeBugCheck(MEMORY_MANAGEMENT
);
1605 * Get the section segment entry and the physical address.
1607 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1608 if (!MmIsPagePresent(Process
, Address
))
1610 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1611 Process
? Process
->UniqueProcessId
: 0, Address
);
1612 KeBugCheck(MEMORY_MANAGEMENT
);
1614 Page
= MmGetPfnForProcess(Process
, Address
);
1615 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1618 * Prepare the context structure for the rmap delete call.
1620 Context
.WasDirty
= FALSE
;
1621 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1622 IS_SWAP_FROM_SSE(Entry
) ||
1623 PFN_FROM_SSE(Entry
) != Page
)
1625 Context
.Private
= TRUE
;
1629 Context
.Private
= FALSE
;
1633 * Take an additional reference to the page or the cache segment.
1635 if (DirectMapped
&& !Context
.Private
)
1637 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1639 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1640 KeBugCheck(MEMORY_MANAGEMENT
);
1645 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1646 MmReferencePage(Page
);
1647 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1650 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1653 * If this wasn't a private page then we should have reduced the entry to
1654 * zero by deleting all the rmaps.
1656 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1658 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1659 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1661 KeBugCheck(MEMORY_MANAGEMENT
);
1666 * If the page wasn't dirty then we can just free it as for a readonly page.
1667 * Since we unmapped all the mappings above we know it will not suddenly
1669 * If the page is from a pagefile section and has no swap entry,
1670 * we can't free the page at this point.
1672 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1673 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1675 if (Context
.Private
)
1677 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1678 Context
.WasDirty
? "dirty" : "clean", Address
);
1679 KeBugCheck(MEMORY_MANAGEMENT
);
1681 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1683 MmSetSavedSwapEntryPage(Page
, 0);
1684 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1685 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1686 PageOp
->Status
= STATUS_SUCCESS
;
1687 MmspCompleteAndReleasePageOp(PageOp
);
1688 return(STATUS_SUCCESS
);
1691 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1693 if (Context
.Private
)
1695 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1696 Context
.WasDirty
? "dirty" : "clean", Address
);
1697 KeBugCheck(MEMORY_MANAGEMENT
);
1699 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1701 MmSetSavedSwapEntryPage(Page
, 0);
1704 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1706 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1707 PageOp
->Status
= STATUS_SUCCESS
;
1708 MmspCompleteAndReleasePageOp(PageOp
);
1709 return(STATUS_SUCCESS
);
1712 else if (!Context
.Private
&& DirectMapped
)
1716 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1718 KeBugCheck(MEMORY_MANAGEMENT
);
1720 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1721 if (!NT_SUCCESS(Status
))
1723 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1724 KeBugCheck(MEMORY_MANAGEMENT
);
1726 PageOp
->Status
= STATUS_SUCCESS
;
1727 MmspCompleteAndReleasePageOp(PageOp
);
1728 return(STATUS_SUCCESS
);
1730 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1734 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1736 KeBugCheck(MEMORY_MANAGEMENT
);
1738 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1739 PageOp
->Status
= STATUS_SUCCESS
;
1740 MmspCompleteAndReleasePageOp(PageOp
);
1741 return(STATUS_SUCCESS
);
1743 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1745 MmSetSavedSwapEntryPage(Page
, 0);
1746 MmLockAddressSpace(AddressSpace
);
1747 Status
= MmCreatePageFileMapping(Process
,
1750 MmUnlockAddressSpace(AddressSpace
);
1751 if (!NT_SUCCESS(Status
))
1753 KeBugCheck(MEMORY_MANAGEMENT
);
1755 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1756 PageOp
->Status
= STATUS_SUCCESS
;
1757 MmspCompleteAndReleasePageOp(PageOp
);
1758 return(STATUS_SUCCESS
);
1762 * If necessary, allocate an entry in the paging file for this page
1766 SwapEntry
= MmAllocSwapPage();
1769 MmShowOutOfSpaceMessagePagingFile();
1770 MmLockAddressSpace(AddressSpace
);
1772 * For private pages restore the old mappings.
1774 if (Context
.Private
)
1776 Status
= MmCreateVirtualMapping(Process
,
1778 MemoryArea
->Protect
,
1781 MmSetDirtyPage(Process
, Address
);
1789 * For non-private pages if the page wasn't direct mapped then
1790 * set it back into the section segment entry so we don't loose
1791 * our copy. Otherwise it will be handled by the cache manager.
1793 Status
= MmCreateVirtualMapping(Process
,
1795 MemoryArea
->Protect
,
1798 MmSetDirtyPage(Process
, Address
);
1802 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1803 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1805 MmUnlockAddressSpace(AddressSpace
);
1806 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1807 MmspCompleteAndReleasePageOp(PageOp
);
1808 return(STATUS_PAGEFILE_QUOTA
);
1813 * Write the page to the pagefile
1815 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1816 if (!NT_SUCCESS(Status
))
1818 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1821 * As above: undo our actions.
1822 * FIXME: Also free the swap page.
1824 MmLockAddressSpace(AddressSpace
);
1825 if (Context
.Private
)
1827 Status
= MmCreateVirtualMapping(Process
,
1829 MemoryArea
->Protect
,
1832 MmSetDirtyPage(Process
, Address
);
1839 Status
= MmCreateVirtualMapping(Process
,
1841 MemoryArea
->Protect
,
1844 MmSetDirtyPage(Process
, Address
);
1848 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1849 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1851 MmUnlockAddressSpace(AddressSpace
);
1852 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1853 MmspCompleteAndReleasePageOp(PageOp
);
1854 return(STATUS_UNSUCCESSFUL
);
1858 * Otherwise we have succeeded.
1860 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1861 MmSetSavedSwapEntryPage(Page
, 0);
1862 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1863 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1865 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1869 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1872 if (Context
.Private
)
1874 MmLockAddressSpace(AddressSpace
);
1875 Status
= MmCreatePageFileMapping(Process
,
1878 MmUnlockAddressSpace(AddressSpace
);
1879 if (!NT_SUCCESS(Status
))
1881 KeBugCheck(MEMORY_MANAGEMENT
);
1886 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1887 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1890 PageOp
->Status
= STATUS_SUCCESS
;
1891 MmspCompleteAndReleasePageOp(PageOp
);
1892 return(STATUS_SUCCESS
);
1897 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
1898 PMEMORY_AREA MemoryArea
,
1903 PROS_SECTION_OBJECT Section
;
1904 PMM_SECTION_SEGMENT Segment
;
1906 SWAPENTRY SwapEntry
;
1910 PFILE_OBJECT FileObject
;
1912 BOOLEAN DirectMapped
;
1913 BOOLEAN IsImageSection
;
1914 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1916 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1918 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1919 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1922 * Get the segment and section.
1924 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1925 Section
= MemoryArea
->Data
.SectionData
.Section
;
1926 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1928 FileObject
= Section
->FileObject
;
1929 DirectMapped
= FALSE
;
1930 if (FileObject
!= NULL
&&
1931 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1933 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1936 * If the file system is letting us go directly to the cache and the
1937 * memory area was mapped at an offset in the file which is page aligned
1938 * then note this is a direct mapped page.
1940 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1941 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1943 DirectMapped
= TRUE
;
1948 * This should never happen since mappings of physical memory are never
1949 * placed in the rmap lists.
1951 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1953 DPRINT1("Trying to write back page from physical memory mapped at %X "
1954 "process %d\n", Address
,
1955 Process
? Process
->UniqueProcessId
: 0);
1956 KeBugCheck(MEMORY_MANAGEMENT
);
1960 * Get the section segment entry and the physical address.
1962 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1963 if (!MmIsPagePresent(Process
, Address
))
1965 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1966 Process
? Process
->UniqueProcessId
: 0, Address
);
1967 KeBugCheck(MEMORY_MANAGEMENT
);
1969 Page
= MmGetPfnForProcess(Process
, Address
);
1970 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1973 * Check for a private (COWed) page.
1975 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1976 IS_SWAP_FROM_SSE(Entry
) ||
1977 PFN_FROM_SSE(Entry
) != Page
)
1987 * Speculatively set all mappings of the page to clean.
1989 MmSetCleanAllRmaps(Page
);
1992 * If this page was direct mapped from the cache then the cache manager
1993 * will take care of writing it back to disk.
1995 if (DirectMapped
&& !Private
)
1997 ASSERT(SwapEntry
== 0);
1998 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1999 PageOp
->Status
= STATUS_SUCCESS
;
2000 MmspCompleteAndReleasePageOp(PageOp
);
2001 return(STATUS_SUCCESS
);
2005 * If necessary, allocate an entry in the paging file for this page
2009 SwapEntry
= MmAllocSwapPage();
2012 MmSetDirtyAllRmaps(Page
);
2013 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2014 MmspCompleteAndReleasePageOp(PageOp
);
2015 return(STATUS_PAGEFILE_QUOTA
);
2017 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2021 * Write the page to the pagefile
2023 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2024 if (!NT_SUCCESS(Status
))
2026 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2028 MmSetDirtyAllRmaps(Page
);
2029 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2030 MmspCompleteAndReleasePageOp(PageOp
);
2031 return(STATUS_UNSUCCESSFUL
);
2035 * Otherwise we have succeeded.
2037 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2038 PageOp
->Status
= STATUS_SUCCESS
;
2039 MmspCompleteAndReleasePageOp(PageOp
);
2040 return(STATUS_SUCCESS
);
2044 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2052 PMEMORY_AREA MemoryArea
;
2053 PMM_SECTION_SEGMENT Segment
;
2054 BOOLEAN DoCOW
= FALSE
;
2056 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2058 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2059 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2061 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
2062 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2067 if (OldProtect
!= NewProtect
)
2069 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2071 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2072 ULONG Protect
= NewProtect
;
2075 * If we doing COW for this segment then check if the page is
2078 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2084 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2085 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2086 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2087 Page
= MmGetPfnForProcess(Process
, Address
);
2089 Protect
= PAGE_READONLY
;
2090 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2091 IS_SWAP_FROM_SSE(Entry
) ||
2092 PFN_FROM_SSE(Entry
) != Page
)
2094 Protect
= NewProtect
;
2098 if (MmIsPagePresent(Process
, Address
))
2100 MmSetPageProtect(Process
, Address
,
2109 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2110 PMEMORY_AREA MemoryArea
,
2118 ULONG_PTR MaxLength
;
2120 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2121 if (Length
> MaxLength
)
2124 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2125 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2127 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2128 Region
->Protect
!= Protect
)
2130 return STATUS_INVALID_PAGE_PROTECTION
;
2133 *OldProtect
= Region
->Protect
;
2134 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2135 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2136 BaseAddress
, Length
, Region
->Type
, Protect
,
2137 MmAlterViewAttributes
);
2143 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2145 PMEMORY_BASIC_INFORMATION Info
,
2146 PSIZE_T ResultLength
)
2149 PVOID RegionBaseAddress
;
2150 PROS_SECTION_OBJECT Section
;
2151 PMM_SECTION_SEGMENT Segment
;
2153 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2154 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2155 Address
, &RegionBaseAddress
);
2158 return STATUS_UNSUCCESSFUL
;
2161 Section
= MemoryArea
->Data
.SectionData
.Section
;
2162 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2164 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2165 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2166 Info
->Type
= MEM_IMAGE
;
2170 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2171 Info
->Type
= MEM_MAPPED
;
2173 Info
->BaseAddress
= RegionBaseAddress
;
2174 Info
->AllocationProtect
= MemoryArea
->Protect
;
2175 Info
->RegionSize
= Region
->Length
;
2176 Info
->State
= MEM_COMMIT
;
2177 Info
->Protect
= Region
->Protect
;
2179 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2180 return(STATUS_SUCCESS
);
2185 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2190 ULONG SavedSwapEntry
;
2195 Length
= PAGE_ROUND_UP(Segment
->Length
);
2196 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2198 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2201 if (IS_SWAP_FROM_SSE(Entry
))
2203 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2207 Page
= PFN_FROM_SSE(Entry
);
2208 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2209 if (SavedSwapEntry
!= 0)
2211 MmSetSavedSwapEntryPage(Page
, 0);
2212 MmFreeSwapPage(SavedSwapEntry
);
2214 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2216 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2222 MmpDeleteSection(PVOID ObjectBody
)
2224 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2226 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2227 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2232 PMM_SECTION_SEGMENT SectionSegments
;
2235 * NOTE: Section->ImageSection can be NULL for short time
2236 * during the section creating. If we fail for some reason
2237 * until the image section is properly initialized we shouldn't
2238 * process further here.
2240 if (Section
->ImageSection
== NULL
)
2243 SectionSegments
= Section
->ImageSection
->Segments
;
2244 NrSegments
= Section
->ImageSection
->NrSegments
;
2246 for (i
= 0; i
< NrSegments
; i
++)
2248 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2250 MmLockSectionSegment(&SectionSegments
[i
]);
2252 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2253 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2257 MmpFreePageFileSegment(&SectionSegments
[i
]);
2259 MmUnlockSectionSegment(&SectionSegments
[i
]);
2266 * NOTE: Section->Segment can be NULL for short time
2267 * during the section creating.
2269 if (Section
->Segment
== NULL
)
2272 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2274 MmpFreePageFileSegment(Section
->Segment
);
2275 MmFreePageTablesSectionSegment(Section
->Segment
);
2276 ExFreePool(Section
->Segment
);
2277 Section
->Segment
= NULL
;
2281 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2284 if (Section
->FileObject
!= NULL
)
2286 CcRosDereferenceCache(Section
->FileObject
);
2287 ObDereferenceObject(Section
->FileObject
);
2288 Section
->FileObject
= NULL
;
2293 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2295 IN ACCESS_MASK GrantedAccess
,
2296 IN ULONG ProcessHandleCount
,
2297 IN ULONG SystemHandleCount
)
2299 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2300 Object
, ProcessHandleCount
);
2306 MmCreatePhysicalMemorySection(VOID
)
2308 PROS_SECTION_OBJECT PhysSection
;
2310 OBJECT_ATTRIBUTES Obj
;
2311 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2312 LARGE_INTEGER SectionSize
;
2316 * Create the section mapping physical memory
2318 SectionSize
.QuadPart
= 0xFFFFFFFF;
2319 InitializeObjectAttributes(&Obj
,
2324 Status
= MmCreateSection((PVOID
)&PhysSection
,
2328 PAGE_EXECUTE_READWRITE
,
2332 if (!NT_SUCCESS(Status
))
2334 DPRINT1("Failed to create PhysicalMemory section\n");
2335 KeBugCheck(MEMORY_MANAGEMENT
);
2337 Status
= ObInsertObject(PhysSection
,
2343 if (!NT_SUCCESS(Status
))
2345 ObDereferenceObject(PhysSection
);
2347 ObCloseHandle(Handle
, KernelMode
);
2348 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2349 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2351 return(STATUS_SUCCESS
);
2357 MmInitSectionImplementation(VOID
)
2359 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2360 UNICODE_STRING Name
;
2362 DPRINT("Creating Section Object Type\n");
2364 /* Initialize the Section object type */
2365 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2366 RtlInitUnicodeString(&Name
, L
"Section");
2367 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2368 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2369 ObjectTypeInitializer
.PoolType
= PagedPool
;
2370 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2371 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2372 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2373 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2374 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2375 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2377 MmCreatePhysicalMemorySection();
2379 return(STATUS_SUCCESS
);
2384 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2385 ACCESS_MASK DesiredAccess
,
2386 POBJECT_ATTRIBUTES ObjectAttributes
,
2387 PLARGE_INTEGER UMaximumSize
,
2388 ULONG SectionPageProtection
,
2389 ULONG AllocationAttributes
)
2391 * Create a section which is backed by the pagefile
2394 LARGE_INTEGER MaximumSize
;
2395 PROS_SECTION_OBJECT Section
;
2396 PMM_SECTION_SEGMENT Segment
;
2399 if (UMaximumSize
== NULL
)
2401 return(STATUS_UNSUCCESSFUL
);
2403 MaximumSize
= *UMaximumSize
;
2406 * Create the section
2408 Status
= ObCreateObject(ExGetPreviousMode(),
2409 MmSectionObjectType
,
2411 ExGetPreviousMode(),
2413 sizeof(ROS_SECTION_OBJECT
),
2416 (PVOID
*)(PVOID
)&Section
);
2417 if (!NT_SUCCESS(Status
))
2425 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2426 Section
->SectionPageProtection
= SectionPageProtection
;
2427 Section
->AllocationAttributes
= AllocationAttributes
;
2428 Section
->MaximumSize
= MaximumSize
;
2429 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2430 TAG_MM_SECTION_SEGMENT
);
2431 if (Segment
== NULL
)
2433 ObDereferenceObject(Section
);
2434 return(STATUS_NO_MEMORY
);
2436 Section
->Segment
= Segment
;
2437 Segment
->ReferenceCount
= 1;
2438 ExInitializeFastMutex(&Segment
->Lock
);
2439 Segment
->FileOffset
= 0;
2440 Segment
->Protection
= SectionPageProtection
;
2441 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2442 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2443 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2444 Segment
->WriteCopy
= FALSE
;
2445 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2446 Segment
->VirtualAddress
= 0;
2447 Segment
->Characteristics
= 0;
2448 *SectionObject
= Section
;
2449 return(STATUS_SUCCESS
);
2455 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2456 ACCESS_MASK DesiredAccess
,
2457 POBJECT_ATTRIBUTES ObjectAttributes
,
2458 PLARGE_INTEGER UMaximumSize
,
2459 ULONG SectionPageProtection
,
2460 ULONG AllocationAttributes
,
2463 * Create a section backed by a data file
2466 PROS_SECTION_OBJECT Section
;
2468 LARGE_INTEGER MaximumSize
;
2469 PFILE_OBJECT FileObject
;
2470 PMM_SECTION_SEGMENT Segment
;
2472 IO_STATUS_BLOCK Iosb
;
2473 LARGE_INTEGER Offset
;
2475 FILE_STANDARD_INFORMATION FileInfo
;
2479 * Create the section
2481 Status
= ObCreateObject(ExGetPreviousMode(),
2482 MmSectionObjectType
,
2484 ExGetPreviousMode(),
2486 sizeof(ROS_SECTION_OBJECT
),
2489 (PVOID
*)(PVOID
)&Section
);
2490 if (!NT_SUCCESS(Status
))
2497 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2498 Section
->SectionPageProtection
= SectionPageProtection
;
2499 Section
->AllocationAttributes
= AllocationAttributes
;
2502 * Check file access required
2504 if (SectionPageProtection
& PAGE_READWRITE
||
2505 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2507 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2511 FileAccess
= FILE_READ_DATA
;
2515 * Reference the file handle
2517 Status
= ObReferenceObjectByHandle(FileHandle
,
2520 ExGetPreviousMode(),
2521 (PVOID
*)(PVOID
)&FileObject
,
2523 if (!NT_SUCCESS(Status
))
2525 ObDereferenceObject(Section
);
2530 * FIXME: This is propably not entirely correct. We can't look into
2531 * the standard FCB header because it might not be initialized yet
2532 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2533 * standard file information is filled on first request).
2535 Status
= IoQueryFileInformation(FileObject
,
2536 FileStandardInformation
,
2537 sizeof(FILE_STANDARD_INFORMATION
),
2540 Iosb
.Information
= Length
;
2541 if (!NT_SUCCESS(Status
))
2543 ObDereferenceObject(Section
);
2544 ObDereferenceObject(FileObject
);
2549 * FIXME: Revise this once a locking order for file size changes is
2552 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2554 MaximumSize
= *UMaximumSize
;
2558 MaximumSize
= FileInfo
.EndOfFile
;
2559 /* Mapping zero-sized files isn't allowed. */
2560 if (MaximumSize
.QuadPart
== 0)
2562 ObDereferenceObject(Section
);
2563 ObDereferenceObject(FileObject
);
2564 return STATUS_FILE_INVALID
;
2568 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2570 Status
= IoSetInformation(FileObject
,
2571 FileAllocationInformation
,
2572 sizeof(LARGE_INTEGER
),
2574 if (!NT_SUCCESS(Status
))
2576 ObDereferenceObject(Section
);
2577 ObDereferenceObject(FileObject
);
2578 return(STATUS_SECTION_NOT_EXTENDED
);
2582 if (FileObject
->SectionObjectPointer
== NULL
||
2583 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2586 * Read a bit so caching is initiated for the file object.
2587 * This is only needed because MiReadPage currently cannot
2588 * handle non-cached streams.
2590 Offset
.QuadPart
= 0;
2591 Status
= ZwReadFile(FileHandle
,
2600 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2602 ObDereferenceObject(Section
);
2603 ObDereferenceObject(FileObject
);
2606 if (FileObject
->SectionObjectPointer
== NULL
||
2607 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2609 /* FIXME: handle this situation */
2610 ObDereferenceObject(Section
);
2611 ObDereferenceObject(FileObject
);
2612 return STATUS_INVALID_PARAMETER
;
2619 Status
= MmspWaitForFileLock(FileObject
);
2620 if (Status
!= STATUS_SUCCESS
)
2622 ObDereferenceObject(Section
);
2623 ObDereferenceObject(FileObject
);
2628 * If this file hasn't been mapped as a data file before then allocate a
2629 * section segment to describe the data file mapping
2631 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2633 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2634 TAG_MM_SECTION_SEGMENT
);
2635 if (Segment
== NULL
)
2637 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2638 ObDereferenceObject(Section
);
2639 ObDereferenceObject(FileObject
);
2640 return(STATUS_NO_MEMORY
);
2642 Section
->Segment
= Segment
;
2643 Segment
->ReferenceCount
= 1;
2644 ExInitializeFastMutex(&Segment
->Lock
);
2646 * Set the lock before assigning the segment to the file object
2648 ExAcquireFastMutex(&Segment
->Lock
);
2649 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2651 Segment
->FileOffset
= 0;
2652 Segment
->Protection
= SectionPageProtection
;
2653 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2654 Segment
->Characteristics
= 0;
2655 Segment
->WriteCopy
= FALSE
;
2656 if (AllocationAttributes
& SEC_RESERVE
)
2658 Segment
->Length
= Segment
->RawLength
= 0;
2662 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2663 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2665 Segment
->VirtualAddress
= 0;
2666 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2671 * If the file is already mapped as a data file then we may need
2675 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2677 Section
->Segment
= Segment
;
2678 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2679 MmLockSectionSegment(Segment
);
2681 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2682 !(AllocationAttributes
& SEC_RESERVE
))
2684 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2685 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2688 MmUnlockSectionSegment(Segment
);
2689 Section
->FileObject
= FileObject
;
2690 Section
->MaximumSize
= MaximumSize
;
2691 CcRosReferenceCache(FileObject
);
2692 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2693 *SectionObject
= Section
;
2694 return(STATUS_SUCCESS
);
2698 TODO: not that great (declaring loaders statically, having to declare all of
2699 them, having to keep them extern, etc.), will fix in the future
2701 extern NTSTATUS NTAPI PeFmtCreateSection
2703 IN CONST VOID
* FileHeader
,
2704 IN SIZE_T FileHeaderSize
,
2706 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2708 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2709 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2712 extern NTSTATUS NTAPI ElfFmtCreateSection
2714 IN CONST VOID
* FileHeader
,
2715 IN SIZE_T FileHeaderSize
,
2717 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2719 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2720 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2723 /* TODO: this is a standard DDK/PSDK macro */
2724 #ifndef RTL_NUMBER_OF
2725 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2728 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2739 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2741 SIZE_T SizeOfSegments
;
2742 PMM_SECTION_SEGMENT Segments
;
2744 /* TODO: check for integer overflow */
2745 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2747 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2749 TAG_MM_SECTION_SEGMENT
);
2752 RtlZeroMemory(Segments
, SizeOfSegments
);
2760 ExeFmtpReadFile(IN PVOID File
,
2761 IN PLARGE_INTEGER Offset
,
2764 OUT PVOID
* AllocBase
,
2765 OUT PULONG ReadSize
)
2768 LARGE_INTEGER FileOffset
;
2770 ULONG OffsetAdjustment
;
2775 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2779 KeBugCheck(MEMORY_MANAGEMENT
);
2782 FileOffset
= *Offset
;
2784 /* Negative/special offset: it cannot be used in this context */
2785 if(FileOffset
.u
.HighPart
< 0)
2787 KeBugCheck(MEMORY_MANAGEMENT
);
2790 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2791 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2792 FileOffset
.u
.LowPart
= AdjustOffset
;
2794 BufferSize
= Length
+ OffsetAdjustment
;
2795 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2798 * It's ok to use paged pool, because this is a temporary buffer only used in
2799 * the loading of executables. The assumption is that MmCreateSection is
2800 * always called at low IRQLs and that these buffers don't survive a brief
2801 * initialization phase
2803 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2808 KeBugCheck(MEMORY_MANAGEMENT
);
2814 Status
= MmspPageRead(File
,
2821 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2822 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2823 * to initialize internal state is even worse. Our cache manager is in need of
2827 IO_STATUS_BLOCK Iosb
;
2829 Status
= ZwReadFile(File
,
2839 if(NT_SUCCESS(Status
))
2841 UsedSize
= Iosb
.Information
;
2846 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2848 Status
= STATUS_IN_PAGE_ERROR
;
2849 ASSERT(!NT_SUCCESS(Status
));
2852 if(NT_SUCCESS(Status
))
2854 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2855 *AllocBase
= Buffer
;
2856 *ReadSize
= UsedSize
- OffsetAdjustment
;
2860 ExFreePoolWithTag(Buffer
, 'rXmM');
2867 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2868 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2869 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2874 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2878 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2880 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2881 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2888 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2892 MmspAssertSegmentsSorted(ImageSectionObject
);
2894 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2896 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2900 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2901 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2902 ImageSectionObject
->Segments
[i
- 1].Length
));
2910 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2914 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2916 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2917 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2925 MmspCompareSegments(const void * x
,
2928 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2929 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2932 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2933 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2937 * Ensures an image section's segments are sorted in memory
2942 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2945 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2947 MmspAssertSegmentsSorted(ImageSectionObject
);
2951 qsort(ImageSectionObject
->Segments
,
2952 ImageSectionObject
->NrSegments
,
2953 sizeof(ImageSectionObject
->Segments
[0]),
2954 MmspCompareSegments
);
2960 * Ensures an image section's segments don't overlap in memory and don't have
2961 * gaps and don't have a null size. We let them map to overlapping file regions,
2962 * though - that's not necessarily an error
2967 MmspCheckSegmentBounds
2969 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2975 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2977 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2981 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2983 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2985 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2993 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2994 * page could be OK (Windows seems to be OK with them), and larger gaps
2995 * could lead to image sections spanning several discontiguous regions
2996 * (NtMapViewOfSection could then refuse to map them, and they could
2997 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2999 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
3000 ImageSectionObject
->Segments
[i
- 1].Length
) !=
3001 ImageSectionObject
->Segments
[i
].VirtualAddress
)
3012 * Merges and pads an image section's segments until they all are page-aligned
3013 * and have a size that is a multiple of the page size
3018 MmspPageAlignSegments
3020 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3026 BOOLEAN Initialized
;
3027 PMM_SECTION_SEGMENT EffectiveSegment
;
3029 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3031 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3035 Initialized
= FALSE
;
3037 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3039 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3042 * The first segment requires special handling
3046 ULONG_PTR VirtualAddress
;
3047 ULONG_PTR VirtualOffset
;
3049 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
3051 /* Round down the virtual address to the nearest page */
3052 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3054 /* Round up the virtual size to the nearest page */
3055 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3056 EffectiveSegment
->VirtualAddress
;
3058 /* Adjust the raw address and size */
3059 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3061 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3067 * Garbage in, garbage out: unaligned base addresses make the file
3068 * offset point in curious and odd places, but that's what we were
3071 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3072 EffectiveSegment
->RawLength
+= VirtualOffset
;
3076 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3077 ULONG_PTR EndOfEffectiveSegment
;
3079 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3080 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3083 * The current segment begins exactly where the current effective
3084 * segment ended, therefore beginning a new effective segment
3086 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3089 ASSERT(LastSegment
<= i
);
3090 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3092 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3094 if (LastSegment
!= i
)
3097 * Copy the current segment. If necessary, the effective segment
3098 * will be expanded later
3100 *EffectiveSegment
= *Segment
;
3104 * Page-align the virtual size. We know for sure the virtual address
3107 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3108 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3111 * The current segment is still part of the current effective segment:
3112 * extend the effective segment to reflect this
3114 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3116 static const ULONG FlagsToProtection
[16] =
3124 PAGE_EXECUTE_READWRITE
,
3125 PAGE_EXECUTE_READWRITE
,
3130 PAGE_EXECUTE_WRITECOPY
,
3131 PAGE_EXECUTE_WRITECOPY
,
3132 PAGE_EXECUTE_WRITECOPY
,
3133 PAGE_EXECUTE_WRITECOPY
3136 unsigned ProtectionFlags
;
3139 * Extend the file size
3142 /* Unaligned segments must be contiguous within the file */
3143 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3144 EffectiveSegment
->RawLength
))
3149 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3152 * Extend the virtual size
3154 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3156 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3157 EffectiveSegment
->VirtualAddress
;
3160 * Merge the protection
3162 EffectiveSegment
->Protection
|= Segment
->Protection
;
3164 /* Clean up redundance */
3165 ProtectionFlags
= 0;
3167 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3168 ProtectionFlags
|= 1 << 0;
3170 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3171 ProtectionFlags
|= 1 << 1;
3173 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3174 ProtectionFlags
|= 1 << 2;
3176 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3177 ProtectionFlags
|= 1 << 3;
3179 ASSERT(ProtectionFlags
< 16);
3180 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3182 /* If a segment was required to be shared and cannot, fail */
3183 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3184 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3190 * We assume no holes between segments at this point
3194 KeBugCheck(MEMORY_MANAGEMENT
);
3198 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3204 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3205 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3207 LARGE_INTEGER Offset
;
3209 PVOID FileHeaderBuffer
;
3210 ULONG FileHeaderSize
;
3212 ULONG OldNrSegments
;
3217 * Read the beginning of the file (2 pages). Should be enough to contain
3218 * all (or most) of the headers
3220 Offset
.QuadPart
= 0;
3222 /* FIXME: use FileObject instead of FileHandle */
3223 Status
= ExeFmtpReadFile (FileHandle
,
3230 if (!NT_SUCCESS(Status
))
3233 if (FileHeaderSize
== 0)
3235 ExFreePool(FileHeaderBuffer
);
3236 return STATUS_UNSUCCESSFUL
;
3240 * Look for a loader that can handle this executable
3242 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3244 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3247 /* FIXME: use FileObject instead of FileHandle */
3248 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3254 ExeFmtpAllocateSegments
);
3256 if (!NT_SUCCESS(Status
))
3258 if (ImageSectionObject
->Segments
)
3260 ExFreePool(ImageSectionObject
->Segments
);
3261 ImageSectionObject
->Segments
= NULL
;
3265 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3269 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3272 * No loader handled the format
3274 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3276 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3277 ASSERT(!NT_SUCCESS(Status
));
3280 if (!NT_SUCCESS(Status
))
3283 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3288 /* FIXME? are these values platform-dependent? */
3289 if(ImageSectionObject
->StackReserve
== 0)
3290 ImageSectionObject
->StackReserve
= 0x40000;
3292 if(ImageSectionObject
->StackCommit
== 0)
3293 ImageSectionObject
->StackCommit
= 0x1000;
3295 if(ImageSectionObject
->ImageBase
== 0)
3297 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3298 ImageSectionObject
->ImageBase
= 0x10000000;
3300 ImageSectionObject
->ImageBase
= 0x00400000;
3304 * And now the fun part: fixing the segments
3307 /* Sort them by virtual address */
3308 MmspSortSegments(ImageSectionObject
, Flags
);
3310 /* Ensure they don't overlap in memory */
3311 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3312 return STATUS_INVALID_IMAGE_FORMAT
;
3314 /* Ensure they are aligned */
3315 OldNrSegments
= ImageSectionObject
->NrSegments
;
3317 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3318 return STATUS_INVALID_IMAGE_FORMAT
;
3320 /* Trim them if the alignment phase merged some of them */
3321 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3323 PMM_SECTION_SEGMENT Segments
;
3324 SIZE_T SizeOfSegments
;
3326 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3328 Segments
= ExAllocatePoolWithTag(PagedPool
,
3330 TAG_MM_SECTION_SEGMENT
);
3332 if (Segments
== NULL
)
3333 return STATUS_INSUFFICIENT_RESOURCES
;
3335 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3336 ExFreePool(ImageSectionObject
->Segments
);
3337 ImageSectionObject
->Segments
= Segments
;
3340 /* And finish their initialization */
3341 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3343 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3344 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3346 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3347 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3350 ASSERT(NT_SUCCESS(Status
));
3355 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3356 ACCESS_MASK DesiredAccess
,
3357 POBJECT_ATTRIBUTES ObjectAttributes
,
3358 PLARGE_INTEGER UMaximumSize
,
3359 ULONG SectionPageProtection
,
3360 ULONG AllocationAttributes
,
3363 PROS_SECTION_OBJECT Section
;
3365 PFILE_OBJECT FileObject
;
3366 PMM_SECTION_SEGMENT SectionSegments
;
3367 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3369 ULONG FileAccess
= 0;
3372 * Specifying a maximum size is meaningless for an image section
3374 if (UMaximumSize
!= NULL
)
3376 return(STATUS_INVALID_PARAMETER_4
);
3380 * Check file access required
3382 if (SectionPageProtection
& PAGE_READWRITE
||
3383 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3385 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3389 FileAccess
= FILE_READ_DATA
;
3393 * Reference the file handle
3395 Status
= ObReferenceObjectByHandle(FileHandle
,
3398 ExGetPreviousMode(),
3399 (PVOID
*)(PVOID
)&FileObject
,
3402 if (!NT_SUCCESS(Status
))
3408 * Create the section
3410 Status
= ObCreateObject (ExGetPreviousMode(),
3411 MmSectionObjectType
,
3413 ExGetPreviousMode(),
3415 sizeof(ROS_SECTION_OBJECT
),
3418 (PVOID
*)(PVOID
)&Section
);
3419 if (!NT_SUCCESS(Status
))
3421 ObDereferenceObject(FileObject
);
3428 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3429 Section
->SectionPageProtection
= SectionPageProtection
;
3430 Section
->AllocationAttributes
= AllocationAttributes
;
3433 * Initialized caching for this file object if previously caching
3434 * was initialized for the same on disk file
3436 Status
= CcTryToInitializeFileCache(FileObject
);
3438 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3440 NTSTATUS StatusExeFmt
;
3442 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3443 if (ImageSectionObject
== NULL
)
3445 ObDereferenceObject(FileObject
);
3446 ObDereferenceObject(Section
);
3447 return(STATUS_NO_MEMORY
);
3450 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3452 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3454 if (!NT_SUCCESS(StatusExeFmt
))
3456 if(ImageSectionObject
->Segments
!= NULL
)
3457 ExFreePool(ImageSectionObject
->Segments
);
3459 ExFreePool(ImageSectionObject
);
3460 ObDereferenceObject(Section
);
3461 ObDereferenceObject(FileObject
);
3462 return(StatusExeFmt
);
3465 Section
->ImageSection
= ImageSectionObject
;
3466 ASSERT(ImageSectionObject
->Segments
);
3471 Status
= MmspWaitForFileLock(FileObject
);
3472 if (!NT_SUCCESS(Status
))
3474 ExFreePool(ImageSectionObject
->Segments
);
3475 ExFreePool(ImageSectionObject
);
3476 ObDereferenceObject(Section
);
3477 ObDereferenceObject(FileObject
);
3481 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3482 ImageSectionObject
, NULL
))
3485 * An other thread has initialized the same image in the background
3487 ExFreePool(ImageSectionObject
->Segments
);
3488 ExFreePool(ImageSectionObject
);
3489 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3490 Section
->ImageSection
= ImageSectionObject
;
3491 SectionSegments
= ImageSectionObject
->Segments
;
3493 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3495 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3499 Status
= StatusExeFmt
;
3506 Status
= MmspWaitForFileLock(FileObject
);
3507 if (Status
!= STATUS_SUCCESS
)
3509 ObDereferenceObject(Section
);
3510 ObDereferenceObject(FileObject
);
3514 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3515 Section
->ImageSection
= ImageSectionObject
;
3516 SectionSegments
= ImageSectionObject
->Segments
;
3519 * Otherwise just reference all the section segments
3521 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3523 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3526 Status
= STATUS_SUCCESS
;
3528 Section
->FileObject
= FileObject
;
3529 CcRosReferenceCache(FileObject
);
3530 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3531 *SectionObject
= Section
;
3539 NtCreateSection (OUT PHANDLE SectionHandle
,
3540 IN ACCESS_MASK DesiredAccess
,
3541 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3542 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3543 IN ULONG SectionPageProtection OPTIONAL
,
3544 IN ULONG AllocationAttributes
,
3545 IN HANDLE FileHandle OPTIONAL
)
3547 LARGE_INTEGER SafeMaximumSize
;
3548 PVOID SectionObject
;
3549 KPROCESSOR_MODE PreviousMode
;
3552 PreviousMode
= ExGetPreviousMode();
3554 if(PreviousMode
!= KernelMode
)
3558 if (MaximumSize
!= NULL
)
3560 /* make a copy on the stack */
3561 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3562 MaximumSize
= &SafeMaximumSize
;
3564 ProbeForWriteHandle(SectionHandle
);
3566 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3568 /* Return the exception code */
3569 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3574 Status
= MmCreateSection(&SectionObject
,
3578 SectionPageProtection
,
3579 AllocationAttributes
,
3582 if (NT_SUCCESS(Status
))
3584 Status
= ObInsertObject ((PVOID
)SectionObject
,
3596 /**********************************************************************
3614 NtOpenSection(PHANDLE SectionHandle
,
3615 ACCESS_MASK DesiredAccess
,
3616 POBJECT_ATTRIBUTES ObjectAttributes
)
3619 KPROCESSOR_MODE PreviousMode
;
3622 PreviousMode
= ExGetPreviousMode();
3624 if(PreviousMode
!= KernelMode
)
3628 ProbeForWriteHandle(SectionHandle
);
3630 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3632 /* Return the exception code */
3633 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3638 Status
= ObOpenObjectByName(ObjectAttributes
,
3639 MmSectionObjectType
,
3646 if(NT_SUCCESS(Status
))
3650 *SectionHandle
= hSection
;
3652 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3654 Status
= _SEH2_GetExceptionCode();
3663 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3664 PROS_SECTION_OBJECT Section
,
3665 PMM_SECTION_SEGMENT Segment
,
3670 ULONG AllocationType
)
3674 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3676 BoundaryAddressMultiple
.QuadPart
= 0;
3678 Status
= MmCreateMemoryArea(AddressSpace
,
3679 MEMORY_AREA_SECTION_VIEW
,
3686 BoundaryAddressMultiple
);
3687 if (!NT_SUCCESS(Status
))
3689 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3690 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3694 ObReferenceObject((PVOID
)Section
);
3696 MArea
->Data
.SectionData
.Segment
= Segment
;
3697 MArea
->Data
.SectionData
.Section
= Section
;
3698 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3699 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3700 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3701 ViewSize
, 0, Protect
);
3703 return(STATUS_SUCCESS
);
3707 /**********************************************************************
3709 * NtMapViewOfSection
3712 * Maps a view of a section into the virtual address space of a
3717 * Handle of the section.
3720 * Handle of the process.
3723 * Desired base address (or NULL) on entry;
3724 * Actual base address of the view on exit.
3727 * Number of high order address bits that must be zero.
3730 * Size in bytes of the initially committed section of
3734 * Offset in bytes from the beginning of the section
3735 * to the beginning of the view.
3738 * Desired length of map (or zero to map all) on entry
3739 * Actual length mapped on exit.
3741 * InheritDisposition
3742 * Specified how the view is to be shared with
3746 * Type of allocation for the pages.
3749 * Protection for the committed region of the view.
3757 NtMapViewOfSection(IN HANDLE SectionHandle
,
3758 IN HANDLE ProcessHandle
,
3759 IN OUT PVOID
* BaseAddress OPTIONAL
,
3760 IN ULONG_PTR ZeroBits OPTIONAL
,
3761 IN SIZE_T CommitSize
,
3762 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3763 IN OUT PSIZE_T ViewSize
,
3764 IN SECTION_INHERIT InheritDisposition
,
3765 IN ULONG AllocationType OPTIONAL
,
3768 PVOID SafeBaseAddress
;
3769 LARGE_INTEGER SafeSectionOffset
;
3770 SIZE_T SafeViewSize
;
3771 PROS_SECTION_OBJECT Section
;
3773 KPROCESSOR_MODE PreviousMode
;
3774 PMMSUPPORT AddressSpace
;
3777 ACCESS_MASK DesiredAccess
;
3780 * Check the protection
3782 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3784 return STATUS_INVALID_PARAMETER_10
;
3787 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3788 if (tmpProtect
!= PAGE_NOACCESS
&&
3789 tmpProtect
!= PAGE_READONLY
&&
3790 tmpProtect
!= PAGE_READWRITE
&&
3791 tmpProtect
!= PAGE_WRITECOPY
&&
3792 tmpProtect
!= PAGE_EXECUTE
&&
3793 tmpProtect
!= PAGE_EXECUTE_READ
&&
3794 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3795 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3797 return STATUS_INVALID_PAGE_PROTECTION
;
3800 PreviousMode
= ExGetPreviousMode();
3802 if(PreviousMode
!= KernelMode
)
3804 SafeBaseAddress
= NULL
;
3805 SafeSectionOffset
.QuadPart
= 0;
3810 if(BaseAddress
!= NULL
)
3812 ProbeForWritePointer(BaseAddress
);
3813 SafeBaseAddress
= *BaseAddress
;
3815 if(SectionOffset
!= NULL
)
3817 ProbeForWriteLargeInteger(SectionOffset
);
3818 SafeSectionOffset
= *SectionOffset
;
3820 ProbeForWriteSize_t(ViewSize
);
3821 SafeViewSize
= *ViewSize
;
3823 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3825 /* Return the exception code */
3826 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3832 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3833 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3834 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3837 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3839 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3840 PROCESS_VM_OPERATION
,
3843 (PVOID
*)(PVOID
)&Process
,
3845 if (!NT_SUCCESS(Status
))
3850 AddressSpace
= &Process
->Vm
;
3852 /* Convert NT Protection Attr to Access Mask */
3853 if (Protect
== PAGE_READONLY
)
3855 DesiredAccess
= SECTION_MAP_READ
;
3857 else if (Protect
== PAGE_READWRITE
)
3859 DesiredAccess
= SECTION_MAP_WRITE
;
3861 else if (Protect
== PAGE_WRITECOPY
)
3863 DesiredAccess
= SECTION_QUERY
;
3865 /* FIXME: Handle other Protection Attributes. For now keep previous behavior */
3868 DesiredAccess
= SECTION_MAP_READ
;
3871 Status
= ObReferenceObjectByHandle(SectionHandle
,
3873 MmSectionObjectType
,
3875 (PVOID
*)(PVOID
)&Section
,
3877 if (!(NT_SUCCESS(Status
)))
3879 DPRINT("ObReference failed rc=%x\n",Status
);
3880 ObDereferenceObject(Process
);
3884 Status
= MmMapViewOfSection(Section
,
3886 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3889 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3890 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3895 /* Check if this is an image for the current process */
3896 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3897 (Process
== PsGetCurrentProcess()) &&
3898 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3900 /* Notify the debugger */
3901 DbgkMapViewOfSection(Section
,
3903 SafeSectionOffset
.LowPart
,
3907 ObDereferenceObject(Section
);
3908 ObDereferenceObject(Process
);
3910 if(NT_SUCCESS(Status
))
3912 /* copy parameters back to the caller */
3915 if(BaseAddress
!= NULL
)
3917 *BaseAddress
= SafeBaseAddress
;
3919 if(SectionOffset
!= NULL
)
3921 *SectionOffset
= SafeSectionOffset
;
3923 if(ViewSize
!= NULL
)
3925 *ViewSize
= SafeViewSize
;
3928 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3930 Status
= _SEH2_GetExceptionCode();
3939 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3940 PFN_NUMBER Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3943 PFILE_OBJECT FileObject
;
3946 SWAPENTRY SavedSwapEntry
;
3949 PROS_SECTION_OBJECT Section
;
3950 PMM_SECTION_SEGMENT Segment
;
3951 PMMSUPPORT AddressSpace
;
3954 AddressSpace
= (PMMSUPPORT
)Context
;
3955 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3957 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3959 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3960 MemoryArea
->Data
.SectionData
.ViewOffset
;
3962 Section
= MemoryArea
->Data
.SectionData
.Section
;
3963 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3965 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3969 MmUnlockSectionSegment(Segment
);
3970 MmUnlockAddressSpace(AddressSpace
);
3972 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3973 if (Status
!= STATUS_SUCCESS
)
3975 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3976 KeBugCheck(MEMORY_MANAGEMENT
);
3979 MmLockAddressSpace(AddressSpace
);
3980 MmLockSectionSegment(Segment
);
3981 MmspCompleteAndReleasePageOp(PageOp
);
3982 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3985 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3988 * For a dirty, datafile, non-private page mark it as dirty in the
3991 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3993 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3995 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3996 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3997 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3998 ASSERT(SwapEntry
== 0);
4007 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4009 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4010 KeBugCheck(MEMORY_MANAGEMENT
);
4012 MmFreeSwapPage(SwapEntry
);
4016 if (IS_SWAP_FROM_SSE(Entry
) ||
4017 Page
!= PFN_FROM_SSE(Entry
))
4022 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4024 DPRINT1("Found a private page in a pagefile section.\n");
4025 KeBugCheck(MEMORY_MANAGEMENT
);
4028 * Just dereference private pages
4030 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4031 if (SavedSwapEntry
!= 0)
4033 MmFreeSwapPage(SavedSwapEntry
);
4034 MmSetSavedSwapEntryPage(Page
, 0);
4036 MmDeleteRmap(Page
, Process
, Address
);
4037 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4041 MmDeleteRmap(Page
, Process
, Address
);
4042 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
4048 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4052 PMEMORY_AREA MemoryArea
;
4053 PROS_SECTION_OBJECT Section
;
4054 PMM_SECTION_SEGMENT Segment
;
4055 PLIST_ENTRY CurrentEntry
;
4056 PMM_REGION CurrentRegion
;
4057 PLIST_ENTRY RegionListHead
;
4059 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4061 if (MemoryArea
== NULL
)
4063 return(STATUS_UNSUCCESSFUL
);
4066 MemoryArea
->DeleteInProgress
= TRUE
;
4067 Section
= MemoryArea
->Data
.SectionData
.Section
;
4068 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4070 MmLockSectionSegment(Segment
);
4072 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4073 while (!IsListEmpty(RegionListHead
))
4075 CurrentEntry
= RemoveHeadList(RegionListHead
);
4076 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4077 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4080 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4082 Status
= MmFreeMemoryArea(AddressSpace
,
4089 Status
= MmFreeMemoryArea(AddressSpace
,
4094 MmUnlockSectionSegment(Segment
);
4095 ObDereferenceObject(Section
);
4096 return(STATUS_SUCCESS
);
4103 MmUnmapViewOfSection(PEPROCESS Process
,
4107 PMEMORY_AREA MemoryArea
;
4108 PMMSUPPORT AddressSpace
;
4109 PROS_SECTION_OBJECT Section
;
4112 PVOID ImageBaseAddress
= 0;
4114 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4115 Process
, BaseAddress
);
4119 AddressSpace
= &Process
->Vm
;
4121 MmLockAddressSpace(AddressSpace
);
4122 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4124 if (MemoryArea
== NULL
||
4125 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4126 MemoryArea
->DeleteInProgress
)
4128 MmUnlockAddressSpace(AddressSpace
);
4129 return STATUS_NOT_MAPPED_VIEW
;
4132 MemoryArea
->DeleteInProgress
= TRUE
;
4134 while (MemoryArea
->PageOpCount
)
4136 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4140 Offset
-= PAGE_SIZE
;
4141 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4142 MemoryArea
->Data
.SectionData
.Segment
,
4143 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4146 MmUnlockAddressSpace(AddressSpace
);
4147 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4148 if (Status
!= STATUS_SUCCESS
)
4150 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4151 KeBugCheck(MEMORY_MANAGEMENT
);
4153 MmLockAddressSpace(AddressSpace
);
4154 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4156 if (MemoryArea
== NULL
||
4157 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4159 MmUnlockAddressSpace(AddressSpace
);
4160 return STATUS_NOT_MAPPED_VIEW
;
4167 Section
= MemoryArea
->Data
.SectionData
.Section
;
4169 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4173 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4174 PMM_SECTION_SEGMENT SectionSegments
;
4175 PMM_SECTION_SEGMENT Segment
;
4177 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4178 ImageSectionObject
= Section
->ImageSection
;
4179 SectionSegments
= ImageSectionObject
->Segments
;
4180 NrSegments
= ImageSectionObject
->NrSegments
;
4182 /* Search for the current segment within the section segments
4183 * and calculate the image base address */
4184 for (i
= 0; i
< NrSegments
; i
++)
4186 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4188 if (Segment
== &SectionSegments
[i
])
4190 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4195 if (i
>= NrSegments
)
4197 KeBugCheck(MEMORY_MANAGEMENT
);
4200 for (i
= 0; i
< NrSegments
; i
++)
4202 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4204 PVOID SBaseAddress
= (PVOID
)
4205 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4207 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4213 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4216 MmUnlockAddressSpace(AddressSpace
);
4218 /* Notify debugger */
4219 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4221 return(STATUS_SUCCESS
);
4224 /**********************************************************************
4226 * NtUnmapViewOfSection
4241 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4245 KPROCESSOR_MODE PreviousMode
;
4248 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4249 ProcessHandle
, BaseAddress
);
4251 PreviousMode
= ExGetPreviousMode();
4253 DPRINT("Referencing process\n");
4254 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4255 PROCESS_VM_OPERATION
,
4258 (PVOID
*)(PVOID
)&Process
,
4260 if (!NT_SUCCESS(Status
))
4262 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4266 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4268 ObDereferenceObject(Process
);
4275 * Queries the information of a section object.
4277 * @param SectionHandle
4278 * Handle to the section object. It must be opened with SECTION_QUERY
4280 * @param SectionInformationClass
4281 * Index to a certain information structure. Can be either
4282 * SectionBasicInformation or SectionImageInformation. The latter
4283 * is valid only for sections that were created with the SEC_IMAGE
4285 * @param SectionInformation
4286 * Caller supplies storage for resulting information.
4288 * Size of the supplied storage.
4289 * @param ResultLength
4297 NtQuerySection(IN HANDLE SectionHandle
,
4298 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4299 OUT PVOID SectionInformation
,
4300 IN SIZE_T SectionInformationLength
,
4301 OUT PSIZE_T ResultLength OPTIONAL
)
4303 PROS_SECTION_OBJECT Section
;
4304 KPROCESSOR_MODE PreviousMode
;
4308 PreviousMode
= ExGetPreviousMode();
4310 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4312 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4314 SectionInformationLength
,
4319 if(!NT_SUCCESS(Status
))
4321 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4325 Status
= ObReferenceObjectByHandle(SectionHandle
,
4327 MmSectionObjectType
,
4329 (PVOID
*)(PVOID
)&Section
,
4331 if (NT_SUCCESS(Status
))
4333 switch (SectionInformationClass
)
4335 case SectionBasicInformation
:
4337 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4341 Sbi
->Attributes
= Section
->AllocationAttributes
;
4342 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4344 Sbi
->BaseAddress
= 0;
4345 Sbi
->Size
.QuadPart
= 0;
4349 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4350 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4353 if (ResultLength
!= NULL
)
4355 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4357 Status
= STATUS_SUCCESS
;
4359 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4361 Status
= _SEH2_GetExceptionCode();
4368 case SectionImageInformation
:
4370 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4374 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4375 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4377 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4378 ImageSectionObject
= Section
->ImageSection
;
4380 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4381 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4382 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4383 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4384 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4385 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4386 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4387 Sii
->Machine
= ImageSectionObject
->Machine
;
4388 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4391 if (ResultLength
!= NULL
)
4393 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4395 Status
= STATUS_SUCCESS
;
4397 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4399 Status
= _SEH2_GetExceptionCode();
4407 ObDereferenceObject(Section
);
4415 * Extends size of file backed section.
4417 * @param SectionHandle
4418 * Handle to the section object. It must be opened with
4419 * SECTION_EXTEND_SIZE access.
4420 * @param NewMaximumSize
4421 * New maximum size of the section in bytes.
4425 * @todo Move the actual code to internal function MmExtendSection.
4429 NtExtendSection(IN HANDLE SectionHandle
,
4430 IN PLARGE_INTEGER NewMaximumSize
)
4432 LARGE_INTEGER SafeNewMaximumSize
;
4433 PROS_SECTION_OBJECT Section
;
4434 KPROCESSOR_MODE PreviousMode
;
4437 PreviousMode
= ExGetPreviousMode();
4439 if(PreviousMode
!= KernelMode
)
4443 /* make a copy on the stack */
4444 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4445 NewMaximumSize
= &SafeNewMaximumSize
;
4447 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4449 /* Return the exception code */
4450 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4455 Status
= ObReferenceObjectByHandle(SectionHandle
,
4456 SECTION_EXTEND_SIZE
,
4457 MmSectionObjectType
,
4461 if (!NT_SUCCESS(Status
))
4466 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4468 ObDereferenceObject(Section
);
4469 return STATUS_INVALID_PARAMETER
;
4473 * - Acquire file extneding resource.
4474 * - Check if we're not resizing the section below it's actual size!
4475 * - Extend segments if needed.
4476 * - Set file information (FileAllocationInformation) to the new size.
4477 * - Release file extending resource.
4480 ObDereferenceObject(Section
);
4482 return STATUS_NOT_IMPLEMENTED
;
4486 /**********************************************************************
4488 * MmAllocateSection@4
4498 * Code taken from ntoskrnl/mm/special.c.
4503 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4505 PHYSICAL_ADDRESS LowAddress
, HighAddress
, SkipBytes
;
4507 PFN_COUNT PageCount
;
4508 PPFN_NUMBER MdlPages
;
4509 MMPTE TempPte
, *PointerPte
;
4512 /* Allocate an MDL */
4513 LowAddress
.QuadPart
= 0;
4514 HighAddress
.QuadPart
= -1;
4515 SkipBytes
.QuadPart
= 0;
4516 Mdl
= MiAllocatePagesForMdl(LowAddress
,
4520 MiPlatformCacheAttributes
[0][MmCached
],
4521 0); // use MM_ALLOCATE_FULLY_REQUIRED
4528 /* Check if we got all we need */
4529 if (Mdl
->ByteCount
< Length
)
4531 /* We didn't get enough */
4532 MmFreePagesFromMdl(Mdl
);
4537 /* Calculate how many pages we should have */
4538 PageCount
= BYTES_TO_PAGES(Length
);
4540 /* Reserve system PTEs */
4541 PointerPte
= MiReserveSystemPtes(PageCount
, SystemPteSpace
);
4544 /* Free the MDL and fail */
4545 MmFreePagesFromMdl(Mdl
);
4550 /* Safe the base address */
4551 BaseAddress
= MiPteToAddress(PointerPte
);
4553 /* Get a pointer to the page array */
4554 MdlPages
= (PPFN_NUMBER
)(Mdl
+ 1);
4556 /* Get the first page's PFN entry */
4557 Pfn
= MI_PFN_ELEMENT(*MdlPages
);
4559 /* Save the pointer to the MDL in the PFN entry */
4560 *(PMDL
*)&Pfn
->OriginalPte
= Mdl
;
4562 /* Setup template PTE */
4563 TempPte
= HyperTemplatePte
;
4569 ASSERT(PointerPte
->u
.Hard
.Valid
== 0);
4570 ASSERT(PointerPte
->u
.Soft
.Transition
== 0);
4573 TempPte
.u
.Hard
.PageFrameNumber
= *MdlPages
++;
4576 *PointerPte
++ = TempPte
;
4577 } while (--PageCount
);
4579 /* Return the base address */
4585 MmFreeSection(PVOID BaseAddress
)
4588 PFN_NUMBER
*MdlPages
, PageFrameNumber
, PageCount
;
4592 /* Get a pointer to the first PTE */
4593 PointerPte
= MiAddressToPte(BaseAddress
);
4595 /* Get the page frame number of the first page */
4596 PageFrameNumber
= PFN_FROM_PTE(PointerPte
);
4598 /* Get the first pages's PFN entry */
4599 Pfn
= MI_PFN_ELEMENT(PageFrameNumber
);
4601 /* Get the MDL from the PFN */
4602 Mdl
= *(PMDL
*)&Pfn
->OriginalPte
;
4603 *(PMDL
*)&Pfn
->OriginalPte
= NULL
;
4605 /* Get the page array and count from the MDL */
4606 MdlPages
= (PPFN_NUMBER
)(Mdl
+ 1);
4607 PageCount
= BYTES_TO_PAGES(Mdl
->ByteCount
);
4609 /* Release the system PTEs */
4610 MiReleaseSystemPtes(PointerPte
, PageCount
, SystemPteSpace
);
4612 /* Free the pages and the MDL */
4613 MmFreePagesFromMdl(Mdl
);
4617 /**********************************************************************
4619 * MmMapViewOfSection
4622 * Maps a view of a section into the virtual address space of a
4627 * Pointer to the section object.
4630 * Pointer to the process.
4633 * Desired base address (or NULL) on entry;
4634 * Actual base address of the view on exit.
4637 * Number of high order address bits that must be zero.
4640 * Size in bytes of the initially committed section of
4644 * Offset in bytes from the beginning of the section
4645 * to the beginning of the view.
4648 * Desired length of map (or zero to map all) on entry
4649 * Actual length mapped on exit.
4651 * InheritDisposition
4652 * Specified how the view is to be shared with
4656 * Type of allocation for the pages.
4659 * Protection for the committed region of the view.
4667 MmMapViewOfSection(IN PVOID SectionObject
,
4668 IN PEPROCESS Process
,
4669 IN OUT PVOID
*BaseAddress
,
4670 IN ULONG_PTR ZeroBits
,
4671 IN SIZE_T CommitSize
,
4672 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4673 IN OUT PSIZE_T ViewSize
,
4674 IN SECTION_INHERIT InheritDisposition
,
4675 IN ULONG AllocationType
,
4678 PROS_SECTION_OBJECT Section
;
4679 PMMSUPPORT AddressSpace
;
4681 NTSTATUS Status
= STATUS_SUCCESS
;
4685 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4687 return STATUS_INVALID_PAGE_PROTECTION
;
4691 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4692 AddressSpace
= &Process
->Vm
;
4694 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4696 MmLockAddressSpace(AddressSpace
);
4698 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4702 ULONG_PTR ImageBase
;
4704 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4705 PMM_SECTION_SEGMENT SectionSegments
;
4707 ImageSectionObject
= Section
->ImageSection
;
4708 SectionSegments
= ImageSectionObject
->Segments
;
4709 NrSegments
= ImageSectionObject
->NrSegments
;
4712 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4715 ImageBase
= ImageSectionObject
->ImageBase
;
4719 for (i
= 0; i
< NrSegments
; i
++)
4721 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4723 ULONG_PTR MaxExtent
;
4724 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4725 SectionSegments
[i
].Length
;
4726 ImageSize
= max(ImageSize
, MaxExtent
);
4730 ImageSectionObject
->ImageSize
= ImageSize
;
4732 /* Check there is enough space to map the section at that point. */
4733 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4734 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4736 /* Fail if the user requested a fixed base address. */
4737 if ((*BaseAddress
) != NULL
)
4739 MmUnlockAddressSpace(AddressSpace
);
4740 return(STATUS_UNSUCCESSFUL
);
4742 /* Otherwise find a gap to map the image. */
4743 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4746 MmUnlockAddressSpace(AddressSpace
);
4747 return(STATUS_UNSUCCESSFUL
);
4751 for (i
= 0; i
< NrSegments
; i
++)
4753 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4755 PVOID SBaseAddress
= (PVOID
)
4756 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4757 MmLockSectionSegment(&SectionSegments
[i
]);
4758 Status
= MmMapViewOfSegment(AddressSpace
,
4760 &SectionSegments
[i
],
4762 SectionSegments
[i
].Length
,
4763 SectionSegments
[i
].Protection
,
4766 MmUnlockSectionSegment(&SectionSegments
[i
]);
4767 if (!NT_SUCCESS(Status
))
4769 MmUnlockAddressSpace(AddressSpace
);
4775 *BaseAddress
= (PVOID
)ImageBase
;
4779 /* check for write access */
4780 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4781 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4783 MmUnlockAddressSpace(AddressSpace
);
4784 return STATUS_SECTION_PROTECTION
;
4786 /* check for read access */
4787 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4788 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4790 MmUnlockAddressSpace(AddressSpace
);
4791 return STATUS_SECTION_PROTECTION
;
4793 /* check for execute access */
4794 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4795 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4797 MmUnlockAddressSpace(AddressSpace
);
4798 return STATUS_SECTION_PROTECTION
;
4801 if (ViewSize
== NULL
)
4803 /* Following this pointer would lead to us to the dark side */
4804 /* What to do? Bugcheck? Return status? Do the mambo? */
4805 KeBugCheck(MEMORY_MANAGEMENT
);
4808 if (SectionOffset
== NULL
)
4814 ViewOffset
= SectionOffset
->u
.LowPart
;
4817 if ((ViewOffset
% PAGE_SIZE
) != 0)
4819 MmUnlockAddressSpace(AddressSpace
);
4820 return(STATUS_MAPPED_ALIGNMENT
);
4823 if ((*ViewSize
) == 0)
4825 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4827 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4829 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4832 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4834 MmLockSectionSegment(Section
->Segment
);
4835 Status
= MmMapViewOfSegment(AddressSpace
,
4842 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4843 MmUnlockSectionSegment(Section
->Segment
);
4844 if (!NT_SUCCESS(Status
))
4846 MmUnlockAddressSpace(AddressSpace
);
4851 MmUnlockAddressSpace(AddressSpace
);
4853 return(STATUS_SUCCESS
);
4860 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4861 IN PLARGE_INTEGER NewFileSize
)
4863 /* Check whether an ImageSectionObject exists */
4864 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4866 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4870 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4872 PMM_SECTION_SEGMENT Segment
;
4874 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4877 if (Segment
->ReferenceCount
!= 0)
4879 /* Check size of file */
4880 if (SectionObjectPointer
->SharedCacheMap
)
4882 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4883 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4891 /* Something must gone wrong
4892 * how can we have a Section but no
4894 DPRINT("ERROR: DataSectionObject without reference!\n");
4898 DPRINT("FIXME: didn't check for outstanding write probes\n");
4908 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4918 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4919 IN MMFLUSH_TYPE FlushType
)
4923 case MmFlushForDelete
:
4924 if (SectionObjectPointer
->ImageSectionObject
||
4925 SectionObjectPointer
->DataSectionObject
)
4929 CcRosSetRemoveOnClose(SectionObjectPointer
);
4931 case MmFlushForWrite
:
4941 MmForceSectionClosed (
4942 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4943 IN BOOLEAN DelayClose
)
4954 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4955 OUT PVOID
* MappedBase
,
4956 IN OUT PSIZE_T ViewSize
)
4958 PROS_SECTION_OBJECT Section
;
4959 PMMSUPPORT AddressSpace
;
4962 DPRINT("MmMapViewInSystemSpace() called\n");
4964 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4965 AddressSpace
= MmGetKernelAddressSpace();
4967 MmLockAddressSpace(AddressSpace
);
4970 if ((*ViewSize
) == 0)
4972 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4974 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4976 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4979 MmLockSectionSegment(Section
->Segment
);
4982 Status
= MmMapViewOfSegment(AddressSpace
,
4991 MmUnlockSectionSegment(Section
->Segment
);
4992 MmUnlockAddressSpace(AddressSpace
);
5002 MmMapViewInSessionSpace (
5004 OUT PVOID
*MappedBase
,
5005 IN OUT PSIZE_T ViewSize
5009 return STATUS_NOT_IMPLEMENTED
;
5017 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
5019 PMMSUPPORT AddressSpace
;
5022 DPRINT("MmUnmapViewInSystemSpace() called\n");
5024 AddressSpace
= MmGetKernelAddressSpace();
5026 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
5036 MmUnmapViewInSessionSpace (
5041 return STATUS_NOT_IMPLEMENTED
;
5044 /**********************************************************************
5049 * Creates a section object.
5052 * SectionObject (OUT)
5053 * Caller supplied storage for the resulting pointer
5054 * to a SECTION_OBJECT instance;
5057 * Specifies the desired access to the section can be a
5059 * STANDARD_RIGHTS_REQUIRED |
5061 * SECTION_MAP_WRITE |
5062 * SECTION_MAP_READ |
5063 * SECTION_MAP_EXECUTE
5065 * ObjectAttributes [OPTIONAL]
5066 * Initialized attributes for the object can be used
5067 * to create a named section;
5070 * Maximizes the size of the memory section. Must be
5071 * non-NULL for a page-file backed section.
5072 * If value specified for a mapped file and the file is
5073 * not large enough, file will be extended.
5075 * SectionPageProtection
5076 * Can be a combination of:
5082 * AllocationAttributes
5083 * Can be a combination of:
5088 * Handle to a file to create a section mapped to a file
5089 * instead of a memory backed section;
5100 MmCreateSection (OUT PVOID
* Section
,
5101 IN ACCESS_MASK DesiredAccess
,
5102 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
5103 IN PLARGE_INTEGER MaximumSize
,
5104 IN ULONG SectionPageProtection
,
5105 IN ULONG AllocationAttributes
,
5106 IN HANDLE FileHandle OPTIONAL
,
5107 IN PFILE_OBJECT File OPTIONAL
)
5110 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
5113 * Check the protection
5115 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
5116 if (Protection
!= PAGE_READONLY
&&
5117 Protection
!= PAGE_READWRITE
&&
5118 Protection
!= PAGE_WRITECOPY
&&
5119 Protection
!= PAGE_EXECUTE
&&
5120 Protection
!= PAGE_EXECUTE_READ
&&
5121 Protection
!= PAGE_EXECUTE_READWRITE
&&
5122 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5124 return STATUS_INVALID_PAGE_PROTECTION
;
5127 if (AllocationAttributes
& SEC_IMAGE
)
5129 return(MmCreateImageSection(SectionObject
,
5133 SectionPageProtection
,
5134 AllocationAttributes
,
5138 if (FileHandle
!= NULL
)
5140 return(MmCreateDataFileSection(SectionObject
,
5144 SectionPageProtection
,
5145 AllocationAttributes
,
5149 return(MmCreatePageFileSection(SectionObject
,
5153 SectionPageProtection
,
5154 AllocationAttributes
));
5159 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
5160 IN PVOID File2MappedAsFile
)
5163 return STATUS_NOT_IMPLEMENTED
;