2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
50 #include <reactos/exeformat.h>
52 #if defined (ALLOC_PRAGMA)
53 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
54 #pragma alloc_text(INIT, MmInitSectionImplementation)
58 /* TYPES *********************************************************************/
62 PROS_SECTION_OBJECT Section
;
63 PMM_SECTION_SEGMENT Segment
;
68 MM_SECTION_PAGEOUT_CONTEXT
;
70 /* GLOBALS *******************************************************************/
72 POBJECT_TYPE MmSectionObjectType
= NULL
;
74 ULONG_PTR MmSubsectionBase
;
76 static GENERIC_MAPPING MmpSectionMapping
= {
77 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
78 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
79 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
82 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
83 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
84 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
85 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
86 #define MAX_SHARE_COUNT 0x7FF
87 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
88 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
89 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
91 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
93 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
94 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
97 /* FUNCTIONS *****************************************************************/
101 MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section
)
106 /* Return the file object */
107 return Section
->FileObject
; // Section->ControlArea->FileObject on NT
112 MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section
,
113 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
115 POBJECT_NAME_INFORMATION ObjectNameInfo
;
119 /* Make sure it's an image section */
121 if (!(Section
->AllocationAttributes
& SEC_IMAGE
))
124 return STATUS_SECTION_NOT_IMAGE
;
127 /* Allocate memory for our structure */
128 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
,
131 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
134 Status
= ObQueryNameString(Section
->FileObject
,
138 if (!NT_SUCCESS(Status
))
140 /* Failed, free memory */
141 ExFreePoolWithTag(ObjectNameInfo
, ' mM');
146 *ModuleName
= ObjectNameInfo
;
147 return STATUS_SUCCESS
;
152 MmGetFileNameForAddress(IN PVOID Address
,
153 OUT PUNICODE_STRING ModuleName
)
155 PROS_SECTION_OBJECT Section
;
156 PMEMORY_AREA MemoryArea
;
157 PMMSUPPORT AddressSpace
;
158 POBJECT_NAME_INFORMATION ModuleNameInformation
;
159 NTSTATUS Status
= STATUS_ADDRESS_NOT_ASSOCIATED
;
161 /* Get the MM_AVL_TABLE from EPROCESS */
162 if (Address
>= MmSystemRangeStart
)
164 AddressSpace
= MmGetKernelAddressSpace();
168 AddressSpace
= &PsGetCurrentProcess()->Vm
;
171 /* Lock address space */
172 MmLockAddressSpace(AddressSpace
);
174 /* Locate the memory area for the process by address */
175 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
177 /* Make sure it's a section view type */
178 if ((MemoryArea
!= NULL
) && (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
))
180 /* Get the section pointer to the SECTION_OBJECT */
181 Section
= MemoryArea
->Data
.SectionData
.Section
;
183 /* Unlock address space */
184 MmUnlockAddressSpace(AddressSpace
);
186 /* Get the filename of the section */
187 Status
= MmGetFileNameForSection(Section
,&ModuleNameInformation
);
189 if (NT_SUCCESS(Status
))
191 /* Init modulename */
192 RtlCreateUnicodeString(ModuleName
,
193 ModuleNameInformation
->Name
.Buffer
);
195 /* Free temp taged buffer from MmGetFileNameForSection() */
196 ExFreePoolWithTag(ModuleNameInformation
, ' mM');
197 DPRINT("Found ModuleName %S by address %p\n",
198 ModuleName
->Buffer
,Address
);
203 /* Unlock address space */
204 MmUnlockAddressSpace(AddressSpace
);
210 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
213 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
214 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
215 * RETURNS: Status of the wait.
218 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
220 LARGE_INTEGER Timeout
;
221 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
223 Timeout
.QuadPart
= -100000000LL; // 10 sec
226 Timeout
.QuadPart
= -100000000; // 10 sec
229 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
234 * FUNCTION: Sets the page op completion event and releases the page op.
235 * ARGUMENTS: PMM_PAGEOP.
236 * RETURNS: In shorter time than it takes you to even read this
237 * description, so don't even think about geting a mug of coffee.
240 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
242 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
243 MmReleasePageOp(PageOp
);
248 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
249 * ARGUMENTS: PFILE_OBJECT to wait for.
250 * RETURNS: Status of the wait.
253 MmspWaitForFileLock(PFILE_OBJECT File
)
255 return STATUS_SUCCESS
;
256 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
261 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
264 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
266 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
268 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
270 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
278 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
280 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
282 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
283 PMM_SECTION_SEGMENT SectionSegments
;
287 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
288 NrSegments
= ImageSectionObject
->NrSegments
;
289 SectionSegments
= ImageSectionObject
->Segments
;
290 for (i
= 0; i
< NrSegments
; i
++)
292 if (SectionSegments
[i
].ReferenceCount
!= 0)
294 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
295 SectionSegments
[i
].ReferenceCount
);
296 KeBugCheck(MEMORY_MANAGEMENT
);
298 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
300 ExFreePool(ImageSectionObject
->Segments
);
301 ExFreePool(ImageSectionObject
);
302 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
304 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
306 PMM_SECTION_SEGMENT Segment
;
308 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
311 if (Segment
->ReferenceCount
!= 0)
313 DPRINT1("Data segment still referenced\n");
314 KeBugCheck(MEMORY_MANAGEMENT
);
316 MmFreePageTablesSectionSegment(Segment
);
318 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
324 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
326 ExAcquireFastMutex(&Segment
->Lock
);
331 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
333 ExReleaseFastMutex(&Segment
->Lock
);
338 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
342 PSECTION_PAGE_TABLE Table
;
343 ULONG DirectoryOffset
;
346 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
348 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
352 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
353 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
357 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
358 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
359 TAG_SECTION_PAGE_TABLE
);
362 KeBugCheck(MEMORY_MANAGEMENT
);
364 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
365 DPRINT("Table %x\n", Table
);
368 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
369 Table
->Entry
[TableOffset
] = Entry
;
375 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
378 PSECTION_PAGE_TABLE Table
;
380 ULONG DirectoryOffset
;
383 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
385 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
387 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
391 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
392 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
393 DPRINT("Table %x\n", Table
);
399 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
400 Entry
= Table
->Entry
[TableOffset
];
406 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
411 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
414 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
415 KeBugCheck(MEMORY_MANAGEMENT
);
417 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
419 DPRINT1("Maximum share count reached\n");
420 KeBugCheck(MEMORY_MANAGEMENT
);
422 if (IS_SWAP_FROM_SSE(Entry
))
424 KeBugCheck(MEMORY_MANAGEMENT
);
426 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
427 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
432 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
433 PMM_SECTION_SEGMENT Segment
,
439 BOOLEAN IsDirectMapped
= FALSE
;
441 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
444 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
445 KeBugCheck(MEMORY_MANAGEMENT
);
447 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
449 DPRINT1("Zero share count for unshare\n");
450 KeBugCheck(MEMORY_MANAGEMENT
);
452 if (IS_SWAP_FROM_SSE(Entry
))
454 KeBugCheck(MEMORY_MANAGEMENT
);
456 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
458 * If we reducing the share count of this entry to zero then set the entry
459 * to zero and tell the cache the page is no longer mapped.
461 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
463 PFILE_OBJECT FileObject
;
465 SWAPENTRY SavedSwapEntry
;
467 BOOLEAN IsImageSection
;
470 FileOffset
= Offset
+ Segment
->FileOffset
;
472 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
474 Page
= PFN_FROM_SSE(Entry
);
475 FileObject
= Section
->FileObject
;
476 if (FileObject
!= NULL
&&
477 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
480 if ((FileOffset
% PAGE_SIZE
) == 0 &&
481 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
484 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
485 IsDirectMapped
= TRUE
;
486 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
487 if (!NT_SUCCESS(Status
))
489 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
490 KeBugCheck(MEMORY_MANAGEMENT
);
495 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
496 if (SavedSwapEntry
== 0)
499 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
500 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
504 * Try to page out this page and set the swap entry
505 * within the section segment. There exist no rmap entry
506 * for this page. The pager thread can't page out a
507 * page without a rmap entry.
509 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
513 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
516 MmReleasePageMemoryConsumer(MC_USER
, Page
);
522 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
523 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
531 * We hold all locks. Nobody can do something with the current
532 * process and the current segment (also not within an other process).
535 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
536 if (!NT_SUCCESS(Status
))
538 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
539 KeBugCheck(MEMORY_MANAGEMENT
);
542 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
543 MmSetSavedSwapEntryPage(Page
, 0);
545 MmReleasePageMemoryConsumer(MC_USER
, Page
);
549 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
550 KeBugCheck(MEMORY_MANAGEMENT
);
556 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
558 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
561 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
564 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
567 PCACHE_SEGMENT CacheSeg
;
568 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
569 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
572 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
581 MiCopyFromUserPage(PFN_TYPE DestPage
, PVOID SourceAddress
)
587 Process
= PsGetCurrentProcess();
588 TempAddress
= MiMapPageInHyperSpace(Process
, DestPage
, &Irql
);
589 if (TempAddress
== NULL
)
591 return(STATUS_NO_MEMORY
);
593 memcpy(TempAddress
, SourceAddress
, PAGE_SIZE
);
594 MiUnmapPageInHyperSpace(Process
, TempAddress
, Irql
);
595 return(STATUS_SUCCESS
);
600 MiReadPage(PMEMORY_AREA MemoryArea
,
604 * FUNCTION: Read a page for a section backed memory area.
606 * MemoryArea - Memory area to read the page for.
607 * Offset - Offset of the page to read.
608 * Page - Variable that receives a page contains the read data.
615 PCACHE_SEGMENT CacheSeg
;
616 PFILE_OBJECT FileObject
;
620 BOOLEAN IsImageSection
;
623 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
624 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
625 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
626 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
627 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
631 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
634 * If the file system is letting us go directly to the cache and the
635 * memory area was mapped at an offset in the file which is page aligned
636 * then get the related cache segment.
638 if ((FileOffset
% PAGE_SIZE
) == 0 &&
639 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
640 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
644 * Get the related cache segment; we use a lower level interface than
645 * filesystems do because it is safe for us to use an offset with a
646 * alignment less than the file system block size.
648 Status
= CcRosGetCacheSegment(Bcb
,
654 if (!NT_SUCCESS(Status
))
661 * If the cache segment isn't up to date then call the file
662 * system to read in the data.
664 Status
= ReadCacheSegment(CacheSeg
);
665 if (!NT_SUCCESS(Status
))
667 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
672 * Retrieve the page from the cache segment that we actually want.
674 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
675 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
677 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
684 ULONG CacheSegOffset
;
687 * Allocate a page, this is rather complicated by the possibility
688 * we might have to move other things out of memory
690 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
691 if (!NT_SUCCESS(Status
))
695 Status
= CcRosGetCacheSegment(Bcb
,
701 if (!NT_SUCCESS(Status
))
708 * If the cache segment isn't up to date then call the file
709 * system to read in the data.
711 Status
= ReadCacheSegment(CacheSeg
);
712 if (!NT_SUCCESS(Status
))
714 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
719 Process
= PsGetCurrentProcess();
720 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
721 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
722 Length
= RawLength
- SegOffset
;
723 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
725 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
727 else if (CacheSegOffset
>= PAGE_SIZE
)
729 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
733 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
734 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
735 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
736 Status
= CcRosGetCacheSegment(Bcb
,
737 FileOffset
+ CacheSegOffset
,
742 if (!NT_SUCCESS(Status
))
749 * If the cache segment isn't up to date then call the file
750 * system to read in the data.
752 Status
= ReadCacheSegment(CacheSeg
);
753 if (!NT_SUCCESS(Status
))
755 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
759 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
760 if (Length
< PAGE_SIZE
)
762 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
766 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
769 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
770 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
772 return(STATUS_SUCCESS
);
777 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
778 MEMORY_AREA
* MemoryArea
,
786 PROS_SECTION_OBJECT Section
;
787 PMM_SECTION_SEGMENT Segment
;
793 BOOLEAN HasSwapEntry
;
794 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
798 * There is a window between taking the page fault and locking the
799 * address space when another thread could load the page so we check
802 if (MmIsPagePresent(Process
, Address
))
806 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
807 MmLockPage(MmGetPfnForProcess(Process
, Address
));
808 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
810 return(STATUS_SUCCESS
);
813 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
814 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
815 + MemoryArea
->Data
.SectionData
.ViewOffset
;
817 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
818 Section
= MemoryArea
->Data
.SectionData
.Section
;
819 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
820 &MemoryArea
->Data
.SectionData
.RegionListHead
,
825 MmLockSectionSegment(Segment
);
828 * Check if this page needs to be mapped COW
830 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
831 (Region
->Protect
== PAGE_READWRITE
||
832 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
834 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
838 Attributes
= Region
->Protect
;
842 * Get or create a page operation descriptor
844 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
847 DPRINT1("MmGetPageOp failed\n");
848 KeBugCheck(MEMORY_MANAGEMENT
);
852 * Check if someone else is already handling this fault, if so wait
855 if (PageOp
->Thread
!= PsGetCurrentThread())
857 MmUnlockSectionSegment(Segment
);
858 MmUnlockAddressSpace(AddressSpace
);
859 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
861 * Check for various strange conditions
863 if (Status
!= STATUS_SUCCESS
)
865 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
866 KeBugCheck(MEMORY_MANAGEMENT
);
868 if (PageOp
->Status
== STATUS_PENDING
)
870 DPRINT1("Woke for page op before completion\n");
871 KeBugCheck(MEMORY_MANAGEMENT
);
873 MmLockAddressSpace(AddressSpace
);
875 * If this wasn't a pagein then restart the operation
877 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
879 MmspCompleteAndReleasePageOp(PageOp
);
880 DPRINT("Address 0x%.8X\n", Address
);
881 return(STATUS_MM_RESTART_OPERATION
);
885 * If the thread handling this fault has failed then we don't retry
887 if (!NT_SUCCESS(PageOp
->Status
))
889 Status
= PageOp
->Status
;
890 MmspCompleteAndReleasePageOp(PageOp
);
891 DPRINT("Address 0x%.8X\n", Address
);
894 MmLockSectionSegment(Segment
);
896 * If the completed fault was for another address space then set the
899 if (!MmIsPagePresent(Process
, Address
))
901 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
902 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
904 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
907 * The page was a private page in another or in our address space
909 MmUnlockSectionSegment(Segment
);
910 MmspCompleteAndReleasePageOp(PageOp
);
911 return(STATUS_MM_RESTART_OPERATION
);
914 Page
= PFN_FROM_SSE(Entry
);
916 MmSharePageEntrySectionSegment(Segment
, Offset
);
918 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
919 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
921 Status
= MmCreateVirtualMapping(Process
,
926 if (!NT_SUCCESS(Status
))
928 DPRINT1("Unable to create virtual mapping\n");
929 KeBugCheck(MEMORY_MANAGEMENT
);
931 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
935 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
937 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
939 MmUnlockSectionSegment(Segment
);
940 PageOp
->Status
= STATUS_SUCCESS
;
941 MmspCompleteAndReleasePageOp(PageOp
);
942 DPRINT("Address 0x%.8X\n", Address
);
943 return(STATUS_SUCCESS
);
946 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
950 * Must be private page we have swapped out.
957 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
959 DPRINT1("Found a swaped out private page in a pagefile section.\n");
960 KeBugCheck(MEMORY_MANAGEMENT
);
963 MmUnlockSectionSegment(Segment
);
964 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
966 MmUnlockAddressSpace(AddressSpace
);
967 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
968 if (!NT_SUCCESS(Status
))
970 KeBugCheck(MEMORY_MANAGEMENT
);
973 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
974 if (!NT_SUCCESS(Status
))
976 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
977 KeBugCheck(MEMORY_MANAGEMENT
);
979 MmLockAddressSpace(AddressSpace
);
980 Status
= MmCreateVirtualMapping(Process
,
985 if (!NT_SUCCESS(Status
))
987 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
988 KeBugCheck(MEMORY_MANAGEMENT
);
993 * Store the swap entry for later use.
995 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
998 * Add the page to the process's working set
1000 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1003 * Finish the operation
1007 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1009 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1011 PageOp
->Status
= STATUS_SUCCESS
;
1012 MmspCompleteAndReleasePageOp(PageOp
);
1013 DPRINT("Address 0x%.8X\n", Address
);
1014 return(STATUS_SUCCESS
);
1018 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
1020 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1022 MmUnlockSectionSegment(Segment
);
1024 * Just map the desired physical page
1026 Page
= Offset
>> PAGE_SHIFT
;
1027 Status
= MmCreateVirtualMappingUnsafe(Process
,
1032 if (!NT_SUCCESS(Status
))
1034 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1035 KeBugCheck(MEMORY_MANAGEMENT
);
1039 * Don't add an rmap entry since the page mapped could be for
1044 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1046 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1050 * Cleanup and release locks
1052 PageOp
->Status
= STATUS_SUCCESS
;
1053 MmspCompleteAndReleasePageOp(PageOp
);
1054 DPRINT("Address 0x%.8X\n", Address
);
1055 return(STATUS_SUCCESS
);
1059 * Map anonymous memory for BSS sections
1061 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1063 MmUnlockSectionSegment(Segment
);
1064 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1065 if (!NT_SUCCESS(Status
))
1067 MmUnlockAddressSpace(AddressSpace
);
1068 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1069 MmLockAddressSpace(AddressSpace
);
1071 if (!NT_SUCCESS(Status
))
1073 KeBugCheck(MEMORY_MANAGEMENT
);
1075 Status
= MmCreateVirtualMapping(Process
,
1080 if (!NT_SUCCESS(Status
))
1082 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1083 KeBugCheck(MEMORY_MANAGEMENT
);
1086 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1089 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1091 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1095 * Cleanup and release locks
1097 PageOp
->Status
= STATUS_SUCCESS
;
1098 MmspCompleteAndReleasePageOp(PageOp
);
1099 DPRINT("Address 0x%.8X\n", Address
);
1100 return(STATUS_SUCCESS
);
1104 * Get the entry corresponding to the offset within the section
1106 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1111 * If the entry is zero (and it can't change because we have
1112 * locked the segment) then we need to load the page.
1116 * Release all our locks and read in the page from disk
1118 MmUnlockSectionSegment(Segment
);
1119 MmUnlockAddressSpace(AddressSpace
);
1121 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1122 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1124 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1125 if (!NT_SUCCESS(Status
))
1127 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1132 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1133 if (!NT_SUCCESS(Status
))
1135 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1138 if (!NT_SUCCESS(Status
))
1141 * FIXME: What do we know in this case?
1144 * Cleanup and release locks
1146 MmLockAddressSpace(AddressSpace
);
1147 PageOp
->Status
= Status
;
1148 MmspCompleteAndReleasePageOp(PageOp
);
1149 DPRINT("Address 0x%.8X\n", Address
);
1153 * Relock the address space and segment
1155 MmLockAddressSpace(AddressSpace
);
1156 MmLockSectionSegment(Segment
);
1159 * Check the entry. No one should change the status of a page
1160 * that has a pending page-in.
1162 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1163 if (Entry
!= Entry1
)
1165 DPRINT1("Someone changed ppte entry while we slept\n");
1166 KeBugCheck(MEMORY_MANAGEMENT
);
1170 * Mark the offset within the section as having valid, in-memory
1173 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1174 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1175 MmUnlockSectionSegment(Segment
);
1177 Status
= MmCreateVirtualMapping(Process
,
1182 if (!NT_SUCCESS(Status
))
1184 DPRINT1("Unable to create virtual mapping\n");
1185 KeBugCheck(MEMORY_MANAGEMENT
);
1187 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1191 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1193 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1195 PageOp
->Status
= STATUS_SUCCESS
;
1196 MmspCompleteAndReleasePageOp(PageOp
);
1197 DPRINT("Address 0x%.8X\n", Address
);
1198 return(STATUS_SUCCESS
);
1200 else if (IS_SWAP_FROM_SSE(Entry
))
1202 SWAPENTRY SwapEntry
;
1204 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1207 * Release all our locks and read in the page from disk
1209 MmUnlockSectionSegment(Segment
);
1211 MmUnlockAddressSpace(AddressSpace
);
1213 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1214 if (!NT_SUCCESS(Status
))
1216 KeBugCheck(MEMORY_MANAGEMENT
);
1219 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1220 if (!NT_SUCCESS(Status
))
1222 KeBugCheck(MEMORY_MANAGEMENT
);
1226 * Relock the address space and segment
1228 MmLockAddressSpace(AddressSpace
);
1229 MmLockSectionSegment(Segment
);
1232 * Check the entry. No one should change the status of a page
1233 * that has a pending page-in.
1235 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1236 if (Entry
!= Entry1
)
1238 DPRINT1("Someone changed ppte entry while we slept\n");
1239 KeBugCheck(MEMORY_MANAGEMENT
);
1243 * Mark the offset within the section as having valid, in-memory
1246 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1247 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1248 MmUnlockSectionSegment(Segment
);
1251 * Save the swap entry.
1253 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1254 Status
= MmCreateVirtualMapping(Process
,
1259 if (!NT_SUCCESS(Status
))
1261 DPRINT1("Unable to create virtual mapping\n");
1262 KeBugCheck(MEMORY_MANAGEMENT
);
1264 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1267 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1269 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1271 PageOp
->Status
= STATUS_SUCCESS
;
1272 MmspCompleteAndReleasePageOp(PageOp
);
1273 DPRINT("Address 0x%.8X\n", Address
);
1274 return(STATUS_SUCCESS
);
1279 * If the section offset is already in-memory and valid then just
1280 * take another reference to the page
1283 Page
= PFN_FROM_SSE(Entry
);
1285 MmSharePageEntrySectionSegment(Segment
, Offset
);
1286 MmUnlockSectionSegment(Segment
);
1288 Status
= MmCreateVirtualMapping(Process
,
1293 if (!NT_SUCCESS(Status
))
1295 DPRINT1("Unable to create virtual mapping\n");
1296 KeBugCheck(MEMORY_MANAGEMENT
);
1298 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1301 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1303 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1305 PageOp
->Status
= STATUS_SUCCESS
;
1306 MmspCompleteAndReleasePageOp(PageOp
);
1307 DPRINT("Address 0x%.8X\n", Address
);
1308 return(STATUS_SUCCESS
);
1314 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1315 MEMORY_AREA
* MemoryArea
,
1319 PMM_SECTION_SEGMENT Segment
;
1320 PROS_SECTION_OBJECT Section
;
1329 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1332 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1335 * Check if the page has been paged out or has already been set readwrite
1337 if (!MmIsPagePresent(Process
, Address
) ||
1338 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1340 DPRINT("Address 0x%.8X\n", Address
);
1341 return(STATUS_SUCCESS
);
1345 * Find the offset of the page
1347 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1348 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1349 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1351 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1352 Section
= MemoryArea
->Data
.SectionData
.Section
;
1353 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1354 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1359 MmLockSectionSegment(Segment
);
1361 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1362 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1364 MmUnlockSectionSegment(Segment
);
1367 * Check if we are doing COW
1369 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1370 (Region
->Protect
== PAGE_READWRITE
||
1371 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1373 DPRINT("Address 0x%.8X\n", Address
);
1374 return(STATUS_ACCESS_VIOLATION
);
1377 if (IS_SWAP_FROM_SSE(Entry
) ||
1378 PFN_FROM_SSE(Entry
) != OldPage
)
1380 /* This is a private page. We must only change the page protection. */
1381 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1382 return(STATUS_SUCCESS
);
1386 * Get or create a pageop
1388 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1389 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1392 DPRINT1("MmGetPageOp failed\n");
1393 KeBugCheck(MEMORY_MANAGEMENT
);
1397 * Wait for any other operations to complete
1399 if (PageOp
->Thread
!= PsGetCurrentThread())
1401 MmUnlockAddressSpace(AddressSpace
);
1402 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1404 * Check for various strange conditions
1406 if (Status
== STATUS_TIMEOUT
)
1408 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1409 KeBugCheck(MEMORY_MANAGEMENT
);
1411 if (PageOp
->Status
== STATUS_PENDING
)
1413 DPRINT1("Woke for page op before completion\n");
1414 KeBugCheck(MEMORY_MANAGEMENT
);
1417 * Restart the operation
1419 MmLockAddressSpace(AddressSpace
);
1420 MmspCompleteAndReleasePageOp(PageOp
);
1421 DPRINT("Address 0x%.8X\n", Address
);
1422 return(STATUS_MM_RESTART_OPERATION
);
1426 * Release locks now we have the pageop
1428 MmUnlockAddressSpace(AddressSpace
);
1433 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1434 if (!NT_SUCCESS(Status
))
1436 KeBugCheck(MEMORY_MANAGEMENT
);
1442 MiCopyFromUserPage(NewPage
, PAddress
);
1444 MmLockAddressSpace(AddressSpace
);
1446 * Delete the old entry.
1448 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1451 * Set the PTE to point to the new page
1453 Status
= MmCreateVirtualMapping(Process
,
1458 if (!NT_SUCCESS(Status
))
1460 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1461 KeBugCheck(MEMORY_MANAGEMENT
);
1464 if (!NT_SUCCESS(Status
))
1466 DPRINT1("Unable to create virtual mapping\n");
1467 KeBugCheck(MEMORY_MANAGEMENT
);
1471 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1472 MmLockPage(NewPage
);
1473 MmUnlockPage(OldPage
);
1474 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1478 * Unshare the old page.
1480 MmDeleteRmap(OldPage
, Process
, PAddress
);
1481 MmInsertRmap(NewPage
, Process
, PAddress
);
1482 MmLockSectionSegment(Segment
);
1483 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1484 MmUnlockSectionSegment(Segment
);
1486 PageOp
->Status
= STATUS_SUCCESS
;
1487 MmspCompleteAndReleasePageOp(PageOp
);
1488 DPRINT("Address 0x%.8X\n", Address
);
1489 return(STATUS_SUCCESS
);
1493 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1495 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1499 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1502 MmLockAddressSpace(&Process
->Vm
);
1505 MmDeleteVirtualMapping(Process
,
1512 PageOutContext
->WasDirty
= TRUE
;
1514 if (!PageOutContext
->Private
)
1516 MmLockSectionSegment(PageOutContext
->Segment
);
1517 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1518 PageOutContext
->Segment
,
1519 PageOutContext
->Offset
,
1520 PageOutContext
->WasDirty
,
1522 MmUnlockSectionSegment(PageOutContext
->Segment
);
1526 MmUnlockAddressSpace(&Process
->Vm
);
1529 if (PageOutContext
->Private
)
1531 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1534 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1539 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1540 MEMORY_AREA
* MemoryArea
,
1545 MM_SECTION_PAGEOUT_CONTEXT Context
;
1546 SWAPENTRY SwapEntry
;
1550 PFILE_OBJECT FileObject
;
1552 BOOLEAN DirectMapped
;
1553 BOOLEAN IsImageSection
;
1554 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1557 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1560 * Get the segment and section.
1562 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1563 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1565 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1566 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1567 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1569 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1571 FileObject
= Context
.Section
->FileObject
;
1572 DirectMapped
= FALSE
;
1573 if (FileObject
!= NULL
&&
1574 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1576 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1579 * If the file system is letting us go directly to the cache and the
1580 * memory area was mapped at an offset in the file which is page aligned
1581 * then note this is a direct mapped page.
1583 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1584 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1586 DirectMapped
= TRUE
;
1592 * This should never happen since mappings of physical memory are never
1593 * placed in the rmap lists.
1595 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1597 DPRINT1("Trying to page out from physical memory section address 0x%X "
1598 "process %d\n", Address
,
1599 Process
? Process
->UniqueProcessId
: 0);
1600 KeBugCheck(MEMORY_MANAGEMENT
);
1604 * Get the section segment entry and the physical address.
1606 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1607 if (!MmIsPagePresent(Process
, Address
))
1609 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1610 Process
? Process
->UniqueProcessId
: 0, Address
);
1611 KeBugCheck(MEMORY_MANAGEMENT
);
1613 Page
= MmGetPfnForProcess(Process
, Address
);
1614 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1617 * Prepare the context structure for the rmap delete call.
1619 Context
.WasDirty
= FALSE
;
1620 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1621 IS_SWAP_FROM_SSE(Entry
) ||
1622 PFN_FROM_SSE(Entry
) != Page
)
1624 Context
.Private
= TRUE
;
1628 Context
.Private
= FALSE
;
1632 * Take an additional reference to the page or the cache segment.
1634 if (DirectMapped
&& !Context
.Private
)
1636 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1638 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1639 KeBugCheck(MEMORY_MANAGEMENT
);
1644 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1645 MmReferencePage(Page
);
1646 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1649 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1652 * If this wasn't a private page then we should have reduced the entry to
1653 * zero by deleting all the rmaps.
1655 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1657 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1658 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1660 KeBugCheck(MEMORY_MANAGEMENT
);
1665 * If the page wasn't dirty then we can just free it as for a readonly page.
1666 * Since we unmapped all the mappings above we know it will not suddenly
1668 * If the page is from a pagefile section and has no swap entry,
1669 * we can't free the page at this point.
1671 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1672 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1674 if (Context
.Private
)
1676 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1677 Context
.WasDirty
? "dirty" : "clean", Address
);
1678 KeBugCheck(MEMORY_MANAGEMENT
);
1680 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1682 MmSetSavedSwapEntryPage(Page
, 0);
1683 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1684 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1685 PageOp
->Status
= STATUS_SUCCESS
;
1686 MmspCompleteAndReleasePageOp(PageOp
);
1687 return(STATUS_SUCCESS
);
1690 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1692 if (Context
.Private
)
1694 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1695 Context
.WasDirty
? "dirty" : "clean", Address
);
1696 KeBugCheck(MEMORY_MANAGEMENT
);
1698 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1700 MmSetSavedSwapEntryPage(Page
, 0);
1703 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1705 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1706 PageOp
->Status
= STATUS_SUCCESS
;
1707 MmspCompleteAndReleasePageOp(PageOp
);
1708 return(STATUS_SUCCESS
);
1711 else if (!Context
.Private
&& DirectMapped
)
1715 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1717 KeBugCheck(MEMORY_MANAGEMENT
);
1719 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1720 if (!NT_SUCCESS(Status
))
1722 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1723 KeBugCheck(MEMORY_MANAGEMENT
);
1725 PageOp
->Status
= STATUS_SUCCESS
;
1726 MmspCompleteAndReleasePageOp(PageOp
);
1727 return(STATUS_SUCCESS
);
1729 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1733 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1735 KeBugCheck(MEMORY_MANAGEMENT
);
1737 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1738 PageOp
->Status
= STATUS_SUCCESS
;
1739 MmspCompleteAndReleasePageOp(PageOp
);
1740 return(STATUS_SUCCESS
);
1742 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1744 MmSetSavedSwapEntryPage(Page
, 0);
1745 MmLockAddressSpace(AddressSpace
);
1746 Status
= MmCreatePageFileMapping(Process
,
1749 MmUnlockAddressSpace(AddressSpace
);
1750 if (!NT_SUCCESS(Status
))
1752 KeBugCheck(MEMORY_MANAGEMENT
);
1754 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1755 PageOp
->Status
= STATUS_SUCCESS
;
1756 MmspCompleteAndReleasePageOp(PageOp
);
1757 return(STATUS_SUCCESS
);
1761 * If necessary, allocate an entry in the paging file for this page
1765 SwapEntry
= MmAllocSwapPage();
1768 MmShowOutOfSpaceMessagePagingFile();
1769 MmLockAddressSpace(AddressSpace
);
1771 * For private pages restore the old mappings.
1773 if (Context
.Private
)
1775 Status
= MmCreateVirtualMapping(Process
,
1777 MemoryArea
->Protect
,
1780 MmSetDirtyPage(Process
, Address
);
1788 * For non-private pages if the page wasn't direct mapped then
1789 * set it back into the section segment entry so we don't loose
1790 * our copy. Otherwise it will be handled by the cache manager.
1792 Status
= MmCreateVirtualMapping(Process
,
1794 MemoryArea
->Protect
,
1797 MmSetDirtyPage(Process
, Address
);
1801 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1802 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1804 MmUnlockAddressSpace(AddressSpace
);
1805 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1806 MmspCompleteAndReleasePageOp(PageOp
);
1807 return(STATUS_PAGEFILE_QUOTA
);
1812 * Write the page to the pagefile
1814 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1815 if (!NT_SUCCESS(Status
))
1817 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1820 * As above: undo our actions.
1821 * FIXME: Also free the swap page.
1823 MmLockAddressSpace(AddressSpace
);
1824 if (Context
.Private
)
1826 Status
= MmCreateVirtualMapping(Process
,
1828 MemoryArea
->Protect
,
1831 MmSetDirtyPage(Process
, Address
);
1838 Status
= MmCreateVirtualMapping(Process
,
1840 MemoryArea
->Protect
,
1843 MmSetDirtyPage(Process
, Address
);
1847 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1848 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1850 MmUnlockAddressSpace(AddressSpace
);
1851 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1852 MmspCompleteAndReleasePageOp(PageOp
);
1853 return(STATUS_UNSUCCESSFUL
);
1857 * Otherwise we have succeeded.
1859 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1860 MmSetSavedSwapEntryPage(Page
, 0);
1861 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1862 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1864 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1868 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1871 if (Context
.Private
)
1873 MmLockAddressSpace(AddressSpace
);
1874 Status
= MmCreatePageFileMapping(Process
,
1877 MmUnlockAddressSpace(AddressSpace
);
1878 if (!NT_SUCCESS(Status
))
1880 KeBugCheck(MEMORY_MANAGEMENT
);
1885 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1886 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1889 PageOp
->Status
= STATUS_SUCCESS
;
1890 MmspCompleteAndReleasePageOp(PageOp
);
1891 return(STATUS_SUCCESS
);
1896 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
1897 PMEMORY_AREA MemoryArea
,
1902 PROS_SECTION_OBJECT Section
;
1903 PMM_SECTION_SEGMENT Segment
;
1905 SWAPENTRY SwapEntry
;
1909 PFILE_OBJECT FileObject
;
1911 BOOLEAN DirectMapped
;
1912 BOOLEAN IsImageSection
;
1913 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1915 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1917 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1918 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1921 * Get the segment and section.
1923 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1924 Section
= MemoryArea
->Data
.SectionData
.Section
;
1925 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1927 FileObject
= Section
->FileObject
;
1928 DirectMapped
= FALSE
;
1929 if (FileObject
!= NULL
&&
1930 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1932 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1935 * If the file system is letting us go directly to the cache and the
1936 * memory area was mapped at an offset in the file which is page aligned
1937 * then note this is a direct mapped page.
1939 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1940 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1942 DirectMapped
= TRUE
;
1947 * This should never happen since mappings of physical memory are never
1948 * placed in the rmap lists.
1950 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1952 DPRINT1("Trying to write back page from physical memory mapped at %X "
1953 "process %d\n", Address
,
1954 Process
? Process
->UniqueProcessId
: 0);
1955 KeBugCheck(MEMORY_MANAGEMENT
);
1959 * Get the section segment entry and the physical address.
1961 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1962 if (!MmIsPagePresent(Process
, Address
))
1964 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1965 Process
? Process
->UniqueProcessId
: 0, Address
);
1966 KeBugCheck(MEMORY_MANAGEMENT
);
1968 Page
= MmGetPfnForProcess(Process
, Address
);
1969 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1972 * Check for a private (COWed) page.
1974 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1975 IS_SWAP_FROM_SSE(Entry
) ||
1976 PFN_FROM_SSE(Entry
) != Page
)
1986 * Speculatively set all mappings of the page to clean.
1988 MmSetCleanAllRmaps(Page
);
1991 * If this page was direct mapped from the cache then the cache manager
1992 * will take care of writing it back to disk.
1994 if (DirectMapped
&& !Private
)
1996 ASSERT(SwapEntry
== 0);
1997 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1998 PageOp
->Status
= STATUS_SUCCESS
;
1999 MmspCompleteAndReleasePageOp(PageOp
);
2000 return(STATUS_SUCCESS
);
2004 * If necessary, allocate an entry in the paging file for this page
2008 SwapEntry
= MmAllocSwapPage();
2011 MmSetDirtyAllRmaps(Page
);
2012 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2013 MmspCompleteAndReleasePageOp(PageOp
);
2014 return(STATUS_PAGEFILE_QUOTA
);
2016 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
2020 * Write the page to the pagefile
2022 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
2023 if (!NT_SUCCESS(Status
))
2025 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
2027 MmSetDirtyAllRmaps(Page
);
2028 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
2029 MmspCompleteAndReleasePageOp(PageOp
);
2030 return(STATUS_UNSUCCESSFUL
);
2034 * Otherwise we have succeeded.
2036 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
2037 PageOp
->Status
= STATUS_SUCCESS
;
2038 MmspCompleteAndReleasePageOp(PageOp
);
2039 return(STATUS_SUCCESS
);
2043 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2051 PMEMORY_AREA MemoryArea
;
2052 PMM_SECTION_SEGMENT Segment
;
2053 BOOLEAN DoCOW
= FALSE
;
2055 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2057 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2058 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2060 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
2061 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2066 if (OldProtect
!= NewProtect
)
2068 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2070 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2071 ULONG Protect
= NewProtect
;
2074 * If we doing COW for this segment then check if the page is
2077 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2083 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2084 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2085 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2086 Page
= MmGetPfnForProcess(Process
, Address
);
2088 Protect
= PAGE_READONLY
;
2089 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2090 IS_SWAP_FROM_SSE(Entry
) ||
2091 PFN_FROM_SSE(Entry
) != Page
)
2093 Protect
= NewProtect
;
2097 if (MmIsPagePresent(Process
, Address
))
2099 MmSetPageProtect(Process
, Address
,
2108 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2109 PMEMORY_AREA MemoryArea
,
2117 ULONG_PTR MaxLength
;
2119 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2120 if (Length
> MaxLength
)
2123 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2124 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2126 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2127 Region
->Protect
!= Protect
)
2129 return STATUS_INVALID_PAGE_PROTECTION
;
2132 *OldProtect
= Region
->Protect
;
2133 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2134 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2135 BaseAddress
, Length
, Region
->Type
, Protect
,
2136 MmAlterViewAttributes
);
2142 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2144 PMEMORY_BASIC_INFORMATION Info
,
2145 PULONG ResultLength
)
2148 PVOID RegionBaseAddress
;
2149 PROS_SECTION_OBJECT Section
;
2150 PMM_SECTION_SEGMENT Segment
;
2152 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2153 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2154 Address
, &RegionBaseAddress
);
2157 return STATUS_UNSUCCESSFUL
;
2160 Section
= MemoryArea
->Data
.SectionData
.Section
;
2161 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2163 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2164 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2165 Info
->Type
= MEM_IMAGE
;
2169 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2170 Info
->Type
= MEM_MAPPED
;
2172 Info
->BaseAddress
= RegionBaseAddress
;
2173 Info
->AllocationProtect
= MemoryArea
->Protect
;
2174 Info
->RegionSize
= Region
->Length
;
2175 Info
->State
= MEM_COMMIT
;
2176 Info
->Protect
= Region
->Protect
;
2178 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2179 return(STATUS_SUCCESS
);
2184 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2189 ULONG SavedSwapEntry
;
2194 Length
= PAGE_ROUND_UP(Segment
->Length
);
2195 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2197 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2200 if (IS_SWAP_FROM_SSE(Entry
))
2202 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2206 Page
= PFN_FROM_SSE(Entry
);
2207 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2208 if (SavedSwapEntry
!= 0)
2210 MmSetSavedSwapEntryPage(Page
, 0);
2211 MmFreeSwapPage(SavedSwapEntry
);
2213 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2215 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2221 MmpDeleteSection(PVOID ObjectBody
)
2223 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2225 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2226 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2231 PMM_SECTION_SEGMENT SectionSegments
;
2234 * NOTE: Section->ImageSection can be NULL for short time
2235 * during the section creating. If we fail for some reason
2236 * until the image section is properly initialized we shouldn't
2237 * process further here.
2239 if (Section
->ImageSection
== NULL
)
2242 SectionSegments
= Section
->ImageSection
->Segments
;
2243 NrSegments
= Section
->ImageSection
->NrSegments
;
2245 for (i
= 0; i
< NrSegments
; i
++)
2247 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2249 MmLockSectionSegment(&SectionSegments
[i
]);
2251 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2252 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2256 MmpFreePageFileSegment(&SectionSegments
[i
]);
2258 MmUnlockSectionSegment(&SectionSegments
[i
]);
2265 * NOTE: Section->Segment can be NULL for short time
2266 * during the section creating.
2268 if (Section
->Segment
== NULL
)
2271 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2273 MmpFreePageFileSegment(Section
->Segment
);
2274 MmFreePageTablesSectionSegment(Section
->Segment
);
2275 ExFreePool(Section
->Segment
);
2276 Section
->Segment
= NULL
;
2280 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2283 if (Section
->FileObject
!= NULL
)
2285 CcRosDereferenceCache(Section
->FileObject
);
2286 ObDereferenceObject(Section
->FileObject
);
2287 Section
->FileObject
= NULL
;
2292 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2294 IN ACCESS_MASK GrantedAccess
,
2295 IN ULONG ProcessHandleCount
,
2296 IN ULONG SystemHandleCount
)
2298 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2299 Object
, ProcessHandleCount
);
2305 MmCreatePhysicalMemorySection(VOID
)
2307 PROS_SECTION_OBJECT PhysSection
;
2309 OBJECT_ATTRIBUTES Obj
;
2310 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2311 LARGE_INTEGER SectionSize
;
2315 * Create the section mapping physical memory
2317 SectionSize
.QuadPart
= 0xFFFFFFFF;
2318 InitializeObjectAttributes(&Obj
,
2323 Status
= MmCreateSection((PVOID
)&PhysSection
,
2327 PAGE_EXECUTE_READWRITE
,
2331 if (!NT_SUCCESS(Status
))
2333 DPRINT1("Failed to create PhysicalMemory section\n");
2334 KeBugCheck(MEMORY_MANAGEMENT
);
2336 Status
= ObInsertObject(PhysSection
,
2342 if (!NT_SUCCESS(Status
))
2344 ObDereferenceObject(PhysSection
);
2346 ObCloseHandle(Handle
, KernelMode
);
2347 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2348 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2350 return(STATUS_SUCCESS
);
2356 MmInitSectionImplementation(VOID
)
2358 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2359 UNICODE_STRING Name
;
2361 DPRINT("Creating Section Object Type\n");
2363 /* Initialize the Section object type */
2364 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2365 RtlInitUnicodeString(&Name
, L
"Section");
2366 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2367 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2368 ObjectTypeInitializer
.PoolType
= PagedPool
;
2369 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2370 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2371 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2372 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2373 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2374 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2376 MmCreatePhysicalMemorySection();
2378 return(STATUS_SUCCESS
);
2383 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2384 ACCESS_MASK DesiredAccess
,
2385 POBJECT_ATTRIBUTES ObjectAttributes
,
2386 PLARGE_INTEGER UMaximumSize
,
2387 ULONG SectionPageProtection
,
2388 ULONG AllocationAttributes
)
2390 * Create a section which is backed by the pagefile
2393 LARGE_INTEGER MaximumSize
;
2394 PROS_SECTION_OBJECT Section
;
2395 PMM_SECTION_SEGMENT Segment
;
2398 if (UMaximumSize
== NULL
)
2400 return(STATUS_UNSUCCESSFUL
);
2402 MaximumSize
= *UMaximumSize
;
2405 * Create the section
2407 Status
= ObCreateObject(ExGetPreviousMode(),
2408 MmSectionObjectType
,
2410 ExGetPreviousMode(),
2412 sizeof(ROS_SECTION_OBJECT
),
2415 (PVOID
*)(PVOID
)&Section
);
2416 if (!NT_SUCCESS(Status
))
2424 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2425 Section
->SectionPageProtection
= SectionPageProtection
;
2426 Section
->AllocationAttributes
= AllocationAttributes
;
2427 Section
->MaximumSize
= MaximumSize
;
2428 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2429 TAG_MM_SECTION_SEGMENT
);
2430 if (Segment
== NULL
)
2432 ObDereferenceObject(Section
);
2433 return(STATUS_NO_MEMORY
);
2435 Section
->Segment
= Segment
;
2436 Segment
->ReferenceCount
= 1;
2437 ExInitializeFastMutex(&Segment
->Lock
);
2438 Segment
->FileOffset
= 0;
2439 Segment
->Protection
= SectionPageProtection
;
2440 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2441 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2442 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2443 Segment
->WriteCopy
= FALSE
;
2444 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2445 Segment
->VirtualAddress
= 0;
2446 Segment
->Characteristics
= 0;
2447 *SectionObject
= Section
;
2448 return(STATUS_SUCCESS
);
2454 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2455 ACCESS_MASK DesiredAccess
,
2456 POBJECT_ATTRIBUTES ObjectAttributes
,
2457 PLARGE_INTEGER UMaximumSize
,
2458 ULONG SectionPageProtection
,
2459 ULONG AllocationAttributes
,
2462 * Create a section backed by a data file
2465 PROS_SECTION_OBJECT Section
;
2467 LARGE_INTEGER MaximumSize
;
2468 PFILE_OBJECT FileObject
;
2469 PMM_SECTION_SEGMENT Segment
;
2471 IO_STATUS_BLOCK Iosb
;
2472 LARGE_INTEGER Offset
;
2474 FILE_STANDARD_INFORMATION FileInfo
;
2478 * Create the section
2480 Status
= ObCreateObject(ExGetPreviousMode(),
2481 MmSectionObjectType
,
2483 ExGetPreviousMode(),
2485 sizeof(ROS_SECTION_OBJECT
),
2488 (PVOID
*)(PVOID
)&Section
);
2489 if (!NT_SUCCESS(Status
))
2496 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
2497 Section
->SectionPageProtection
= SectionPageProtection
;
2498 Section
->AllocationAttributes
= AllocationAttributes
;
2501 * Check file access required
2503 if (SectionPageProtection
& PAGE_READWRITE
||
2504 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2506 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2510 FileAccess
= FILE_READ_DATA
;
2514 * Reference the file handle
2516 Status
= ObReferenceObjectByHandle(FileHandle
,
2519 ExGetPreviousMode(),
2520 (PVOID
*)(PVOID
)&FileObject
,
2522 if (!NT_SUCCESS(Status
))
2524 ObDereferenceObject(Section
);
2529 * FIXME: This is propably not entirely correct. We can't look into
2530 * the standard FCB header because it might not be initialized yet
2531 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2532 * standard file information is filled on first request).
2534 Status
= IoQueryFileInformation(FileObject
,
2535 FileStandardInformation
,
2536 sizeof(FILE_STANDARD_INFORMATION
),
2539 Iosb
.Information
= Length
;
2540 if (!NT_SUCCESS(Status
))
2542 ObDereferenceObject(Section
);
2543 ObDereferenceObject(FileObject
);
2548 * FIXME: Revise this once a locking order for file size changes is
2551 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2553 MaximumSize
= *UMaximumSize
;
2557 MaximumSize
= FileInfo
.EndOfFile
;
2558 /* Mapping zero-sized files isn't allowed. */
2559 if (MaximumSize
.QuadPart
== 0)
2561 ObDereferenceObject(Section
);
2562 ObDereferenceObject(FileObject
);
2563 return STATUS_FILE_INVALID
;
2567 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2569 Status
= IoSetInformation(FileObject
,
2570 FileAllocationInformation
,
2571 sizeof(LARGE_INTEGER
),
2573 if (!NT_SUCCESS(Status
))
2575 ObDereferenceObject(Section
);
2576 ObDereferenceObject(FileObject
);
2577 return(STATUS_SECTION_NOT_EXTENDED
);
2581 if (FileObject
->SectionObjectPointer
== NULL
||
2582 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2585 * Read a bit so caching is initiated for the file object.
2586 * This is only needed because MiReadPage currently cannot
2587 * handle non-cached streams.
2589 Offset
.QuadPart
= 0;
2590 Status
= ZwReadFile(FileHandle
,
2599 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2601 ObDereferenceObject(Section
);
2602 ObDereferenceObject(FileObject
);
2605 if (FileObject
->SectionObjectPointer
== NULL
||
2606 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2608 /* FIXME: handle this situation */
2609 ObDereferenceObject(Section
);
2610 ObDereferenceObject(FileObject
);
2611 return STATUS_INVALID_PARAMETER
;
2618 Status
= MmspWaitForFileLock(FileObject
);
2619 if (Status
!= STATUS_SUCCESS
)
2621 ObDereferenceObject(Section
);
2622 ObDereferenceObject(FileObject
);
2627 * If this file hasn't been mapped as a data file before then allocate a
2628 * section segment to describe the data file mapping
2630 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2632 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2633 TAG_MM_SECTION_SEGMENT
);
2634 if (Segment
== NULL
)
2636 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2637 ObDereferenceObject(Section
);
2638 ObDereferenceObject(FileObject
);
2639 return(STATUS_NO_MEMORY
);
2641 Section
->Segment
= Segment
;
2642 Segment
->ReferenceCount
= 1;
2643 ExInitializeFastMutex(&Segment
->Lock
);
2645 * Set the lock before assigning the segment to the file object
2647 ExAcquireFastMutex(&Segment
->Lock
);
2648 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2650 Segment
->FileOffset
= 0;
2651 Segment
->Protection
= SectionPageProtection
;
2652 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2653 Segment
->Characteristics
= 0;
2654 Segment
->WriteCopy
= FALSE
;
2655 if (AllocationAttributes
& SEC_RESERVE
)
2657 Segment
->Length
= Segment
->RawLength
= 0;
2661 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2662 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2664 Segment
->VirtualAddress
= 0;
2665 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2670 * If the file is already mapped as a data file then we may need
2674 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2676 Section
->Segment
= Segment
;
2677 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2678 MmLockSectionSegment(Segment
);
2680 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2681 !(AllocationAttributes
& SEC_RESERVE
))
2683 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2684 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2687 MmUnlockSectionSegment(Segment
);
2688 Section
->FileObject
= FileObject
;
2689 Section
->MaximumSize
= MaximumSize
;
2690 CcRosReferenceCache(FileObject
);
2691 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2692 *SectionObject
= Section
;
2693 return(STATUS_SUCCESS
);
2697 TODO: not that great (declaring loaders statically, having to declare all of
2698 them, having to keep them extern, etc.), will fix in the future
2700 extern NTSTATUS NTAPI PeFmtCreateSection
2702 IN CONST VOID
* FileHeader
,
2703 IN SIZE_T FileHeaderSize
,
2705 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2707 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2708 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2711 extern NTSTATUS NTAPI ElfFmtCreateSection
2713 IN CONST VOID
* FileHeader
,
2714 IN SIZE_T FileHeaderSize
,
2716 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2718 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2719 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2722 /* TODO: this is a standard DDK/PSDK macro */
2723 #ifndef RTL_NUMBER_OF
2724 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2727 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2738 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2740 SIZE_T SizeOfSegments
;
2741 PMM_SECTION_SEGMENT Segments
;
2743 /* TODO: check for integer overflow */
2744 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2746 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2748 TAG_MM_SECTION_SEGMENT
);
2751 RtlZeroMemory(Segments
, SizeOfSegments
);
2759 ExeFmtpReadFile(IN PVOID File
,
2760 IN PLARGE_INTEGER Offset
,
2763 OUT PVOID
* AllocBase
,
2764 OUT PULONG ReadSize
)
2767 LARGE_INTEGER FileOffset
;
2769 ULONG OffsetAdjustment
;
2774 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2778 KeBugCheck(MEMORY_MANAGEMENT
);
2781 FileOffset
= *Offset
;
2783 /* Negative/special offset: it cannot be used in this context */
2784 if(FileOffset
.u
.HighPart
< 0)
2786 KeBugCheck(MEMORY_MANAGEMENT
);
2789 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2790 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2791 FileOffset
.u
.LowPart
= AdjustOffset
;
2793 BufferSize
= Length
+ OffsetAdjustment
;
2794 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2797 * It's ok to use paged pool, because this is a temporary buffer only used in
2798 * the loading of executables. The assumption is that MmCreateSection is
2799 * always called at low IRQLs and that these buffers don't survive a brief
2800 * initialization phase
2802 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2807 KeBugCheck(MEMORY_MANAGEMENT
);
2813 Status
= MmspPageRead(File
,
2820 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2821 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2822 * to initialize internal state is even worse. Our cache manager is in need of
2826 IO_STATUS_BLOCK Iosb
;
2828 Status
= ZwReadFile(File
,
2838 if(NT_SUCCESS(Status
))
2840 UsedSize
= Iosb
.Information
;
2845 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2847 Status
= STATUS_IN_PAGE_ERROR
;
2848 ASSERT(!NT_SUCCESS(Status
));
2851 if(NT_SUCCESS(Status
))
2853 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2854 *AllocBase
= Buffer
;
2855 *ReadSize
= UsedSize
- OffsetAdjustment
;
2859 ExFreePoolWithTag(Buffer
, 'rXmM');
2866 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2867 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2868 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2873 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2877 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2879 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2880 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2887 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2891 MmspAssertSegmentsSorted(ImageSectionObject
);
2893 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2895 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2899 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2900 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2901 ImageSectionObject
->Segments
[i
- 1].Length
));
2909 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2913 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2915 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2916 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2924 MmspCompareSegments(const void * x
,
2927 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2928 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2931 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2932 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2936 * Ensures an image section's segments are sorted in memory
2941 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2944 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2946 MmspAssertSegmentsSorted(ImageSectionObject
);
2950 qsort(ImageSectionObject
->Segments
,
2951 ImageSectionObject
->NrSegments
,
2952 sizeof(ImageSectionObject
->Segments
[0]),
2953 MmspCompareSegments
);
2959 * Ensures an image section's segments don't overlap in memory and don't have
2960 * gaps and don't have a null size. We let them map to overlapping file regions,
2961 * though - that's not necessarily an error
2966 MmspCheckSegmentBounds
2968 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2974 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2976 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2980 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2982 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2984 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2992 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2993 * page could be OK (Windows seems to be OK with them), and larger gaps
2994 * could lead to image sections spanning several discontiguous regions
2995 * (NtMapViewOfSection could then refuse to map them, and they could
2996 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2998 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2999 ImageSectionObject
->Segments
[i
- 1].Length
) !=
3000 ImageSectionObject
->Segments
[i
].VirtualAddress
)
3011 * Merges and pads an image section's segments until they all are page-aligned
3012 * and have a size that is a multiple of the page size
3017 MmspPageAlignSegments
3019 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
3025 BOOLEAN Initialized
;
3026 PMM_SECTION_SEGMENT EffectiveSegment
;
3028 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
3030 MmspAssertSegmentsPageAligned(ImageSectionObject
);
3034 Initialized
= FALSE
;
3036 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3038 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3041 * The first segment requires special handling
3045 ULONG_PTR VirtualAddress
;
3046 ULONG_PTR VirtualOffset
;
3048 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
3050 /* Round down the virtual address to the nearest page */
3051 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3053 /* Round up the virtual size to the nearest page */
3054 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3055 EffectiveSegment
->VirtualAddress
;
3057 /* Adjust the raw address and size */
3058 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3060 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3066 * Garbage in, garbage out: unaligned base addresses make the file
3067 * offset point in curious and odd places, but that's what we were
3070 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3071 EffectiveSegment
->RawLength
+= VirtualOffset
;
3075 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3076 ULONG_PTR EndOfEffectiveSegment
;
3078 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3079 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3082 * The current segment begins exactly where the current effective
3083 * segment ended, therefore beginning a new effective segment
3085 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3088 ASSERT(LastSegment
<= i
);
3089 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3091 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3093 if (LastSegment
!= i
)
3096 * Copy the current segment. If necessary, the effective segment
3097 * will be expanded later
3099 *EffectiveSegment
= *Segment
;
3103 * Page-align the virtual size. We know for sure the virtual address
3106 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3107 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3110 * The current segment is still part of the current effective segment:
3111 * extend the effective segment to reflect this
3113 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3115 static const ULONG FlagsToProtection
[16] =
3123 PAGE_EXECUTE_READWRITE
,
3124 PAGE_EXECUTE_READWRITE
,
3129 PAGE_EXECUTE_WRITECOPY
,
3130 PAGE_EXECUTE_WRITECOPY
,
3131 PAGE_EXECUTE_WRITECOPY
,
3132 PAGE_EXECUTE_WRITECOPY
3135 unsigned ProtectionFlags
;
3138 * Extend the file size
3141 /* Unaligned segments must be contiguous within the file */
3142 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3143 EffectiveSegment
->RawLength
))
3148 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3151 * Extend the virtual size
3153 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3155 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3156 EffectiveSegment
->VirtualAddress
;
3159 * Merge the protection
3161 EffectiveSegment
->Protection
|= Segment
->Protection
;
3163 /* Clean up redundance */
3164 ProtectionFlags
= 0;
3166 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3167 ProtectionFlags
|= 1 << 0;
3169 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3170 ProtectionFlags
|= 1 << 1;
3172 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3173 ProtectionFlags
|= 1 << 2;
3175 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3176 ProtectionFlags
|= 1 << 3;
3178 ASSERT(ProtectionFlags
< 16);
3179 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3181 /* If a segment was required to be shared and cannot, fail */
3182 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3183 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3189 * We assume no holes between segments at this point
3193 KeBugCheck(MEMORY_MANAGEMENT
);
3197 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3203 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3204 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3206 LARGE_INTEGER Offset
;
3208 PVOID FileHeaderBuffer
;
3209 ULONG FileHeaderSize
;
3211 ULONG OldNrSegments
;
3216 * Read the beginning of the file (2 pages). Should be enough to contain
3217 * all (or most) of the headers
3219 Offset
.QuadPart
= 0;
3221 /* FIXME: use FileObject instead of FileHandle */
3222 Status
= ExeFmtpReadFile (FileHandle
,
3229 if (!NT_SUCCESS(Status
))
3232 if (FileHeaderSize
== 0)
3234 ExFreePool(FileHeaderBuffer
);
3235 return STATUS_UNSUCCESSFUL
;
3239 * Look for a loader that can handle this executable
3241 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3243 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3246 /* FIXME: use FileObject instead of FileHandle */
3247 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3253 ExeFmtpAllocateSegments
);
3255 if (!NT_SUCCESS(Status
))
3257 if (ImageSectionObject
->Segments
)
3259 ExFreePool(ImageSectionObject
->Segments
);
3260 ImageSectionObject
->Segments
= NULL
;
3264 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3268 ExFreePoolWithTag(FileHeaderBuffer
, 'rXmM');
3271 * No loader handled the format
3273 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3275 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3276 ASSERT(!NT_SUCCESS(Status
));
3279 if (!NT_SUCCESS(Status
))
3282 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3287 /* FIXME? are these values platform-dependent? */
3288 if(ImageSectionObject
->StackReserve
== 0)
3289 ImageSectionObject
->StackReserve
= 0x40000;
3291 if(ImageSectionObject
->StackCommit
== 0)
3292 ImageSectionObject
->StackCommit
= 0x1000;
3294 if(ImageSectionObject
->ImageBase
== 0)
3296 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3297 ImageSectionObject
->ImageBase
= 0x10000000;
3299 ImageSectionObject
->ImageBase
= 0x00400000;
3303 * And now the fun part: fixing the segments
3306 /* Sort them by virtual address */
3307 MmspSortSegments(ImageSectionObject
, Flags
);
3309 /* Ensure they don't overlap in memory */
3310 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3311 return STATUS_INVALID_IMAGE_FORMAT
;
3313 /* Ensure they are aligned */
3314 OldNrSegments
= ImageSectionObject
->NrSegments
;
3316 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3317 return STATUS_INVALID_IMAGE_FORMAT
;
3319 /* Trim them if the alignment phase merged some of them */
3320 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3322 PMM_SECTION_SEGMENT Segments
;
3323 SIZE_T SizeOfSegments
;
3325 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3327 Segments
= ExAllocatePoolWithTag(PagedPool
,
3329 TAG_MM_SECTION_SEGMENT
);
3331 if (Segments
== NULL
)
3332 return STATUS_INSUFFICIENT_RESOURCES
;
3334 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3335 ExFreePool(ImageSectionObject
->Segments
);
3336 ImageSectionObject
->Segments
= Segments
;
3339 /* And finish their initialization */
3340 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3342 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3343 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3345 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3346 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3349 ASSERT(NT_SUCCESS(Status
));
3354 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3355 ACCESS_MASK DesiredAccess
,
3356 POBJECT_ATTRIBUTES ObjectAttributes
,
3357 PLARGE_INTEGER UMaximumSize
,
3358 ULONG SectionPageProtection
,
3359 ULONG AllocationAttributes
,
3362 PROS_SECTION_OBJECT Section
;
3364 PFILE_OBJECT FileObject
;
3365 PMM_SECTION_SEGMENT SectionSegments
;
3366 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3368 ULONG FileAccess
= 0;
3371 * Specifying a maximum size is meaningless for an image section
3373 if (UMaximumSize
!= NULL
)
3375 return(STATUS_INVALID_PARAMETER_4
);
3379 * Check file access required
3381 if (SectionPageProtection
& PAGE_READWRITE
||
3382 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3384 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3388 FileAccess
= FILE_READ_DATA
;
3392 * Reference the file handle
3394 Status
= ObReferenceObjectByHandle(FileHandle
,
3397 ExGetPreviousMode(),
3398 (PVOID
*)(PVOID
)&FileObject
,
3401 if (!NT_SUCCESS(Status
))
3407 * Create the section
3409 Status
= ObCreateObject (ExGetPreviousMode(),
3410 MmSectionObjectType
,
3412 ExGetPreviousMode(),
3414 sizeof(ROS_SECTION_OBJECT
),
3417 (PVOID
*)(PVOID
)&Section
);
3418 if (!NT_SUCCESS(Status
))
3420 ObDereferenceObject(FileObject
);
3427 RtlZeroMemory(Section
, sizeof(ROS_SECTION_OBJECT
));
3428 Section
->SectionPageProtection
= SectionPageProtection
;
3429 Section
->AllocationAttributes
= AllocationAttributes
;
3432 * Initialized caching for this file object if previously caching
3433 * was initialized for the same on disk file
3435 Status
= CcTryToInitializeFileCache(FileObject
);
3437 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3439 NTSTATUS StatusExeFmt
;
3441 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3442 if (ImageSectionObject
== NULL
)
3444 ObDereferenceObject(FileObject
);
3445 ObDereferenceObject(Section
);
3446 return(STATUS_NO_MEMORY
);
3449 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3451 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3453 if (!NT_SUCCESS(StatusExeFmt
))
3455 if(ImageSectionObject
->Segments
!= NULL
)
3456 ExFreePool(ImageSectionObject
->Segments
);
3458 ExFreePool(ImageSectionObject
);
3459 ObDereferenceObject(Section
);
3460 ObDereferenceObject(FileObject
);
3461 return(StatusExeFmt
);
3464 Section
->ImageSection
= ImageSectionObject
;
3465 ASSERT(ImageSectionObject
->Segments
);
3470 Status
= MmspWaitForFileLock(FileObject
);
3471 if (!NT_SUCCESS(Status
))
3473 ExFreePool(ImageSectionObject
->Segments
);
3474 ExFreePool(ImageSectionObject
);
3475 ObDereferenceObject(Section
);
3476 ObDereferenceObject(FileObject
);
3480 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3481 ImageSectionObject
, NULL
))
3484 * An other thread has initialized the same image in the background
3486 ExFreePool(ImageSectionObject
->Segments
);
3487 ExFreePool(ImageSectionObject
);
3488 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3489 Section
->ImageSection
= ImageSectionObject
;
3490 SectionSegments
= ImageSectionObject
->Segments
;
3492 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3494 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3498 Status
= StatusExeFmt
;
3505 Status
= MmspWaitForFileLock(FileObject
);
3506 if (Status
!= STATUS_SUCCESS
)
3508 ObDereferenceObject(Section
);
3509 ObDereferenceObject(FileObject
);
3513 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3514 Section
->ImageSection
= ImageSectionObject
;
3515 SectionSegments
= ImageSectionObject
->Segments
;
3518 * Otherwise just reference all the section segments
3520 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3522 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3525 Status
= STATUS_SUCCESS
;
3527 Section
->FileObject
= FileObject
;
3528 CcRosReferenceCache(FileObject
);
3529 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3530 *SectionObject
= Section
;
3538 NtCreateSection (OUT PHANDLE SectionHandle
,
3539 IN ACCESS_MASK DesiredAccess
,
3540 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3541 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3542 IN ULONG SectionPageProtection OPTIONAL
,
3543 IN ULONG AllocationAttributes
,
3544 IN HANDLE FileHandle OPTIONAL
)
3546 LARGE_INTEGER SafeMaximumSize
;
3547 PVOID SectionObject
;
3548 KPROCESSOR_MODE PreviousMode
;
3551 PreviousMode
= ExGetPreviousMode();
3553 if(PreviousMode
!= KernelMode
)
3557 if (MaximumSize
!= NULL
)
3559 /* make a copy on the stack */
3560 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3561 MaximumSize
= &SafeMaximumSize
;
3563 ProbeForWriteHandle(SectionHandle
);
3565 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3567 /* Return the exception code */
3568 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3573 Status
= MmCreateSection(&SectionObject
,
3577 SectionPageProtection
,
3578 AllocationAttributes
,
3581 if (NT_SUCCESS(Status
))
3583 Status
= ObInsertObject ((PVOID
)SectionObject
,
3595 /**********************************************************************
3613 NtOpenSection(PHANDLE SectionHandle
,
3614 ACCESS_MASK DesiredAccess
,
3615 POBJECT_ATTRIBUTES ObjectAttributes
)
3618 KPROCESSOR_MODE PreviousMode
;
3621 PreviousMode
= ExGetPreviousMode();
3623 if(PreviousMode
!= KernelMode
)
3627 ProbeForWriteHandle(SectionHandle
);
3629 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3631 /* Return the exception code */
3632 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3637 Status
= ObOpenObjectByName(ObjectAttributes
,
3638 MmSectionObjectType
,
3645 if(NT_SUCCESS(Status
))
3649 *SectionHandle
= hSection
;
3651 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3653 Status
= _SEH2_GetExceptionCode();
3662 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3663 PROS_SECTION_OBJECT Section
,
3664 PMM_SECTION_SEGMENT Segment
,
3669 ULONG AllocationType
)
3673 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3675 BoundaryAddressMultiple
.QuadPart
= 0;
3677 Status
= MmCreateMemoryArea(AddressSpace
,
3678 MEMORY_AREA_SECTION_VIEW
,
3685 BoundaryAddressMultiple
);
3686 if (!NT_SUCCESS(Status
))
3688 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3689 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3693 ObReferenceObject((PVOID
)Section
);
3695 MArea
->Data
.SectionData
.Segment
= Segment
;
3696 MArea
->Data
.SectionData
.Section
= Section
;
3697 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3698 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3699 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3700 ViewSize
, 0, Protect
);
3702 return(STATUS_SUCCESS
);
3706 /**********************************************************************
3708 * NtMapViewOfSection
3711 * Maps a view of a section into the virtual address space of a
3716 * Handle of the section.
3719 * Handle of the process.
3722 * Desired base address (or NULL) on entry;
3723 * Actual base address of the view on exit.
3726 * Number of high order address bits that must be zero.
3729 * Size in bytes of the initially committed section of
3733 * Offset in bytes from the beginning of the section
3734 * to the beginning of the view.
3737 * Desired length of map (or zero to map all) on entry
3738 * Actual length mapped on exit.
3740 * InheritDisposition
3741 * Specified how the view is to be shared with
3745 * Type of allocation for the pages.
3748 * Protection for the committed region of the view.
3756 NtMapViewOfSection(IN HANDLE SectionHandle
,
3757 IN HANDLE ProcessHandle
,
3758 IN OUT PVOID
* BaseAddress OPTIONAL
,
3759 IN ULONG_PTR ZeroBits OPTIONAL
,
3760 IN SIZE_T CommitSize
,
3761 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3762 IN OUT PSIZE_T ViewSize
,
3763 IN SECTION_INHERIT InheritDisposition
,
3764 IN ULONG AllocationType OPTIONAL
,
3767 PVOID SafeBaseAddress
;
3768 LARGE_INTEGER SafeSectionOffset
;
3769 SIZE_T SafeViewSize
;
3770 PROS_SECTION_OBJECT Section
;
3772 KPROCESSOR_MODE PreviousMode
;
3773 PMMSUPPORT AddressSpace
;
3776 ACCESS_MASK DesiredAccess
;
3779 * Check the protection
3781 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3783 return STATUS_INVALID_PARAMETER_10
;
3786 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3787 if (tmpProtect
!= PAGE_NOACCESS
&&
3788 tmpProtect
!= PAGE_READONLY
&&
3789 tmpProtect
!= PAGE_READWRITE
&&
3790 tmpProtect
!= PAGE_WRITECOPY
&&
3791 tmpProtect
!= PAGE_EXECUTE
&&
3792 tmpProtect
!= PAGE_EXECUTE_READ
&&
3793 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3794 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3796 return STATUS_INVALID_PAGE_PROTECTION
;
3799 PreviousMode
= ExGetPreviousMode();
3801 if(PreviousMode
!= KernelMode
)
3803 SafeBaseAddress
= NULL
;
3804 SafeSectionOffset
.QuadPart
= 0;
3809 if(BaseAddress
!= NULL
)
3811 ProbeForWritePointer(BaseAddress
);
3812 SafeBaseAddress
= *BaseAddress
;
3814 if(SectionOffset
!= NULL
)
3816 ProbeForWriteLargeInteger(SectionOffset
);
3817 SafeSectionOffset
= *SectionOffset
;
3819 ProbeForWriteSize_t(ViewSize
);
3820 SafeViewSize
= *ViewSize
;
3822 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3824 /* Return the exception code */
3825 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3831 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3832 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3833 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3836 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3838 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3839 PROCESS_VM_OPERATION
,
3842 (PVOID
*)(PVOID
)&Process
,
3844 if (!NT_SUCCESS(Status
))
3849 AddressSpace
= &Process
->Vm
;
3851 /* Convert NT Protection Attr to Access Mask */
3852 if (Protect
== PAGE_READONLY
)
3854 DesiredAccess
= SECTION_MAP_READ
;
3856 else if (Protect
== PAGE_READWRITE
)
3858 DesiredAccess
= SECTION_MAP_WRITE
;
3860 else if (Protect
== PAGE_WRITECOPY
)
3862 DesiredAccess
= SECTION_QUERY
;
3864 /* FIXME: Handle other Protection Attributes. For now keep previous behavior */
3867 DesiredAccess
= SECTION_MAP_READ
;
3870 Status
= ObReferenceObjectByHandle(SectionHandle
,
3872 MmSectionObjectType
,
3874 (PVOID
*)(PVOID
)&Section
,
3876 if (!(NT_SUCCESS(Status
)))
3878 DPRINT("ObReference failed rc=%x\n",Status
);
3879 ObDereferenceObject(Process
);
3883 Status
= MmMapViewOfSection(Section
,
3885 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3888 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3889 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3894 /* Check if this is an image for the current process */
3895 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3896 (Process
== PsGetCurrentProcess()) &&
3897 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3899 /* Notify the debugger */
3900 DbgkMapViewOfSection(Section
,
3902 SafeSectionOffset
.LowPart
,
3906 ObDereferenceObject(Section
);
3907 ObDereferenceObject(Process
);
3909 if(NT_SUCCESS(Status
))
3911 /* copy parameters back to the caller */
3914 if(BaseAddress
!= NULL
)
3916 *BaseAddress
= SafeBaseAddress
;
3918 if(SectionOffset
!= NULL
)
3920 *SectionOffset
= SafeSectionOffset
;
3922 if(ViewSize
!= NULL
)
3924 *ViewSize
= SafeViewSize
;
3927 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3929 Status
= _SEH2_GetExceptionCode();
3938 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3939 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3942 PFILE_OBJECT FileObject
;
3945 SWAPENTRY SavedSwapEntry
;
3948 PROS_SECTION_OBJECT Section
;
3949 PMM_SECTION_SEGMENT Segment
;
3950 PMMSUPPORT AddressSpace
;
3953 AddressSpace
= (PMMSUPPORT
)Context
;
3954 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3956 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3958 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3959 MemoryArea
->Data
.SectionData
.ViewOffset
;
3961 Section
= MemoryArea
->Data
.SectionData
.Section
;
3962 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3964 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3968 MmUnlockSectionSegment(Segment
);
3969 MmUnlockAddressSpace(AddressSpace
);
3971 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3972 if (Status
!= STATUS_SUCCESS
)
3974 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3975 KeBugCheck(MEMORY_MANAGEMENT
);
3978 MmLockAddressSpace(AddressSpace
);
3979 MmLockSectionSegment(Segment
);
3980 MmspCompleteAndReleasePageOp(PageOp
);
3981 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3984 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3987 * For a dirty, datafile, non-private page mark it as dirty in the
3990 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3992 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3994 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3995 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3996 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3997 ASSERT(SwapEntry
== 0);
4006 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4008 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
4009 KeBugCheck(MEMORY_MANAGEMENT
);
4011 MmFreeSwapPage(SwapEntry
);
4015 if (IS_SWAP_FROM_SSE(Entry
) ||
4016 Page
!= PFN_FROM_SSE(Entry
))
4021 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
4023 DPRINT1("Found a private page in a pagefile section.\n");
4024 KeBugCheck(MEMORY_MANAGEMENT
);
4027 * Just dereference private pages
4029 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
4030 if (SavedSwapEntry
!= 0)
4032 MmFreeSwapPage(SavedSwapEntry
);
4033 MmSetSavedSwapEntryPage(Page
, 0);
4035 MmDeleteRmap(Page
, Process
, Address
);
4036 MmReleasePageMemoryConsumer(MC_USER
, Page
);
4040 MmDeleteRmap(Page
, Process
, Address
);
4041 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
4047 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
4051 PMEMORY_AREA MemoryArea
;
4052 PROS_SECTION_OBJECT Section
;
4053 PMM_SECTION_SEGMENT Segment
;
4054 PLIST_ENTRY CurrentEntry
;
4055 PMM_REGION CurrentRegion
;
4056 PLIST_ENTRY RegionListHead
;
4058 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4060 if (MemoryArea
== NULL
)
4062 return(STATUS_UNSUCCESSFUL
);
4065 MemoryArea
->DeleteInProgress
= TRUE
;
4066 Section
= MemoryArea
->Data
.SectionData
.Section
;
4067 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4069 MmLockSectionSegment(Segment
);
4071 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4072 while (!IsListEmpty(RegionListHead
))
4074 CurrentEntry
= RemoveHeadList(RegionListHead
);
4075 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4076 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4079 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4081 Status
= MmFreeMemoryArea(AddressSpace
,
4088 Status
= MmFreeMemoryArea(AddressSpace
,
4093 MmUnlockSectionSegment(Segment
);
4094 ObDereferenceObject(Section
);
4095 return(STATUS_SUCCESS
);
4102 MmUnmapViewOfSection(PEPROCESS Process
,
4106 PMEMORY_AREA MemoryArea
;
4107 PMMSUPPORT AddressSpace
;
4108 PROS_SECTION_OBJECT Section
;
4111 PVOID ImageBaseAddress
= 0;
4113 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4114 Process
, BaseAddress
);
4118 AddressSpace
= &Process
->Vm
;
4120 MmLockAddressSpace(AddressSpace
);
4121 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4123 if (MemoryArea
== NULL
||
4124 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4125 MemoryArea
->DeleteInProgress
)
4127 MmUnlockAddressSpace(AddressSpace
);
4128 return STATUS_NOT_MAPPED_VIEW
;
4131 MemoryArea
->DeleteInProgress
= TRUE
;
4133 while (MemoryArea
->PageOpCount
)
4135 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4139 Offset
-= PAGE_SIZE
;
4140 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4141 MemoryArea
->Data
.SectionData
.Segment
,
4142 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4145 MmUnlockAddressSpace(AddressSpace
);
4146 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4147 if (Status
!= STATUS_SUCCESS
)
4149 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4150 KeBugCheck(MEMORY_MANAGEMENT
);
4152 MmLockAddressSpace(AddressSpace
);
4153 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4155 if (MemoryArea
== NULL
||
4156 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4158 MmUnlockAddressSpace(AddressSpace
);
4159 return STATUS_NOT_MAPPED_VIEW
;
4166 Section
= MemoryArea
->Data
.SectionData
.Section
;
4168 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4172 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4173 PMM_SECTION_SEGMENT SectionSegments
;
4174 PMM_SECTION_SEGMENT Segment
;
4176 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4177 ImageSectionObject
= Section
->ImageSection
;
4178 SectionSegments
= ImageSectionObject
->Segments
;
4179 NrSegments
= ImageSectionObject
->NrSegments
;
4181 /* Search for the current segment within the section segments
4182 * and calculate the image base address */
4183 for (i
= 0; i
< NrSegments
; i
++)
4185 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4187 if (Segment
== &SectionSegments
[i
])
4189 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4194 if (i
>= NrSegments
)
4196 KeBugCheck(MEMORY_MANAGEMENT
);
4199 for (i
= 0; i
< NrSegments
; i
++)
4201 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4203 PVOID SBaseAddress
= (PVOID
)
4204 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4206 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4212 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4215 MmUnlockAddressSpace(AddressSpace
);
4217 /* Notify debugger */
4218 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4220 return(STATUS_SUCCESS
);
4223 /**********************************************************************
4225 * NtUnmapViewOfSection
4240 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4244 KPROCESSOR_MODE PreviousMode
;
4247 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4248 ProcessHandle
, BaseAddress
);
4250 PreviousMode
= ExGetPreviousMode();
4252 DPRINT("Referencing process\n");
4253 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4254 PROCESS_VM_OPERATION
,
4257 (PVOID
*)(PVOID
)&Process
,
4259 if (!NT_SUCCESS(Status
))
4261 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4265 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4267 ObDereferenceObject(Process
);
4274 * Queries the information of a section object.
4276 * @param SectionHandle
4277 * Handle to the section object. It must be opened with SECTION_QUERY
4279 * @param SectionInformationClass
4280 * Index to a certain information structure. Can be either
4281 * SectionBasicInformation or SectionImageInformation. The latter
4282 * is valid only for sections that were created with the SEC_IMAGE
4284 * @param SectionInformation
4285 * Caller supplies storage for resulting information.
4287 * Size of the supplied storage.
4288 * @param ResultLength
4296 NtQuerySection(IN HANDLE SectionHandle
,
4297 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4298 OUT PVOID SectionInformation
,
4299 IN SIZE_T SectionInformationLength
,
4300 OUT PSIZE_T ResultLength OPTIONAL
)
4302 PROS_SECTION_OBJECT Section
;
4303 KPROCESSOR_MODE PreviousMode
;
4307 PreviousMode
= ExGetPreviousMode();
4309 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4311 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4313 SectionInformationLength
,
4318 if(!NT_SUCCESS(Status
))
4320 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4324 Status
= ObReferenceObjectByHandle(SectionHandle
,
4326 MmSectionObjectType
,
4328 (PVOID
*)(PVOID
)&Section
,
4330 if (NT_SUCCESS(Status
))
4332 switch (SectionInformationClass
)
4334 case SectionBasicInformation
:
4336 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4340 Sbi
->Attributes
= Section
->AllocationAttributes
;
4341 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4343 Sbi
->BaseAddress
= 0;
4344 Sbi
->Size
.QuadPart
= 0;
4348 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4349 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4352 if (ResultLength
!= NULL
)
4354 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4356 Status
= STATUS_SUCCESS
;
4358 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4360 Status
= _SEH2_GetExceptionCode();
4367 case SectionImageInformation
:
4369 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4373 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4374 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4376 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4377 ImageSectionObject
= Section
->ImageSection
;
4379 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4380 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4381 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4382 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4383 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4384 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4385 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4386 Sii
->Machine
= ImageSectionObject
->Machine
;
4387 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4390 if (ResultLength
!= NULL
)
4392 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4394 Status
= STATUS_SUCCESS
;
4396 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4398 Status
= _SEH2_GetExceptionCode();
4406 ObDereferenceObject(Section
);
4414 * Extends size of file backed section.
4416 * @param SectionHandle
4417 * Handle to the section object. It must be opened with
4418 * SECTION_EXTEND_SIZE access.
4419 * @param NewMaximumSize
4420 * New maximum size of the section in bytes.
4424 * @todo Move the actual code to internal function MmExtendSection.
4428 NtExtendSection(IN HANDLE SectionHandle
,
4429 IN PLARGE_INTEGER NewMaximumSize
)
4431 LARGE_INTEGER SafeNewMaximumSize
;
4432 PROS_SECTION_OBJECT Section
;
4433 KPROCESSOR_MODE PreviousMode
;
4436 PreviousMode
= ExGetPreviousMode();
4438 if(PreviousMode
!= KernelMode
)
4442 /* make a copy on the stack */
4443 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4444 NewMaximumSize
= &SafeNewMaximumSize
;
4446 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4448 /* Return the exception code */
4449 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4454 Status
= ObReferenceObjectByHandle(SectionHandle
,
4455 SECTION_EXTEND_SIZE
,
4456 MmSectionObjectType
,
4460 if (!NT_SUCCESS(Status
))
4465 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4467 ObDereferenceObject(Section
);
4468 return STATUS_INVALID_PARAMETER
;
4472 * - Acquire file extneding resource.
4473 * - Check if we're not resizing the section below it's actual size!
4474 * - Extend segments if needed.
4475 * - Set file information (FileAllocationInformation) to the new size.
4476 * - Release file extending resource.
4479 ObDereferenceObject(Section
);
4481 return STATUS_NOT_IMPLEMENTED
;
4485 /**********************************************************************
4487 * MmAllocateSection@4
4497 * Code taken from ntoskrnl/mm/special.c.
4502 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4507 PMMSUPPORT AddressSpace
;
4508 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4510 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4512 BoundaryAddressMultiple
.QuadPart
= 0;
4514 AddressSpace
= MmGetKernelAddressSpace();
4515 Result
= BaseAddress
;
4516 MmLockAddressSpace(AddressSpace
);
4517 Status
= MmCreateMemoryArea (AddressSpace
,
4525 BoundaryAddressMultiple
);
4526 MmUnlockAddressSpace(AddressSpace
);
4528 if (!NT_SUCCESS(Status
))
4532 DPRINT("Result %p\n",Result
);
4534 /* Create a virtual mapping for this memory area */
4535 MmMapMemoryArea(Result
, Length
, MC_NPPOOL
, PAGE_READWRITE
);
4537 return ((PVOID
)Result
);
4541 /**********************************************************************
4543 * MmMapViewOfSection
4546 * Maps a view of a section into the virtual address space of a
4551 * Pointer to the section object.
4554 * Pointer to the process.
4557 * Desired base address (or NULL) on entry;
4558 * Actual base address of the view on exit.
4561 * Number of high order address bits that must be zero.
4564 * Size in bytes of the initially committed section of
4568 * Offset in bytes from the beginning of the section
4569 * to the beginning of the view.
4572 * Desired length of map (or zero to map all) on entry
4573 * Actual length mapped on exit.
4575 * InheritDisposition
4576 * Specified how the view is to be shared with
4580 * Type of allocation for the pages.
4583 * Protection for the committed region of the view.
4591 MmMapViewOfSection(IN PVOID SectionObject
,
4592 IN PEPROCESS Process
,
4593 IN OUT PVOID
*BaseAddress
,
4594 IN ULONG_PTR ZeroBits
,
4595 IN SIZE_T CommitSize
,
4596 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4597 IN OUT PSIZE_T ViewSize
,
4598 IN SECTION_INHERIT InheritDisposition
,
4599 IN ULONG AllocationType
,
4602 PROS_SECTION_OBJECT Section
;
4603 PMMSUPPORT AddressSpace
;
4605 NTSTATUS Status
= STATUS_SUCCESS
;
4609 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4611 return STATUS_INVALID_PAGE_PROTECTION
;
4615 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4616 AddressSpace
= &Process
->Vm
;
4618 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4620 MmLockAddressSpace(AddressSpace
);
4622 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4626 ULONG_PTR ImageBase
;
4628 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4629 PMM_SECTION_SEGMENT SectionSegments
;
4631 ImageSectionObject
= Section
->ImageSection
;
4632 SectionSegments
= ImageSectionObject
->Segments
;
4633 NrSegments
= ImageSectionObject
->NrSegments
;
4636 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4639 ImageBase
= ImageSectionObject
->ImageBase
;
4643 for (i
= 0; i
< NrSegments
; i
++)
4645 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4647 ULONG_PTR MaxExtent
;
4648 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4649 SectionSegments
[i
].Length
;
4650 ImageSize
= max(ImageSize
, MaxExtent
);
4654 ImageSectionObject
->ImageSize
= ImageSize
;
4656 /* Check there is enough space to map the section at that point. */
4657 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4658 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4660 /* Fail if the user requested a fixed base address. */
4661 if ((*BaseAddress
) != NULL
)
4663 MmUnlockAddressSpace(AddressSpace
);
4664 return(STATUS_UNSUCCESSFUL
);
4666 /* Otherwise find a gap to map the image. */
4667 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4670 MmUnlockAddressSpace(AddressSpace
);
4671 return(STATUS_UNSUCCESSFUL
);
4675 for (i
= 0; i
< NrSegments
; i
++)
4677 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4679 PVOID SBaseAddress
= (PVOID
)
4680 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4681 MmLockSectionSegment(&SectionSegments
[i
]);
4682 Status
= MmMapViewOfSegment(AddressSpace
,
4684 &SectionSegments
[i
],
4686 SectionSegments
[i
].Length
,
4687 SectionSegments
[i
].Protection
,
4690 MmUnlockSectionSegment(&SectionSegments
[i
]);
4691 if (!NT_SUCCESS(Status
))
4693 MmUnlockAddressSpace(AddressSpace
);
4699 *BaseAddress
= (PVOID
)ImageBase
;
4703 /* check for write access */
4704 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4705 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4707 MmUnlockAddressSpace(AddressSpace
);
4708 return STATUS_SECTION_PROTECTION
;
4710 /* check for read access */
4711 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4712 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4714 MmUnlockAddressSpace(AddressSpace
);
4715 return STATUS_SECTION_PROTECTION
;
4717 /* check for execute access */
4718 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4719 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4721 MmUnlockAddressSpace(AddressSpace
);
4722 return STATUS_SECTION_PROTECTION
;
4725 if (ViewSize
== NULL
)
4727 /* Following this pointer would lead to us to the dark side */
4728 /* What to do? Bugcheck? Return status? Do the mambo? */
4729 KeBugCheck(MEMORY_MANAGEMENT
);
4732 if (SectionOffset
== NULL
)
4738 ViewOffset
= SectionOffset
->u
.LowPart
;
4741 if ((ViewOffset
% PAGE_SIZE
) != 0)
4743 MmUnlockAddressSpace(AddressSpace
);
4744 return(STATUS_MAPPED_ALIGNMENT
);
4747 if ((*ViewSize
) == 0)
4749 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4751 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4753 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4756 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4758 MmLockSectionSegment(Section
->Segment
);
4759 Status
= MmMapViewOfSegment(AddressSpace
,
4766 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4767 MmUnlockSectionSegment(Section
->Segment
);
4768 if (!NT_SUCCESS(Status
))
4770 MmUnlockAddressSpace(AddressSpace
);
4775 MmUnlockAddressSpace(AddressSpace
);
4777 return(STATUS_SUCCESS
);
4784 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4785 IN PLARGE_INTEGER NewFileSize
)
4787 /* Check whether an ImageSectionObject exists */
4788 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4790 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4794 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4796 PMM_SECTION_SEGMENT Segment
;
4798 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4801 if (Segment
->ReferenceCount
!= 0)
4803 /* Check size of file */
4804 if (SectionObjectPointer
->SharedCacheMap
)
4806 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4807 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4815 /* Something must gone wrong
4816 * how can we have a Section but no
4818 DPRINT("ERROR: DataSectionObject without reference!\n");
4822 DPRINT("FIXME: didn't check for outstanding write probes\n");
4832 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4842 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4843 IN MMFLUSH_TYPE FlushType
)
4847 case MmFlushForDelete
:
4848 if (SectionObjectPointer
->ImageSectionObject
||
4849 SectionObjectPointer
->DataSectionObject
)
4853 CcRosSetRemoveOnClose(SectionObjectPointer
);
4855 case MmFlushForWrite
:
4865 MmForceSectionClosed (
4866 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4867 IN BOOLEAN DelayClose
)
4878 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4879 OUT PVOID
* MappedBase
,
4880 IN OUT PSIZE_T ViewSize
)
4882 PROS_SECTION_OBJECT Section
;
4883 PMMSUPPORT AddressSpace
;
4886 DPRINT("MmMapViewInSystemSpace() called\n");
4888 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4889 AddressSpace
= MmGetKernelAddressSpace();
4891 MmLockAddressSpace(AddressSpace
);
4894 if ((*ViewSize
) == 0)
4896 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4898 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4900 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4903 MmLockSectionSegment(Section
->Segment
);
4906 Status
= MmMapViewOfSegment(AddressSpace
,
4915 MmUnlockSectionSegment(Section
->Segment
);
4916 MmUnlockAddressSpace(AddressSpace
);
4926 MmMapViewInSessionSpace (
4928 OUT PVOID
*MappedBase
,
4929 IN OUT PSIZE_T ViewSize
4933 return STATUS_NOT_IMPLEMENTED
;
4941 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4943 PMMSUPPORT AddressSpace
;
4946 DPRINT("MmUnmapViewInSystemSpace() called\n");
4948 AddressSpace
= MmGetKernelAddressSpace();
4950 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4960 MmUnmapViewInSessionSpace (
4965 return STATUS_NOT_IMPLEMENTED
;
4968 /**********************************************************************
4973 * Creates a section object.
4976 * SectionObject (OUT)
4977 * Caller supplied storage for the resulting pointer
4978 * to a SECTION_OBJECT instance;
4981 * Specifies the desired access to the section can be a
4983 * STANDARD_RIGHTS_REQUIRED |
4985 * SECTION_MAP_WRITE |
4986 * SECTION_MAP_READ |
4987 * SECTION_MAP_EXECUTE
4989 * ObjectAttributes [OPTIONAL]
4990 * Initialized attributes for the object can be used
4991 * to create a named section;
4994 * Maximizes the size of the memory section. Must be
4995 * non-NULL for a page-file backed section.
4996 * If value specified for a mapped file and the file is
4997 * not large enough, file will be extended.
4999 * SectionPageProtection
5000 * Can be a combination of:
5006 * AllocationAttributes
5007 * Can be a combination of:
5012 * Handle to a file to create a section mapped to a file
5013 * instead of a memory backed section;
5024 MmCreateSection (OUT PVOID
* Section
,
5025 IN ACCESS_MASK DesiredAccess
,
5026 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
5027 IN PLARGE_INTEGER MaximumSize
,
5028 IN ULONG SectionPageProtection
,
5029 IN ULONG AllocationAttributes
,
5030 IN HANDLE FileHandle OPTIONAL
,
5031 IN PFILE_OBJECT File OPTIONAL
)
5034 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
5037 * Check the protection
5039 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
5040 if (Protection
!= PAGE_READONLY
&&
5041 Protection
!= PAGE_READWRITE
&&
5042 Protection
!= PAGE_WRITECOPY
&&
5043 Protection
!= PAGE_EXECUTE
&&
5044 Protection
!= PAGE_EXECUTE_READ
&&
5045 Protection
!= PAGE_EXECUTE_READWRITE
&&
5046 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5048 return STATUS_INVALID_PAGE_PROTECTION
;
5051 if (AllocationAttributes
& SEC_IMAGE
)
5053 return(MmCreateImageSection(SectionObject
,
5057 SectionPageProtection
,
5058 AllocationAttributes
,
5062 if (FileHandle
!= NULL
)
5064 return(MmCreateDataFileSection(SectionObject
,
5068 SectionPageProtection
,
5069 AllocationAttributes
,
5073 return(MmCreatePageFileSection(SectionObject
,
5077 SectionPageProtection
,
5078 AllocationAttributes
));
5083 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
5084 IN PVOID File2MappedAsFile
)
5087 return STATUS_NOT_IMPLEMENTED
;