2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
50 #include <reactos/exeformat.h>
52 #if defined (ALLOC_PRAGMA)
53 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
54 #pragma alloc_text(INIT, MmInitSectionImplementation)
58 /* TYPES *********************************************************************/
62 PROS_SECTION_OBJECT Section
;
63 PMM_SECTION_SEGMENT Segment
;
68 MM_SECTION_PAGEOUT_CONTEXT
;
70 /* GLOBALS *******************************************************************/
72 POBJECT_TYPE MmSectionObjectType
= NULL
;
74 static GENERIC_MAPPING MmpSectionMapping
= {
75 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
76 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
77 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
80 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
81 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
82 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
83 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
84 #define MAX_SHARE_COUNT 0x7FF
85 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
86 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
87 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
89 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
91 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
92 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
95 /* FUNCTIONS *****************************************************************/
99 MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section
)
104 /* Return the file object */
105 return Section
->FileObject
; // Section->ControlArea->FileObject on NT
110 MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section
,
111 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
113 POBJECT_NAME_INFORMATION ObjectNameInfo
;
117 /* Make sure it's an image section */
119 if (!(Section
->AllocationAttributes
& SEC_IMAGE
))
122 return STATUS_SECTION_NOT_IMAGE
;
125 /* Allocate memory for our structure */
126 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
,
128 TAG('M', 'm', ' ', ' '));
129 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
132 Status
= ObQueryNameString(Section
->FileObject
,
136 if (!NT_SUCCESS(Status
))
138 /* Failed, free memory */
139 ExFreePoolWithTag(ObjectNameInfo
, TAG('M', 'm', ' ', ' '));
144 *ModuleName
= ObjectNameInfo
;
145 return STATUS_SUCCESS
;
150 MmGetFileNameForAddress(IN PVOID Address
,
151 OUT PUNICODE_STRING ModuleName
)
153 PROS_SECTION_OBJECT Section
;
154 PMEMORY_AREA MemoryArea
;
155 PMM_AVL_TABLE AddressSpace
;
156 POBJECT_NAME_INFORMATION ModuleNameInformation
;
157 NTSTATUS Status
= STATUS_ADDRESS_NOT_ASSOCIATED
;
159 /* Get the MM_AVL_TABLE from EPROCESS */
160 if (Address
>= MmSystemRangeStart
)
162 AddressSpace
= MmGetKernelAddressSpace();
166 AddressSpace
= &PsGetCurrentProcess()->VadRoot
;
169 /* Lock address space */
170 MmLockAddressSpace(AddressSpace
);
172 /* Locate the memory area for the process by address */
173 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
175 /* Make sure it's a section view type */
176 if ((MemoryArea
!= NULL
) && (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
))
178 /* Get the section pointer to the SECTION_OBJECT */
179 Section
= MemoryArea
->Data
.SectionData
.Section
;
181 /* Unlock address space */
182 MmUnlockAddressSpace(AddressSpace
);
184 /* Get the filename of the section */
185 Status
= MmGetFileNameForSection(Section
,&ModuleNameInformation
);
187 if (NT_SUCCESS(Status
))
189 /* Init modulename */
190 RtlCreateUnicodeString(ModuleName
,
191 ModuleNameInformation
->Name
.Buffer
);
193 /* Free temp taged buffer from MmGetFileNameForSection() */
194 ExFreePoolWithTag(ModuleNameInformation
, TAG('M', 'm', ' ', ' '));
195 DPRINT("Found ModuleName %S by address %p\n",
196 ModuleName
->Buffer
,Address
);
201 /* Unlock address space */
202 MmUnlockAddressSpace(AddressSpace
);
208 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
211 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
212 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
213 * RETURNS: Status of the wait.
216 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
218 LARGE_INTEGER Timeout
;
219 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
221 Timeout
.QuadPart
= -100000000LL; // 10 sec
224 Timeout
.QuadPart
= -100000000; // 10 sec
227 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
232 * FUNCTION: Sets the page op completion event and releases the page op.
233 * ARGUMENTS: PMM_PAGEOP.
234 * RETURNS: In shorter time than it takes you to even read this
235 * description, so don't even think about geting a mug of coffee.
238 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
240 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
241 MmReleasePageOp(PageOp
);
246 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
247 * ARGUMENTS: PFILE_OBJECT to wait for.
248 * RETURNS: Status of the wait.
251 MmspWaitForFileLock(PFILE_OBJECT File
)
253 return STATUS_SUCCESS
;
254 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
259 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
262 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
264 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
266 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
268 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
276 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
278 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
280 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
281 PMM_SECTION_SEGMENT SectionSegments
;
285 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
286 NrSegments
= ImageSectionObject
->NrSegments
;
287 SectionSegments
= ImageSectionObject
->Segments
;
288 for (i
= 0; i
< NrSegments
; i
++)
290 if (SectionSegments
[i
].ReferenceCount
!= 0)
292 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
293 SectionSegments
[i
].ReferenceCount
);
294 KeBugCheck(MEMORY_MANAGEMENT
);
296 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
298 ExFreePool(ImageSectionObject
->Segments
);
299 ExFreePool(ImageSectionObject
);
300 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
302 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
304 PMM_SECTION_SEGMENT Segment
;
306 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
309 if (Segment
->ReferenceCount
!= 0)
311 DPRINT1("Data segment still referenced\n");
312 KeBugCheck(MEMORY_MANAGEMENT
);
314 MmFreePageTablesSectionSegment(Segment
);
316 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
322 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
324 ExAcquireFastMutex(&Segment
->Lock
);
329 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
331 ExReleaseFastMutex(&Segment
->Lock
);
336 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
340 PSECTION_PAGE_TABLE Table
;
341 ULONG DirectoryOffset
;
344 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
346 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
350 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
351 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
355 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
356 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
357 TAG_SECTION_PAGE_TABLE
);
360 KeBugCheck(MEMORY_MANAGEMENT
);
362 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
363 DPRINT("Table %x\n", Table
);
366 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
367 Table
->Entry
[TableOffset
] = Entry
;
373 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
376 PSECTION_PAGE_TABLE Table
;
378 ULONG DirectoryOffset
;
381 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
383 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
385 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
389 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
390 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
391 DPRINT("Table %x\n", Table
);
397 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
398 Entry
= Table
->Entry
[TableOffset
];
404 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
409 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
412 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
413 KeBugCheck(MEMORY_MANAGEMENT
);
415 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
417 DPRINT1("Maximum share count reached\n");
418 KeBugCheck(MEMORY_MANAGEMENT
);
420 if (IS_SWAP_FROM_SSE(Entry
))
422 KeBugCheck(MEMORY_MANAGEMENT
);
424 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
425 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
430 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
431 PMM_SECTION_SEGMENT Segment
,
437 BOOLEAN IsDirectMapped
= FALSE
;
439 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
442 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
443 KeBugCheck(MEMORY_MANAGEMENT
);
445 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
447 DPRINT1("Zero share count for unshare\n");
448 KeBugCheck(MEMORY_MANAGEMENT
);
450 if (IS_SWAP_FROM_SSE(Entry
))
452 KeBugCheck(MEMORY_MANAGEMENT
);
454 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
456 * If we reducing the share count of this entry to zero then set the entry
457 * to zero and tell the cache the page is no longer mapped.
459 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
461 PFILE_OBJECT FileObject
;
463 SWAPENTRY SavedSwapEntry
;
465 BOOLEAN IsImageSection
;
468 FileOffset
= Offset
+ Segment
->FileOffset
;
470 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
472 Page
= PFN_FROM_SSE(Entry
);
473 FileObject
= Section
->FileObject
;
474 if (FileObject
!= NULL
&&
475 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
478 if ((FileOffset
% PAGE_SIZE
) == 0 &&
479 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
482 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
483 IsDirectMapped
= TRUE
;
484 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
485 if (!NT_SUCCESS(Status
))
487 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
488 KeBugCheck(MEMORY_MANAGEMENT
);
493 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
494 if (SavedSwapEntry
== 0)
497 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
498 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
502 * Try to page out this page and set the swap entry
503 * within the section segment. There exist no rmap entry
504 * for this page. The pager thread can't page out a
505 * page without a rmap entry.
507 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
511 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
514 MmReleasePageMemoryConsumer(MC_USER
, Page
);
520 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
521 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
529 * We hold all locks. Nobody can do something with the current
530 * process and the current segment (also not within an other process).
533 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
534 if (!NT_SUCCESS(Status
))
536 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
537 KeBugCheck(MEMORY_MANAGEMENT
);
540 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
541 MmSetSavedSwapEntryPage(Page
, 0);
543 MmReleasePageMemoryConsumer(MC_USER
, Page
);
547 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
548 KeBugCheck(MEMORY_MANAGEMENT
);
554 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
556 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
559 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
562 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
565 PCACHE_SEGMENT CacheSeg
;
566 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
567 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
570 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
579 MiReadPage(PMEMORY_AREA MemoryArea
,
583 * FUNCTION: Read a page for a section backed memory area.
585 * MemoryArea - Memory area to read the page for.
586 * Offset - Offset of the page to read.
587 * Page - Variable that receives a page contains the read data.
594 PCACHE_SEGMENT CacheSeg
;
595 PFILE_OBJECT FileObject
;
599 BOOLEAN IsImageSection
;
602 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
603 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
604 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
605 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
606 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
610 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
613 * If the file system is letting us go directly to the cache and the
614 * memory area was mapped at an offset in the file which is page aligned
615 * then get the related cache segment.
617 if ((FileOffset
% PAGE_SIZE
) == 0 &&
618 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
619 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
623 * Get the related cache segment; we use a lower level interface than
624 * filesystems do because it is safe for us to use an offset with a
625 * alignment less than the file system block size.
627 Status
= CcRosGetCacheSegment(Bcb
,
633 if (!NT_SUCCESS(Status
))
640 * If the cache segment isn't up to date then call the file
641 * system to read in the data.
643 Status
= ReadCacheSegment(CacheSeg
);
644 if (!NT_SUCCESS(Status
))
646 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
651 * Retrieve the page from the cache segment that we actually want.
653 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
654 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
656 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
661 ULONG CacheSegOffset
;
663 * Allocate a page, this is rather complicated by the possibility
664 * we might have to move other things out of memory
666 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
667 if (!NT_SUCCESS(Status
))
671 Status
= CcRosGetCacheSegment(Bcb
,
677 if (!NT_SUCCESS(Status
))
684 * If the cache segment isn't up to date then call the file
685 * system to read in the data.
687 Status
= ReadCacheSegment(CacheSeg
);
688 if (!NT_SUCCESS(Status
))
690 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
694 PageAddr
= MiMapPagesToZeroInHyperSpace(*Page
);
695 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
696 Length
= RawLength
- SegOffset
;
697 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
699 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
701 else if (CacheSegOffset
>= PAGE_SIZE
)
703 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
707 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
708 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
709 Status
= CcRosGetCacheSegment(Bcb
,
710 FileOffset
+ CacheSegOffset
,
715 if (!NT_SUCCESS(Status
))
717 MiUnmapPagesInZeroSpace(PageAddr
);
723 * If the cache segment isn't up to date then call the file
724 * system to read in the data.
726 Status
= ReadCacheSegment(CacheSeg
);
727 if (!NT_SUCCESS(Status
))
729 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
730 MiUnmapPagesInZeroSpace(PageAddr
);
734 if (Length
< PAGE_SIZE
)
736 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
740 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
743 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
744 MiUnmapPagesInZeroSpace(PageAddr
);
746 return(STATUS_SUCCESS
);
751 MmNotPresentFaultSectionView(PMM_AVL_TABLE AddressSpace
,
752 MEMORY_AREA
* MemoryArea
,
760 PROS_SECTION_OBJECT Section
;
761 PMM_SECTION_SEGMENT Segment
;
767 BOOLEAN HasSwapEntry
;
768 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
771 * There is a window between taking the page fault and locking the
772 * address space when another thread could load the page so we check
775 if (MmIsPagePresent(Process
, Address
))
779 MmLockPage(MmGetPfnForProcess(Process
, Address
));
781 return(STATUS_SUCCESS
);
784 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
785 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
786 + MemoryArea
->Data
.SectionData
.ViewOffset
;
788 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
789 Section
= MemoryArea
->Data
.SectionData
.Section
;
790 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
791 &MemoryArea
->Data
.SectionData
.RegionListHead
,
796 MmLockSectionSegment(Segment
);
799 * Check if this page needs to be mapped COW
801 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
802 (Region
->Protect
== PAGE_READWRITE
||
803 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
805 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
809 Attributes
= Region
->Protect
;
813 * Get or create a page operation descriptor
815 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
818 DPRINT1("MmGetPageOp failed\n");
819 KeBugCheck(MEMORY_MANAGEMENT
);
823 * Check if someone else is already handling this fault, if so wait
826 if (PageOp
->Thread
!= PsGetCurrentThread())
828 MmUnlockSectionSegment(Segment
);
829 MmUnlockAddressSpace(AddressSpace
);
830 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
832 * Check for various strange conditions
834 if (Status
!= STATUS_SUCCESS
)
836 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
837 KeBugCheck(MEMORY_MANAGEMENT
);
839 if (PageOp
->Status
== STATUS_PENDING
)
841 DPRINT1("Woke for page op before completion\n");
842 KeBugCheck(MEMORY_MANAGEMENT
);
844 MmLockAddressSpace(AddressSpace
);
846 * If this wasn't a pagein then restart the operation
848 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
850 MmspCompleteAndReleasePageOp(PageOp
);
851 DPRINT("Address 0x%.8X\n", Address
);
852 return(STATUS_MM_RESTART_OPERATION
);
856 * If the thread handling this fault has failed then we don't retry
858 if (!NT_SUCCESS(PageOp
->Status
))
860 Status
= PageOp
->Status
;
861 MmspCompleteAndReleasePageOp(PageOp
);
862 DPRINT("Address 0x%.8X\n", Address
);
865 MmLockSectionSegment(Segment
);
867 * If the completed fault was for another address space then set the
870 if (!MmIsPagePresent(Process
, Address
))
872 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
873 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
875 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
878 * The page was a private page in another or in our address space
880 MmUnlockSectionSegment(Segment
);
881 MmspCompleteAndReleasePageOp(PageOp
);
882 return(STATUS_MM_RESTART_OPERATION
);
885 Page
= PFN_FROM_SSE(Entry
);
887 MmSharePageEntrySectionSegment(Segment
, Offset
);
889 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
890 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
892 Status
= MmCreateVirtualMapping(Process
,
897 if (!NT_SUCCESS(Status
))
899 DPRINT1("Unable to create virtual mapping\n");
900 KeBugCheck(MEMORY_MANAGEMENT
);
902 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
908 MmUnlockSectionSegment(Segment
);
909 PageOp
->Status
= STATUS_SUCCESS
;
910 MmspCompleteAndReleasePageOp(PageOp
);
911 DPRINT("Address 0x%.8X\n", Address
);
912 return(STATUS_SUCCESS
);
915 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
919 * Must be private page we have swapped out.
926 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
928 DPRINT1("Found a swaped out private page in a pagefile section.\n");
929 KeBugCheck(MEMORY_MANAGEMENT
);
932 MmUnlockSectionSegment(Segment
);
933 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
935 MmUnlockAddressSpace(AddressSpace
);
936 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
937 if (!NT_SUCCESS(Status
))
939 KeBugCheck(MEMORY_MANAGEMENT
);
942 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
943 if (!NT_SUCCESS(Status
))
945 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
946 KeBugCheck(MEMORY_MANAGEMENT
);
948 MmLockAddressSpace(AddressSpace
);
949 Status
= MmCreateVirtualMapping(Process
,
954 if (!NT_SUCCESS(Status
))
956 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
957 KeBugCheck(MEMORY_MANAGEMENT
);
962 * Store the swap entry for later use.
964 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
967 * Add the page to the process's working set
969 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
972 * Finish the operation
978 PageOp
->Status
= STATUS_SUCCESS
;
979 MmspCompleteAndReleasePageOp(PageOp
);
980 DPRINT("Address 0x%.8X\n", Address
);
981 return(STATUS_SUCCESS
);
985 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
987 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
989 MmUnlockSectionSegment(Segment
);
991 * Just map the desired physical page
993 Page
= Offset
>> PAGE_SHIFT
;
994 Status
= MmCreateVirtualMappingUnsafe(Process
,
999 if (!NT_SUCCESS(Status
))
1001 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1002 KeBugCheck(MEMORY_MANAGEMENT
);
1006 * Don't add an rmap entry since the page mapped could be for
1011 MmLockPageUnsafe(Page
);
1015 * Cleanup and release locks
1017 PageOp
->Status
= STATUS_SUCCESS
;
1018 MmspCompleteAndReleasePageOp(PageOp
);
1019 DPRINT("Address 0x%.8X\n", Address
);
1020 return(STATUS_SUCCESS
);
1024 * Map anonymous memory for BSS sections
1026 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1028 MmUnlockSectionSegment(Segment
);
1029 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1030 if (!NT_SUCCESS(Status
))
1032 MmUnlockAddressSpace(AddressSpace
);
1033 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1034 MmLockAddressSpace(AddressSpace
);
1036 if (!NT_SUCCESS(Status
))
1038 KeBugCheck(MEMORY_MANAGEMENT
);
1040 Status
= MmCreateVirtualMapping(Process
,
1045 if (!NT_SUCCESS(Status
))
1047 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1048 KeBugCheck(MEMORY_MANAGEMENT
);
1051 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1058 * Cleanup and release locks
1060 PageOp
->Status
= STATUS_SUCCESS
;
1061 MmspCompleteAndReleasePageOp(PageOp
);
1062 DPRINT("Address 0x%.8X\n", Address
);
1063 return(STATUS_SUCCESS
);
1067 * Get the entry corresponding to the offset within the section
1069 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1074 * If the entry is zero (and it can't change because we have
1075 * locked the segment) then we need to load the page.
1079 * Release all our locks and read in the page from disk
1081 MmUnlockSectionSegment(Segment
);
1082 MmUnlockAddressSpace(AddressSpace
);
1084 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1085 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1087 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1088 if (!NT_SUCCESS(Status
))
1090 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1095 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1096 if (!NT_SUCCESS(Status
))
1098 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1101 if (!NT_SUCCESS(Status
))
1104 * FIXME: What do we know in this case?
1107 * Cleanup and release locks
1109 MmLockAddressSpace(AddressSpace
);
1110 PageOp
->Status
= Status
;
1111 MmspCompleteAndReleasePageOp(PageOp
);
1112 DPRINT("Address 0x%.8X\n", Address
);
1116 * Relock the address space and segment
1118 MmLockAddressSpace(AddressSpace
);
1119 MmLockSectionSegment(Segment
);
1122 * Check the entry. No one should change the status of a page
1123 * that has a pending page-in.
1125 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1126 if (Entry
!= Entry1
)
1128 DPRINT1("Someone changed ppte entry while we slept\n");
1129 KeBugCheck(MEMORY_MANAGEMENT
);
1133 * Mark the offset within the section as having valid, in-memory
1136 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1137 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1138 MmUnlockSectionSegment(Segment
);
1140 Status
= MmCreateVirtualMapping(Process
,
1145 if (!NT_SUCCESS(Status
))
1147 DPRINT1("Unable to create virtual mapping\n");
1148 KeBugCheck(MEMORY_MANAGEMENT
);
1150 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1156 PageOp
->Status
= STATUS_SUCCESS
;
1157 MmspCompleteAndReleasePageOp(PageOp
);
1158 DPRINT("Address 0x%.8X\n", Address
);
1159 return(STATUS_SUCCESS
);
1161 else if (IS_SWAP_FROM_SSE(Entry
))
1163 SWAPENTRY SwapEntry
;
1165 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1168 * Release all our locks and read in the page from disk
1170 MmUnlockSectionSegment(Segment
);
1172 MmUnlockAddressSpace(AddressSpace
);
1174 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1175 if (!NT_SUCCESS(Status
))
1177 KeBugCheck(MEMORY_MANAGEMENT
);
1180 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1181 if (!NT_SUCCESS(Status
))
1183 KeBugCheck(MEMORY_MANAGEMENT
);
1187 * Relock the address space and segment
1189 MmLockAddressSpace(AddressSpace
);
1190 MmLockSectionSegment(Segment
);
1193 * Check the entry. No one should change the status of a page
1194 * that has a pending page-in.
1196 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1197 if (Entry
!= Entry1
)
1199 DPRINT1("Someone changed ppte entry while we slept\n");
1200 KeBugCheck(MEMORY_MANAGEMENT
);
1204 * Mark the offset within the section as having valid, in-memory
1207 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1208 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1209 MmUnlockSectionSegment(Segment
);
1212 * Save the swap entry.
1214 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1215 Status
= MmCreateVirtualMapping(Process
,
1220 if (!NT_SUCCESS(Status
))
1222 DPRINT1("Unable to create virtual mapping\n");
1223 KeBugCheck(MEMORY_MANAGEMENT
);
1225 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1230 PageOp
->Status
= STATUS_SUCCESS
;
1231 MmspCompleteAndReleasePageOp(PageOp
);
1232 DPRINT("Address 0x%.8X\n", Address
);
1233 return(STATUS_SUCCESS
);
1238 * If the section offset is already in-memory and valid then just
1239 * take another reference to the page
1242 Page
= PFN_FROM_SSE(Entry
);
1244 MmSharePageEntrySectionSegment(Segment
, Offset
);
1245 MmUnlockSectionSegment(Segment
);
1247 Status
= MmCreateVirtualMapping(Process
,
1252 if (!NT_SUCCESS(Status
))
1254 DPRINT1("Unable to create virtual mapping\n");
1255 KeBugCheck(MEMORY_MANAGEMENT
);
1257 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1262 PageOp
->Status
= STATUS_SUCCESS
;
1263 MmspCompleteAndReleasePageOp(PageOp
);
1264 DPRINT("Address 0x%.8X\n", Address
);
1265 return(STATUS_SUCCESS
);
1271 MmAccessFaultSectionView(PMM_AVL_TABLE AddressSpace
,
1272 MEMORY_AREA
* MemoryArea
,
1276 PMM_SECTION_SEGMENT Segment
;
1277 PROS_SECTION_OBJECT Section
;
1286 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1288 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1291 * Check if the page has been paged out or has already been set readwrite
1293 if (!MmIsPagePresent(Process
, Address
) ||
1294 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1296 DPRINT("Address 0x%.8X\n", Address
);
1297 return(STATUS_SUCCESS
);
1301 * Find the offset of the page
1303 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1304 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1305 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1307 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1308 Section
= MemoryArea
->Data
.SectionData
.Section
;
1309 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1310 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1315 MmLockSectionSegment(Segment
);
1317 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1318 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1320 MmUnlockSectionSegment(Segment
);
1323 * Check if we are doing COW
1325 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1326 (Region
->Protect
== PAGE_READWRITE
||
1327 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1329 DPRINT("Address 0x%.8X\n", Address
);
1330 return(STATUS_ACCESS_VIOLATION
);
1333 if (IS_SWAP_FROM_SSE(Entry
) ||
1334 PFN_FROM_SSE(Entry
) != OldPage
)
1336 /* This is a private page. We must only change the page protection. */
1337 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1338 return(STATUS_SUCCESS
);
1342 * Get or create a pageop
1344 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1345 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1348 DPRINT1("MmGetPageOp failed\n");
1349 KeBugCheck(MEMORY_MANAGEMENT
);
1353 * Wait for any other operations to complete
1355 if (PageOp
->Thread
!= PsGetCurrentThread())
1357 MmUnlockAddressSpace(AddressSpace
);
1358 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1360 * Check for various strange conditions
1362 if (Status
== STATUS_TIMEOUT
)
1364 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1365 KeBugCheck(MEMORY_MANAGEMENT
);
1367 if (PageOp
->Status
== STATUS_PENDING
)
1369 DPRINT1("Woke for page op before completion\n");
1370 KeBugCheck(MEMORY_MANAGEMENT
);
1373 * Restart the operation
1375 MmLockAddressSpace(AddressSpace
);
1376 MmspCompleteAndReleasePageOp(PageOp
);
1377 DPRINT("Address 0x%.8X\n", Address
);
1378 return(STATUS_MM_RESTART_OPERATION
);
1382 * Release locks now we have the pageop
1384 MmUnlockAddressSpace(AddressSpace
);
1389 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1390 if (!NT_SUCCESS(Status
))
1392 KeBugCheck(MEMORY_MANAGEMENT
);
1398 MiCopyFromUserPage(NewPage
, PAddress
);
1400 MmLockAddressSpace(AddressSpace
);
1402 * Delete the old entry.
1404 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1407 * Set the PTE to point to the new page
1409 Status
= MmCreateVirtualMapping(Process
,
1414 if (!NT_SUCCESS(Status
))
1416 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1417 KeBugCheck(MEMORY_MANAGEMENT
);
1420 if (!NT_SUCCESS(Status
))
1422 DPRINT1("Unable to create virtual mapping\n");
1423 KeBugCheck(MEMORY_MANAGEMENT
);
1427 MmLockPage(NewPage
);
1428 MmUnlockPage(OldPage
);
1432 * Unshare the old page.
1434 MmDeleteRmap(OldPage
, Process
, PAddress
);
1435 MmInsertRmap(NewPage
, Process
, PAddress
);
1436 MmLockSectionSegment(Segment
);
1437 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1438 MmUnlockSectionSegment(Segment
);
1440 PageOp
->Status
= STATUS_SUCCESS
;
1441 MmspCompleteAndReleasePageOp(PageOp
);
1442 DPRINT("Address 0x%.8X\n", Address
);
1443 return(STATUS_SUCCESS
);
1447 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1449 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1453 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1456 MmLockAddressSpace(&Process
->VadRoot
);
1459 MmDeleteVirtualMapping(Process
,
1466 PageOutContext
->WasDirty
= TRUE
;
1468 if (!PageOutContext
->Private
)
1470 MmLockSectionSegment(PageOutContext
->Segment
);
1471 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1472 PageOutContext
->Segment
,
1473 PageOutContext
->Offset
,
1474 PageOutContext
->WasDirty
,
1476 MmUnlockSectionSegment(PageOutContext
->Segment
);
1480 MmUnlockAddressSpace(&Process
->VadRoot
);
1483 if (PageOutContext
->Private
)
1485 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1488 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1493 MmPageOutSectionView(PMM_AVL_TABLE AddressSpace
,
1494 MEMORY_AREA
* MemoryArea
,
1499 MM_SECTION_PAGEOUT_CONTEXT Context
;
1500 SWAPENTRY SwapEntry
;
1504 PFILE_OBJECT FileObject
;
1506 BOOLEAN DirectMapped
;
1507 BOOLEAN IsImageSection
;
1508 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1510 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1513 * Get the segment and section.
1515 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1516 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1518 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1519 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1520 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1522 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1524 FileObject
= Context
.Section
->FileObject
;
1525 DirectMapped
= FALSE
;
1526 if (FileObject
!= NULL
&&
1527 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1529 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1532 * If the file system is letting us go directly to the cache and the
1533 * memory area was mapped at an offset in the file which is page aligned
1534 * then note this is a direct mapped page.
1536 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1537 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1539 DirectMapped
= TRUE
;
1545 * This should never happen since mappings of physical memory are never
1546 * placed in the rmap lists.
1548 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1550 DPRINT1("Trying to page out from physical memory section address 0x%X "
1551 "process %d\n", Address
,
1552 Process
? Process
->UniqueProcessId
: 0);
1553 KeBugCheck(MEMORY_MANAGEMENT
);
1557 * Get the section segment entry and the physical address.
1559 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1560 if (!MmIsPagePresent(Process
, Address
))
1562 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1563 Process
? Process
->UniqueProcessId
: 0, Address
);
1564 KeBugCheck(MEMORY_MANAGEMENT
);
1566 Page
= MmGetPfnForProcess(Process
, Address
);
1567 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1570 * Prepare the context structure for the rmap delete call.
1572 Context
.WasDirty
= FALSE
;
1573 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1574 IS_SWAP_FROM_SSE(Entry
) ||
1575 PFN_FROM_SSE(Entry
) != Page
)
1577 Context
.Private
= TRUE
;
1581 Context
.Private
= FALSE
;
1585 * Take an additional reference to the page or the cache segment.
1587 if (DirectMapped
&& !Context
.Private
)
1589 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1591 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1592 KeBugCheck(MEMORY_MANAGEMENT
);
1597 MmReferencePage(Page
);
1600 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1603 * If this wasn't a private page then we should have reduced the entry to
1604 * zero by deleting all the rmaps.
1606 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1608 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1609 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1611 KeBugCheck(MEMORY_MANAGEMENT
);
1616 * If the page wasn't dirty then we can just free it as for a readonly page.
1617 * Since we unmapped all the mappings above we know it will not suddenly
1619 * If the page is from a pagefile section and has no swap entry,
1620 * we can't free the page at this point.
1622 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1623 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1625 if (Context
.Private
)
1627 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1628 Context
.WasDirty
? "dirty" : "clean", Address
);
1629 KeBugCheck(MEMORY_MANAGEMENT
);
1631 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1633 MmSetSavedSwapEntryPage(Page
, 0);
1634 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1635 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1636 PageOp
->Status
= STATUS_SUCCESS
;
1637 MmspCompleteAndReleasePageOp(PageOp
);
1638 return(STATUS_SUCCESS
);
1641 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1643 if (Context
.Private
)
1645 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1646 Context
.WasDirty
? "dirty" : "clean", Address
);
1647 KeBugCheck(MEMORY_MANAGEMENT
);
1649 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1651 MmSetSavedSwapEntryPage(Page
, 0);
1654 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1656 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1657 PageOp
->Status
= STATUS_SUCCESS
;
1658 MmspCompleteAndReleasePageOp(PageOp
);
1659 return(STATUS_SUCCESS
);
1662 else if (!Context
.Private
&& DirectMapped
)
1666 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1668 KeBugCheck(MEMORY_MANAGEMENT
);
1670 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1671 if (!NT_SUCCESS(Status
))
1673 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1674 KeBugCheck(MEMORY_MANAGEMENT
);
1676 PageOp
->Status
= STATUS_SUCCESS
;
1677 MmspCompleteAndReleasePageOp(PageOp
);
1678 return(STATUS_SUCCESS
);
1680 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1684 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1686 KeBugCheck(MEMORY_MANAGEMENT
);
1688 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1689 PageOp
->Status
= STATUS_SUCCESS
;
1690 MmspCompleteAndReleasePageOp(PageOp
);
1691 return(STATUS_SUCCESS
);
1693 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1695 MmSetSavedSwapEntryPage(Page
, 0);
1696 MmLockAddressSpace(AddressSpace
);
1697 Status
= MmCreatePageFileMapping(Process
,
1700 MmUnlockAddressSpace(AddressSpace
);
1701 if (!NT_SUCCESS(Status
))
1703 KeBugCheck(MEMORY_MANAGEMENT
);
1705 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1706 PageOp
->Status
= STATUS_SUCCESS
;
1707 MmspCompleteAndReleasePageOp(PageOp
);
1708 return(STATUS_SUCCESS
);
1712 * If necessary, allocate an entry in the paging file for this page
1716 SwapEntry
= MmAllocSwapPage();
1719 MmShowOutOfSpaceMessagePagingFile();
1720 MmLockAddressSpace(AddressSpace
);
1722 * For private pages restore the old mappings.
1724 if (Context
.Private
)
1726 Status
= MmCreateVirtualMapping(Process
,
1728 MemoryArea
->Protect
,
1731 MmSetDirtyPage(Process
, Address
);
1739 * For non-private pages if the page wasn't direct mapped then
1740 * set it back into the section segment entry so we don't loose
1741 * our copy. Otherwise it will be handled by the cache manager.
1743 Status
= MmCreateVirtualMapping(Process
,
1745 MemoryArea
->Protect
,
1748 MmSetDirtyPage(Process
, Address
);
1752 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1753 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1755 MmUnlockAddressSpace(AddressSpace
);
1756 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1757 MmspCompleteAndReleasePageOp(PageOp
);
1758 return(STATUS_PAGEFILE_QUOTA
);
1763 * Write the page to the pagefile
1765 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1766 if (!NT_SUCCESS(Status
))
1768 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1771 * As above: undo our actions.
1772 * FIXME: Also free the swap page.
1774 MmLockAddressSpace(AddressSpace
);
1775 if (Context
.Private
)
1777 Status
= MmCreateVirtualMapping(Process
,
1779 MemoryArea
->Protect
,
1782 MmSetDirtyPage(Process
, Address
);
1789 Status
= MmCreateVirtualMapping(Process
,
1791 MemoryArea
->Protect
,
1794 MmSetDirtyPage(Process
, Address
);
1798 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1799 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1801 MmUnlockAddressSpace(AddressSpace
);
1802 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1803 MmspCompleteAndReleasePageOp(PageOp
);
1804 return(STATUS_UNSUCCESSFUL
);
1808 * Otherwise we have succeeded.
1810 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1811 MmSetSavedSwapEntryPage(Page
, 0);
1812 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1813 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1815 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1819 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1822 if (Context
.Private
)
1824 MmLockAddressSpace(AddressSpace
);
1825 Status
= MmCreatePageFileMapping(Process
,
1828 MmUnlockAddressSpace(AddressSpace
);
1829 if (!NT_SUCCESS(Status
))
1831 KeBugCheck(MEMORY_MANAGEMENT
);
1836 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1837 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1840 PageOp
->Status
= STATUS_SUCCESS
;
1841 MmspCompleteAndReleasePageOp(PageOp
);
1842 return(STATUS_SUCCESS
);
1847 MmWritePageSectionView(PMM_AVL_TABLE AddressSpace
,
1848 PMEMORY_AREA MemoryArea
,
1853 PROS_SECTION_OBJECT Section
;
1854 PMM_SECTION_SEGMENT Segment
;
1856 SWAPENTRY SwapEntry
;
1860 PFILE_OBJECT FileObject
;
1862 BOOLEAN DirectMapped
;
1863 BOOLEAN IsImageSection
;
1864 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1866 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1868 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1869 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1872 * Get the segment and section.
1874 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1875 Section
= MemoryArea
->Data
.SectionData
.Section
;
1876 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1878 FileObject
= Section
->FileObject
;
1879 DirectMapped
= FALSE
;
1880 if (FileObject
!= NULL
&&
1881 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1883 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1886 * If the file system is letting us go directly to the cache and the
1887 * memory area was mapped at an offset in the file which is page aligned
1888 * then note this is a direct mapped page.
1890 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1891 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1893 DirectMapped
= TRUE
;
1898 * This should never happen since mappings of physical memory are never
1899 * placed in the rmap lists.
1901 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1903 DPRINT1("Trying to write back page from physical memory mapped at %X "
1904 "process %d\n", Address
,
1905 Process
? Process
->UniqueProcessId
: 0);
1906 KeBugCheck(MEMORY_MANAGEMENT
);
1910 * Get the section segment entry and the physical address.
1912 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1913 if (!MmIsPagePresent(Process
, Address
))
1915 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1916 Process
? Process
->UniqueProcessId
: 0, Address
);
1917 KeBugCheck(MEMORY_MANAGEMENT
);
1919 Page
= MmGetPfnForProcess(Process
, Address
);
1920 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1923 * Check for a private (COWed) page.
1925 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1926 IS_SWAP_FROM_SSE(Entry
) ||
1927 PFN_FROM_SSE(Entry
) != Page
)
1937 * Speculatively set all mappings of the page to clean.
1939 MmSetCleanAllRmaps(Page
);
1942 * If this page was direct mapped from the cache then the cache manager
1943 * will take care of writing it back to disk.
1945 if (DirectMapped
&& !Private
)
1947 ASSERT(SwapEntry
== 0);
1948 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1949 PageOp
->Status
= STATUS_SUCCESS
;
1950 MmspCompleteAndReleasePageOp(PageOp
);
1951 return(STATUS_SUCCESS
);
1955 * If necessary, allocate an entry in the paging file for this page
1959 SwapEntry
= MmAllocSwapPage();
1962 MmSetDirtyAllRmaps(Page
);
1963 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1964 MmspCompleteAndReleasePageOp(PageOp
);
1965 return(STATUS_PAGEFILE_QUOTA
);
1967 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1971 * Write the page to the pagefile
1973 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1974 if (!NT_SUCCESS(Status
))
1976 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1978 MmSetDirtyAllRmaps(Page
);
1979 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1980 MmspCompleteAndReleasePageOp(PageOp
);
1981 return(STATUS_UNSUCCESSFUL
);
1985 * Otherwise we have succeeded.
1987 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1988 PageOp
->Status
= STATUS_SUCCESS
;
1989 MmspCompleteAndReleasePageOp(PageOp
);
1990 return(STATUS_SUCCESS
);
1994 MmAlterViewAttributes(PMM_AVL_TABLE AddressSpace
,
2002 PMEMORY_AREA MemoryArea
;
2003 PMM_SECTION_SEGMENT Segment
;
2004 BOOLEAN DoCOW
= FALSE
;
2006 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2008 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2009 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2011 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
2012 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2017 if (OldProtect
!= NewProtect
)
2019 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2021 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2022 ULONG Protect
= NewProtect
;
2025 * If we doing COW for this segment then check if the page is
2028 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2034 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2035 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2036 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2037 Page
= MmGetPfnForProcess(Process
, Address
);
2039 Protect
= PAGE_READONLY
;
2040 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2041 IS_SWAP_FROM_SSE(Entry
) ||
2042 PFN_FROM_SSE(Entry
) != Page
)
2044 Protect
= NewProtect
;
2048 if (MmIsPagePresent(Process
, Address
))
2050 MmSetPageProtect(Process
, Address
,
2059 MmProtectSectionView(PMM_AVL_TABLE AddressSpace
,
2060 PMEMORY_AREA MemoryArea
,
2068 ULONG_PTR MaxLength
;
2070 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2071 if (Length
> MaxLength
)
2074 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2075 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2077 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2078 Region
->Protect
!= Protect
)
2080 return STATUS_INVALID_PAGE_PROTECTION
;
2083 *OldProtect
= Region
->Protect
;
2084 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2085 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2086 BaseAddress
, Length
, Region
->Type
, Protect
,
2087 MmAlterViewAttributes
);
2093 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2095 PMEMORY_BASIC_INFORMATION Info
,
2096 PULONG ResultLength
)
2099 PVOID RegionBaseAddress
;
2100 PROS_SECTION_OBJECT Section
;
2101 PMM_SECTION_SEGMENT Segment
;
2103 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2104 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2105 Address
, &RegionBaseAddress
);
2108 return STATUS_UNSUCCESSFUL
;
2111 Section
= MemoryArea
->Data
.SectionData
.Section
;
2112 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2114 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2115 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2116 Info
->Type
= MEM_IMAGE
;
2120 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2121 Info
->Type
= MEM_MAPPED
;
2123 Info
->BaseAddress
= RegionBaseAddress
;
2124 Info
->AllocationProtect
= MemoryArea
->Protect
;
2125 Info
->RegionSize
= Region
->Length
;
2126 Info
->State
= MEM_COMMIT
;
2127 Info
->Protect
= Region
->Protect
;
2129 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2130 return(STATUS_SUCCESS
);
2135 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2140 ULONG SavedSwapEntry
;
2145 Length
= PAGE_ROUND_UP(Segment
->Length
);
2146 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2148 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2151 if (IS_SWAP_FROM_SSE(Entry
))
2153 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2157 Page
= PFN_FROM_SSE(Entry
);
2158 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2159 if (SavedSwapEntry
!= 0)
2161 MmSetSavedSwapEntryPage(Page
, 0);
2162 MmFreeSwapPage(SavedSwapEntry
);
2164 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2166 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2172 MmpDeleteSection(PVOID ObjectBody
)
2174 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2176 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2177 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2182 PMM_SECTION_SEGMENT SectionSegments
;
2185 * NOTE: Section->ImageSection can be NULL for short time
2186 * during the section creating. If we fail for some reason
2187 * until the image section is properly initialized we shouldn't
2188 * process further here.
2190 if (Section
->ImageSection
== NULL
)
2193 SectionSegments
= Section
->ImageSection
->Segments
;
2194 NrSegments
= Section
->ImageSection
->NrSegments
;
2196 for (i
= 0; i
< NrSegments
; i
++)
2198 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2200 MmLockSectionSegment(&SectionSegments
[i
]);
2202 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2203 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2207 MmpFreePageFileSegment(&SectionSegments
[i
]);
2209 MmUnlockSectionSegment(&SectionSegments
[i
]);
2216 * NOTE: Section->Segment can be NULL for short time
2217 * during the section creating.
2219 if (Section
->Segment
== NULL
)
2222 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2224 MmpFreePageFileSegment(Section
->Segment
);
2225 MmFreePageTablesSectionSegment(Section
->Segment
);
2226 ExFreePool(Section
->Segment
);
2227 Section
->Segment
= NULL
;
2231 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2234 if (Section
->FileObject
!= NULL
)
2236 CcRosDereferenceCache(Section
->FileObject
);
2237 ObDereferenceObject(Section
->FileObject
);
2238 Section
->FileObject
= NULL
;
2243 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2245 IN ACCESS_MASK GrantedAccess
,
2246 IN ULONG ProcessHandleCount
,
2247 IN ULONG SystemHandleCount
)
2249 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2250 Object
, ProcessHandleCount
);
2256 MmCreatePhysicalMemorySection(VOID
)
2258 PROS_SECTION_OBJECT PhysSection
;
2260 OBJECT_ATTRIBUTES Obj
;
2261 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2262 LARGE_INTEGER SectionSize
;
2266 * Create the section mapping physical memory
2268 SectionSize
.QuadPart
= 0xFFFFFFFF;
2269 InitializeObjectAttributes(&Obj
,
2274 Status
= MmCreateSection((PVOID
)&PhysSection
,
2278 PAGE_EXECUTE_READWRITE
,
2282 if (!NT_SUCCESS(Status
))
2284 DPRINT1("Failed to create PhysicalMemory section\n");
2285 KeBugCheck(MEMORY_MANAGEMENT
);
2287 Status
= ObInsertObject(PhysSection
,
2293 if (!NT_SUCCESS(Status
))
2295 ObDereferenceObject(PhysSection
);
2297 ObCloseHandle(Handle
, KernelMode
);
2298 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2299 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2301 return(STATUS_SUCCESS
);
2307 MmInitSectionImplementation(VOID
)
2309 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2310 UNICODE_STRING Name
;
2312 DPRINT("Creating Section Object Type\n");
2314 /* Initialize the Section object type */
2315 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2316 RtlInitUnicodeString(&Name
, L
"Section");
2317 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2318 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2319 ObjectTypeInitializer
.PoolType
= PagedPool
;
2320 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2321 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2322 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2323 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2324 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2325 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2327 return(STATUS_SUCCESS
);
2332 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2333 ACCESS_MASK DesiredAccess
,
2334 POBJECT_ATTRIBUTES ObjectAttributes
,
2335 PLARGE_INTEGER UMaximumSize
,
2336 ULONG SectionPageProtection
,
2337 ULONG AllocationAttributes
)
2339 * Create a section which is backed by the pagefile
2342 LARGE_INTEGER MaximumSize
;
2343 PROS_SECTION_OBJECT Section
;
2344 PMM_SECTION_SEGMENT Segment
;
2347 if (UMaximumSize
== NULL
)
2349 return(STATUS_UNSUCCESSFUL
);
2351 MaximumSize
= *UMaximumSize
;
2354 * Create the section
2356 Status
= ObCreateObject(ExGetPreviousMode(),
2357 MmSectionObjectType
,
2359 ExGetPreviousMode(),
2361 sizeof(ROS_SECTION_OBJECT
),
2364 (PVOID
*)(PVOID
)&Section
);
2365 if (!NT_SUCCESS(Status
))
2373 Section
->SectionPageProtection
= SectionPageProtection
;
2374 Section
->AllocationAttributes
= AllocationAttributes
;
2375 Section
->Segment
= NULL
;
2376 Section
->FileObject
= NULL
;
2377 Section
->MaximumSize
= MaximumSize
;
2378 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2379 TAG_MM_SECTION_SEGMENT
);
2380 if (Segment
== NULL
)
2382 ObDereferenceObject(Section
);
2383 return(STATUS_NO_MEMORY
);
2385 Section
->Segment
= Segment
;
2386 Segment
->ReferenceCount
= 1;
2387 ExInitializeFastMutex(&Segment
->Lock
);
2388 Segment
->FileOffset
= 0;
2389 Segment
->Protection
= SectionPageProtection
;
2390 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2391 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2392 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2393 Segment
->WriteCopy
= FALSE
;
2394 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2395 Segment
->VirtualAddress
= 0;
2396 Segment
->Characteristics
= 0;
2397 *SectionObject
= Section
;
2398 return(STATUS_SUCCESS
);
2404 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2405 ACCESS_MASK DesiredAccess
,
2406 POBJECT_ATTRIBUTES ObjectAttributes
,
2407 PLARGE_INTEGER UMaximumSize
,
2408 ULONG SectionPageProtection
,
2409 ULONG AllocationAttributes
,
2412 * Create a section backed by a data file
2415 PROS_SECTION_OBJECT Section
;
2417 LARGE_INTEGER MaximumSize
;
2418 PFILE_OBJECT FileObject
;
2419 PMM_SECTION_SEGMENT Segment
;
2421 IO_STATUS_BLOCK Iosb
;
2422 LARGE_INTEGER Offset
;
2424 FILE_STANDARD_INFORMATION FileInfo
;
2427 * Create the section
2429 Status
= ObCreateObject(ExGetPreviousMode(),
2430 MmSectionObjectType
,
2432 ExGetPreviousMode(),
2434 sizeof(ROS_SECTION_OBJECT
),
2437 (PVOID
*)(PVOID
)&Section
);
2438 if (!NT_SUCCESS(Status
))
2445 Section
->SectionPageProtection
= SectionPageProtection
;
2446 Section
->AllocationAttributes
= AllocationAttributes
;
2447 Section
->Segment
= NULL
;
2450 * Check file access required
2452 if (SectionPageProtection
& PAGE_READWRITE
||
2453 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2455 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2459 FileAccess
= FILE_READ_DATA
;
2463 * Reference the file handle
2465 Status
= ObReferenceObjectByHandle(FileHandle
,
2468 ExGetPreviousMode(),
2469 (PVOID
*)(PVOID
)&FileObject
,
2471 if (!NT_SUCCESS(Status
))
2473 ObDereferenceObject(Section
);
2478 * FIXME: This is propably not entirely correct. We can't look into
2479 * the standard FCB header because it might not be initialized yet
2480 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2481 * standard file information is filled on first request).
2483 Status
= IoQueryFileInformation(FileObject
,
2484 FileStandardInformation
,
2485 sizeof(FILE_STANDARD_INFORMATION
),
2488 if (!NT_SUCCESS(Status
))
2490 ObDereferenceObject(Section
);
2491 ObDereferenceObject(FileObject
);
2496 * FIXME: Revise this once a locking order for file size changes is
2499 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2501 MaximumSize
= *UMaximumSize
;
2505 MaximumSize
= FileInfo
.EndOfFile
;
2506 /* Mapping zero-sized files isn't allowed. */
2507 if (MaximumSize
.QuadPart
== 0)
2509 ObDereferenceObject(Section
);
2510 ObDereferenceObject(FileObject
);
2511 return STATUS_FILE_INVALID
;
2515 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2517 Status
= IoSetInformation(FileObject
,
2518 FileAllocationInformation
,
2519 sizeof(LARGE_INTEGER
),
2521 if (!NT_SUCCESS(Status
))
2523 ObDereferenceObject(Section
);
2524 ObDereferenceObject(FileObject
);
2525 return(STATUS_SECTION_NOT_EXTENDED
);
2529 if (FileObject
->SectionObjectPointer
== NULL
||
2530 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2533 * Read a bit so caching is initiated for the file object.
2534 * This is only needed because MiReadPage currently cannot
2535 * handle non-cached streams.
2537 Offset
.QuadPart
= 0;
2538 Status
= ZwReadFile(FileHandle
,
2547 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2549 ObDereferenceObject(Section
);
2550 ObDereferenceObject(FileObject
);
2553 if (FileObject
->SectionObjectPointer
== NULL
||
2554 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2556 /* FIXME: handle this situation */
2557 ObDereferenceObject(Section
);
2558 ObDereferenceObject(FileObject
);
2559 return STATUS_INVALID_PARAMETER
;
2566 Status
= MmspWaitForFileLock(FileObject
);
2567 if (Status
!= STATUS_SUCCESS
)
2569 ObDereferenceObject(Section
);
2570 ObDereferenceObject(FileObject
);
2575 * If this file hasn't been mapped as a data file before then allocate a
2576 * section segment to describe the data file mapping
2578 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2580 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2581 TAG_MM_SECTION_SEGMENT
);
2582 if (Segment
== NULL
)
2584 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2585 ObDereferenceObject(Section
);
2586 ObDereferenceObject(FileObject
);
2587 return(STATUS_NO_MEMORY
);
2589 Section
->Segment
= Segment
;
2590 Segment
->ReferenceCount
= 1;
2591 ExInitializeFastMutex(&Segment
->Lock
);
2593 * Set the lock before assigning the segment to the file object
2595 ExAcquireFastMutex(&Segment
->Lock
);
2596 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2598 Segment
->FileOffset
= 0;
2599 Segment
->Protection
= SectionPageProtection
;
2600 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2601 Segment
->Characteristics
= 0;
2602 Segment
->WriteCopy
= FALSE
;
2603 if (AllocationAttributes
& SEC_RESERVE
)
2605 Segment
->Length
= Segment
->RawLength
= 0;
2609 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2610 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2612 Segment
->VirtualAddress
= 0;
2613 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2618 * If the file is already mapped as a data file then we may need
2622 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2624 Section
->Segment
= Segment
;
2625 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2626 MmLockSectionSegment(Segment
);
2628 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2629 !(AllocationAttributes
& SEC_RESERVE
))
2631 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2632 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2635 MmUnlockSectionSegment(Segment
);
2636 Section
->FileObject
= FileObject
;
2637 Section
->MaximumSize
= MaximumSize
;
2638 CcRosReferenceCache(FileObject
);
2639 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2640 *SectionObject
= Section
;
2641 return(STATUS_SUCCESS
);
2645 TODO: not that great (declaring loaders statically, having to declare all of
2646 them, having to keep them extern, etc.), will fix in the future
2648 extern NTSTATUS NTAPI PeFmtCreateSection
2650 IN CONST VOID
* FileHeader
,
2651 IN SIZE_T FileHeaderSize
,
2653 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2655 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2656 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2659 extern NTSTATUS NTAPI ElfFmtCreateSection
2661 IN CONST VOID
* FileHeader
,
2662 IN SIZE_T FileHeaderSize
,
2664 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2666 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2667 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2670 /* TODO: this is a standard DDK/PSDK macro */
2671 #ifndef RTL_NUMBER_OF
2672 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2675 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2686 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2688 SIZE_T SizeOfSegments
;
2689 PMM_SECTION_SEGMENT Segments
;
2691 /* TODO: check for integer overflow */
2692 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2694 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2696 TAG_MM_SECTION_SEGMENT
);
2699 RtlZeroMemory(Segments
, SizeOfSegments
);
2707 ExeFmtpReadFile(IN PVOID File
,
2708 IN PLARGE_INTEGER Offset
,
2711 OUT PVOID
* AllocBase
,
2712 OUT PULONG ReadSize
)
2715 LARGE_INTEGER FileOffset
;
2717 ULONG OffsetAdjustment
;
2722 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2726 KeBugCheck(MEMORY_MANAGEMENT
);
2729 FileOffset
= *Offset
;
2731 /* Negative/special offset: it cannot be used in this context */
2732 if(FileOffset
.u
.HighPart
< 0)
2734 KeBugCheck(MEMORY_MANAGEMENT
);
2737 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2738 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2739 FileOffset
.u
.LowPart
= AdjustOffset
;
2741 BufferSize
= Length
+ OffsetAdjustment
;
2742 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2745 * It's ok to use paged pool, because this is a temporary buffer only used in
2746 * the loading of executables. The assumption is that MmCreateSection is
2747 * always called at low IRQLs and that these buffers don't survive a brief
2748 * initialization phase
2750 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2752 TAG('M', 'm', 'X', 'r'));
2757 Status
= MmspPageRead(File
,
2764 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2765 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2766 * to initialize internal state is even worse. Our cache manager is in need of
2770 IO_STATUS_BLOCK Iosb
;
2772 Status
= ZwReadFile(File
,
2782 if(NT_SUCCESS(Status
))
2784 UsedSize
= Iosb
.Information
;
2789 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2791 Status
= STATUS_IN_PAGE_ERROR
;
2792 ASSERT(!NT_SUCCESS(Status
));
2795 if(NT_SUCCESS(Status
))
2797 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2798 *AllocBase
= Buffer
;
2799 *ReadSize
= UsedSize
- OffsetAdjustment
;
2803 ExFreePoolWithTag(Buffer
, TAG('M', 'm', 'X', 'r'));
2810 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2811 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2812 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2817 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2821 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2823 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2824 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2831 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2835 MmspAssertSegmentsSorted(ImageSectionObject
);
2837 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2839 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2843 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2844 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2845 ImageSectionObject
->Segments
[i
- 1].Length
));
2853 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2857 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2859 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2860 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2868 MmspCompareSegments(const void * x
,
2871 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2872 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2875 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2876 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2880 * Ensures an image section's segments are sorted in memory
2885 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2888 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2890 MmspAssertSegmentsSorted(ImageSectionObject
);
2894 qsort(ImageSectionObject
->Segments
,
2895 ImageSectionObject
->NrSegments
,
2896 sizeof(ImageSectionObject
->Segments
[0]),
2897 MmspCompareSegments
);
2903 * Ensures an image section's segments don't overlap in memory and don't have
2904 * gaps and don't have a null size. We let them map to overlapping file regions,
2905 * though - that's not necessarily an error
2910 MmspCheckSegmentBounds
2912 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2918 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2920 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2924 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2926 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2928 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2936 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2937 * page could be OK (Windows seems to be OK with them), and larger gaps
2938 * could lead to image sections spanning several discontiguous regions
2939 * (NtMapViewOfSection could then refuse to map them, and they could
2940 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2942 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2943 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2944 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2955 * Merges and pads an image section's segments until they all are page-aligned
2956 * and have a size that is a multiple of the page size
2961 MmspPageAlignSegments
2963 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2969 BOOLEAN Initialized
;
2970 PMM_SECTION_SEGMENT EffectiveSegment
;
2972 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2974 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2978 Initialized
= FALSE
;
2980 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2982 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2985 * The first segment requires special handling
2989 ULONG_PTR VirtualAddress
;
2990 ULONG_PTR VirtualOffset
;
2992 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2994 /* Round down the virtual address to the nearest page */
2995 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2997 /* Round up the virtual size to the nearest page */
2998 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
2999 EffectiveSegment
->VirtualAddress
;
3001 /* Adjust the raw address and size */
3002 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3004 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3010 * Garbage in, garbage out: unaligned base addresses make the file
3011 * offset point in curious and odd places, but that's what we were
3014 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3015 EffectiveSegment
->RawLength
+= VirtualOffset
;
3019 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3020 ULONG_PTR EndOfEffectiveSegment
;
3022 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3023 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3026 * The current segment begins exactly where the current effective
3027 * segment ended, therefore beginning a new effective segment
3029 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3032 ASSERT(LastSegment
<= i
);
3033 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3035 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3037 if (LastSegment
!= i
)
3040 * Copy the current segment. If necessary, the effective segment
3041 * will be expanded later
3043 *EffectiveSegment
= *Segment
;
3047 * Page-align the virtual size. We know for sure the virtual address
3050 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3051 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3054 * The current segment is still part of the current effective segment:
3055 * extend the effective segment to reflect this
3057 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3059 static const ULONG FlagsToProtection
[16] =
3067 PAGE_EXECUTE_READWRITE
,
3068 PAGE_EXECUTE_READWRITE
,
3073 PAGE_EXECUTE_WRITECOPY
,
3074 PAGE_EXECUTE_WRITECOPY
,
3075 PAGE_EXECUTE_WRITECOPY
,
3076 PAGE_EXECUTE_WRITECOPY
3079 unsigned ProtectionFlags
;
3082 * Extend the file size
3085 /* Unaligned segments must be contiguous within the file */
3086 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3087 EffectiveSegment
->RawLength
))
3092 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3095 * Extend the virtual size
3097 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3099 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3100 EffectiveSegment
->VirtualAddress
;
3103 * Merge the protection
3105 EffectiveSegment
->Protection
|= Segment
->Protection
;
3107 /* Clean up redundance */
3108 ProtectionFlags
= 0;
3110 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3111 ProtectionFlags
|= 1 << 0;
3113 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3114 ProtectionFlags
|= 1 << 1;
3116 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3117 ProtectionFlags
|= 1 << 2;
3119 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3120 ProtectionFlags
|= 1 << 3;
3122 ASSERT(ProtectionFlags
< 16);
3123 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3125 /* If a segment was required to be shared and cannot, fail */
3126 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3127 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3133 * We assume no holes between segments at this point
3137 KeBugCheck(MEMORY_MANAGEMENT
);
3141 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3147 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3148 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3150 LARGE_INTEGER Offset
;
3152 PVOID FileHeaderBuffer
;
3153 ULONG FileHeaderSize
;
3155 ULONG OldNrSegments
;
3160 * Read the beginning of the file (2 pages). Should be enough to contain
3161 * all (or most) of the headers
3163 Offset
.QuadPart
= 0;
3165 /* FIXME: use FileObject instead of FileHandle */
3166 Status
= ExeFmtpReadFile (FileHandle
,
3173 if (!NT_SUCCESS(Status
))
3176 if (FileHeaderSize
== 0)
3178 ExFreePool(FileHeaderBuffer
);
3179 return STATUS_UNSUCCESSFUL
;
3183 * Look for a loader that can handle this executable
3185 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3187 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3190 /* FIXME: use FileObject instead of FileHandle */
3191 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3197 ExeFmtpAllocateSegments
);
3199 if (!NT_SUCCESS(Status
))
3201 if (ImageSectionObject
->Segments
)
3203 ExFreePool(ImageSectionObject
->Segments
);
3204 ImageSectionObject
->Segments
= NULL
;
3208 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3212 ExFreePoolWithTag(FileHeaderBuffer
, TAG('M', 'm', 'X', 'r'));
3215 * No loader handled the format
3217 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3219 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3220 ASSERT(!NT_SUCCESS(Status
));
3223 if (!NT_SUCCESS(Status
))
3226 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3231 /* FIXME? are these values platform-dependent? */
3232 if(ImageSectionObject
->StackReserve
== 0)
3233 ImageSectionObject
->StackReserve
= 0x40000;
3235 if(ImageSectionObject
->StackCommit
== 0)
3236 ImageSectionObject
->StackCommit
= 0x1000;
3238 if(ImageSectionObject
->ImageBase
== 0)
3240 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3241 ImageSectionObject
->ImageBase
= 0x10000000;
3243 ImageSectionObject
->ImageBase
= 0x00400000;
3247 * And now the fun part: fixing the segments
3250 /* Sort them by virtual address */
3251 MmspSortSegments(ImageSectionObject
, Flags
);
3253 /* Ensure they don't overlap in memory */
3254 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3255 return STATUS_INVALID_IMAGE_FORMAT
;
3257 /* Ensure they are aligned */
3258 OldNrSegments
= ImageSectionObject
->NrSegments
;
3260 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3261 return STATUS_INVALID_IMAGE_FORMAT
;
3263 /* Trim them if the alignment phase merged some of them */
3264 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3266 PMM_SECTION_SEGMENT Segments
;
3267 SIZE_T SizeOfSegments
;
3269 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3271 Segments
= ExAllocatePoolWithTag(PagedPool
,
3273 TAG_MM_SECTION_SEGMENT
);
3275 if (Segments
== NULL
)
3276 return STATUS_INSUFFICIENT_RESOURCES
;
3278 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3279 ExFreePool(ImageSectionObject
->Segments
);
3280 ImageSectionObject
->Segments
= Segments
;
3283 /* And finish their initialization */
3284 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3286 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3287 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3289 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3290 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3293 ASSERT(NT_SUCCESS(Status
));
3298 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3299 ACCESS_MASK DesiredAccess
,
3300 POBJECT_ATTRIBUTES ObjectAttributes
,
3301 PLARGE_INTEGER UMaximumSize
,
3302 ULONG SectionPageProtection
,
3303 ULONG AllocationAttributes
,
3306 PROS_SECTION_OBJECT Section
;
3308 PFILE_OBJECT FileObject
;
3309 PMM_SECTION_SEGMENT SectionSegments
;
3310 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3312 ULONG FileAccess
= 0;
3315 * Specifying a maximum size is meaningless for an image section
3317 if (UMaximumSize
!= NULL
)
3319 return(STATUS_INVALID_PARAMETER_4
);
3323 * Check file access required
3325 if (SectionPageProtection
& PAGE_READWRITE
||
3326 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3328 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3332 FileAccess
= FILE_READ_DATA
;
3336 * Reference the file handle
3338 Status
= ObReferenceObjectByHandle(FileHandle
,
3341 ExGetPreviousMode(),
3342 (PVOID
*)(PVOID
)&FileObject
,
3345 if (!NT_SUCCESS(Status
))
3351 * Create the section
3353 Status
= ObCreateObject (ExGetPreviousMode(),
3354 MmSectionObjectType
,
3356 ExGetPreviousMode(),
3358 sizeof(ROS_SECTION_OBJECT
),
3361 (PVOID
*)(PVOID
)&Section
);
3362 if (!NT_SUCCESS(Status
))
3364 ObDereferenceObject(FileObject
);
3371 Section
->SectionPageProtection
= SectionPageProtection
;
3372 Section
->AllocationAttributes
= AllocationAttributes
;
3375 * Initialized caching for this file object if previously caching
3376 * was initialized for the same on disk file
3378 Status
= CcTryToInitializeFileCache(FileObject
);
3380 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3382 NTSTATUS StatusExeFmt
;
3384 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3385 if (ImageSectionObject
== NULL
)
3387 ObDereferenceObject(FileObject
);
3388 ObDereferenceObject(Section
);
3389 return(STATUS_NO_MEMORY
);
3392 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3394 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3396 if (!NT_SUCCESS(StatusExeFmt
))
3398 if(ImageSectionObject
->Segments
!= NULL
)
3399 ExFreePool(ImageSectionObject
->Segments
);
3401 ExFreePool(ImageSectionObject
);
3402 ObDereferenceObject(Section
);
3403 ObDereferenceObject(FileObject
);
3404 return(StatusExeFmt
);
3407 Section
->ImageSection
= ImageSectionObject
;
3408 ASSERT(ImageSectionObject
->Segments
);
3413 Status
= MmspWaitForFileLock(FileObject
);
3414 if (!NT_SUCCESS(Status
))
3416 ExFreePool(ImageSectionObject
->Segments
);
3417 ExFreePool(ImageSectionObject
);
3418 ObDereferenceObject(Section
);
3419 ObDereferenceObject(FileObject
);
3423 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3424 ImageSectionObject
, NULL
))
3427 * An other thread has initialized the same image in the background
3429 ExFreePool(ImageSectionObject
->Segments
);
3430 ExFreePool(ImageSectionObject
);
3431 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3432 Section
->ImageSection
= ImageSectionObject
;
3433 SectionSegments
= ImageSectionObject
->Segments
;
3435 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3437 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3441 Status
= StatusExeFmt
;
3448 Status
= MmspWaitForFileLock(FileObject
);
3449 if (Status
!= STATUS_SUCCESS
)
3451 ObDereferenceObject(Section
);
3452 ObDereferenceObject(FileObject
);
3456 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3457 Section
->ImageSection
= ImageSectionObject
;
3458 SectionSegments
= ImageSectionObject
->Segments
;
3461 * Otherwise just reference all the section segments
3463 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3465 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3468 Status
= STATUS_SUCCESS
;
3470 Section
->FileObject
= FileObject
;
3471 CcRosReferenceCache(FileObject
);
3472 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3473 *SectionObject
= Section
;
3481 NtCreateSection (OUT PHANDLE SectionHandle
,
3482 IN ACCESS_MASK DesiredAccess
,
3483 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3484 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3485 IN ULONG SectionPageProtection OPTIONAL
,
3486 IN ULONG AllocationAttributes
,
3487 IN HANDLE FileHandle OPTIONAL
)
3489 LARGE_INTEGER SafeMaximumSize
;
3490 PVOID SectionObject
;
3491 KPROCESSOR_MODE PreviousMode
;
3492 NTSTATUS Status
= STATUS_SUCCESS
;
3494 PreviousMode
= ExGetPreviousMode();
3496 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3500 /* make a copy on the stack */
3501 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3502 MaximumSize
= &SafeMaximumSize
;
3504 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3506 Status
= _SEH2_GetExceptionCode();
3510 if(!NT_SUCCESS(Status
))
3516 Status
= MmCreateSection(&SectionObject
,
3520 SectionPageProtection
,
3521 AllocationAttributes
,
3524 if (NT_SUCCESS(Status
))
3526 Status
= ObInsertObject ((PVOID
)SectionObject
,
3538 /**********************************************************************
3556 NtOpenSection(PHANDLE SectionHandle
,
3557 ACCESS_MASK DesiredAccess
,
3558 POBJECT_ATTRIBUTES ObjectAttributes
)
3561 KPROCESSOR_MODE PreviousMode
;
3562 NTSTATUS Status
= STATUS_SUCCESS
;
3564 PreviousMode
= ExGetPreviousMode();
3566 if(PreviousMode
!= KernelMode
)
3570 ProbeForWriteHandle(SectionHandle
);
3572 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3574 Status
= _SEH2_GetExceptionCode();
3578 if(!NT_SUCCESS(Status
))
3584 Status
= ObOpenObjectByName(ObjectAttributes
,
3585 MmSectionObjectType
,
3592 if(NT_SUCCESS(Status
))
3596 *SectionHandle
= hSection
;
3598 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3600 Status
= _SEH2_GetExceptionCode();
3609 MmMapViewOfSegment(PMM_AVL_TABLE AddressSpace
,
3610 PROS_SECTION_OBJECT Section
,
3611 PMM_SECTION_SEGMENT Segment
,
3616 ULONG AllocationType
)
3620 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3622 BoundaryAddressMultiple
.QuadPart
= 0;
3624 Status
= MmCreateMemoryArea(AddressSpace
,
3625 MEMORY_AREA_SECTION_VIEW
,
3632 BoundaryAddressMultiple
);
3633 if (!NT_SUCCESS(Status
))
3635 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3636 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3640 ObReferenceObject((PVOID
)Section
);
3642 MArea
->Data
.SectionData
.Segment
= Segment
;
3643 MArea
->Data
.SectionData
.Section
= Section
;
3644 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3645 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3646 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3647 ViewSize
, 0, Protect
);
3649 return(STATUS_SUCCESS
);
3653 /**********************************************************************
3655 * NtMapViewOfSection
3658 * Maps a view of a section into the virtual address space of a
3663 * Handle of the section.
3666 * Handle of the process.
3669 * Desired base address (or NULL) on entry;
3670 * Actual base address of the view on exit.
3673 * Number of high order address bits that must be zero.
3676 * Size in bytes of the initially committed section of
3680 * Offset in bytes from the beginning of the section
3681 * to the beginning of the view.
3684 * Desired length of map (or zero to map all) on entry
3685 * Actual length mapped on exit.
3687 * InheritDisposition
3688 * Specified how the view is to be shared with
3692 * Type of allocation for the pages.
3695 * Protection for the committed region of the view.
3703 NtMapViewOfSection(IN HANDLE SectionHandle
,
3704 IN HANDLE ProcessHandle
,
3705 IN OUT PVOID
* BaseAddress OPTIONAL
,
3706 IN ULONG_PTR ZeroBits OPTIONAL
,
3707 IN SIZE_T CommitSize
,
3708 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3709 IN OUT PSIZE_T ViewSize
,
3710 IN SECTION_INHERIT InheritDisposition
,
3711 IN ULONG AllocationType OPTIONAL
,
3714 PVOID SafeBaseAddress
;
3715 LARGE_INTEGER SafeSectionOffset
;
3716 SIZE_T SafeViewSize
;
3717 PROS_SECTION_OBJECT Section
;
3719 KPROCESSOR_MODE PreviousMode
;
3720 PMM_AVL_TABLE AddressSpace
;
3721 NTSTATUS Status
= STATUS_SUCCESS
;
3725 * Check the protection
3727 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3729 return STATUS_INVALID_PARAMETER_10
;
3732 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3733 if (tmpProtect
!= PAGE_NOACCESS
&&
3734 tmpProtect
!= PAGE_READONLY
&&
3735 tmpProtect
!= PAGE_READWRITE
&&
3736 tmpProtect
!= PAGE_WRITECOPY
&&
3737 tmpProtect
!= PAGE_EXECUTE
&&
3738 tmpProtect
!= PAGE_EXECUTE_READ
&&
3739 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3740 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3742 return STATUS_INVALID_PAGE_PROTECTION
;
3745 PreviousMode
= ExGetPreviousMode();
3747 if(PreviousMode
!= KernelMode
)
3749 SafeBaseAddress
= NULL
;
3750 SafeSectionOffset
.QuadPart
= 0;
3755 if(BaseAddress
!= NULL
)
3757 ProbeForWritePointer(BaseAddress
);
3758 SafeBaseAddress
= *BaseAddress
;
3760 if(SectionOffset
!= NULL
)
3762 ProbeForWriteLargeInteger(SectionOffset
);
3763 SafeSectionOffset
= *SectionOffset
;
3765 ProbeForWriteSize_t(ViewSize
);
3766 SafeViewSize
= *ViewSize
;
3768 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3770 Status
= _SEH2_GetExceptionCode();
3774 if(!NT_SUCCESS(Status
))
3781 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3782 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3783 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3786 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3788 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3789 PROCESS_VM_OPERATION
,
3792 (PVOID
*)(PVOID
)&Process
,
3794 if (!NT_SUCCESS(Status
))
3799 AddressSpace
= &Process
->VadRoot
;
3801 Status
= ObReferenceObjectByHandle(SectionHandle
,
3803 MmSectionObjectType
,
3805 (PVOID
*)(PVOID
)&Section
,
3807 if (!(NT_SUCCESS(Status
)))
3809 DPRINT("ObReference failed rc=%x\n",Status
);
3810 ObDereferenceObject(Process
);
3814 Status
= MmMapViewOfSection(Section
,
3816 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3819 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3820 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3825 /* Check if this is an image for the current process */
3826 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3827 (Process
== PsGetCurrentProcess()) &&
3828 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3830 /* Notify the debugger */
3831 DbgkMapViewOfSection(Section
,
3833 SafeSectionOffset
.LowPart
,
3837 ObDereferenceObject(Section
);
3838 ObDereferenceObject(Process
);
3840 if(NT_SUCCESS(Status
))
3842 /* copy parameters back to the caller */
3845 if(BaseAddress
!= NULL
)
3847 *BaseAddress
= SafeBaseAddress
;
3849 if(SectionOffset
!= NULL
)
3851 *SectionOffset
= SafeSectionOffset
;
3853 if(ViewSize
!= NULL
)
3855 *ViewSize
= SafeViewSize
;
3858 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3860 Status
= _SEH2_GetExceptionCode();
3869 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3870 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3873 PFILE_OBJECT FileObject
;
3876 SWAPENTRY SavedSwapEntry
;
3879 PROS_SECTION_OBJECT Section
;
3880 PMM_SECTION_SEGMENT Segment
;
3881 PMM_AVL_TABLE AddressSpace
;
3884 AddressSpace
= (PMM_AVL_TABLE
)Context
;
3885 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3887 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3889 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3890 MemoryArea
->Data
.SectionData
.ViewOffset
;
3892 Section
= MemoryArea
->Data
.SectionData
.Section
;
3893 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3895 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3899 MmUnlockSectionSegment(Segment
);
3900 MmUnlockAddressSpace(AddressSpace
);
3902 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3903 if (Status
!= STATUS_SUCCESS
)
3905 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3906 KeBugCheck(MEMORY_MANAGEMENT
);
3909 MmLockAddressSpace(AddressSpace
);
3910 MmLockSectionSegment(Segment
);
3911 MmspCompleteAndReleasePageOp(PageOp
);
3912 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3915 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3918 * For a dirty, datafile, non-private page mark it as dirty in the
3921 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3923 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3925 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3926 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3927 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3928 ASSERT(SwapEntry
== 0);
3937 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3939 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3940 KeBugCheck(MEMORY_MANAGEMENT
);
3942 MmFreeSwapPage(SwapEntry
);
3946 if (IS_SWAP_FROM_SSE(Entry
) ||
3947 Page
!= PFN_FROM_SSE(Entry
))
3952 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3954 DPRINT1("Found a private page in a pagefile section.\n");
3955 KeBugCheck(MEMORY_MANAGEMENT
);
3958 * Just dereference private pages
3960 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3961 if (SavedSwapEntry
!= 0)
3963 MmFreeSwapPage(SavedSwapEntry
);
3964 MmSetSavedSwapEntryPage(Page
, 0);
3966 MmDeleteRmap(Page
, Process
, Address
);
3967 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3971 MmDeleteRmap(Page
, Process
, Address
);
3972 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3978 MmUnmapViewOfSegment(PMM_AVL_TABLE AddressSpace
,
3982 PMEMORY_AREA MemoryArea
;
3983 PROS_SECTION_OBJECT Section
;
3984 PMM_SECTION_SEGMENT Segment
;
3985 PLIST_ENTRY CurrentEntry
;
3986 PMM_REGION CurrentRegion
;
3987 PLIST_ENTRY RegionListHead
;
3989 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3991 if (MemoryArea
== NULL
)
3993 return(STATUS_UNSUCCESSFUL
);
3996 MemoryArea
->DeleteInProgress
= TRUE
;
3997 Section
= MemoryArea
->Data
.SectionData
.Section
;
3998 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4000 MmLockSectionSegment(Segment
);
4002 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4003 while (!IsListEmpty(RegionListHead
))
4005 CurrentEntry
= RemoveHeadList(RegionListHead
);
4006 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4007 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4010 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4012 Status
= MmFreeMemoryArea(AddressSpace
,
4019 Status
= MmFreeMemoryArea(AddressSpace
,
4024 MmUnlockSectionSegment(Segment
);
4025 ObDereferenceObject(Section
);
4026 return(STATUS_SUCCESS
);
4033 MmUnmapViewOfSection(PEPROCESS Process
,
4037 PMEMORY_AREA MemoryArea
;
4038 PMM_AVL_TABLE AddressSpace
;
4039 PROS_SECTION_OBJECT Section
;
4042 PVOID ImageBaseAddress
= 0;
4044 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4045 Process
, BaseAddress
);
4049 AddressSpace
= &Process
->VadRoot
;
4051 MmLockAddressSpace(AddressSpace
);
4052 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4054 if (MemoryArea
== NULL
||
4055 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4056 MemoryArea
->DeleteInProgress
)
4058 MmUnlockAddressSpace(AddressSpace
);
4059 return STATUS_NOT_MAPPED_VIEW
;
4062 MemoryArea
->DeleteInProgress
= TRUE
;
4064 while (MemoryArea
->PageOpCount
)
4066 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4070 Offset
-= PAGE_SIZE
;
4071 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4072 MemoryArea
->Data
.SectionData
.Segment
,
4073 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4076 MmUnlockAddressSpace(AddressSpace
);
4077 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4078 if (Status
!= STATUS_SUCCESS
)
4080 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4081 KeBugCheck(MEMORY_MANAGEMENT
);
4083 MmLockAddressSpace(AddressSpace
);
4084 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4086 if (MemoryArea
== NULL
||
4087 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4089 MmUnlockAddressSpace(AddressSpace
);
4090 return STATUS_NOT_MAPPED_VIEW
;
4097 Section
= MemoryArea
->Data
.SectionData
.Section
;
4099 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4103 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4104 PMM_SECTION_SEGMENT SectionSegments
;
4105 PMM_SECTION_SEGMENT Segment
;
4107 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4108 ImageSectionObject
= Section
->ImageSection
;
4109 SectionSegments
= ImageSectionObject
->Segments
;
4110 NrSegments
= ImageSectionObject
->NrSegments
;
4112 /* Search for the current segment within the section segments
4113 * and calculate the image base address */
4114 for (i
= 0; i
< NrSegments
; i
++)
4116 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4118 if (Segment
== &SectionSegments
[i
])
4120 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4125 if (i
>= NrSegments
)
4127 KeBugCheck(MEMORY_MANAGEMENT
);
4130 for (i
= 0; i
< NrSegments
; i
++)
4132 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4134 PVOID SBaseAddress
= (PVOID
)
4135 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4137 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4143 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4146 /* Notify debugger */
4147 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4149 MmUnlockAddressSpace(AddressSpace
);
4150 return(STATUS_SUCCESS
);
4153 /**********************************************************************
4155 * NtUnmapViewOfSection
4170 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4174 KPROCESSOR_MODE PreviousMode
;
4177 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4178 ProcessHandle
, BaseAddress
);
4180 PreviousMode
= ExGetPreviousMode();
4182 DPRINT("Referencing process\n");
4183 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4184 PROCESS_VM_OPERATION
,
4187 (PVOID
*)(PVOID
)&Process
,
4189 if (!NT_SUCCESS(Status
))
4191 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4195 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4197 ObDereferenceObject(Process
);
4204 * Queries the information of a section object.
4206 * @param SectionHandle
4207 * Handle to the section object. It must be opened with SECTION_QUERY
4209 * @param SectionInformationClass
4210 * Index to a certain information structure. Can be either
4211 * SectionBasicInformation or SectionImageInformation. The latter
4212 * is valid only for sections that were created with the SEC_IMAGE
4214 * @param SectionInformation
4215 * Caller supplies storage for resulting information.
4217 * Size of the supplied storage.
4218 * @param ResultLength
4226 NtQuerySection(IN HANDLE SectionHandle
,
4227 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4228 OUT PVOID SectionInformation
,
4229 IN ULONG SectionInformationLength
,
4230 OUT PULONG ResultLength OPTIONAL
)
4232 PROS_SECTION_OBJECT Section
;
4233 KPROCESSOR_MODE PreviousMode
;
4234 NTSTATUS Status
= STATUS_SUCCESS
;
4236 PreviousMode
= ExGetPreviousMode();
4238 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4240 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4242 SectionInformationLength
,
4246 if(!NT_SUCCESS(Status
))
4248 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4252 Status
= ObReferenceObjectByHandle(SectionHandle
,
4254 MmSectionObjectType
,
4256 (PVOID
*)(PVOID
)&Section
,
4258 if (NT_SUCCESS(Status
))
4260 switch (SectionInformationClass
)
4262 case SectionBasicInformation
:
4264 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4268 Sbi
->Attributes
= Section
->AllocationAttributes
;
4269 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4271 Sbi
->BaseAddress
= 0;
4272 Sbi
->Size
.QuadPart
= 0;
4276 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4277 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4280 if (ResultLength
!= NULL
)
4282 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4284 Status
= STATUS_SUCCESS
;
4286 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4288 Status
= _SEH2_GetExceptionCode();
4295 case SectionImageInformation
:
4297 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4301 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4302 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4304 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4305 ImageSectionObject
= Section
->ImageSection
;
4307 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4308 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4309 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4310 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4311 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4312 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4313 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4314 Sii
->Machine
= ImageSectionObject
->Machine
;
4315 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4318 if (ResultLength
!= NULL
)
4320 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4322 Status
= STATUS_SUCCESS
;
4324 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4326 Status
= _SEH2_GetExceptionCode();
4334 ObDereferenceObject(Section
);
4342 * Extends size of file backed section.
4344 * @param SectionHandle
4345 * Handle to the section object. It must be opened with
4346 * SECTION_EXTEND_SIZE access.
4347 * @param NewMaximumSize
4348 * New maximum size of the section in bytes.
4352 * @todo Move the actual code to internal function MmExtendSection.
4356 NtExtendSection(IN HANDLE SectionHandle
,
4357 IN PLARGE_INTEGER NewMaximumSize
)
4359 LARGE_INTEGER SafeNewMaximumSize
;
4360 PROS_SECTION_OBJECT Section
;
4361 KPROCESSOR_MODE PreviousMode
;
4362 NTSTATUS Status
= STATUS_SUCCESS
;
4364 PreviousMode
= ExGetPreviousMode();
4366 if(PreviousMode
!= KernelMode
)
4370 /* make a copy on the stack */
4371 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4372 NewMaximumSize
= &SafeNewMaximumSize
;
4374 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4376 Status
= _SEH2_GetExceptionCode();
4380 if(!NT_SUCCESS(Status
))
4386 Status
= ObReferenceObjectByHandle(SectionHandle
,
4387 SECTION_EXTEND_SIZE
,
4388 MmSectionObjectType
,
4392 if (!NT_SUCCESS(Status
))
4397 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4399 ObfDereferenceObject(Section
);
4400 return STATUS_INVALID_PARAMETER
;
4404 * - Acquire file extneding resource.
4405 * - Check if we're not resizing the section below it's actual size!
4406 * - Extend segments if needed.
4407 * - Set file information (FileAllocationInformation) to the new size.
4408 * - Release file extending resource.
4411 ObDereferenceObject(Section
);
4413 return STATUS_NOT_IMPLEMENTED
;
4417 /**********************************************************************
4419 * MmAllocateSection@4
4429 * Code taken from ntoskrnl/mm/special.c.
4434 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4439 PMM_AVL_TABLE AddressSpace
;
4440 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4442 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4444 BoundaryAddressMultiple
.QuadPart
= 0;
4446 AddressSpace
= MmGetKernelAddressSpace();
4447 Result
= BaseAddress
;
4448 MmLockAddressSpace(AddressSpace
);
4449 Status
= MmCreateMemoryArea (AddressSpace
,
4457 BoundaryAddressMultiple
);
4458 MmUnlockAddressSpace(AddressSpace
);
4460 if (!NT_SUCCESS(Status
))
4464 DPRINT("Result %p\n",Result
);
4466 /* Create a virtual mapping for this memory area */
4467 MmMapMemoryArea(Result
, Length
, MC_NPPOOL
, PAGE_READWRITE
);
4469 return ((PVOID
)Result
);
4473 /**********************************************************************
4475 * MmMapViewOfSection
4478 * Maps a view of a section into the virtual address space of a
4483 * Pointer to the section object.
4486 * Pointer to the process.
4489 * Desired base address (or NULL) on entry;
4490 * Actual base address of the view on exit.
4493 * Number of high order address bits that must be zero.
4496 * Size in bytes of the initially committed section of
4500 * Offset in bytes from the beginning of the section
4501 * to the beginning of the view.
4504 * Desired length of map (or zero to map all) on entry
4505 * Actual length mapped on exit.
4507 * InheritDisposition
4508 * Specified how the view is to be shared with
4512 * Type of allocation for the pages.
4515 * Protection for the committed region of the view.
4523 MmMapViewOfSection(IN PVOID SectionObject
,
4524 IN PEPROCESS Process
,
4525 IN OUT PVOID
*BaseAddress
,
4526 IN ULONG_PTR ZeroBits
,
4527 IN SIZE_T CommitSize
,
4528 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4529 IN OUT PSIZE_T ViewSize
,
4530 IN SECTION_INHERIT InheritDisposition
,
4531 IN ULONG AllocationType
,
4534 PROS_SECTION_OBJECT Section
;
4535 PMM_AVL_TABLE AddressSpace
;
4537 NTSTATUS Status
= STATUS_SUCCESS
;
4541 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4543 return STATUS_INVALID_PAGE_PROTECTION
;
4547 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4548 AddressSpace
= &Process
->VadRoot
;
4550 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4552 MmLockAddressSpace(AddressSpace
);
4554 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4558 ULONG_PTR ImageBase
;
4560 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4561 PMM_SECTION_SEGMENT SectionSegments
;
4563 ImageSectionObject
= Section
->ImageSection
;
4564 SectionSegments
= ImageSectionObject
->Segments
;
4565 NrSegments
= ImageSectionObject
->NrSegments
;
4568 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4571 ImageBase
= ImageSectionObject
->ImageBase
;
4575 for (i
= 0; i
< NrSegments
; i
++)
4577 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4579 ULONG_PTR MaxExtent
;
4580 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4581 SectionSegments
[i
].Length
;
4582 ImageSize
= max(ImageSize
, MaxExtent
);
4586 ImageSectionObject
->ImageSize
= ImageSize
;
4588 /* Check there is enough space to map the section at that point. */
4589 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4590 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4592 /* Fail if the user requested a fixed base address. */
4593 if ((*BaseAddress
) != NULL
)
4595 MmUnlockAddressSpace(AddressSpace
);
4596 return(STATUS_UNSUCCESSFUL
);
4598 /* Otherwise find a gap to map the image. */
4599 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4602 MmUnlockAddressSpace(AddressSpace
);
4603 return(STATUS_UNSUCCESSFUL
);
4607 for (i
= 0; i
< NrSegments
; i
++)
4609 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4611 PVOID SBaseAddress
= (PVOID
)
4612 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4613 MmLockSectionSegment(&SectionSegments
[i
]);
4614 Status
= MmMapViewOfSegment(AddressSpace
,
4616 &SectionSegments
[i
],
4618 SectionSegments
[i
].Length
,
4619 SectionSegments
[i
].Protection
,
4622 MmUnlockSectionSegment(&SectionSegments
[i
]);
4623 if (!NT_SUCCESS(Status
))
4625 MmUnlockAddressSpace(AddressSpace
);
4631 *BaseAddress
= (PVOID
)ImageBase
;
4635 /* check for write access */
4636 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4637 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4639 MmUnlockAddressSpace(AddressSpace
);
4640 return STATUS_SECTION_PROTECTION
;
4642 /* check for read access */
4643 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4644 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4646 MmUnlockAddressSpace(AddressSpace
);
4647 return STATUS_SECTION_PROTECTION
;
4649 /* check for execute access */
4650 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4651 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4653 MmUnlockAddressSpace(AddressSpace
);
4654 return STATUS_SECTION_PROTECTION
;
4657 if (ViewSize
== NULL
)
4659 /* Following this pointer would lead to us to the dark side */
4660 /* What to do? Bugcheck? Return status? Do the mambo? */
4661 KeBugCheck(MEMORY_MANAGEMENT
);
4664 if (SectionOffset
== NULL
)
4670 ViewOffset
= SectionOffset
->u
.LowPart
;
4673 if ((ViewOffset
% PAGE_SIZE
) != 0)
4675 MmUnlockAddressSpace(AddressSpace
);
4676 return(STATUS_MAPPED_ALIGNMENT
);
4679 if ((*ViewSize
) == 0)
4681 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4683 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4685 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4688 MmLockSectionSegment(Section
->Segment
);
4689 Status
= MmMapViewOfSegment(AddressSpace
,
4696 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4697 MmUnlockSectionSegment(Section
->Segment
);
4698 if (!NT_SUCCESS(Status
))
4700 MmUnlockAddressSpace(AddressSpace
);
4705 MmUnlockAddressSpace(AddressSpace
);
4707 return(STATUS_SUCCESS
);
4714 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4715 IN PLARGE_INTEGER NewFileSize
)
4717 /* Check whether an ImageSectionObject exists */
4718 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4720 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4724 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4726 PMM_SECTION_SEGMENT Segment
;
4728 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4731 if (Segment
->ReferenceCount
!= 0)
4733 /* Check size of file */
4734 if (SectionObjectPointer
->SharedCacheMap
)
4736 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4737 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4745 /* Something must gone wrong
4746 * how can we have a Section but no
4748 DPRINT1("ERROR: DataSectionObject without reference!\n");
4752 DPRINT1("FIXME: didn't check for outstanding write probes\n");
4762 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4772 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4773 IN MMFLUSH_TYPE FlushType
)
4777 case MmFlushForDelete
:
4778 if (SectionObjectPointer
->ImageSectionObject
||
4779 SectionObjectPointer
->DataSectionObject
)
4783 CcRosSetRemoveOnClose(SectionObjectPointer
);
4785 case MmFlushForWrite
:
4795 MmForceSectionClosed (
4796 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4797 IN BOOLEAN DelayClose
)
4808 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4809 OUT PVOID
* MappedBase
,
4810 IN OUT PULONG ViewSize
)
4812 PROS_SECTION_OBJECT Section
;
4813 PMM_AVL_TABLE AddressSpace
;
4816 DPRINT("MmMapViewInSystemSpace() called\n");
4818 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4819 AddressSpace
= MmGetKernelAddressSpace();
4821 MmLockAddressSpace(AddressSpace
);
4824 if ((*ViewSize
) == 0)
4826 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4828 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4830 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4833 MmLockSectionSegment(Section
->Segment
);
4836 Status
= MmMapViewOfSegment(AddressSpace
,
4845 MmUnlockSectionSegment(Section
->Segment
);
4846 MmUnlockAddressSpace(AddressSpace
);
4856 MmMapViewInSessionSpace (
4858 OUT PVOID
*MappedBase
,
4859 IN OUT PSIZE_T ViewSize
4863 return STATUS_NOT_IMPLEMENTED
;
4871 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4873 PMM_AVL_TABLE AddressSpace
;
4876 DPRINT("MmUnmapViewInSystemSpace() called\n");
4878 AddressSpace
= MmGetKernelAddressSpace();
4880 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4890 MmUnmapViewInSessionSpace (
4895 return STATUS_NOT_IMPLEMENTED
;
4902 MmSetBankedSection (ULONG Unknown0
,
4910 return (STATUS_NOT_IMPLEMENTED
);
4914 /**********************************************************************
4919 * Creates a section object.
4922 * SectionObject (OUT)
4923 * Caller supplied storage for the resulting pointer
4924 * to a SECTION_OBJECT instance;
4927 * Specifies the desired access to the section can be a
4929 * STANDARD_RIGHTS_REQUIRED |
4931 * SECTION_MAP_WRITE |
4932 * SECTION_MAP_READ |
4933 * SECTION_MAP_EXECUTE
4935 * ObjectAttributes [OPTIONAL]
4936 * Initialized attributes for the object can be used
4937 * to create a named section;
4940 * Maximizes the size of the memory section. Must be
4941 * non-NULL for a page-file backed section.
4942 * If value specified for a mapped file and the file is
4943 * not large enough, file will be extended.
4945 * SectionPageProtection
4946 * Can be a combination of:
4952 * AllocationAttributes
4953 * Can be a combination of:
4958 * Handle to a file to create a section mapped to a file
4959 * instead of a memory backed section;
4970 MmCreateSection (OUT PVOID
* Section
,
4971 IN ACCESS_MASK DesiredAccess
,
4972 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4973 IN PLARGE_INTEGER MaximumSize
,
4974 IN ULONG SectionPageProtection
,
4975 IN ULONG AllocationAttributes
,
4976 IN HANDLE FileHandle OPTIONAL
,
4977 IN PFILE_OBJECT File OPTIONAL
)
4980 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4983 * Check the protection
4985 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4986 if (Protection
!= PAGE_NOACCESS
&&
4987 Protection
!= PAGE_READONLY
&&
4988 Protection
!= PAGE_READWRITE
&&
4989 Protection
!= PAGE_WRITECOPY
&&
4990 Protection
!= PAGE_EXECUTE
&&
4991 Protection
!= PAGE_EXECUTE_READ
&&
4992 Protection
!= PAGE_EXECUTE_READWRITE
&&
4993 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4995 return STATUS_INVALID_PAGE_PROTECTION
;
4998 if (AllocationAttributes
& SEC_IMAGE
)
5000 return(MmCreateImageSection(SectionObject
,
5004 SectionPageProtection
,
5005 AllocationAttributes
,
5009 if (FileHandle
!= NULL
)
5011 return(MmCreateDataFileSection(SectionObject
,
5015 SectionPageProtection
,
5016 AllocationAttributes
,
5020 return(MmCreatePageFileSection(SectionObject
,
5024 SectionPageProtection
,
5025 AllocationAttributes
));
5030 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
5031 IN OUT PULONG_PTR NumberOfPages
,
5032 IN OUT PULONG_PTR UserPfnArray
)
5035 return STATUS_NOT_IMPLEMENTED
;
5040 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
5041 IN ULONG_PTR NumberOfPages
,
5042 IN OUT PULONG_PTR UserPfnArray
)
5045 return STATUS_NOT_IMPLEMENTED
;
5050 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
5051 IN ULONG_PTR NumberOfPages
,
5052 IN OUT PULONG_PTR UserPfnArray
)
5055 return STATUS_NOT_IMPLEMENTED
;
5060 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
5061 IN OUT PULONG_PTR NumberOfPages
,
5062 IN OUT PULONG_PTR UserPfnArray
)
5065 return STATUS_NOT_IMPLEMENTED
;
5070 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
5071 IN PVOID File2MappedAsFile
)
5074 return STATUS_NOT_IMPLEMENTED
;