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 PMMSUPPORT 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()->Vm
;
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
);
663 ULONG CacheSegOffset
;
666 * Allocate a page, this is rather complicated by the possibility
667 * we might have to move other things out of memory
669 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
670 if (!NT_SUCCESS(Status
))
674 Status
= CcRosGetCacheSegment(Bcb
,
680 if (!NT_SUCCESS(Status
))
687 * If the cache segment isn't up to date then call the file
688 * system to read in the data.
690 Status
= ReadCacheSegment(CacheSeg
);
691 if (!NT_SUCCESS(Status
))
693 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
698 Process
= PsGetCurrentProcess();
699 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
700 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
701 Length
= RawLength
- SegOffset
;
702 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
704 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
706 else if (CacheSegOffset
>= PAGE_SIZE
)
708 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
712 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
713 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
714 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
715 Status
= CcRosGetCacheSegment(Bcb
,
716 FileOffset
+ CacheSegOffset
,
721 if (!NT_SUCCESS(Status
))
728 * If the cache segment isn't up to date then call the file
729 * system to read in the data.
731 Status
= ReadCacheSegment(CacheSeg
);
732 if (!NT_SUCCESS(Status
))
734 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
738 PageAddr
= MiMapPageInHyperSpace(Process
, *Page
, &Irql
);
739 if (Length
< PAGE_SIZE
)
741 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
745 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
748 MiUnmapPageInHyperSpace(Process
, PageAddr
, Irql
);
749 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
751 return(STATUS_SUCCESS
);
756 MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace
,
757 MEMORY_AREA
* MemoryArea
,
765 PROS_SECTION_OBJECT Section
;
766 PMM_SECTION_SEGMENT Segment
;
772 BOOLEAN HasSwapEntry
;
773 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
776 * There is a window between taking the page fault and locking the
777 * address space when another thread could load the page so we check
780 if (MmIsPagePresent(Process
, Address
))
784 MmLockPage(MmGetPfnForProcess(Process
, Address
));
786 return(STATUS_SUCCESS
);
789 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
790 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
791 + MemoryArea
->Data
.SectionData
.ViewOffset
;
793 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
794 Section
= MemoryArea
->Data
.SectionData
.Section
;
795 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
796 &MemoryArea
->Data
.SectionData
.RegionListHead
,
801 MmLockSectionSegment(Segment
);
804 * Check if this page needs to be mapped COW
806 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
807 (Region
->Protect
== PAGE_READWRITE
||
808 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
810 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
814 Attributes
= Region
->Protect
;
818 * Get or create a page operation descriptor
820 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
823 DPRINT1("MmGetPageOp failed\n");
824 KeBugCheck(MEMORY_MANAGEMENT
);
828 * Check if someone else is already handling this fault, if so wait
831 if (PageOp
->Thread
!= PsGetCurrentThread())
833 MmUnlockSectionSegment(Segment
);
834 MmUnlockAddressSpace(AddressSpace
);
835 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
837 * Check for various strange conditions
839 if (Status
!= STATUS_SUCCESS
)
841 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
842 KeBugCheck(MEMORY_MANAGEMENT
);
844 if (PageOp
->Status
== STATUS_PENDING
)
846 DPRINT1("Woke for page op before completion\n");
847 KeBugCheck(MEMORY_MANAGEMENT
);
849 MmLockAddressSpace(AddressSpace
);
851 * If this wasn't a pagein then restart the operation
853 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
855 MmspCompleteAndReleasePageOp(PageOp
);
856 DPRINT("Address 0x%.8X\n", Address
);
857 return(STATUS_MM_RESTART_OPERATION
);
861 * If the thread handling this fault has failed then we don't retry
863 if (!NT_SUCCESS(PageOp
->Status
))
865 Status
= PageOp
->Status
;
866 MmspCompleteAndReleasePageOp(PageOp
);
867 DPRINT("Address 0x%.8X\n", Address
);
870 MmLockSectionSegment(Segment
);
872 * If the completed fault was for another address space then set the
875 if (!MmIsPagePresent(Process
, Address
))
877 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
878 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
880 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
883 * The page was a private page in another or in our address space
885 MmUnlockSectionSegment(Segment
);
886 MmspCompleteAndReleasePageOp(PageOp
);
887 return(STATUS_MM_RESTART_OPERATION
);
890 Page
= PFN_FROM_SSE(Entry
);
892 MmSharePageEntrySectionSegment(Segment
, Offset
);
894 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
895 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
897 Status
= MmCreateVirtualMapping(Process
,
902 if (!NT_SUCCESS(Status
))
904 DPRINT1("Unable to create virtual mapping\n");
905 KeBugCheck(MEMORY_MANAGEMENT
);
907 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
913 MmUnlockSectionSegment(Segment
);
914 PageOp
->Status
= STATUS_SUCCESS
;
915 MmspCompleteAndReleasePageOp(PageOp
);
916 DPRINT("Address 0x%.8X\n", Address
);
917 return(STATUS_SUCCESS
);
920 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
924 * Must be private page we have swapped out.
931 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
933 DPRINT1("Found a swaped out private page in a pagefile section.\n");
934 KeBugCheck(MEMORY_MANAGEMENT
);
937 MmUnlockSectionSegment(Segment
);
938 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
940 MmUnlockAddressSpace(AddressSpace
);
941 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
942 if (!NT_SUCCESS(Status
))
944 KeBugCheck(MEMORY_MANAGEMENT
);
947 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
948 if (!NT_SUCCESS(Status
))
950 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
951 KeBugCheck(MEMORY_MANAGEMENT
);
953 MmLockAddressSpace(AddressSpace
);
954 Status
= MmCreateVirtualMapping(Process
,
959 if (!NT_SUCCESS(Status
))
961 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
962 KeBugCheck(MEMORY_MANAGEMENT
);
967 * Store the swap entry for later use.
969 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
972 * Add the page to the process's working set
974 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
977 * Finish the operation
983 PageOp
->Status
= STATUS_SUCCESS
;
984 MmspCompleteAndReleasePageOp(PageOp
);
985 DPRINT("Address 0x%.8X\n", Address
);
986 return(STATUS_SUCCESS
);
990 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
992 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
994 MmUnlockSectionSegment(Segment
);
996 * Just map the desired physical page
998 Page
= Offset
>> PAGE_SHIFT
;
999 Status
= MmCreateVirtualMappingUnsafe(Process
,
1004 if (!NT_SUCCESS(Status
))
1006 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1007 KeBugCheck(MEMORY_MANAGEMENT
);
1011 * Don't add an rmap entry since the page mapped could be for
1016 MmLockPageUnsafe(Page
);
1020 * Cleanup and release locks
1022 PageOp
->Status
= STATUS_SUCCESS
;
1023 MmspCompleteAndReleasePageOp(PageOp
);
1024 DPRINT("Address 0x%.8X\n", Address
);
1025 return(STATUS_SUCCESS
);
1029 * Map anonymous memory for BSS sections
1031 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1033 MmUnlockSectionSegment(Segment
);
1034 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1035 if (!NT_SUCCESS(Status
))
1037 MmUnlockAddressSpace(AddressSpace
);
1038 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1039 MmLockAddressSpace(AddressSpace
);
1041 if (!NT_SUCCESS(Status
))
1043 KeBugCheck(MEMORY_MANAGEMENT
);
1045 Status
= MmCreateVirtualMapping(Process
,
1050 if (!NT_SUCCESS(Status
))
1052 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1053 KeBugCheck(MEMORY_MANAGEMENT
);
1056 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1063 * Cleanup and release locks
1065 PageOp
->Status
= STATUS_SUCCESS
;
1066 MmspCompleteAndReleasePageOp(PageOp
);
1067 DPRINT("Address 0x%.8X\n", Address
);
1068 return(STATUS_SUCCESS
);
1072 * Get the entry corresponding to the offset within the section
1074 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1079 * If the entry is zero (and it can't change because we have
1080 * locked the segment) then we need to load the page.
1084 * Release all our locks and read in the page from disk
1086 MmUnlockSectionSegment(Segment
);
1087 MmUnlockAddressSpace(AddressSpace
);
1089 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1090 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1092 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1093 if (!NT_SUCCESS(Status
))
1095 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1100 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1101 if (!NT_SUCCESS(Status
))
1103 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1106 if (!NT_SUCCESS(Status
))
1109 * FIXME: What do we know in this case?
1112 * Cleanup and release locks
1114 MmLockAddressSpace(AddressSpace
);
1115 PageOp
->Status
= Status
;
1116 MmspCompleteAndReleasePageOp(PageOp
);
1117 DPRINT("Address 0x%.8X\n", Address
);
1121 * Relock the address space and segment
1123 MmLockAddressSpace(AddressSpace
);
1124 MmLockSectionSegment(Segment
);
1127 * Check the entry. No one should change the status of a page
1128 * that has a pending page-in.
1130 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1131 if (Entry
!= Entry1
)
1133 DPRINT1("Someone changed ppte entry while we slept\n");
1134 KeBugCheck(MEMORY_MANAGEMENT
);
1138 * Mark the offset within the section as having valid, in-memory
1141 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1142 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1143 MmUnlockSectionSegment(Segment
);
1145 Status
= MmCreateVirtualMapping(Process
,
1150 if (!NT_SUCCESS(Status
))
1152 DPRINT1("Unable to create virtual mapping\n");
1153 KeBugCheck(MEMORY_MANAGEMENT
);
1155 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1161 PageOp
->Status
= STATUS_SUCCESS
;
1162 MmspCompleteAndReleasePageOp(PageOp
);
1163 DPRINT("Address 0x%.8X\n", Address
);
1164 return(STATUS_SUCCESS
);
1166 else if (IS_SWAP_FROM_SSE(Entry
))
1168 SWAPENTRY SwapEntry
;
1170 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1173 * Release all our locks and read in the page from disk
1175 MmUnlockSectionSegment(Segment
);
1177 MmUnlockAddressSpace(AddressSpace
);
1179 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1180 if (!NT_SUCCESS(Status
))
1182 KeBugCheck(MEMORY_MANAGEMENT
);
1185 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1186 if (!NT_SUCCESS(Status
))
1188 KeBugCheck(MEMORY_MANAGEMENT
);
1192 * Relock the address space and segment
1194 MmLockAddressSpace(AddressSpace
);
1195 MmLockSectionSegment(Segment
);
1198 * Check the entry. No one should change the status of a page
1199 * that has a pending page-in.
1201 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1202 if (Entry
!= Entry1
)
1204 DPRINT1("Someone changed ppte entry while we slept\n");
1205 KeBugCheck(MEMORY_MANAGEMENT
);
1209 * Mark the offset within the section as having valid, in-memory
1212 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1213 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1214 MmUnlockSectionSegment(Segment
);
1217 * Save the swap entry.
1219 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1220 Status
= MmCreateVirtualMapping(Process
,
1225 if (!NT_SUCCESS(Status
))
1227 DPRINT1("Unable to create virtual mapping\n");
1228 KeBugCheck(MEMORY_MANAGEMENT
);
1230 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1235 PageOp
->Status
= STATUS_SUCCESS
;
1236 MmspCompleteAndReleasePageOp(PageOp
);
1237 DPRINT("Address 0x%.8X\n", Address
);
1238 return(STATUS_SUCCESS
);
1243 * If the section offset is already in-memory and valid then just
1244 * take another reference to the page
1247 Page
= PFN_FROM_SSE(Entry
);
1249 MmSharePageEntrySectionSegment(Segment
, Offset
);
1250 MmUnlockSectionSegment(Segment
);
1252 Status
= MmCreateVirtualMapping(Process
,
1257 if (!NT_SUCCESS(Status
))
1259 DPRINT1("Unable to create virtual mapping\n");
1260 KeBugCheck(MEMORY_MANAGEMENT
);
1262 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1267 PageOp
->Status
= STATUS_SUCCESS
;
1268 MmspCompleteAndReleasePageOp(PageOp
);
1269 DPRINT("Address 0x%.8X\n", Address
);
1270 return(STATUS_SUCCESS
);
1276 MmAccessFaultSectionView(PMMSUPPORT AddressSpace
,
1277 MEMORY_AREA
* MemoryArea
,
1281 PMM_SECTION_SEGMENT Segment
;
1282 PROS_SECTION_OBJECT Section
;
1291 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1293 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1296 * Check if the page has been paged out or has already been set readwrite
1298 if (!MmIsPagePresent(Process
, Address
) ||
1299 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1301 DPRINT("Address 0x%.8X\n", Address
);
1302 return(STATUS_SUCCESS
);
1306 * Find the offset of the page
1308 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1309 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1310 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1312 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1313 Section
= MemoryArea
->Data
.SectionData
.Section
;
1314 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1315 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1320 MmLockSectionSegment(Segment
);
1322 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1323 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1325 MmUnlockSectionSegment(Segment
);
1328 * Check if we are doing COW
1330 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1331 (Region
->Protect
== PAGE_READWRITE
||
1332 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1334 DPRINT("Address 0x%.8X\n", Address
);
1335 return(STATUS_ACCESS_VIOLATION
);
1338 if (IS_SWAP_FROM_SSE(Entry
) ||
1339 PFN_FROM_SSE(Entry
) != OldPage
)
1341 /* This is a private page. We must only change the page protection. */
1342 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1343 return(STATUS_SUCCESS
);
1347 * Get or create a pageop
1349 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1350 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1353 DPRINT1("MmGetPageOp failed\n");
1354 KeBugCheck(MEMORY_MANAGEMENT
);
1358 * Wait for any other operations to complete
1360 if (PageOp
->Thread
!= PsGetCurrentThread())
1362 MmUnlockAddressSpace(AddressSpace
);
1363 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1365 * Check for various strange conditions
1367 if (Status
== STATUS_TIMEOUT
)
1369 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1370 KeBugCheck(MEMORY_MANAGEMENT
);
1372 if (PageOp
->Status
== STATUS_PENDING
)
1374 DPRINT1("Woke for page op before completion\n");
1375 KeBugCheck(MEMORY_MANAGEMENT
);
1378 * Restart the operation
1380 MmLockAddressSpace(AddressSpace
);
1381 MmspCompleteAndReleasePageOp(PageOp
);
1382 DPRINT("Address 0x%.8X\n", Address
);
1383 return(STATUS_MM_RESTART_OPERATION
);
1387 * Release locks now we have the pageop
1389 MmUnlockAddressSpace(AddressSpace
);
1394 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1395 if (!NT_SUCCESS(Status
))
1397 KeBugCheck(MEMORY_MANAGEMENT
);
1403 MiCopyFromUserPage(NewPage
, PAddress
);
1405 MmLockAddressSpace(AddressSpace
);
1407 * Delete the old entry.
1409 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1412 * Set the PTE to point to the new page
1414 Status
= MmCreateVirtualMapping(Process
,
1419 if (!NT_SUCCESS(Status
))
1421 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1422 KeBugCheck(MEMORY_MANAGEMENT
);
1425 if (!NT_SUCCESS(Status
))
1427 DPRINT1("Unable to create virtual mapping\n");
1428 KeBugCheck(MEMORY_MANAGEMENT
);
1432 MmLockPage(NewPage
);
1433 MmUnlockPage(OldPage
);
1437 * Unshare the old page.
1439 MmDeleteRmap(OldPage
, Process
, PAddress
);
1440 MmInsertRmap(NewPage
, Process
, PAddress
);
1441 MmLockSectionSegment(Segment
);
1442 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1443 MmUnlockSectionSegment(Segment
);
1445 PageOp
->Status
= STATUS_SUCCESS
;
1446 MmspCompleteAndReleasePageOp(PageOp
);
1447 DPRINT("Address 0x%.8X\n", Address
);
1448 return(STATUS_SUCCESS
);
1452 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1454 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1458 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1461 MmLockAddressSpace(&Process
->Vm
);
1464 MmDeleteVirtualMapping(Process
,
1471 PageOutContext
->WasDirty
= TRUE
;
1473 if (!PageOutContext
->Private
)
1475 MmLockSectionSegment(PageOutContext
->Segment
);
1476 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1477 PageOutContext
->Segment
,
1478 PageOutContext
->Offset
,
1479 PageOutContext
->WasDirty
,
1481 MmUnlockSectionSegment(PageOutContext
->Segment
);
1485 MmUnlockAddressSpace(&Process
->Vm
);
1488 if (PageOutContext
->Private
)
1490 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1493 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1498 MmPageOutSectionView(PMMSUPPORT AddressSpace
,
1499 MEMORY_AREA
* MemoryArea
,
1504 MM_SECTION_PAGEOUT_CONTEXT Context
;
1505 SWAPENTRY SwapEntry
;
1509 PFILE_OBJECT FileObject
;
1511 BOOLEAN DirectMapped
;
1512 BOOLEAN IsImageSection
;
1513 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1515 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1518 * Get the segment and section.
1520 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1521 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1523 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1524 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1525 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1527 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1529 FileObject
= Context
.Section
->FileObject
;
1530 DirectMapped
= FALSE
;
1531 if (FileObject
!= NULL
&&
1532 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1534 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1537 * If the file system is letting us go directly to the cache and the
1538 * memory area was mapped at an offset in the file which is page aligned
1539 * then note this is a direct mapped page.
1541 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1542 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1544 DirectMapped
= TRUE
;
1550 * This should never happen since mappings of physical memory are never
1551 * placed in the rmap lists.
1553 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1555 DPRINT1("Trying to page out from physical memory section address 0x%X "
1556 "process %d\n", Address
,
1557 Process
? Process
->UniqueProcessId
: 0);
1558 KeBugCheck(MEMORY_MANAGEMENT
);
1562 * Get the section segment entry and the physical address.
1564 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1565 if (!MmIsPagePresent(Process
, Address
))
1567 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1568 Process
? Process
->UniqueProcessId
: 0, Address
);
1569 KeBugCheck(MEMORY_MANAGEMENT
);
1571 Page
= MmGetPfnForProcess(Process
, Address
);
1572 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1575 * Prepare the context structure for the rmap delete call.
1577 Context
.WasDirty
= FALSE
;
1578 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1579 IS_SWAP_FROM_SSE(Entry
) ||
1580 PFN_FROM_SSE(Entry
) != Page
)
1582 Context
.Private
= TRUE
;
1586 Context
.Private
= FALSE
;
1590 * Take an additional reference to the page or the cache segment.
1592 if (DirectMapped
&& !Context
.Private
)
1594 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1596 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1597 KeBugCheck(MEMORY_MANAGEMENT
);
1602 MmReferencePage(Page
);
1605 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1608 * If this wasn't a private page then we should have reduced the entry to
1609 * zero by deleting all the rmaps.
1611 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1613 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1614 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1616 KeBugCheck(MEMORY_MANAGEMENT
);
1621 * If the page wasn't dirty then we can just free it as for a readonly page.
1622 * Since we unmapped all the mappings above we know it will not suddenly
1624 * If the page is from a pagefile section and has no swap entry,
1625 * we can't free the page at this point.
1627 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1628 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1630 if (Context
.Private
)
1632 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1633 Context
.WasDirty
? "dirty" : "clean", Address
);
1634 KeBugCheck(MEMORY_MANAGEMENT
);
1636 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1638 MmSetSavedSwapEntryPage(Page
, 0);
1639 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1640 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1641 PageOp
->Status
= STATUS_SUCCESS
;
1642 MmspCompleteAndReleasePageOp(PageOp
);
1643 return(STATUS_SUCCESS
);
1646 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1648 if (Context
.Private
)
1650 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1651 Context
.WasDirty
? "dirty" : "clean", Address
);
1652 KeBugCheck(MEMORY_MANAGEMENT
);
1654 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1656 MmSetSavedSwapEntryPage(Page
, 0);
1659 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1661 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1662 PageOp
->Status
= STATUS_SUCCESS
;
1663 MmspCompleteAndReleasePageOp(PageOp
);
1664 return(STATUS_SUCCESS
);
1667 else if (!Context
.Private
&& DirectMapped
)
1671 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1673 KeBugCheck(MEMORY_MANAGEMENT
);
1675 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1676 if (!NT_SUCCESS(Status
))
1678 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1679 KeBugCheck(MEMORY_MANAGEMENT
);
1681 PageOp
->Status
= STATUS_SUCCESS
;
1682 MmspCompleteAndReleasePageOp(PageOp
);
1683 return(STATUS_SUCCESS
);
1685 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1689 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1691 KeBugCheck(MEMORY_MANAGEMENT
);
1693 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1694 PageOp
->Status
= STATUS_SUCCESS
;
1695 MmspCompleteAndReleasePageOp(PageOp
);
1696 return(STATUS_SUCCESS
);
1698 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1700 MmSetSavedSwapEntryPage(Page
, 0);
1701 MmLockAddressSpace(AddressSpace
);
1702 Status
= MmCreatePageFileMapping(Process
,
1705 MmUnlockAddressSpace(AddressSpace
);
1706 if (!NT_SUCCESS(Status
))
1708 KeBugCheck(MEMORY_MANAGEMENT
);
1710 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1711 PageOp
->Status
= STATUS_SUCCESS
;
1712 MmspCompleteAndReleasePageOp(PageOp
);
1713 return(STATUS_SUCCESS
);
1717 * If necessary, allocate an entry in the paging file for this page
1721 SwapEntry
= MmAllocSwapPage();
1724 MmShowOutOfSpaceMessagePagingFile();
1725 MmLockAddressSpace(AddressSpace
);
1727 * For private pages restore the old mappings.
1729 if (Context
.Private
)
1731 Status
= MmCreateVirtualMapping(Process
,
1733 MemoryArea
->Protect
,
1736 MmSetDirtyPage(Process
, Address
);
1744 * For non-private pages if the page wasn't direct mapped then
1745 * set it back into the section segment entry so we don't loose
1746 * our copy. Otherwise it will be handled by the cache manager.
1748 Status
= MmCreateVirtualMapping(Process
,
1750 MemoryArea
->Protect
,
1753 MmSetDirtyPage(Process
, Address
);
1757 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1758 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1760 MmUnlockAddressSpace(AddressSpace
);
1761 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1762 MmspCompleteAndReleasePageOp(PageOp
);
1763 return(STATUS_PAGEFILE_QUOTA
);
1768 * Write the page to the pagefile
1770 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1771 if (!NT_SUCCESS(Status
))
1773 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1776 * As above: undo our actions.
1777 * FIXME: Also free the swap page.
1779 MmLockAddressSpace(AddressSpace
);
1780 if (Context
.Private
)
1782 Status
= MmCreateVirtualMapping(Process
,
1784 MemoryArea
->Protect
,
1787 MmSetDirtyPage(Process
, Address
);
1794 Status
= MmCreateVirtualMapping(Process
,
1796 MemoryArea
->Protect
,
1799 MmSetDirtyPage(Process
, Address
);
1803 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1804 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1806 MmUnlockAddressSpace(AddressSpace
);
1807 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1808 MmspCompleteAndReleasePageOp(PageOp
);
1809 return(STATUS_UNSUCCESSFUL
);
1813 * Otherwise we have succeeded.
1815 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1816 MmSetSavedSwapEntryPage(Page
, 0);
1817 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1818 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1820 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1824 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1827 if (Context
.Private
)
1829 MmLockAddressSpace(AddressSpace
);
1830 Status
= MmCreatePageFileMapping(Process
,
1833 MmUnlockAddressSpace(AddressSpace
);
1834 if (!NT_SUCCESS(Status
))
1836 KeBugCheck(MEMORY_MANAGEMENT
);
1841 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1842 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1845 PageOp
->Status
= STATUS_SUCCESS
;
1846 MmspCompleteAndReleasePageOp(PageOp
);
1847 return(STATUS_SUCCESS
);
1852 MmWritePageSectionView(PMMSUPPORT AddressSpace
,
1853 PMEMORY_AREA MemoryArea
,
1858 PROS_SECTION_OBJECT Section
;
1859 PMM_SECTION_SEGMENT Segment
;
1861 SWAPENTRY SwapEntry
;
1865 PFILE_OBJECT FileObject
;
1867 BOOLEAN DirectMapped
;
1868 BOOLEAN IsImageSection
;
1869 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1871 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1873 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1874 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1877 * Get the segment and section.
1879 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1880 Section
= MemoryArea
->Data
.SectionData
.Section
;
1881 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1883 FileObject
= Section
->FileObject
;
1884 DirectMapped
= FALSE
;
1885 if (FileObject
!= NULL
&&
1886 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1888 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1891 * If the file system is letting us go directly to the cache and the
1892 * memory area was mapped at an offset in the file which is page aligned
1893 * then note this is a direct mapped page.
1895 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1896 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1898 DirectMapped
= TRUE
;
1903 * This should never happen since mappings of physical memory are never
1904 * placed in the rmap lists.
1906 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1908 DPRINT1("Trying to write back page from physical memory mapped at %X "
1909 "process %d\n", Address
,
1910 Process
? Process
->UniqueProcessId
: 0);
1911 KeBugCheck(MEMORY_MANAGEMENT
);
1915 * Get the section segment entry and the physical address.
1917 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1918 if (!MmIsPagePresent(Process
, Address
))
1920 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1921 Process
? Process
->UniqueProcessId
: 0, Address
);
1922 KeBugCheck(MEMORY_MANAGEMENT
);
1924 Page
= MmGetPfnForProcess(Process
, Address
);
1925 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1928 * Check for a private (COWed) page.
1930 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1931 IS_SWAP_FROM_SSE(Entry
) ||
1932 PFN_FROM_SSE(Entry
) != Page
)
1942 * Speculatively set all mappings of the page to clean.
1944 MmSetCleanAllRmaps(Page
);
1947 * If this page was direct mapped from the cache then the cache manager
1948 * will take care of writing it back to disk.
1950 if (DirectMapped
&& !Private
)
1952 ASSERT(SwapEntry
== 0);
1953 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1954 PageOp
->Status
= STATUS_SUCCESS
;
1955 MmspCompleteAndReleasePageOp(PageOp
);
1956 return(STATUS_SUCCESS
);
1960 * If necessary, allocate an entry in the paging file for this page
1964 SwapEntry
= MmAllocSwapPage();
1967 MmSetDirtyAllRmaps(Page
);
1968 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1969 MmspCompleteAndReleasePageOp(PageOp
);
1970 return(STATUS_PAGEFILE_QUOTA
);
1972 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1976 * Write the page to the pagefile
1978 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1979 if (!NT_SUCCESS(Status
))
1981 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1983 MmSetDirtyAllRmaps(Page
);
1984 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1985 MmspCompleteAndReleasePageOp(PageOp
);
1986 return(STATUS_UNSUCCESSFUL
);
1990 * Otherwise we have succeeded.
1992 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1993 PageOp
->Status
= STATUS_SUCCESS
;
1994 MmspCompleteAndReleasePageOp(PageOp
);
1995 return(STATUS_SUCCESS
);
1999 MmAlterViewAttributes(PMMSUPPORT AddressSpace
,
2007 PMEMORY_AREA MemoryArea
;
2008 PMM_SECTION_SEGMENT Segment
;
2009 BOOLEAN DoCOW
= FALSE
;
2011 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2013 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2014 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2016 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
2017 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2022 if (OldProtect
!= NewProtect
)
2024 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2026 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2027 ULONG Protect
= NewProtect
;
2030 * If we doing COW for this segment then check if the page is
2033 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2039 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2040 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2041 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2042 Page
= MmGetPfnForProcess(Process
, Address
);
2044 Protect
= PAGE_READONLY
;
2045 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2046 IS_SWAP_FROM_SSE(Entry
) ||
2047 PFN_FROM_SSE(Entry
) != Page
)
2049 Protect
= NewProtect
;
2053 if (MmIsPagePresent(Process
, Address
))
2055 MmSetPageProtect(Process
, Address
,
2064 MmProtectSectionView(PMMSUPPORT AddressSpace
,
2065 PMEMORY_AREA MemoryArea
,
2073 ULONG_PTR MaxLength
;
2075 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2076 if (Length
> MaxLength
)
2079 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2080 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2082 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2083 Region
->Protect
!= Protect
)
2085 return STATUS_INVALID_PAGE_PROTECTION
;
2088 *OldProtect
= Region
->Protect
;
2089 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2090 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2091 BaseAddress
, Length
, Region
->Type
, Protect
,
2092 MmAlterViewAttributes
);
2098 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2100 PMEMORY_BASIC_INFORMATION Info
,
2101 PSIZE_T ResultLength
)
2104 PVOID RegionBaseAddress
;
2105 PROS_SECTION_OBJECT Section
;
2106 PMM_SECTION_SEGMENT Segment
;
2108 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2109 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2110 Address
, &RegionBaseAddress
);
2113 return STATUS_UNSUCCESSFUL
;
2116 Section
= MemoryArea
->Data
.SectionData
.Section
;
2117 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2119 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2120 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2121 Info
->Type
= MEM_IMAGE
;
2125 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2126 Info
->Type
= MEM_MAPPED
;
2128 Info
->BaseAddress
= RegionBaseAddress
;
2129 Info
->AllocationProtect
= MemoryArea
->Protect
;
2130 Info
->RegionSize
= Region
->Length
;
2131 Info
->State
= MEM_COMMIT
;
2132 Info
->Protect
= Region
->Protect
;
2134 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2135 return(STATUS_SUCCESS
);
2140 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2145 ULONG SavedSwapEntry
;
2150 Length
= PAGE_ROUND_UP(Segment
->Length
);
2151 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2153 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2156 if (IS_SWAP_FROM_SSE(Entry
))
2158 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2162 Page
= PFN_FROM_SSE(Entry
);
2163 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2164 if (SavedSwapEntry
!= 0)
2166 MmSetSavedSwapEntryPage(Page
, 0);
2167 MmFreeSwapPage(SavedSwapEntry
);
2169 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2171 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2177 MmpDeleteSection(PVOID ObjectBody
)
2179 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2181 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2182 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2187 PMM_SECTION_SEGMENT SectionSegments
;
2190 * NOTE: Section->ImageSection can be NULL for short time
2191 * during the section creating. If we fail for some reason
2192 * until the image section is properly initialized we shouldn't
2193 * process further here.
2195 if (Section
->ImageSection
== NULL
)
2198 SectionSegments
= Section
->ImageSection
->Segments
;
2199 NrSegments
= Section
->ImageSection
->NrSegments
;
2201 for (i
= 0; i
< NrSegments
; i
++)
2203 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2205 MmLockSectionSegment(&SectionSegments
[i
]);
2207 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2208 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2212 MmpFreePageFileSegment(&SectionSegments
[i
]);
2214 MmUnlockSectionSegment(&SectionSegments
[i
]);
2221 * NOTE: Section->Segment can be NULL for short time
2222 * during the section creating.
2224 if (Section
->Segment
== NULL
)
2227 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2229 MmpFreePageFileSegment(Section
->Segment
);
2230 MmFreePageTablesSectionSegment(Section
->Segment
);
2231 ExFreePool(Section
->Segment
);
2232 Section
->Segment
= NULL
;
2236 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2239 if (Section
->FileObject
!= NULL
)
2241 CcRosDereferenceCache(Section
->FileObject
);
2242 ObDereferenceObject(Section
->FileObject
);
2243 Section
->FileObject
= NULL
;
2248 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2250 IN ACCESS_MASK GrantedAccess
,
2251 IN ULONG ProcessHandleCount
,
2252 IN ULONG SystemHandleCount
)
2254 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2255 Object
, ProcessHandleCount
);
2261 MmCreatePhysicalMemorySection(VOID
)
2263 PROS_SECTION_OBJECT PhysSection
;
2265 OBJECT_ATTRIBUTES Obj
;
2266 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2267 LARGE_INTEGER SectionSize
;
2271 * Create the section mapping physical memory
2273 SectionSize
.QuadPart
= 0xFFFFFFFF;
2274 InitializeObjectAttributes(&Obj
,
2279 Status
= MmCreateSection((PVOID
)&PhysSection
,
2283 PAGE_EXECUTE_READWRITE
,
2287 if (!NT_SUCCESS(Status
))
2289 DPRINT1("Failed to create PhysicalMemory section\n");
2290 KeBugCheck(MEMORY_MANAGEMENT
);
2292 Status
= ObInsertObject(PhysSection
,
2298 if (!NT_SUCCESS(Status
))
2300 ObDereferenceObject(PhysSection
);
2302 ObCloseHandle(Handle
, KernelMode
);
2303 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2304 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2306 return(STATUS_SUCCESS
);
2312 MmInitSectionImplementation(VOID
)
2314 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2315 UNICODE_STRING Name
;
2317 DPRINT("Creating Section Object Type\n");
2319 /* Initialize the Section object type */
2320 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2321 RtlInitUnicodeString(&Name
, L
"Section");
2322 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2323 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2324 ObjectTypeInitializer
.PoolType
= PagedPool
;
2325 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2326 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2327 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2328 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2329 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2330 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2332 return(STATUS_SUCCESS
);
2337 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2338 ACCESS_MASK DesiredAccess
,
2339 POBJECT_ATTRIBUTES ObjectAttributes
,
2340 PLARGE_INTEGER UMaximumSize
,
2341 ULONG SectionPageProtection
,
2342 ULONG AllocationAttributes
)
2344 * Create a section which is backed by the pagefile
2347 LARGE_INTEGER MaximumSize
;
2348 PROS_SECTION_OBJECT Section
;
2349 PMM_SECTION_SEGMENT Segment
;
2352 if (UMaximumSize
== NULL
)
2354 return(STATUS_UNSUCCESSFUL
);
2356 MaximumSize
= *UMaximumSize
;
2359 * Create the section
2361 Status
= ObCreateObject(ExGetPreviousMode(),
2362 MmSectionObjectType
,
2364 ExGetPreviousMode(),
2366 sizeof(ROS_SECTION_OBJECT
),
2369 (PVOID
*)(PVOID
)&Section
);
2370 if (!NT_SUCCESS(Status
))
2378 Section
->SectionPageProtection
= SectionPageProtection
;
2379 Section
->AllocationAttributes
= AllocationAttributes
;
2380 Section
->Segment
= NULL
;
2381 Section
->FileObject
= NULL
;
2382 Section
->MaximumSize
= MaximumSize
;
2383 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2384 TAG_MM_SECTION_SEGMENT
);
2385 if (Segment
== NULL
)
2387 ObDereferenceObject(Section
);
2388 return(STATUS_NO_MEMORY
);
2390 Section
->Segment
= Segment
;
2391 Segment
->ReferenceCount
= 1;
2392 ExInitializeFastMutex(&Segment
->Lock
);
2393 Segment
->FileOffset
= 0;
2394 Segment
->Protection
= SectionPageProtection
;
2395 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2396 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2397 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2398 Segment
->WriteCopy
= FALSE
;
2399 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2400 Segment
->VirtualAddress
= 0;
2401 Segment
->Characteristics
= 0;
2402 *SectionObject
= Section
;
2403 return(STATUS_SUCCESS
);
2409 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2410 ACCESS_MASK DesiredAccess
,
2411 POBJECT_ATTRIBUTES ObjectAttributes
,
2412 PLARGE_INTEGER UMaximumSize
,
2413 ULONG SectionPageProtection
,
2414 ULONG AllocationAttributes
,
2417 * Create a section backed by a data file
2420 PROS_SECTION_OBJECT Section
;
2422 LARGE_INTEGER MaximumSize
;
2423 PFILE_OBJECT FileObject
;
2424 PMM_SECTION_SEGMENT Segment
;
2426 IO_STATUS_BLOCK Iosb
;
2427 LARGE_INTEGER Offset
;
2429 FILE_STANDARD_INFORMATION FileInfo
;
2433 * Create the section
2435 Status
= ObCreateObject(ExGetPreviousMode(),
2436 MmSectionObjectType
,
2438 ExGetPreviousMode(),
2440 sizeof(ROS_SECTION_OBJECT
),
2443 (PVOID
*)(PVOID
)&Section
);
2444 if (!NT_SUCCESS(Status
))
2451 Section
->SectionPageProtection
= SectionPageProtection
;
2452 Section
->AllocationAttributes
= AllocationAttributes
;
2453 Section
->Segment
= NULL
;
2456 * Check file access required
2458 if (SectionPageProtection
& PAGE_READWRITE
||
2459 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2461 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2465 FileAccess
= FILE_READ_DATA
;
2469 * Reference the file handle
2471 Status
= ObReferenceObjectByHandle(FileHandle
,
2474 ExGetPreviousMode(),
2475 (PVOID
*)(PVOID
)&FileObject
,
2477 if (!NT_SUCCESS(Status
))
2479 ObDereferenceObject(Section
);
2484 * FIXME: This is propably not entirely correct. We can't look into
2485 * the standard FCB header because it might not be initialized yet
2486 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2487 * standard file information is filled on first request).
2489 Status
= IoQueryFileInformation(FileObject
,
2490 FileStandardInformation
,
2491 sizeof(FILE_STANDARD_INFORMATION
),
2494 Iosb
.Information
= Length
;
2495 if (!NT_SUCCESS(Status
))
2497 ObDereferenceObject(Section
);
2498 ObDereferenceObject(FileObject
);
2503 * FIXME: Revise this once a locking order for file size changes is
2506 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2508 MaximumSize
= *UMaximumSize
;
2512 MaximumSize
= FileInfo
.EndOfFile
;
2513 /* Mapping zero-sized files isn't allowed. */
2514 if (MaximumSize
.QuadPart
== 0)
2516 ObDereferenceObject(Section
);
2517 ObDereferenceObject(FileObject
);
2518 return STATUS_FILE_INVALID
;
2522 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2524 Status
= IoSetInformation(FileObject
,
2525 FileAllocationInformation
,
2526 sizeof(LARGE_INTEGER
),
2528 if (!NT_SUCCESS(Status
))
2530 ObDereferenceObject(Section
);
2531 ObDereferenceObject(FileObject
);
2532 return(STATUS_SECTION_NOT_EXTENDED
);
2536 if (FileObject
->SectionObjectPointer
== NULL
||
2537 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2540 * Read a bit so caching is initiated for the file object.
2541 * This is only needed because MiReadPage currently cannot
2542 * handle non-cached streams.
2544 Offset
.QuadPart
= 0;
2545 Status
= ZwReadFile(FileHandle
,
2554 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2556 ObDereferenceObject(Section
);
2557 ObDereferenceObject(FileObject
);
2560 if (FileObject
->SectionObjectPointer
== NULL
||
2561 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2563 /* FIXME: handle this situation */
2564 ObDereferenceObject(Section
);
2565 ObDereferenceObject(FileObject
);
2566 return STATUS_INVALID_PARAMETER
;
2573 Status
= MmspWaitForFileLock(FileObject
);
2574 if (Status
!= STATUS_SUCCESS
)
2576 ObDereferenceObject(Section
);
2577 ObDereferenceObject(FileObject
);
2582 * If this file hasn't been mapped as a data file before then allocate a
2583 * section segment to describe the data file mapping
2585 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2587 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2588 TAG_MM_SECTION_SEGMENT
);
2589 if (Segment
== NULL
)
2591 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2592 ObDereferenceObject(Section
);
2593 ObDereferenceObject(FileObject
);
2594 return(STATUS_NO_MEMORY
);
2596 Section
->Segment
= Segment
;
2597 Segment
->ReferenceCount
= 1;
2598 ExInitializeFastMutex(&Segment
->Lock
);
2600 * Set the lock before assigning the segment to the file object
2602 ExAcquireFastMutex(&Segment
->Lock
);
2603 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2605 Segment
->FileOffset
= 0;
2606 Segment
->Protection
= SectionPageProtection
;
2607 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2608 Segment
->Characteristics
= 0;
2609 Segment
->WriteCopy
= FALSE
;
2610 if (AllocationAttributes
& SEC_RESERVE
)
2612 Segment
->Length
= Segment
->RawLength
= 0;
2616 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2617 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2619 Segment
->VirtualAddress
= 0;
2620 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2625 * If the file is already mapped as a data file then we may need
2629 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2631 Section
->Segment
= Segment
;
2632 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2633 MmLockSectionSegment(Segment
);
2635 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2636 !(AllocationAttributes
& SEC_RESERVE
))
2638 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2639 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2642 MmUnlockSectionSegment(Segment
);
2643 Section
->FileObject
= FileObject
;
2644 Section
->MaximumSize
= MaximumSize
;
2645 CcRosReferenceCache(FileObject
);
2646 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2647 *SectionObject
= Section
;
2648 return(STATUS_SUCCESS
);
2652 TODO: not that great (declaring loaders statically, having to declare all of
2653 them, having to keep them extern, etc.), will fix in the future
2655 extern NTSTATUS NTAPI PeFmtCreateSection
2657 IN CONST VOID
* FileHeader
,
2658 IN SIZE_T FileHeaderSize
,
2660 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2662 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2663 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2666 extern NTSTATUS NTAPI ElfFmtCreateSection
2668 IN CONST VOID
* FileHeader
,
2669 IN SIZE_T FileHeaderSize
,
2671 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2673 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2674 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2677 /* TODO: this is a standard DDK/PSDK macro */
2678 #ifndef RTL_NUMBER_OF
2679 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2682 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2693 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2695 SIZE_T SizeOfSegments
;
2696 PMM_SECTION_SEGMENT Segments
;
2698 /* TODO: check for integer overflow */
2699 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2701 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2703 TAG_MM_SECTION_SEGMENT
);
2706 RtlZeroMemory(Segments
, SizeOfSegments
);
2714 ExeFmtpReadFile(IN PVOID File
,
2715 IN PLARGE_INTEGER Offset
,
2718 OUT PVOID
* AllocBase
,
2719 OUT PULONG ReadSize
)
2722 LARGE_INTEGER FileOffset
;
2724 ULONG OffsetAdjustment
;
2729 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2733 KeBugCheck(MEMORY_MANAGEMENT
);
2736 FileOffset
= *Offset
;
2738 /* Negative/special offset: it cannot be used in this context */
2739 if(FileOffset
.u
.HighPart
< 0)
2741 KeBugCheck(MEMORY_MANAGEMENT
);
2744 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2745 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2746 FileOffset
.u
.LowPart
= AdjustOffset
;
2748 BufferSize
= Length
+ OffsetAdjustment
;
2749 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2752 * It's ok to use paged pool, because this is a temporary buffer only used in
2753 * the loading of executables. The assumption is that MmCreateSection is
2754 * always called at low IRQLs and that these buffers don't survive a brief
2755 * initialization phase
2757 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2759 TAG('M', 'm', 'X', 'r'));
2764 Status
= MmspPageRead(File
,
2771 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2772 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2773 * to initialize internal state is even worse. Our cache manager is in need of
2777 IO_STATUS_BLOCK Iosb
;
2779 Status
= ZwReadFile(File
,
2789 if(NT_SUCCESS(Status
))
2791 UsedSize
= Iosb
.Information
;
2796 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2798 Status
= STATUS_IN_PAGE_ERROR
;
2799 ASSERT(!NT_SUCCESS(Status
));
2802 if(NT_SUCCESS(Status
))
2804 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2805 *AllocBase
= Buffer
;
2806 *ReadSize
= UsedSize
- OffsetAdjustment
;
2810 ExFreePoolWithTag(Buffer
, TAG('M', 'm', 'X', 'r'));
2817 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2818 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2819 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2824 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2828 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2830 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2831 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2838 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2842 MmspAssertSegmentsSorted(ImageSectionObject
);
2844 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2846 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2850 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2851 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2852 ImageSectionObject
->Segments
[i
- 1].Length
));
2860 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2864 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2866 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2867 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2875 MmspCompareSegments(const void * x
,
2878 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2879 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2882 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2883 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2887 * Ensures an image section's segments are sorted in memory
2892 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2895 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2897 MmspAssertSegmentsSorted(ImageSectionObject
);
2901 qsort(ImageSectionObject
->Segments
,
2902 ImageSectionObject
->NrSegments
,
2903 sizeof(ImageSectionObject
->Segments
[0]),
2904 MmspCompareSegments
);
2910 * Ensures an image section's segments don't overlap in memory and don't have
2911 * gaps and don't have a null size. We let them map to overlapping file regions,
2912 * though - that's not necessarily an error
2917 MmspCheckSegmentBounds
2919 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2925 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2927 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2931 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2933 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2935 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2943 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2944 * page could be OK (Windows seems to be OK with them), and larger gaps
2945 * could lead to image sections spanning several discontiguous regions
2946 * (NtMapViewOfSection could then refuse to map them, and they could
2947 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2949 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2950 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2951 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2962 * Merges and pads an image section's segments until they all are page-aligned
2963 * and have a size that is a multiple of the page size
2968 MmspPageAlignSegments
2970 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2976 BOOLEAN Initialized
;
2977 PMM_SECTION_SEGMENT EffectiveSegment
;
2979 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2981 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2985 Initialized
= FALSE
;
2987 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2989 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2992 * The first segment requires special handling
2996 ULONG_PTR VirtualAddress
;
2997 ULONG_PTR VirtualOffset
;
2999 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
3001 /* Round down the virtual address to the nearest page */
3002 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
3004 /* Round up the virtual size to the nearest page */
3005 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3006 EffectiveSegment
->VirtualAddress
;
3008 /* Adjust the raw address and size */
3009 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3011 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3017 * Garbage in, garbage out: unaligned base addresses make the file
3018 * offset point in curious and odd places, but that's what we were
3021 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3022 EffectiveSegment
->RawLength
+= VirtualOffset
;
3026 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3027 ULONG_PTR EndOfEffectiveSegment
;
3029 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3030 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3033 * The current segment begins exactly where the current effective
3034 * segment ended, therefore beginning a new effective segment
3036 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3039 ASSERT(LastSegment
<= i
);
3040 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3042 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3044 if (LastSegment
!= i
)
3047 * Copy the current segment. If necessary, the effective segment
3048 * will be expanded later
3050 *EffectiveSegment
= *Segment
;
3054 * Page-align the virtual size. We know for sure the virtual address
3057 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3058 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3061 * The current segment is still part of the current effective segment:
3062 * extend the effective segment to reflect this
3064 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3066 static const ULONG FlagsToProtection
[16] =
3074 PAGE_EXECUTE_READWRITE
,
3075 PAGE_EXECUTE_READWRITE
,
3080 PAGE_EXECUTE_WRITECOPY
,
3081 PAGE_EXECUTE_WRITECOPY
,
3082 PAGE_EXECUTE_WRITECOPY
,
3083 PAGE_EXECUTE_WRITECOPY
3086 unsigned ProtectionFlags
;
3089 * Extend the file size
3092 /* Unaligned segments must be contiguous within the file */
3093 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3094 EffectiveSegment
->RawLength
))
3099 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3102 * Extend the virtual size
3104 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3106 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3107 EffectiveSegment
->VirtualAddress
;
3110 * Merge the protection
3112 EffectiveSegment
->Protection
|= Segment
->Protection
;
3114 /* Clean up redundance */
3115 ProtectionFlags
= 0;
3117 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3118 ProtectionFlags
|= 1 << 0;
3120 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3121 ProtectionFlags
|= 1 << 1;
3123 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3124 ProtectionFlags
|= 1 << 2;
3126 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3127 ProtectionFlags
|= 1 << 3;
3129 ASSERT(ProtectionFlags
< 16);
3130 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3132 /* If a segment was required to be shared and cannot, fail */
3133 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3134 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3140 * We assume no holes between segments at this point
3144 KeBugCheck(MEMORY_MANAGEMENT
);
3148 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3154 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3155 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3157 LARGE_INTEGER Offset
;
3159 PVOID FileHeaderBuffer
;
3160 ULONG FileHeaderSize
;
3162 ULONG OldNrSegments
;
3167 * Read the beginning of the file (2 pages). Should be enough to contain
3168 * all (or most) of the headers
3170 Offset
.QuadPart
= 0;
3172 /* FIXME: use FileObject instead of FileHandle */
3173 Status
= ExeFmtpReadFile (FileHandle
,
3180 if (!NT_SUCCESS(Status
))
3183 if (FileHeaderSize
== 0)
3185 ExFreePool(FileHeaderBuffer
);
3186 return STATUS_UNSUCCESSFUL
;
3190 * Look for a loader that can handle this executable
3192 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3194 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3197 /* FIXME: use FileObject instead of FileHandle */
3198 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3204 ExeFmtpAllocateSegments
);
3206 if (!NT_SUCCESS(Status
))
3208 if (ImageSectionObject
->Segments
)
3210 ExFreePool(ImageSectionObject
->Segments
);
3211 ImageSectionObject
->Segments
= NULL
;
3215 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3219 ExFreePoolWithTag(FileHeaderBuffer
, TAG('M', 'm', 'X', 'r'));
3222 * No loader handled the format
3224 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3226 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3227 ASSERT(!NT_SUCCESS(Status
));
3230 if (!NT_SUCCESS(Status
))
3233 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3238 /* FIXME? are these values platform-dependent? */
3239 if(ImageSectionObject
->StackReserve
== 0)
3240 ImageSectionObject
->StackReserve
= 0x40000;
3242 if(ImageSectionObject
->StackCommit
== 0)
3243 ImageSectionObject
->StackCommit
= 0x1000;
3245 if(ImageSectionObject
->ImageBase
== 0)
3247 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3248 ImageSectionObject
->ImageBase
= 0x10000000;
3250 ImageSectionObject
->ImageBase
= 0x00400000;
3254 * And now the fun part: fixing the segments
3257 /* Sort them by virtual address */
3258 MmspSortSegments(ImageSectionObject
, Flags
);
3260 /* Ensure they don't overlap in memory */
3261 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3262 return STATUS_INVALID_IMAGE_FORMAT
;
3264 /* Ensure they are aligned */
3265 OldNrSegments
= ImageSectionObject
->NrSegments
;
3267 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3268 return STATUS_INVALID_IMAGE_FORMAT
;
3270 /* Trim them if the alignment phase merged some of them */
3271 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3273 PMM_SECTION_SEGMENT Segments
;
3274 SIZE_T SizeOfSegments
;
3276 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3278 Segments
= ExAllocatePoolWithTag(PagedPool
,
3280 TAG_MM_SECTION_SEGMENT
);
3282 if (Segments
== NULL
)
3283 return STATUS_INSUFFICIENT_RESOURCES
;
3285 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3286 ExFreePool(ImageSectionObject
->Segments
);
3287 ImageSectionObject
->Segments
= Segments
;
3290 /* And finish their initialization */
3291 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3293 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3294 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3296 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3297 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3300 ASSERT(NT_SUCCESS(Status
));
3305 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3306 ACCESS_MASK DesiredAccess
,
3307 POBJECT_ATTRIBUTES ObjectAttributes
,
3308 PLARGE_INTEGER UMaximumSize
,
3309 ULONG SectionPageProtection
,
3310 ULONG AllocationAttributes
,
3313 PROS_SECTION_OBJECT Section
;
3315 PFILE_OBJECT FileObject
;
3316 PMM_SECTION_SEGMENT SectionSegments
;
3317 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3319 ULONG FileAccess
= 0;
3322 * Specifying a maximum size is meaningless for an image section
3324 if (UMaximumSize
!= NULL
)
3326 return(STATUS_INVALID_PARAMETER_4
);
3330 * Check file access required
3332 if (SectionPageProtection
& PAGE_READWRITE
||
3333 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3335 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3339 FileAccess
= FILE_READ_DATA
;
3343 * Reference the file handle
3345 Status
= ObReferenceObjectByHandle(FileHandle
,
3348 ExGetPreviousMode(),
3349 (PVOID
*)(PVOID
)&FileObject
,
3352 if (!NT_SUCCESS(Status
))
3358 * Create the section
3360 Status
= ObCreateObject (ExGetPreviousMode(),
3361 MmSectionObjectType
,
3363 ExGetPreviousMode(),
3365 sizeof(ROS_SECTION_OBJECT
),
3368 (PVOID
*)(PVOID
)&Section
);
3369 if (!NT_SUCCESS(Status
))
3371 ObDereferenceObject(FileObject
);
3378 Section
->SectionPageProtection
= SectionPageProtection
;
3379 Section
->AllocationAttributes
= AllocationAttributes
;
3382 * Initialized caching for this file object if previously caching
3383 * was initialized for the same on disk file
3385 Status
= CcTryToInitializeFileCache(FileObject
);
3387 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3389 NTSTATUS StatusExeFmt
;
3391 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3392 if (ImageSectionObject
== NULL
)
3394 ObDereferenceObject(FileObject
);
3395 ObDereferenceObject(Section
);
3396 return(STATUS_NO_MEMORY
);
3399 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3401 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3403 if (!NT_SUCCESS(StatusExeFmt
))
3405 if(ImageSectionObject
->Segments
!= NULL
)
3406 ExFreePool(ImageSectionObject
->Segments
);
3408 ExFreePool(ImageSectionObject
);
3409 ObDereferenceObject(Section
);
3410 ObDereferenceObject(FileObject
);
3411 return(StatusExeFmt
);
3414 Section
->ImageSection
= ImageSectionObject
;
3415 ASSERT(ImageSectionObject
->Segments
);
3420 Status
= MmspWaitForFileLock(FileObject
);
3421 if (!NT_SUCCESS(Status
))
3423 ExFreePool(ImageSectionObject
->Segments
);
3424 ExFreePool(ImageSectionObject
);
3425 ObDereferenceObject(Section
);
3426 ObDereferenceObject(FileObject
);
3430 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3431 ImageSectionObject
, NULL
))
3434 * An other thread has initialized the same image in the background
3436 ExFreePool(ImageSectionObject
->Segments
);
3437 ExFreePool(ImageSectionObject
);
3438 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3439 Section
->ImageSection
= ImageSectionObject
;
3440 SectionSegments
= ImageSectionObject
->Segments
;
3442 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3444 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3448 Status
= StatusExeFmt
;
3455 Status
= MmspWaitForFileLock(FileObject
);
3456 if (Status
!= STATUS_SUCCESS
)
3458 ObDereferenceObject(Section
);
3459 ObDereferenceObject(FileObject
);
3463 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3464 Section
->ImageSection
= ImageSectionObject
;
3465 SectionSegments
= ImageSectionObject
->Segments
;
3468 * Otherwise just reference all the section segments
3470 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3472 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3475 Status
= STATUS_SUCCESS
;
3477 Section
->FileObject
= FileObject
;
3478 CcRosReferenceCache(FileObject
);
3479 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3480 *SectionObject
= Section
;
3488 NtCreateSection (OUT PHANDLE SectionHandle
,
3489 IN ACCESS_MASK DesiredAccess
,
3490 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3491 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3492 IN ULONG SectionPageProtection OPTIONAL
,
3493 IN ULONG AllocationAttributes
,
3494 IN HANDLE FileHandle OPTIONAL
)
3496 LARGE_INTEGER SafeMaximumSize
;
3497 PVOID SectionObject
;
3498 KPROCESSOR_MODE PreviousMode
;
3499 NTSTATUS Status
= STATUS_SUCCESS
;
3501 PreviousMode
= ExGetPreviousMode();
3503 if(PreviousMode
!= KernelMode
)
3507 if (MaximumSize
!= NULL
)
3509 /* make a copy on the stack */
3510 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3511 MaximumSize
= &SafeMaximumSize
;
3513 ProbeForWriteHandle(SectionHandle
);
3515 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3517 Status
= _SEH2_GetExceptionCode();
3521 if(!NT_SUCCESS(Status
))
3527 Status
= MmCreateSection(&SectionObject
,
3531 SectionPageProtection
,
3532 AllocationAttributes
,
3535 if (NT_SUCCESS(Status
))
3537 Status
= ObInsertObject ((PVOID
)SectionObject
,
3549 /**********************************************************************
3567 NtOpenSection(PHANDLE SectionHandle
,
3568 ACCESS_MASK DesiredAccess
,
3569 POBJECT_ATTRIBUTES ObjectAttributes
)
3572 KPROCESSOR_MODE PreviousMode
;
3573 NTSTATUS Status
= STATUS_SUCCESS
;
3575 PreviousMode
= ExGetPreviousMode();
3577 if(PreviousMode
!= KernelMode
)
3581 ProbeForWriteHandle(SectionHandle
);
3583 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3585 Status
= _SEH2_GetExceptionCode();
3589 if(!NT_SUCCESS(Status
))
3595 Status
= ObOpenObjectByName(ObjectAttributes
,
3596 MmSectionObjectType
,
3603 if(NT_SUCCESS(Status
))
3607 *SectionHandle
= hSection
;
3609 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3611 Status
= _SEH2_GetExceptionCode();
3620 MmMapViewOfSegment(PMMSUPPORT AddressSpace
,
3621 PROS_SECTION_OBJECT Section
,
3622 PMM_SECTION_SEGMENT Segment
,
3627 ULONG AllocationType
)
3631 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3633 BoundaryAddressMultiple
.QuadPart
= 0;
3635 Status
= MmCreateMemoryArea(AddressSpace
,
3636 MEMORY_AREA_SECTION_VIEW
,
3643 BoundaryAddressMultiple
);
3644 if (!NT_SUCCESS(Status
))
3646 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3647 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3651 ObReferenceObject((PVOID
)Section
);
3653 MArea
->Data
.SectionData
.Segment
= Segment
;
3654 MArea
->Data
.SectionData
.Section
= Section
;
3655 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3656 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3657 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3658 ViewSize
, 0, Protect
);
3660 return(STATUS_SUCCESS
);
3664 /**********************************************************************
3666 * NtMapViewOfSection
3669 * Maps a view of a section into the virtual address space of a
3674 * Handle of the section.
3677 * Handle of the process.
3680 * Desired base address (or NULL) on entry;
3681 * Actual base address of the view on exit.
3684 * Number of high order address bits that must be zero.
3687 * Size in bytes of the initially committed section of
3691 * Offset in bytes from the beginning of the section
3692 * to the beginning of the view.
3695 * Desired length of map (or zero to map all) on entry
3696 * Actual length mapped on exit.
3698 * InheritDisposition
3699 * Specified how the view is to be shared with
3703 * Type of allocation for the pages.
3706 * Protection for the committed region of the view.
3714 NtMapViewOfSection(IN HANDLE SectionHandle
,
3715 IN HANDLE ProcessHandle
,
3716 IN OUT PVOID
* BaseAddress OPTIONAL
,
3717 IN ULONG_PTR ZeroBits OPTIONAL
,
3718 IN SIZE_T CommitSize
,
3719 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3720 IN OUT PSIZE_T ViewSize
,
3721 IN SECTION_INHERIT InheritDisposition
,
3722 IN ULONG AllocationType OPTIONAL
,
3725 PVOID SafeBaseAddress
;
3726 LARGE_INTEGER SafeSectionOffset
;
3727 SIZE_T SafeViewSize
;
3728 PROS_SECTION_OBJECT Section
;
3730 KPROCESSOR_MODE PreviousMode
;
3731 PMMSUPPORT AddressSpace
;
3732 NTSTATUS Status
= STATUS_SUCCESS
;
3736 * Check the protection
3738 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3740 return STATUS_INVALID_PARAMETER_10
;
3743 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3744 if (tmpProtect
!= PAGE_NOACCESS
&&
3745 tmpProtect
!= PAGE_READONLY
&&
3746 tmpProtect
!= PAGE_READWRITE
&&
3747 tmpProtect
!= PAGE_WRITECOPY
&&
3748 tmpProtect
!= PAGE_EXECUTE
&&
3749 tmpProtect
!= PAGE_EXECUTE_READ
&&
3750 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3751 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3753 return STATUS_INVALID_PAGE_PROTECTION
;
3756 PreviousMode
= ExGetPreviousMode();
3758 if(PreviousMode
!= KernelMode
)
3760 SafeBaseAddress
= NULL
;
3761 SafeSectionOffset
.QuadPart
= 0;
3766 if(BaseAddress
!= NULL
)
3768 ProbeForWritePointer(BaseAddress
);
3769 SafeBaseAddress
= *BaseAddress
;
3771 if(SectionOffset
!= NULL
)
3773 ProbeForWriteLargeInteger(SectionOffset
);
3774 SafeSectionOffset
= *SectionOffset
;
3776 ProbeForWriteSize_t(ViewSize
);
3777 SafeViewSize
= *ViewSize
;
3779 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3781 Status
= _SEH2_GetExceptionCode();
3785 if(!NT_SUCCESS(Status
))
3792 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3793 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3794 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3797 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3799 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3800 PROCESS_VM_OPERATION
,
3803 (PVOID
*)(PVOID
)&Process
,
3805 if (!NT_SUCCESS(Status
))
3810 AddressSpace
= &Process
->Vm
;
3812 Status
= ObReferenceObjectByHandle(SectionHandle
,
3814 MmSectionObjectType
,
3816 (PVOID
*)(PVOID
)&Section
,
3818 if (!(NT_SUCCESS(Status
)))
3820 DPRINT("ObReference failed rc=%x\n",Status
);
3821 ObDereferenceObject(Process
);
3825 Status
= MmMapViewOfSection(Section
,
3827 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3830 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3831 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3836 /* Check if this is an image for the current process */
3837 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3838 (Process
== PsGetCurrentProcess()) &&
3839 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3841 /* Notify the debugger */
3842 DbgkMapViewOfSection(Section
,
3844 SafeSectionOffset
.LowPart
,
3848 ObDereferenceObject(Section
);
3849 ObDereferenceObject(Process
);
3851 if(NT_SUCCESS(Status
))
3853 /* copy parameters back to the caller */
3856 if(BaseAddress
!= NULL
)
3858 *BaseAddress
= SafeBaseAddress
;
3860 if(SectionOffset
!= NULL
)
3862 *SectionOffset
= SafeSectionOffset
;
3864 if(ViewSize
!= NULL
)
3866 *ViewSize
= SafeViewSize
;
3869 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3871 Status
= _SEH2_GetExceptionCode();
3880 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3881 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3884 PFILE_OBJECT FileObject
;
3887 SWAPENTRY SavedSwapEntry
;
3890 PROS_SECTION_OBJECT Section
;
3891 PMM_SECTION_SEGMENT Segment
;
3892 PMMSUPPORT AddressSpace
;
3895 AddressSpace
= (PMMSUPPORT
)Context
;
3896 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3898 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3900 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3901 MemoryArea
->Data
.SectionData
.ViewOffset
;
3903 Section
= MemoryArea
->Data
.SectionData
.Section
;
3904 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3906 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3910 MmUnlockSectionSegment(Segment
);
3911 MmUnlockAddressSpace(AddressSpace
);
3913 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3914 if (Status
!= STATUS_SUCCESS
)
3916 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3917 KeBugCheck(MEMORY_MANAGEMENT
);
3920 MmLockAddressSpace(AddressSpace
);
3921 MmLockSectionSegment(Segment
);
3922 MmspCompleteAndReleasePageOp(PageOp
);
3923 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3926 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3929 * For a dirty, datafile, non-private page mark it as dirty in the
3932 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3934 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3936 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3937 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3938 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3939 ASSERT(SwapEntry
== 0);
3948 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3950 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3951 KeBugCheck(MEMORY_MANAGEMENT
);
3953 MmFreeSwapPage(SwapEntry
);
3957 if (IS_SWAP_FROM_SSE(Entry
) ||
3958 Page
!= PFN_FROM_SSE(Entry
))
3963 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3965 DPRINT1("Found a private page in a pagefile section.\n");
3966 KeBugCheck(MEMORY_MANAGEMENT
);
3969 * Just dereference private pages
3971 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3972 if (SavedSwapEntry
!= 0)
3974 MmFreeSwapPage(SavedSwapEntry
);
3975 MmSetSavedSwapEntryPage(Page
, 0);
3977 MmDeleteRmap(Page
, Process
, Address
);
3978 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3982 MmDeleteRmap(Page
, Process
, Address
);
3983 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3989 MmUnmapViewOfSegment(PMMSUPPORT AddressSpace
,
3993 PMEMORY_AREA MemoryArea
;
3994 PROS_SECTION_OBJECT Section
;
3995 PMM_SECTION_SEGMENT Segment
;
3996 PLIST_ENTRY CurrentEntry
;
3997 PMM_REGION CurrentRegion
;
3998 PLIST_ENTRY RegionListHead
;
4000 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4002 if (MemoryArea
== NULL
)
4004 return(STATUS_UNSUCCESSFUL
);
4007 MemoryArea
->DeleteInProgress
= TRUE
;
4008 Section
= MemoryArea
->Data
.SectionData
.Section
;
4009 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4011 MmLockSectionSegment(Segment
);
4013 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4014 while (!IsListEmpty(RegionListHead
))
4016 CurrentEntry
= RemoveHeadList(RegionListHead
);
4017 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4018 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4021 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4023 Status
= MmFreeMemoryArea(AddressSpace
,
4030 Status
= MmFreeMemoryArea(AddressSpace
,
4035 MmUnlockSectionSegment(Segment
);
4036 ObDereferenceObject(Section
);
4037 return(STATUS_SUCCESS
);
4044 MmUnmapViewOfSection(PEPROCESS Process
,
4048 PMEMORY_AREA MemoryArea
;
4049 PMMSUPPORT AddressSpace
;
4050 PROS_SECTION_OBJECT Section
;
4053 PVOID ImageBaseAddress
= 0;
4055 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4056 Process
, BaseAddress
);
4060 AddressSpace
= &Process
->Vm
;
4062 MmLockAddressSpace(AddressSpace
);
4063 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4065 if (MemoryArea
== NULL
||
4066 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4067 MemoryArea
->DeleteInProgress
)
4069 MmUnlockAddressSpace(AddressSpace
);
4070 return STATUS_NOT_MAPPED_VIEW
;
4073 MemoryArea
->DeleteInProgress
= TRUE
;
4075 while (MemoryArea
->PageOpCount
)
4077 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4081 Offset
-= PAGE_SIZE
;
4082 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4083 MemoryArea
->Data
.SectionData
.Segment
,
4084 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4087 MmUnlockAddressSpace(AddressSpace
);
4088 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4089 if (Status
!= STATUS_SUCCESS
)
4091 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4092 KeBugCheck(MEMORY_MANAGEMENT
);
4094 MmLockAddressSpace(AddressSpace
);
4095 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4097 if (MemoryArea
== NULL
||
4098 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4100 MmUnlockAddressSpace(AddressSpace
);
4101 return STATUS_NOT_MAPPED_VIEW
;
4108 Section
= MemoryArea
->Data
.SectionData
.Section
;
4110 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4114 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4115 PMM_SECTION_SEGMENT SectionSegments
;
4116 PMM_SECTION_SEGMENT Segment
;
4118 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4119 ImageSectionObject
= Section
->ImageSection
;
4120 SectionSegments
= ImageSectionObject
->Segments
;
4121 NrSegments
= ImageSectionObject
->NrSegments
;
4123 /* Search for the current segment within the section segments
4124 * and calculate the image base address */
4125 for (i
= 0; i
< NrSegments
; i
++)
4127 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4129 if (Segment
== &SectionSegments
[i
])
4131 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4136 if (i
>= NrSegments
)
4138 KeBugCheck(MEMORY_MANAGEMENT
);
4141 for (i
= 0; i
< NrSegments
; i
++)
4143 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4145 PVOID SBaseAddress
= (PVOID
)
4146 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4148 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4154 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4157 MmUnlockAddressSpace(AddressSpace
);
4159 /* Notify debugger */
4160 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4162 return(STATUS_SUCCESS
);
4165 /**********************************************************************
4167 * NtUnmapViewOfSection
4182 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4186 KPROCESSOR_MODE PreviousMode
;
4189 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4190 ProcessHandle
, BaseAddress
);
4192 PreviousMode
= ExGetPreviousMode();
4194 DPRINT("Referencing process\n");
4195 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4196 PROCESS_VM_OPERATION
,
4199 (PVOID
*)(PVOID
)&Process
,
4201 if (!NT_SUCCESS(Status
))
4203 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4207 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4209 ObDereferenceObject(Process
);
4216 * Queries the information of a section object.
4218 * @param SectionHandle
4219 * Handle to the section object. It must be opened with SECTION_QUERY
4221 * @param SectionInformationClass
4222 * Index to a certain information structure. Can be either
4223 * SectionBasicInformation or SectionImageInformation. The latter
4224 * is valid only for sections that were created with the SEC_IMAGE
4226 * @param SectionInformation
4227 * Caller supplies storage for resulting information.
4229 * Size of the supplied storage.
4230 * @param ResultLength
4238 NtQuerySection(IN HANDLE SectionHandle
,
4239 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4240 OUT PVOID SectionInformation
,
4241 IN SIZE_T SectionInformationLength
,
4242 OUT PSIZE_T ResultLength OPTIONAL
)
4244 PROS_SECTION_OBJECT Section
;
4245 KPROCESSOR_MODE PreviousMode
;
4246 NTSTATUS Status
= STATUS_SUCCESS
;
4249 PreviousMode
= ExGetPreviousMode();
4251 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4253 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4255 SectionInformationLength
,
4260 if(!NT_SUCCESS(Status
))
4262 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4266 Status
= ObReferenceObjectByHandle(SectionHandle
,
4268 MmSectionObjectType
,
4270 (PVOID
*)(PVOID
)&Section
,
4272 if (NT_SUCCESS(Status
))
4274 switch (SectionInformationClass
)
4276 case SectionBasicInformation
:
4278 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4282 Sbi
->Attributes
= Section
->AllocationAttributes
;
4283 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4285 Sbi
->BaseAddress
= 0;
4286 Sbi
->Size
.QuadPart
= 0;
4290 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4291 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4294 if (ResultLength
!= NULL
)
4296 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4298 Status
= STATUS_SUCCESS
;
4300 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4302 Status
= _SEH2_GetExceptionCode();
4309 case SectionImageInformation
:
4311 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4315 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4316 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4318 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4319 ImageSectionObject
= Section
->ImageSection
;
4321 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4322 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4323 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4324 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4325 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4326 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4327 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4328 Sii
->Machine
= ImageSectionObject
->Machine
;
4329 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4332 if (ResultLength
!= NULL
)
4334 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4336 Status
= STATUS_SUCCESS
;
4338 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4340 Status
= _SEH2_GetExceptionCode();
4348 ObDereferenceObject(Section
);
4356 * Extends size of file backed section.
4358 * @param SectionHandle
4359 * Handle to the section object. It must be opened with
4360 * SECTION_EXTEND_SIZE access.
4361 * @param NewMaximumSize
4362 * New maximum size of the section in bytes.
4366 * @todo Move the actual code to internal function MmExtendSection.
4370 NtExtendSection(IN HANDLE SectionHandle
,
4371 IN PLARGE_INTEGER NewMaximumSize
)
4373 LARGE_INTEGER SafeNewMaximumSize
;
4374 PROS_SECTION_OBJECT Section
;
4375 KPROCESSOR_MODE PreviousMode
;
4376 NTSTATUS Status
= STATUS_SUCCESS
;
4378 PreviousMode
= ExGetPreviousMode();
4380 if(PreviousMode
!= KernelMode
)
4384 /* make a copy on the stack */
4385 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4386 NewMaximumSize
= &SafeNewMaximumSize
;
4388 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4390 Status
= _SEH2_GetExceptionCode();
4394 if(!NT_SUCCESS(Status
))
4400 Status
= ObReferenceObjectByHandle(SectionHandle
,
4401 SECTION_EXTEND_SIZE
,
4402 MmSectionObjectType
,
4406 if (!NT_SUCCESS(Status
))
4411 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4413 ObfDereferenceObject(Section
);
4414 return STATUS_INVALID_PARAMETER
;
4418 * - Acquire file extneding resource.
4419 * - Check if we're not resizing the section below it's actual size!
4420 * - Extend segments if needed.
4421 * - Set file information (FileAllocationInformation) to the new size.
4422 * - Release file extending resource.
4425 ObDereferenceObject(Section
);
4427 return STATUS_NOT_IMPLEMENTED
;
4431 /**********************************************************************
4433 * MmAllocateSection@4
4443 * Code taken from ntoskrnl/mm/special.c.
4448 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4453 PMMSUPPORT AddressSpace
;
4454 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4456 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4458 BoundaryAddressMultiple
.QuadPart
= 0;
4460 AddressSpace
= MmGetKernelAddressSpace();
4461 Result
= BaseAddress
;
4462 MmLockAddressSpace(AddressSpace
);
4463 Status
= MmCreateMemoryArea (AddressSpace
,
4471 BoundaryAddressMultiple
);
4472 MmUnlockAddressSpace(AddressSpace
);
4474 if (!NT_SUCCESS(Status
))
4478 DPRINT("Result %p\n",Result
);
4480 /* Create a virtual mapping for this memory area */
4481 MmMapMemoryArea(Result
, Length
, MC_NPPOOL
, PAGE_READWRITE
);
4483 return ((PVOID
)Result
);
4487 /**********************************************************************
4489 * MmMapViewOfSection
4492 * Maps a view of a section into the virtual address space of a
4497 * Pointer to the section object.
4500 * Pointer to the process.
4503 * Desired base address (or NULL) on entry;
4504 * Actual base address of the view on exit.
4507 * Number of high order address bits that must be zero.
4510 * Size in bytes of the initially committed section of
4514 * Offset in bytes from the beginning of the section
4515 * to the beginning of the view.
4518 * Desired length of map (or zero to map all) on entry
4519 * Actual length mapped on exit.
4521 * InheritDisposition
4522 * Specified how the view is to be shared with
4526 * Type of allocation for the pages.
4529 * Protection for the committed region of the view.
4537 MmMapViewOfSection(IN PVOID SectionObject
,
4538 IN PEPROCESS Process
,
4539 IN OUT PVOID
*BaseAddress
,
4540 IN ULONG_PTR ZeroBits
,
4541 IN SIZE_T CommitSize
,
4542 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4543 IN OUT PSIZE_T ViewSize
,
4544 IN SECTION_INHERIT InheritDisposition
,
4545 IN ULONG AllocationType
,
4548 PROS_SECTION_OBJECT Section
;
4549 PMMSUPPORT AddressSpace
;
4551 NTSTATUS Status
= STATUS_SUCCESS
;
4555 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4557 return STATUS_INVALID_PAGE_PROTECTION
;
4561 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4562 AddressSpace
= &Process
->Vm
;
4564 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4566 MmLockAddressSpace(AddressSpace
);
4568 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4572 ULONG_PTR ImageBase
;
4574 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4575 PMM_SECTION_SEGMENT SectionSegments
;
4577 ImageSectionObject
= Section
->ImageSection
;
4578 SectionSegments
= ImageSectionObject
->Segments
;
4579 NrSegments
= ImageSectionObject
->NrSegments
;
4582 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4585 ImageBase
= ImageSectionObject
->ImageBase
;
4589 for (i
= 0; i
< NrSegments
; i
++)
4591 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4593 ULONG_PTR MaxExtent
;
4594 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4595 SectionSegments
[i
].Length
;
4596 ImageSize
= max(ImageSize
, MaxExtent
);
4600 ImageSectionObject
->ImageSize
= ImageSize
;
4602 /* Check there is enough space to map the section at that point. */
4603 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4604 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4606 /* Fail if the user requested a fixed base address. */
4607 if ((*BaseAddress
) != NULL
)
4609 MmUnlockAddressSpace(AddressSpace
);
4610 return(STATUS_UNSUCCESSFUL
);
4612 /* Otherwise find a gap to map the image. */
4613 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4616 MmUnlockAddressSpace(AddressSpace
);
4617 return(STATUS_UNSUCCESSFUL
);
4621 for (i
= 0; i
< NrSegments
; i
++)
4623 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4625 PVOID SBaseAddress
= (PVOID
)
4626 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4627 MmLockSectionSegment(&SectionSegments
[i
]);
4628 Status
= MmMapViewOfSegment(AddressSpace
,
4630 &SectionSegments
[i
],
4632 SectionSegments
[i
].Length
,
4633 SectionSegments
[i
].Protection
,
4636 MmUnlockSectionSegment(&SectionSegments
[i
]);
4637 if (!NT_SUCCESS(Status
))
4639 MmUnlockAddressSpace(AddressSpace
);
4645 *BaseAddress
= (PVOID
)ImageBase
;
4649 /* check for write access */
4650 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4651 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4653 MmUnlockAddressSpace(AddressSpace
);
4654 return STATUS_SECTION_PROTECTION
;
4656 /* check for read access */
4657 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4658 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4660 MmUnlockAddressSpace(AddressSpace
);
4661 return STATUS_SECTION_PROTECTION
;
4663 /* check for execute access */
4664 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4665 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4667 MmUnlockAddressSpace(AddressSpace
);
4668 return STATUS_SECTION_PROTECTION
;
4671 if (ViewSize
== NULL
)
4673 /* Following this pointer would lead to us to the dark side */
4674 /* What to do? Bugcheck? Return status? Do the mambo? */
4675 KeBugCheck(MEMORY_MANAGEMENT
);
4678 if (SectionOffset
== NULL
)
4684 ViewOffset
= SectionOffset
->u
.LowPart
;
4687 if ((ViewOffset
% PAGE_SIZE
) != 0)
4689 MmUnlockAddressSpace(AddressSpace
);
4690 return(STATUS_MAPPED_ALIGNMENT
);
4693 if ((*ViewSize
) == 0)
4695 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4697 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4699 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4702 *ViewSize
= PAGE_ROUND_UP(*ViewSize
);
4704 MmLockSectionSegment(Section
->Segment
);
4705 Status
= MmMapViewOfSegment(AddressSpace
,
4712 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4713 MmUnlockSectionSegment(Section
->Segment
);
4714 if (!NT_SUCCESS(Status
))
4716 MmUnlockAddressSpace(AddressSpace
);
4721 MmUnlockAddressSpace(AddressSpace
);
4723 return(STATUS_SUCCESS
);
4730 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4731 IN PLARGE_INTEGER NewFileSize
)
4733 /* Check whether an ImageSectionObject exists */
4734 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4736 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4740 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4742 PMM_SECTION_SEGMENT Segment
;
4744 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4747 if (Segment
->ReferenceCount
!= 0)
4749 /* Check size of file */
4750 if (SectionObjectPointer
->SharedCacheMap
)
4752 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4753 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4761 /* Something must gone wrong
4762 * how can we have a Section but no
4764 DPRINT1("ERROR: DataSectionObject without reference!\n");
4768 DPRINT("FIXME: didn't check for outstanding write probes\n");
4778 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4788 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4789 IN MMFLUSH_TYPE FlushType
)
4793 case MmFlushForDelete
:
4794 if (SectionObjectPointer
->ImageSectionObject
||
4795 SectionObjectPointer
->DataSectionObject
)
4799 CcRosSetRemoveOnClose(SectionObjectPointer
);
4801 case MmFlushForWrite
:
4811 MmForceSectionClosed (
4812 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4813 IN BOOLEAN DelayClose
)
4824 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4825 OUT PVOID
* MappedBase
,
4826 IN OUT PSIZE_T ViewSize
)
4828 PROS_SECTION_OBJECT Section
;
4829 PMMSUPPORT AddressSpace
;
4832 DPRINT("MmMapViewInSystemSpace() called\n");
4834 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4835 AddressSpace
= MmGetKernelAddressSpace();
4837 MmLockAddressSpace(AddressSpace
);
4840 if ((*ViewSize
) == 0)
4842 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4844 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4846 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4849 MmLockSectionSegment(Section
->Segment
);
4852 Status
= MmMapViewOfSegment(AddressSpace
,
4861 MmUnlockSectionSegment(Section
->Segment
);
4862 MmUnlockAddressSpace(AddressSpace
);
4872 MmMapViewInSessionSpace (
4874 OUT PVOID
*MappedBase
,
4875 IN OUT PSIZE_T ViewSize
4879 return STATUS_NOT_IMPLEMENTED
;
4887 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4889 PMMSUPPORT AddressSpace
;
4892 DPRINT("MmUnmapViewInSystemSpace() called\n");
4894 AddressSpace
= MmGetKernelAddressSpace();
4896 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4906 MmUnmapViewInSessionSpace (
4911 return STATUS_NOT_IMPLEMENTED
;
4918 MmSetBankedSection (ULONG Unknown0
,
4926 return (STATUS_NOT_IMPLEMENTED
);
4930 /**********************************************************************
4935 * Creates a section object.
4938 * SectionObject (OUT)
4939 * Caller supplied storage for the resulting pointer
4940 * to a SECTION_OBJECT instance;
4943 * Specifies the desired access to the section can be a
4945 * STANDARD_RIGHTS_REQUIRED |
4947 * SECTION_MAP_WRITE |
4948 * SECTION_MAP_READ |
4949 * SECTION_MAP_EXECUTE
4951 * ObjectAttributes [OPTIONAL]
4952 * Initialized attributes for the object can be used
4953 * to create a named section;
4956 * Maximizes the size of the memory section. Must be
4957 * non-NULL for a page-file backed section.
4958 * If value specified for a mapped file and the file is
4959 * not large enough, file will be extended.
4961 * SectionPageProtection
4962 * Can be a combination of:
4968 * AllocationAttributes
4969 * Can be a combination of:
4974 * Handle to a file to create a section mapped to a file
4975 * instead of a memory backed section;
4986 MmCreateSection (OUT PVOID
* Section
,
4987 IN ACCESS_MASK DesiredAccess
,
4988 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4989 IN PLARGE_INTEGER MaximumSize
,
4990 IN ULONG SectionPageProtection
,
4991 IN ULONG AllocationAttributes
,
4992 IN HANDLE FileHandle OPTIONAL
,
4993 IN PFILE_OBJECT File OPTIONAL
)
4996 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4999 * Check the protection
5001 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
5002 if (Protection
!= PAGE_READONLY
&&
5003 Protection
!= PAGE_READWRITE
&&
5004 Protection
!= PAGE_WRITECOPY
&&
5005 Protection
!= PAGE_EXECUTE
&&
5006 Protection
!= PAGE_EXECUTE_READ
&&
5007 Protection
!= PAGE_EXECUTE_READWRITE
&&
5008 Protection
!= PAGE_EXECUTE_WRITECOPY
)
5010 return STATUS_INVALID_PAGE_PROTECTION
;
5013 if (AllocationAttributes
& SEC_IMAGE
)
5015 return(MmCreateImageSection(SectionObject
,
5019 SectionPageProtection
,
5020 AllocationAttributes
,
5024 if (FileHandle
!= NULL
)
5026 return(MmCreateDataFileSection(SectionObject
,
5030 SectionPageProtection
,
5031 AllocationAttributes
,
5035 return(MmCreatePageFileSection(SectionObject
,
5039 SectionPageProtection
,
5040 AllocationAttributes
));
5045 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
5046 IN OUT PULONG_PTR NumberOfPages
,
5047 IN OUT PULONG_PTR UserPfnArray
)
5050 return STATUS_NOT_IMPLEMENTED
;
5055 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
5056 IN ULONG_PTR NumberOfPages
,
5057 IN OUT PULONG_PTR UserPfnArray
)
5060 return STATUS_NOT_IMPLEMENTED
;
5065 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
5066 IN ULONG_PTR NumberOfPages
,
5067 IN OUT PULONG_PTR UserPfnArray
)
5070 return STATUS_NOT_IMPLEMENTED
;
5075 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
5076 IN OUT PULONG_PTR NumberOfPages
,
5077 IN OUT PULONG_PTR UserPfnArray
)
5080 return STATUS_NOT_IMPLEMENTED
;
5085 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
5086 IN PVOID File2MappedAsFile
)
5089 return STATUS_NOT_IMPLEMENTED
;