2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/section.c
21 * PURPOSE: Implements section objects
23 * PROGRAMMERS: Rex Jolliff
36 * Thomas Weidenmueller
37 * Gunnar Andre' Dalsnes
45 /* INCLUDES *****************************************************************/
50 #include <reactos/exeformat.h>
52 #if defined (ALLOC_PRAGMA)
53 #pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
54 #pragma alloc_text(INIT, MmInitSectionImplementation)
58 /* TYPES *********************************************************************/
62 PROS_SECTION_OBJECT Section
;
63 PMM_SECTION_SEGMENT Segment
;
68 MM_SECTION_PAGEOUT_CONTEXT
;
70 /* GLOBALS *******************************************************************/
72 POBJECT_TYPE MmSectionObjectType
= NULL
;
74 static GENERIC_MAPPING MmpSectionMapping
= {
75 STANDARD_RIGHTS_READ
| SECTION_MAP_READ
| SECTION_QUERY
,
76 STANDARD_RIGHTS_WRITE
| SECTION_MAP_WRITE
,
77 STANDARD_RIGHTS_EXECUTE
| SECTION_MAP_EXECUTE
,
80 #define PAGE_FROM_SSE(E) ((E) & 0xFFFFF000)
81 #define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
82 #define SHARE_COUNT_FROM_SSE(E) (((E) & 0x00000FFE) >> 1)
83 #define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
84 #define MAX_SHARE_COUNT 0x7FF
85 #define MAKE_SSE(P, C) ((P) | ((C) << 1))
86 #define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
87 #define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
89 static const INFORMATION_CLASS_INFO ExSectionInfoClass
[] =
91 ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionBasicInformation */
92 ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* SectionImageInformation */
95 /* FUNCTIONS *****************************************************************/
99 MmGetFileObjectForSection(IN PROS_SECTION_OBJECT Section
)
104 /* Return the file object */
105 return Section
->FileObject
; // Section->ControlArea->FileObject on NT
110 MmGetFileNameForSection(IN PROS_SECTION_OBJECT Section
,
111 OUT POBJECT_NAME_INFORMATION
*ModuleName
)
113 POBJECT_NAME_INFORMATION ObjectNameInfo
;
117 /* Make sure it's an image section */
119 if (!(Section
->AllocationAttributes
& SEC_IMAGE
))
122 return STATUS_SECTION_NOT_IMAGE
;
125 /* Allocate memory for our structure */
126 ObjectNameInfo
= ExAllocatePoolWithTag(PagedPool
,
128 TAG('M', 'm', ' ', ' '));
129 if (!ObjectNameInfo
) return STATUS_NO_MEMORY
;
132 Status
= ObQueryNameString(Section
->FileObject
,
136 if (!NT_SUCCESS(Status
))
138 /* Failed, free memory */
139 ExFreePoolWithTag(ObjectNameInfo
, TAG('M', 'm', ' ', ' '));
144 *ModuleName
= ObjectNameInfo
;
145 return STATUS_SUCCESS
;
150 MmGetFileNameForAddress(IN PVOID Address
,
151 OUT PUNICODE_STRING ModuleName
)
153 PROS_SECTION_OBJECT Section
;
154 PMEMORY_AREA MemoryArea
;
155 PMM_AVL_TABLE AddressSpace
;
156 POBJECT_NAME_INFORMATION ModuleNameInformation
;
157 NTSTATUS Status
= STATUS_ADDRESS_NOT_ASSOCIATED
;
159 /* Get the MM_AVL_TABLE from EPROCESS */
160 if (Address
>= MmSystemRangeStart
)
162 AddressSpace
= MmGetKernelAddressSpace();
166 AddressSpace
= &PsGetCurrentProcess()->VadRoot
;
169 /* Lock address space */
170 MmLockAddressSpace(AddressSpace
);
172 /* Locate the memory area for the process by address */
173 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, Address
);
175 /* Make sure it's a section view type */
176 if ((MemoryArea
!= NULL
) && (MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
))
178 /* Get the section pointer to the SECTION_OBJECT */
179 Section
= MemoryArea
->Data
.SectionData
.Section
;
181 /* Unlock address space */
182 MmUnlockAddressSpace(AddressSpace
);
184 /* Get the filename of the section */
185 Status
= MmGetFileNameForSection(Section
,&ModuleNameInformation
);
187 if (NT_SUCCESS(Status
))
189 /* Init modulename */
190 RtlCreateUnicodeString(ModuleName
,
191 ModuleNameInformation
->Name
.Buffer
);
193 /* Free temp taged buffer from MmGetFileNameForSection() */
194 ExFreePoolWithTag(ModuleNameInformation
, TAG('M', 'm', ' ', ' '));
195 DPRINT("Found ModuleName %S by address %p\n",
196 ModuleName
->Buffer
,Address
);
201 /* Unlock address space */
202 MmUnlockAddressSpace(AddressSpace
);
208 /* Note: Mmsp prefix denotes "Memory Manager Section Private". */
211 * FUNCTION: Waits in kernel mode up to ten seconds for an MM_PAGEOP event.
212 * ARGUMENTS: PMM_PAGEOP which event we should wait for.
213 * RETURNS: Status of the wait.
216 MmspWaitForPageOpCompletionEvent(PMM_PAGEOP PageOp
)
218 LARGE_INTEGER Timeout
;
219 #ifdef __GNUC__ /* TODO: Use other macro to check for suffix to use? */
221 Timeout
.QuadPart
= -100000000LL; // 10 sec
224 Timeout
.QuadPart
= -100000000; // 10 sec
227 return KeWaitForSingleObject(&PageOp
->CompletionEvent
, 0, KernelMode
, FALSE
, &Timeout
);
232 * FUNCTION: Sets the page op completion event and releases the page op.
233 * ARGUMENTS: PMM_PAGEOP.
234 * RETURNS: In shorter time than it takes you to even read this
235 * description, so don't even think about geting a mug of coffee.
238 MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp
)
240 KeSetEvent(&PageOp
->CompletionEvent
, IO_NO_INCREMENT
, FALSE
);
241 MmReleasePageOp(PageOp
);
246 * FUNCTION: Waits in kernel mode indefinitely for a file object lock.
247 * ARGUMENTS: PFILE_OBJECT to wait for.
248 * RETURNS: Status of the wait.
251 MmspWaitForFileLock(PFILE_OBJECT File
)
253 return STATUS_SUCCESS
;
254 //return KeWaitForSingleObject(&File->Lock, 0, KernelMode, FALSE, NULL);
259 MmFreePageTablesSectionSegment(PMM_SECTION_SEGMENT Segment
)
262 if (Segment
->Length
> NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
264 for (i
= 0; i
< NR_SECTION_PAGE_TABLES
; i
++)
266 if (Segment
->PageDirectory
.PageTables
[i
] != NULL
)
268 ExFreePool(Segment
->PageDirectory
.PageTables
[i
]);
276 MmFreeSectionSegments(PFILE_OBJECT FileObject
)
278 if (FileObject
->SectionObjectPointer
->ImageSectionObject
!= NULL
)
280 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
281 PMM_SECTION_SEGMENT SectionSegments
;
285 ImageSectionObject
= (PMM_IMAGE_SECTION_OBJECT
)FileObject
->SectionObjectPointer
->ImageSectionObject
;
286 NrSegments
= ImageSectionObject
->NrSegments
;
287 SectionSegments
= ImageSectionObject
->Segments
;
288 for (i
= 0; i
< NrSegments
; i
++)
290 if (SectionSegments
[i
].ReferenceCount
!= 0)
292 DPRINT1("Image segment %d still referenced (was %d)\n", i
,
293 SectionSegments
[i
].ReferenceCount
);
294 KeBugCheck(MEMORY_MANAGEMENT
);
296 MmFreePageTablesSectionSegment(&SectionSegments
[i
]);
298 ExFreePool(ImageSectionObject
->Segments
);
299 ExFreePool(ImageSectionObject
);
300 FileObject
->SectionObjectPointer
->ImageSectionObject
= NULL
;
302 if (FileObject
->SectionObjectPointer
->DataSectionObject
!= NULL
)
304 PMM_SECTION_SEGMENT Segment
;
306 Segment
= (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
309 if (Segment
->ReferenceCount
!= 0)
311 DPRINT1("Data segment still referenced\n");
312 KeBugCheck(MEMORY_MANAGEMENT
);
314 MmFreePageTablesSectionSegment(Segment
);
316 FileObject
->SectionObjectPointer
->DataSectionObject
= NULL
;
322 MmLockSectionSegment(PMM_SECTION_SEGMENT Segment
)
324 ExAcquireFastMutex(&Segment
->Lock
);
329 MmUnlockSectionSegment(PMM_SECTION_SEGMENT Segment
)
331 ExReleaseFastMutex(&Segment
->Lock
);
336 MmSetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
340 PSECTION_PAGE_TABLE Table
;
341 ULONG DirectoryOffset
;
344 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
346 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
350 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
351 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
355 Segment
->PageDirectory
.PageTables
[DirectoryOffset
] =
356 ExAllocatePoolWithTag(NonPagedPool
, sizeof(SECTION_PAGE_TABLE
),
357 TAG_SECTION_PAGE_TABLE
);
360 KeBugCheck(MEMORY_MANAGEMENT
);
362 memset(Table
, 0, sizeof(SECTION_PAGE_TABLE
));
363 DPRINT("Table %x\n", Table
);
366 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
367 Table
->Entry
[TableOffset
] = Entry
;
373 MmGetPageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
376 PSECTION_PAGE_TABLE Table
;
378 ULONG DirectoryOffset
;
381 DPRINT("MmGetPageEntrySection(Segment %x, Offset %x)\n", Segment
, Offset
);
383 if (Segment
->Length
<= NR_SECTION_PAGE_TABLES
* PAGE_SIZE
)
385 Table
= (PSECTION_PAGE_TABLE
)&Segment
->PageDirectory
;
389 DirectoryOffset
= PAGE_TO_SECTION_PAGE_DIRECTORY_OFFSET(Offset
);
390 Table
= Segment
->PageDirectory
.PageTables
[DirectoryOffset
];
391 DPRINT("Table %x\n", Table
);
397 TableOffset
= PAGE_TO_SECTION_PAGE_TABLE_OFFSET(Offset
);
398 Entry
= Table
->Entry
[TableOffset
];
404 MmSharePageEntrySectionSegment(PMM_SECTION_SEGMENT Segment
,
409 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
412 DPRINT1("Entry == 0 for MmSharePageEntrySectionSegment\n");
413 KeBugCheck(MEMORY_MANAGEMENT
);
415 if (SHARE_COUNT_FROM_SSE(Entry
) == MAX_SHARE_COUNT
)
417 DPRINT1("Maximum share count reached\n");
418 KeBugCheck(MEMORY_MANAGEMENT
);
420 if (IS_SWAP_FROM_SSE(Entry
))
422 KeBugCheck(MEMORY_MANAGEMENT
);
424 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) + 1);
425 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
430 MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section
,
431 PMM_SECTION_SEGMENT Segment
,
437 BOOLEAN IsDirectMapped
= FALSE
;
439 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
442 DPRINT1("Entry == 0 for MmUnsharePageEntrySectionSegment\n");
443 KeBugCheck(MEMORY_MANAGEMENT
);
445 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
447 DPRINT1("Zero share count for unshare\n");
448 KeBugCheck(MEMORY_MANAGEMENT
);
450 if (IS_SWAP_FROM_SSE(Entry
))
452 KeBugCheck(MEMORY_MANAGEMENT
);
454 Entry
= MAKE_SSE(PAGE_FROM_SSE(Entry
), SHARE_COUNT_FROM_SSE(Entry
) - 1);
456 * If we reducing the share count of this entry to zero then set the entry
457 * to zero and tell the cache the page is no longer mapped.
459 if (SHARE_COUNT_FROM_SSE(Entry
) == 0)
461 PFILE_OBJECT FileObject
;
463 SWAPENTRY SavedSwapEntry
;
465 BOOLEAN IsImageSection
;
468 FileOffset
= Offset
+ Segment
->FileOffset
;
470 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
472 Page
= PFN_FROM_SSE(Entry
);
473 FileObject
= Section
->FileObject
;
474 if (FileObject
!= NULL
&&
475 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
478 if ((FileOffset
% PAGE_SIZE
) == 0 &&
479 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
482 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
483 IsDirectMapped
= TRUE
;
484 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, Dirty
);
485 if (!NT_SUCCESS(Status
))
487 DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status
);
488 KeBugCheck(MEMORY_MANAGEMENT
);
493 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
494 if (SavedSwapEntry
== 0)
497 ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
498 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)))
502 * Try to page out this page and set the swap entry
503 * within the section segment. There exist no rmap entry
504 * for this page. The pager thread can't page out a
505 * page without a rmap entry.
507 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
511 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
514 MmReleasePageMemoryConsumer(MC_USER
, Page
);
520 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
521 (Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
529 * We hold all locks. Nobody can do something with the current
530 * process and the current segment (also not within an other process).
533 Status
= MmWriteToSwapPage(SavedSwapEntry
, Page
);
534 if (!NT_SUCCESS(Status
))
536 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n", Status
);
537 KeBugCheck(MEMORY_MANAGEMENT
);
540 MmSetPageEntrySectionSegment(Segment
, Offset
, MAKE_SWAP_SSE(SavedSwapEntry
));
541 MmSetSavedSwapEntryPage(Page
, 0);
543 MmReleasePageMemoryConsumer(MC_USER
, Page
);
547 DPRINT1("Found a swapentry for a non private page in an image or data file sgment\n");
548 KeBugCheck(MEMORY_MANAGEMENT
);
554 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
556 return(SHARE_COUNT_FROM_SSE(Entry
) > 0);
559 BOOLEAN
MiIsPageFromCache(PMEMORY_AREA MemoryArea
,
562 if (!(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
565 PCACHE_SEGMENT CacheSeg
;
566 Bcb
= MemoryArea
->Data
.SectionData
.Section
->FileObject
->SectionObjectPointer
->SharedCacheMap
;
567 CacheSeg
= CcRosLookupCacheSegment(Bcb
, SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
);
570 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, CacheSeg
->Valid
, FALSE
, TRUE
);
579 MiReadPage(PMEMORY_AREA MemoryArea
,
583 * FUNCTION: Read a page for a section backed memory area.
585 * MemoryArea - Memory area to read the page for.
586 * Offset - Offset of the page to read.
587 * Page - Variable that receives a page contains the read data.
594 PCACHE_SEGMENT CacheSeg
;
595 PFILE_OBJECT FileObject
;
599 BOOLEAN IsImageSection
;
602 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
603 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
604 RawLength
= MemoryArea
->Data
.SectionData
.Segment
->RawLength
;
605 FileOffset
= SegOffset
+ MemoryArea
->Data
.SectionData
.Segment
->FileOffset
;
606 IsImageSection
= MemoryArea
->Data
.SectionData
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
610 DPRINT("%S %x\n", FileObject
->FileName
.Buffer
, FileOffset
);
613 * If the file system is letting us go directly to the cache and the
614 * memory area was mapped at an offset in the file which is page aligned
615 * then get the related cache segment.
617 if ((FileOffset
% PAGE_SIZE
) == 0 &&
618 (SegOffset
+ PAGE_SIZE
<= RawLength
|| !IsImageSection
) &&
619 !(MemoryArea
->Data
.SectionData
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
623 * Get the related cache segment; we use a lower level interface than
624 * filesystems do because it is safe for us to use an offset with a
625 * alignment less than the file system block size.
627 Status
= CcRosGetCacheSegment(Bcb
,
633 if (!NT_SUCCESS(Status
))
640 * If the cache segment isn't up to date then call the file
641 * system to read in the data.
643 Status
= ReadCacheSegment(CacheSeg
);
644 if (!NT_SUCCESS(Status
))
646 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
651 * Retrieve the page from the cache segment that we actually want.
653 (*Page
) = MmGetPhysicalAddress((char*)BaseAddress
+
654 FileOffset
- BaseOffset
).LowPart
>> PAGE_SHIFT
;
656 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, TRUE
);
661 ULONG CacheSegOffset
;
663 * Allocate a page, this is rather complicated by the possibility
664 * we might have to move other things out of memory
666 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, Page
);
667 if (!NT_SUCCESS(Status
))
671 Status
= CcRosGetCacheSegment(Bcb
,
677 if (!NT_SUCCESS(Status
))
684 * If the cache segment isn't up to date then call the file
685 * system to read in the data.
687 Status
= ReadCacheSegment(CacheSeg
);
688 if (!NT_SUCCESS(Status
))
690 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
695 PageAddr
= MmCreateHyperspaceMapping(*Page
);
696 CacheSegOffset
= BaseOffset
+ CacheSeg
->Bcb
->CacheSegmentSize
- FileOffset
;
697 Length
= RawLength
- SegOffset
;
698 if (Length
<= CacheSegOffset
&& Length
<= PAGE_SIZE
)
700 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, Length
);
702 else if (CacheSegOffset
>= PAGE_SIZE
)
704 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, PAGE_SIZE
);
708 memcpy(PageAddr
, (char*)BaseAddress
+ FileOffset
- BaseOffset
, CacheSegOffset
);
709 MmDeleteHyperspaceMapping(PageAddr
);
710 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
711 Status
= CcRosGetCacheSegment(Bcb
,
712 FileOffset
+ CacheSegOffset
,
717 if (!NT_SUCCESS(Status
))
724 * If the cache segment isn't up to date then call the file
725 * system to read in the data.
727 Status
= ReadCacheSegment(CacheSeg
);
728 if (!NT_SUCCESS(Status
))
730 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, FALSE
, FALSE
, FALSE
);
734 PageAddr
= MmCreateHyperspaceMapping(*Page
);
735 if (Length
< PAGE_SIZE
)
737 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, Length
- CacheSegOffset
);
741 memcpy((char*)PageAddr
+ CacheSegOffset
, BaseAddress
, PAGE_SIZE
- CacheSegOffset
);
744 MmDeleteHyperspaceMapping(PageAddr
);
745 CcRosReleaseCacheSegment(Bcb
, CacheSeg
, TRUE
, FALSE
, FALSE
);
747 return(STATUS_SUCCESS
);
752 MmNotPresentFaultSectionView(PMM_AVL_TABLE AddressSpace
,
753 MEMORY_AREA
* MemoryArea
,
761 PROS_SECTION_OBJECT Section
;
762 PMM_SECTION_SEGMENT Segment
;
768 BOOLEAN HasSwapEntry
;
769 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
772 * There is a window between taking the page fault and locking the
773 * address space when another thread could load the page so we check
776 if (MmIsPagePresent(Process
, Address
))
780 MmLockPage(MmGetPfnForProcess(Process
, Address
));
782 return(STATUS_SUCCESS
);
785 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
786 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
787 + MemoryArea
->Data
.SectionData
.ViewOffset
;
789 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
790 Section
= MemoryArea
->Data
.SectionData
.Section
;
791 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
792 &MemoryArea
->Data
.SectionData
.RegionListHead
,
797 MmLockSectionSegment(Segment
);
800 * Check if this page needs to be mapped COW
802 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
803 (Region
->Protect
== PAGE_READWRITE
||
804 Region
->Protect
== PAGE_EXECUTE_READWRITE
))
806 Attributes
= Region
->Protect
== PAGE_READWRITE
? PAGE_READONLY
: PAGE_EXECUTE_READ
;
810 Attributes
= Region
->Protect
;
814 * Get or create a page operation descriptor
816 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
, MM_PAGEOP_PAGEIN
, FALSE
);
819 DPRINT1("MmGetPageOp failed\n");
820 KeBugCheck(MEMORY_MANAGEMENT
);
824 * Check if someone else is already handling this fault, if so wait
827 if (PageOp
->Thread
!= PsGetCurrentThread())
829 MmUnlockSectionSegment(Segment
);
830 MmUnlockAddressSpace(AddressSpace
);
831 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
833 * Check for various strange conditions
835 if (Status
!= STATUS_SUCCESS
)
837 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
838 KeBugCheck(MEMORY_MANAGEMENT
);
840 if (PageOp
->Status
== STATUS_PENDING
)
842 DPRINT1("Woke for page op before completion\n");
843 KeBugCheck(MEMORY_MANAGEMENT
);
845 MmLockAddressSpace(AddressSpace
);
847 * If this wasn't a pagein then restart the operation
849 if (PageOp
->OpType
!= MM_PAGEOP_PAGEIN
)
851 MmspCompleteAndReleasePageOp(PageOp
);
852 DPRINT("Address 0x%.8X\n", Address
);
853 return(STATUS_MM_RESTART_OPERATION
);
857 * If the thread handling this fault has failed then we don't retry
859 if (!NT_SUCCESS(PageOp
->Status
))
861 Status
= PageOp
->Status
;
862 MmspCompleteAndReleasePageOp(PageOp
);
863 DPRINT("Address 0x%.8X\n", Address
);
866 MmLockSectionSegment(Segment
);
868 * If the completed fault was for another address space then set the
871 if (!MmIsPagePresent(Process
, Address
))
873 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
874 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
876 if (PAGE_FROM_SSE(Entry
) == 0 || HasSwapEntry
)
879 * The page was a private page in another or in our address space
881 MmUnlockSectionSegment(Segment
);
882 MmspCompleteAndReleasePageOp(PageOp
);
883 return(STATUS_MM_RESTART_OPERATION
);
886 Page
= PFN_FROM_SSE(Entry
);
888 MmSharePageEntrySectionSegment(Segment
, Offset
);
890 /* FIXME: Should we call MmCreateVirtualMappingUnsafe if
891 * (Section->AllocationAttributes & SEC_PHYSICALMEMORY) is true?
893 Status
= MmCreateVirtualMapping(Process
,
898 if (!NT_SUCCESS(Status
))
900 DPRINT1("Unable to create virtual mapping\n");
901 KeBugCheck(MEMORY_MANAGEMENT
);
903 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
909 MmUnlockSectionSegment(Segment
);
910 PageOp
->Status
= STATUS_SUCCESS
;
911 MmspCompleteAndReleasePageOp(PageOp
);
912 DPRINT("Address 0x%.8X\n", Address
);
913 return(STATUS_SUCCESS
);
916 HasSwapEntry
= MmIsPageSwapEntry(Process
, (PVOID
)PAddress
);
920 * Must be private page we have swapped out.
927 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
929 DPRINT1("Found a swaped out private page in a pagefile section.\n");
930 KeBugCheck(MEMORY_MANAGEMENT
);
933 MmUnlockSectionSegment(Segment
);
934 MmDeletePageFileMapping(Process
, (PVOID
)PAddress
, &SwapEntry
);
936 MmUnlockAddressSpace(AddressSpace
);
937 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
938 if (!NT_SUCCESS(Status
))
940 KeBugCheck(MEMORY_MANAGEMENT
);
943 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
944 if (!NT_SUCCESS(Status
))
946 DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status
);
947 KeBugCheck(MEMORY_MANAGEMENT
);
949 MmLockAddressSpace(AddressSpace
);
950 Status
= MmCreateVirtualMapping(Process
,
955 if (!NT_SUCCESS(Status
))
957 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
958 KeBugCheck(MEMORY_MANAGEMENT
);
963 * Store the swap entry for later use.
965 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
968 * Add the page to the process's working set
970 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
973 * Finish the operation
979 PageOp
->Status
= STATUS_SUCCESS
;
980 MmspCompleteAndReleasePageOp(PageOp
);
981 DPRINT("Address 0x%.8X\n", Address
);
982 return(STATUS_SUCCESS
);
986 * Satisfying a page fault on a map of /Device/PhysicalMemory is easy
988 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
990 MmUnlockSectionSegment(Segment
);
992 * Just map the desired physical page
994 Page
= Offset
>> PAGE_SHIFT
;
995 Status
= MmCreateVirtualMappingUnsafe(Process
,
1000 if (!NT_SUCCESS(Status
))
1002 DPRINT("MmCreateVirtualMappingUnsafe failed, not out of memory\n");
1003 KeBugCheck(MEMORY_MANAGEMENT
);
1007 * Don't add an rmap entry since the page mapped could be for
1012 MmLockPageUnsafe(Page
);
1016 * Cleanup and release locks
1018 PageOp
->Status
= STATUS_SUCCESS
;
1019 MmspCompleteAndReleasePageOp(PageOp
);
1020 DPRINT("Address 0x%.8X\n", Address
);
1021 return(STATUS_SUCCESS
);
1025 * Map anonymous memory for BSS sections
1027 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
1029 MmUnlockSectionSegment(Segment
);
1030 Status
= MmRequestPageMemoryConsumer(MC_USER
, FALSE
, &Page
);
1031 if (!NT_SUCCESS(Status
))
1033 MmUnlockAddressSpace(AddressSpace
);
1034 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1035 MmLockAddressSpace(AddressSpace
);
1037 if (!NT_SUCCESS(Status
))
1039 KeBugCheck(MEMORY_MANAGEMENT
);
1041 Status
= MmCreateVirtualMapping(Process
,
1046 if (!NT_SUCCESS(Status
))
1048 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1049 KeBugCheck(MEMORY_MANAGEMENT
);
1052 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1059 * Cleanup and release locks
1061 PageOp
->Status
= STATUS_SUCCESS
;
1062 MmspCompleteAndReleasePageOp(PageOp
);
1063 DPRINT("Address 0x%.8X\n", Address
);
1064 return(STATUS_SUCCESS
);
1068 * Get the entry corresponding to the offset within the section
1070 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1075 * If the entry is zero (and it can't change because we have
1076 * locked the segment) then we need to load the page.
1080 * Release all our locks and read in the page from disk
1082 MmUnlockSectionSegment(Segment
);
1083 MmUnlockAddressSpace(AddressSpace
);
1085 if ((Segment
->Flags
& MM_PAGEFILE_SEGMENT
) ||
1086 (Offset
>= PAGE_ROUND_UP(Segment
->RawLength
) && Section
->AllocationAttributes
& SEC_IMAGE
))
1088 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1089 if (!NT_SUCCESS(Status
))
1091 DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status
);
1096 Status
= MiReadPage(MemoryArea
, Offset
, &Page
);
1097 if (!NT_SUCCESS(Status
))
1099 DPRINT1("MiReadPage failed (Status %x)\n", Status
);
1102 if (!NT_SUCCESS(Status
))
1105 * FIXME: What do we know in this case?
1108 * Cleanup and release locks
1110 MmLockAddressSpace(AddressSpace
);
1111 PageOp
->Status
= Status
;
1112 MmspCompleteAndReleasePageOp(PageOp
);
1113 DPRINT("Address 0x%.8X\n", Address
);
1117 * Relock the address space and segment
1119 MmLockAddressSpace(AddressSpace
);
1120 MmLockSectionSegment(Segment
);
1123 * Check the entry. No one should change the status of a page
1124 * that has a pending page-in.
1126 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1127 if (Entry
!= Entry1
)
1129 DPRINT1("Someone changed ppte entry while we slept\n");
1130 KeBugCheck(MEMORY_MANAGEMENT
);
1134 * Mark the offset within the section as having valid, in-memory
1137 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1138 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1139 MmUnlockSectionSegment(Segment
);
1141 Status
= MmCreateVirtualMapping(Process
,
1146 if (!NT_SUCCESS(Status
))
1148 DPRINT1("Unable to create virtual mapping\n");
1149 KeBugCheck(MEMORY_MANAGEMENT
);
1151 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1157 PageOp
->Status
= STATUS_SUCCESS
;
1158 MmspCompleteAndReleasePageOp(PageOp
);
1159 DPRINT("Address 0x%.8X\n", Address
);
1160 return(STATUS_SUCCESS
);
1162 else if (IS_SWAP_FROM_SSE(Entry
))
1164 SWAPENTRY SwapEntry
;
1166 SwapEntry
= SWAPENTRY_FROM_SSE(Entry
);
1169 * Release all our locks and read in the page from disk
1171 MmUnlockSectionSegment(Segment
);
1173 MmUnlockAddressSpace(AddressSpace
);
1175 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &Page
);
1176 if (!NT_SUCCESS(Status
))
1178 KeBugCheck(MEMORY_MANAGEMENT
);
1181 Status
= MmReadFromSwapPage(SwapEntry
, Page
);
1182 if (!NT_SUCCESS(Status
))
1184 KeBugCheck(MEMORY_MANAGEMENT
);
1188 * Relock the address space and segment
1190 MmLockAddressSpace(AddressSpace
);
1191 MmLockSectionSegment(Segment
);
1194 * Check the entry. No one should change the status of a page
1195 * that has a pending page-in.
1197 Entry1
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1198 if (Entry
!= Entry1
)
1200 DPRINT1("Someone changed ppte entry while we slept\n");
1201 KeBugCheck(MEMORY_MANAGEMENT
);
1205 * Mark the offset within the section as having valid, in-memory
1208 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1209 MmSetPageEntrySectionSegment(Segment
, Offset
, Entry
);
1210 MmUnlockSectionSegment(Segment
);
1213 * Save the swap entry.
1215 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1216 Status
= MmCreateVirtualMapping(Process
,
1221 if (!NT_SUCCESS(Status
))
1223 DPRINT1("Unable to create virtual mapping\n");
1224 KeBugCheck(MEMORY_MANAGEMENT
);
1226 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1231 PageOp
->Status
= STATUS_SUCCESS
;
1232 MmspCompleteAndReleasePageOp(PageOp
);
1233 DPRINT("Address 0x%.8X\n", Address
);
1234 return(STATUS_SUCCESS
);
1239 * If the section offset is already in-memory and valid then just
1240 * take another reference to the page
1243 Page
= PFN_FROM_SSE(Entry
);
1245 MmSharePageEntrySectionSegment(Segment
, Offset
);
1246 MmUnlockSectionSegment(Segment
);
1248 Status
= MmCreateVirtualMapping(Process
,
1253 if (!NT_SUCCESS(Status
))
1255 DPRINT1("Unable to create virtual mapping\n");
1256 KeBugCheck(MEMORY_MANAGEMENT
);
1258 MmInsertRmap(Page
, Process
, (PVOID
)PAddress
);
1263 PageOp
->Status
= STATUS_SUCCESS
;
1264 MmspCompleteAndReleasePageOp(PageOp
);
1265 DPRINT("Address 0x%.8X\n", Address
);
1266 return(STATUS_SUCCESS
);
1272 MmAccessFaultSectionView(PMM_AVL_TABLE AddressSpace
,
1273 MEMORY_AREA
* MemoryArea
,
1277 PMM_SECTION_SEGMENT Segment
;
1278 PROS_SECTION_OBJECT Section
;
1287 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1289 DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace
, MemoryArea
, Address
, Locked
);
1292 * Check if the page has been paged out or has already been set readwrite
1294 if (!MmIsPagePresent(Process
, Address
) ||
1295 MmGetPageProtect(Process
, Address
) & PAGE_READWRITE
)
1297 DPRINT("Address 0x%.8X\n", Address
);
1298 return(STATUS_SUCCESS
);
1302 * Find the offset of the page
1304 PAddress
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
1305 Offset
= (ULONG_PTR
)PAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
1306 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1308 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1309 Section
= MemoryArea
->Data
.SectionData
.Section
;
1310 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
1311 &MemoryArea
->Data
.SectionData
.RegionListHead
,
1316 MmLockSectionSegment(Segment
);
1318 OldPage
= MmGetPfnForProcess(NULL
, Address
);
1319 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1321 MmUnlockSectionSegment(Segment
);
1324 * Check if we are doing COW
1326 if (!((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
1327 (Region
->Protect
== PAGE_READWRITE
||
1328 Region
->Protect
== PAGE_EXECUTE_READWRITE
)))
1330 DPRINT("Address 0x%.8X\n", Address
);
1331 return(STATUS_ACCESS_VIOLATION
);
1334 if (IS_SWAP_FROM_SSE(Entry
) ||
1335 PFN_FROM_SSE(Entry
) != OldPage
)
1337 /* This is a private page. We must only change the page protection. */
1338 MmSetPageProtect(Process
, PAddress
, Region
->Protect
);
1339 return(STATUS_SUCCESS
);
1343 * Get or create a pageop
1345 PageOp
= MmGetPageOp(MemoryArea
, NULL
, 0, Segment
, Offset
,
1346 MM_PAGEOP_ACCESSFAULT
, FALSE
);
1349 DPRINT1("MmGetPageOp failed\n");
1350 KeBugCheck(MEMORY_MANAGEMENT
);
1354 * Wait for any other operations to complete
1356 if (PageOp
->Thread
!= PsGetCurrentThread())
1358 MmUnlockAddressSpace(AddressSpace
);
1359 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
1361 * Check for various strange conditions
1363 if (Status
== STATUS_TIMEOUT
)
1365 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
1366 KeBugCheck(MEMORY_MANAGEMENT
);
1368 if (PageOp
->Status
== STATUS_PENDING
)
1370 DPRINT1("Woke for page op before completion\n");
1371 KeBugCheck(MEMORY_MANAGEMENT
);
1374 * Restart the operation
1376 MmLockAddressSpace(AddressSpace
);
1377 MmspCompleteAndReleasePageOp(PageOp
);
1378 DPRINT("Address 0x%.8X\n", Address
);
1379 return(STATUS_MM_RESTART_OPERATION
);
1383 * Release locks now we have the pageop
1385 MmUnlockAddressSpace(AddressSpace
);
1390 Status
= MmRequestPageMemoryConsumer(MC_USER
, TRUE
, &NewPage
);
1391 if (!NT_SUCCESS(Status
))
1393 KeBugCheck(MEMORY_MANAGEMENT
);
1399 MiCopyFromUserPage(NewPage
, PAddress
);
1401 MmLockAddressSpace(AddressSpace
);
1403 * Delete the old entry.
1405 MmDeleteVirtualMapping(Process
, Address
, FALSE
, NULL
, NULL
);
1408 * Set the PTE to point to the new page
1410 Status
= MmCreateVirtualMapping(Process
,
1415 if (!NT_SUCCESS(Status
))
1417 DPRINT("MmCreateVirtualMapping failed, not out of memory\n");
1418 KeBugCheck(MEMORY_MANAGEMENT
);
1421 if (!NT_SUCCESS(Status
))
1423 DPRINT1("Unable to create virtual mapping\n");
1424 KeBugCheck(MEMORY_MANAGEMENT
);
1428 MmLockPage(NewPage
);
1429 MmUnlockPage(OldPage
);
1433 * Unshare the old page.
1435 MmDeleteRmap(OldPage
, Process
, PAddress
);
1436 MmInsertRmap(NewPage
, Process
, PAddress
);
1437 MmLockSectionSegment(Segment
);
1438 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, FALSE
, FALSE
);
1439 MmUnlockSectionSegment(Segment
);
1441 PageOp
->Status
= STATUS_SUCCESS
;
1442 MmspCompleteAndReleasePageOp(PageOp
);
1443 DPRINT("Address 0x%.8X\n", Address
);
1444 return(STATUS_SUCCESS
);
1448 MmPageOutDeleteMapping(PVOID Context
, PEPROCESS Process
, PVOID Address
)
1450 MM_SECTION_PAGEOUT_CONTEXT
* PageOutContext
;
1454 PageOutContext
= (MM_SECTION_PAGEOUT_CONTEXT
*)Context
;
1457 MmLockAddressSpace(&Process
->VadRoot
);
1460 MmDeleteVirtualMapping(Process
,
1467 PageOutContext
->WasDirty
= TRUE
;
1469 if (!PageOutContext
->Private
)
1471 MmLockSectionSegment(PageOutContext
->Segment
);
1472 MmUnsharePageEntrySectionSegment((PROS_SECTION_OBJECT
)PageOutContext
->Section
,
1473 PageOutContext
->Segment
,
1474 PageOutContext
->Offset
,
1475 PageOutContext
->WasDirty
,
1477 MmUnlockSectionSegment(PageOutContext
->Segment
);
1481 MmUnlockAddressSpace(&Process
->VadRoot
);
1484 if (PageOutContext
->Private
)
1486 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1489 DPRINT("PhysicalAddress %x, Address %x\n", Page
<< PAGE_SHIFT
, Address
);
1494 MmPageOutSectionView(PMM_AVL_TABLE AddressSpace
,
1495 MEMORY_AREA
* MemoryArea
,
1500 MM_SECTION_PAGEOUT_CONTEXT Context
;
1501 SWAPENTRY SwapEntry
;
1505 PFILE_OBJECT FileObject
;
1507 BOOLEAN DirectMapped
;
1508 BOOLEAN IsImageSection
;
1509 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1511 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1514 * Get the segment and section.
1516 Context
.Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1517 Context
.Section
= MemoryArea
->Data
.SectionData
.Section
;
1519 Context
.Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1520 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1521 FileOffset
= Context
.Offset
+ Context
.Segment
->FileOffset
;
1523 IsImageSection
= Context
.Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1525 FileObject
= Context
.Section
->FileObject
;
1526 DirectMapped
= FALSE
;
1527 if (FileObject
!= NULL
&&
1528 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1530 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1533 * If the file system is letting us go directly to the cache and the
1534 * memory area was mapped at an offset in the file which is page aligned
1535 * then note this is a direct mapped page.
1537 if ((FileOffset
% PAGE_SIZE
) == 0 &&
1538 (Context
.Offset
+ PAGE_SIZE
<= Context
.Segment
->RawLength
|| !IsImageSection
))
1540 DirectMapped
= TRUE
;
1546 * This should never happen since mappings of physical memory are never
1547 * placed in the rmap lists.
1549 if (Context
.Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1551 DPRINT1("Trying to page out from physical memory section address 0x%X "
1552 "process %d\n", Address
,
1553 Process
? Process
->UniqueProcessId
: 0);
1554 KeBugCheck(MEMORY_MANAGEMENT
);
1558 * Get the section segment entry and the physical address.
1560 Entry
= MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
);
1561 if (!MmIsPagePresent(Process
, Address
))
1563 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1564 Process
? Process
->UniqueProcessId
: 0, Address
);
1565 KeBugCheck(MEMORY_MANAGEMENT
);
1567 Page
= MmGetPfnForProcess(Process
, Address
);
1568 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1571 * Prepare the context structure for the rmap delete call.
1573 Context
.WasDirty
= FALSE
;
1574 if (Context
.Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1575 IS_SWAP_FROM_SSE(Entry
) ||
1576 PFN_FROM_SSE(Entry
) != Page
)
1578 Context
.Private
= TRUE
;
1582 Context
.Private
= FALSE
;
1586 * Take an additional reference to the page or the cache segment.
1588 if (DirectMapped
&& !Context
.Private
)
1590 if(!MiIsPageFromCache(MemoryArea
, Context
.Offset
))
1592 DPRINT1("Direct mapped non private page is not associated with the cache.\n");
1593 KeBugCheck(MEMORY_MANAGEMENT
);
1598 MmReferencePage(Page
);
1601 MmDeleteAllRmaps(Page
, (PVOID
)&Context
, MmPageOutDeleteMapping
);
1604 * If this wasn't a private page then we should have reduced the entry to
1605 * zero by deleting all the rmaps.
1607 if (!Context
.Private
&& MmGetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
) != 0)
1609 if (!(Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
) &&
1610 !(Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1612 KeBugCheck(MEMORY_MANAGEMENT
);
1617 * If the page wasn't dirty then we can just free it as for a readonly page.
1618 * Since we unmapped all the mappings above we know it will not suddenly
1620 * If the page is from a pagefile section and has no swap entry,
1621 * we can't free the page at this point.
1623 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1624 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
1626 if (Context
.Private
)
1628 DPRINT1("Found a %s private page (address %x) in a pagefile segment.\n",
1629 Context
.WasDirty
? "dirty" : "clean", Address
);
1630 KeBugCheck(MEMORY_MANAGEMENT
);
1632 if (!Context
.WasDirty
&& SwapEntry
!= 0)
1634 MmSetSavedSwapEntryPage(Page
, 0);
1635 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1636 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1637 PageOp
->Status
= STATUS_SUCCESS
;
1638 MmspCompleteAndReleasePageOp(PageOp
);
1639 return(STATUS_SUCCESS
);
1642 else if (Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1644 if (Context
.Private
)
1646 DPRINT1("Found a %s private page (address %x) in a shared section segment.\n",
1647 Context
.WasDirty
? "dirty" : "clean", Address
);
1648 KeBugCheck(MEMORY_MANAGEMENT
);
1650 if (!Context
.WasDirty
|| SwapEntry
!= 0)
1652 MmSetSavedSwapEntryPage(Page
, 0);
1655 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1657 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1658 PageOp
->Status
= STATUS_SUCCESS
;
1659 MmspCompleteAndReleasePageOp(PageOp
);
1660 return(STATUS_SUCCESS
);
1663 else if (!Context
.Private
&& DirectMapped
)
1667 DPRINT1("Found a swapentry for a non private and direct mapped page (address %x)\n",
1669 KeBugCheck(MEMORY_MANAGEMENT
);
1671 Status
= CcRosUnmapCacheSegment(Bcb
, FileOffset
, FALSE
);
1672 if (!NT_SUCCESS(Status
))
1674 DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status
);
1675 KeBugCheck(MEMORY_MANAGEMENT
);
1677 PageOp
->Status
= STATUS_SUCCESS
;
1678 MmspCompleteAndReleasePageOp(PageOp
);
1679 return(STATUS_SUCCESS
);
1681 else if (!Context
.WasDirty
&& !DirectMapped
&& !Context
.Private
)
1685 DPRINT1("Found a swap entry for a non dirty, non private and not direct mapped page (address %x)\n",
1687 KeBugCheck(MEMORY_MANAGEMENT
);
1689 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1690 PageOp
->Status
= STATUS_SUCCESS
;
1691 MmspCompleteAndReleasePageOp(PageOp
);
1692 return(STATUS_SUCCESS
);
1694 else if (!Context
.WasDirty
&& Context
.Private
&& SwapEntry
!= 0)
1696 MmSetSavedSwapEntryPage(Page
, 0);
1697 MmLockAddressSpace(AddressSpace
);
1698 Status
= MmCreatePageFileMapping(Process
,
1701 MmUnlockAddressSpace(AddressSpace
);
1702 if (!NT_SUCCESS(Status
))
1704 KeBugCheck(MEMORY_MANAGEMENT
);
1706 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1707 PageOp
->Status
= STATUS_SUCCESS
;
1708 MmspCompleteAndReleasePageOp(PageOp
);
1709 return(STATUS_SUCCESS
);
1713 * If necessary, allocate an entry in the paging file for this page
1717 SwapEntry
= MmAllocSwapPage();
1720 MmShowOutOfSpaceMessagePagingFile();
1721 MmLockAddressSpace(AddressSpace
);
1723 * For private pages restore the old mappings.
1725 if (Context
.Private
)
1727 Status
= MmCreateVirtualMapping(Process
,
1729 MemoryArea
->Protect
,
1732 MmSetDirtyPage(Process
, Address
);
1740 * For non-private pages if the page wasn't direct mapped then
1741 * set it back into the section segment entry so we don't loose
1742 * our copy. Otherwise it will be handled by the cache manager.
1744 Status
= MmCreateVirtualMapping(Process
,
1746 MemoryArea
->Protect
,
1749 MmSetDirtyPage(Process
, Address
);
1753 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1754 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1756 MmUnlockAddressSpace(AddressSpace
);
1757 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1758 MmspCompleteAndReleasePageOp(PageOp
);
1759 return(STATUS_PAGEFILE_QUOTA
);
1764 * Write the page to the pagefile
1766 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1767 if (!NT_SUCCESS(Status
))
1769 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1772 * As above: undo our actions.
1773 * FIXME: Also free the swap page.
1775 MmLockAddressSpace(AddressSpace
);
1776 if (Context
.Private
)
1778 Status
= MmCreateVirtualMapping(Process
,
1780 MemoryArea
->Protect
,
1783 MmSetDirtyPage(Process
, Address
);
1790 Status
= MmCreateVirtualMapping(Process
,
1792 MemoryArea
->Protect
,
1795 MmSetDirtyPage(Process
, Address
);
1799 Entry
= MAKE_SSE(Page
<< PAGE_SHIFT
, 1);
1800 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1802 MmUnlockAddressSpace(AddressSpace
);
1803 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1804 MmspCompleteAndReleasePageOp(PageOp
);
1805 return(STATUS_UNSUCCESSFUL
);
1809 * Otherwise we have succeeded.
1811 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1812 MmSetSavedSwapEntryPage(Page
, 0);
1813 if (Context
.Segment
->Flags
& MM_PAGEFILE_SEGMENT
||
1814 Context
.Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
)
1816 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, MAKE_SWAP_SSE(SwapEntry
));
1820 MmReleasePageMemoryConsumer(MC_USER
, Page
);
1823 if (Context
.Private
)
1825 MmLockAddressSpace(AddressSpace
);
1826 Status
= MmCreatePageFileMapping(Process
,
1829 MmUnlockAddressSpace(AddressSpace
);
1830 if (!NT_SUCCESS(Status
))
1832 KeBugCheck(MEMORY_MANAGEMENT
);
1837 Entry
= MAKE_SWAP_SSE(SwapEntry
);
1838 MmSetPageEntrySectionSegment(Context
.Segment
, Context
.Offset
, Entry
);
1841 PageOp
->Status
= STATUS_SUCCESS
;
1842 MmspCompleteAndReleasePageOp(PageOp
);
1843 return(STATUS_SUCCESS
);
1848 MmWritePageSectionView(PMM_AVL_TABLE AddressSpace
,
1849 PMEMORY_AREA MemoryArea
,
1854 PROS_SECTION_OBJECT Section
;
1855 PMM_SECTION_SEGMENT Segment
;
1857 SWAPENTRY SwapEntry
;
1861 PFILE_OBJECT FileObject
;
1863 BOOLEAN DirectMapped
;
1864 BOOLEAN IsImageSection
;
1865 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
1867 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
1869 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
1870 + MemoryArea
->Data
.SectionData
.ViewOffset
;
1873 * Get the segment and section.
1875 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
1876 Section
= MemoryArea
->Data
.SectionData
.Section
;
1877 IsImageSection
= Section
->AllocationAttributes
& SEC_IMAGE
? TRUE
: FALSE
;
1879 FileObject
= Section
->FileObject
;
1880 DirectMapped
= FALSE
;
1881 if (FileObject
!= NULL
&&
1882 !(Segment
->Characteristics
& IMAGE_SCN_MEM_SHARED
))
1884 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
1887 * If the file system is letting us go directly to the cache and the
1888 * memory area was mapped at an offset in the file which is page aligned
1889 * then note this is a direct mapped page.
1891 if (((Offset
+ Segment
->FileOffset
) % PAGE_SIZE
) == 0 &&
1892 (Offset
+ PAGE_SIZE
<= Segment
->RawLength
|| !IsImageSection
))
1894 DirectMapped
= TRUE
;
1899 * This should never happen since mappings of physical memory are never
1900 * placed in the rmap lists.
1902 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
1904 DPRINT1("Trying to write back page from physical memory mapped at %X "
1905 "process %d\n", Address
,
1906 Process
? Process
->UniqueProcessId
: 0);
1907 KeBugCheck(MEMORY_MANAGEMENT
);
1911 * Get the section segment entry and the physical address.
1913 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
1914 if (!MmIsPagePresent(Process
, Address
))
1916 DPRINT1("Trying to page out not-present page at (%d,0x%.8X).\n",
1917 Process
? Process
->UniqueProcessId
: 0, Address
);
1918 KeBugCheck(MEMORY_MANAGEMENT
);
1920 Page
= MmGetPfnForProcess(Process
, Address
);
1921 SwapEntry
= MmGetSavedSwapEntryPage(Page
);
1924 * Check for a private (COWed) page.
1926 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
1927 IS_SWAP_FROM_SSE(Entry
) ||
1928 PFN_FROM_SSE(Entry
) != Page
)
1938 * Speculatively set all mappings of the page to clean.
1940 MmSetCleanAllRmaps(Page
);
1943 * If this page was direct mapped from the cache then the cache manager
1944 * will take care of writing it back to disk.
1946 if (DirectMapped
&& !Private
)
1948 ASSERT(SwapEntry
== 0);
1949 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
1950 PageOp
->Status
= STATUS_SUCCESS
;
1951 MmspCompleteAndReleasePageOp(PageOp
);
1952 return(STATUS_SUCCESS
);
1956 * If necessary, allocate an entry in the paging file for this page
1960 SwapEntry
= MmAllocSwapPage();
1963 MmSetDirtyAllRmaps(Page
);
1964 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1965 MmspCompleteAndReleasePageOp(PageOp
);
1966 return(STATUS_PAGEFILE_QUOTA
);
1968 MmSetSavedSwapEntryPage(Page
, SwapEntry
);
1972 * Write the page to the pagefile
1974 Status
= MmWriteToSwapPage(SwapEntry
, Page
);
1975 if (!NT_SUCCESS(Status
))
1977 DPRINT1("MM: Failed to write to swap page (Status was 0x%.8X)\n",
1979 MmSetDirtyAllRmaps(Page
);
1980 PageOp
->Status
= STATUS_UNSUCCESSFUL
;
1981 MmspCompleteAndReleasePageOp(PageOp
);
1982 return(STATUS_UNSUCCESSFUL
);
1986 * Otherwise we have succeeded.
1988 DPRINT("MM: Wrote section page 0x%.8X to swap!\n", Page
<< PAGE_SHIFT
);
1989 PageOp
->Status
= STATUS_SUCCESS
;
1990 MmspCompleteAndReleasePageOp(PageOp
);
1991 return(STATUS_SUCCESS
);
1995 MmAlterViewAttributes(PMM_AVL_TABLE AddressSpace
,
2003 PMEMORY_AREA MemoryArea
;
2004 PMM_SECTION_SEGMENT Segment
;
2005 BOOLEAN DoCOW
= FALSE
;
2007 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
2009 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
2010 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2012 if ((Segment
->WriteCopy
|| MemoryArea
->Data
.SectionData
.WriteCopyView
) &&
2013 (NewProtect
== PAGE_READWRITE
|| NewProtect
== PAGE_EXECUTE_READWRITE
))
2018 if (OldProtect
!= NewProtect
)
2020 for (i
= 0; i
< PAGE_ROUND_UP(RegionSize
) / PAGE_SIZE
; i
++)
2022 PVOID Address
= (char*)BaseAddress
+ (i
* PAGE_SIZE
);
2023 ULONG Protect
= NewProtect
;
2026 * If we doing COW for this segment then check if the page is
2029 if (DoCOW
&& MmIsPagePresent(Process
, Address
))
2035 Offset
= (ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
2036 + MemoryArea
->Data
.SectionData
.ViewOffset
;
2037 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2038 Page
= MmGetPfnForProcess(Process
, Address
);
2040 Protect
= PAGE_READONLY
;
2041 if (Segment
->Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
||
2042 IS_SWAP_FROM_SSE(Entry
) ||
2043 PFN_FROM_SSE(Entry
) != Page
)
2045 Protect
= NewProtect
;
2049 if (MmIsPagePresent(Process
, Address
))
2051 MmSetPageProtect(Process
, Address
,
2060 MmProtectSectionView(PMM_AVL_TABLE AddressSpace
,
2061 PMEMORY_AREA MemoryArea
,
2069 ULONG_PTR MaxLength
;
2071 MaxLength
= (ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)BaseAddress
;
2072 if (Length
> MaxLength
)
2075 Region
= MmFindRegion(MemoryArea
->StartingAddress
,
2076 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2078 if ((MemoryArea
->Flags
& SEC_NO_CHANGE
) &&
2079 Region
->Protect
!= Protect
)
2081 return STATUS_INVALID_PAGE_PROTECTION
;
2084 *OldProtect
= Region
->Protect
;
2085 Status
= MmAlterRegion(AddressSpace
, MemoryArea
->StartingAddress
,
2086 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2087 BaseAddress
, Length
, Region
->Type
, Protect
,
2088 MmAlterViewAttributes
);
2094 MmQuerySectionView(PMEMORY_AREA MemoryArea
,
2096 PMEMORY_BASIC_INFORMATION Info
,
2097 PULONG ResultLength
)
2100 PVOID RegionBaseAddress
;
2101 PROS_SECTION_OBJECT Section
;
2102 PMM_SECTION_SEGMENT Segment
;
2104 Region
= MmFindRegion((PVOID
)MemoryArea
->StartingAddress
,
2105 &MemoryArea
->Data
.SectionData
.RegionListHead
,
2106 Address
, &RegionBaseAddress
);
2109 return STATUS_UNSUCCESSFUL
;
2112 Section
= MemoryArea
->Data
.SectionData
.Section
;
2113 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2115 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
2116 Info
->AllocationBase
= (PUCHAR
)MemoryArea
->StartingAddress
- Segment
->VirtualAddress
;
2117 Info
->Type
= MEM_IMAGE
;
2121 Info
->AllocationBase
= MemoryArea
->StartingAddress
;
2122 Info
->Type
= MEM_MAPPED
;
2124 Info
->BaseAddress
= RegionBaseAddress
;
2125 Info
->AllocationProtect
= MemoryArea
->Protect
;
2126 Info
->RegionSize
= Region
->Length
;
2127 Info
->State
= MEM_COMMIT
;
2128 Info
->Protect
= Region
->Protect
;
2130 *ResultLength
= sizeof(MEMORY_BASIC_INFORMATION
);
2131 return(STATUS_SUCCESS
);
2136 MmpFreePageFileSegment(PMM_SECTION_SEGMENT Segment
)
2141 ULONG SavedSwapEntry
;
2146 Length
= PAGE_ROUND_UP(Segment
->Length
);
2147 for (Offset
= 0; Offset
< Length
; Offset
+= PAGE_SIZE
)
2149 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
2152 if (IS_SWAP_FROM_SSE(Entry
))
2154 MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry
));
2158 Page
= PFN_FROM_SSE(Entry
);
2159 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
2160 if (SavedSwapEntry
!= 0)
2162 MmSetSavedSwapEntryPage(Page
, 0);
2163 MmFreeSwapPage(SavedSwapEntry
);
2165 MmReleasePageMemoryConsumer(MC_USER
, Page
);
2167 MmSetPageEntrySectionSegment(Segment
, Offset
, 0);
2173 MmpDeleteSection(PVOID ObjectBody
)
2175 PROS_SECTION_OBJECT Section
= (PROS_SECTION_OBJECT
)ObjectBody
;
2177 DPRINT("MmpDeleteSection(ObjectBody %x)\n", ObjectBody
);
2178 if (Section
->AllocationAttributes
& SEC_IMAGE
)
2183 PMM_SECTION_SEGMENT SectionSegments
;
2186 * NOTE: Section->ImageSection can be NULL for short time
2187 * during the section creating. If we fail for some reason
2188 * until the image section is properly initialized we shouldn't
2189 * process further here.
2191 if (Section
->ImageSection
== NULL
)
2194 SectionSegments
= Section
->ImageSection
->Segments
;
2195 NrSegments
= Section
->ImageSection
->NrSegments
;
2197 for (i
= 0; i
< NrSegments
; i
++)
2199 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2201 MmLockSectionSegment(&SectionSegments
[i
]);
2203 RefCount
= InterlockedDecrementUL(&SectionSegments
[i
].ReferenceCount
);
2204 if (SectionSegments
[i
].Characteristics
& IMAGE_SCN_MEM_SHARED
)
2208 MmpFreePageFileSegment(&SectionSegments
[i
]);
2210 MmUnlockSectionSegment(&SectionSegments
[i
]);
2217 * NOTE: Section->Segment can be NULL for short time
2218 * during the section creating.
2220 if (Section
->Segment
== NULL
)
2223 if (Section
->Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
2225 MmpFreePageFileSegment(Section
->Segment
);
2226 MmFreePageTablesSectionSegment(Section
->Segment
);
2227 ExFreePool(Section
->Segment
);
2228 Section
->Segment
= NULL
;
2232 (void)InterlockedDecrementUL(&Section
->Segment
->ReferenceCount
);
2235 if (Section
->FileObject
!= NULL
)
2237 CcRosDereferenceCache(Section
->FileObject
);
2238 ObDereferenceObject(Section
->FileObject
);
2239 Section
->FileObject
= NULL
;
2244 MmpCloseSection(IN PEPROCESS Process OPTIONAL
,
2246 IN ACCESS_MASK GrantedAccess
,
2247 IN ULONG ProcessHandleCount
,
2248 IN ULONG SystemHandleCount
)
2250 DPRINT("MmpCloseSection(OB %x, HC %d)\n",
2251 Object
, ProcessHandleCount
);
2257 MmCreatePhysicalMemorySection(VOID
)
2259 PROS_SECTION_OBJECT PhysSection
;
2261 OBJECT_ATTRIBUTES Obj
;
2262 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\Device\\PhysicalMemory");
2263 LARGE_INTEGER SectionSize
;
2267 * Create the section mapping physical memory
2269 SectionSize
.QuadPart
= 0xFFFFFFFF;
2270 InitializeObjectAttributes(&Obj
,
2275 Status
= MmCreateSection((PVOID
)&PhysSection
,
2279 PAGE_EXECUTE_READWRITE
,
2283 if (!NT_SUCCESS(Status
))
2285 DPRINT1("Failed to create PhysicalMemory section\n");
2286 KeBugCheck(MEMORY_MANAGEMENT
);
2288 Status
= ObInsertObject(PhysSection
,
2294 if (!NT_SUCCESS(Status
))
2296 ObDereferenceObject(PhysSection
);
2298 ObCloseHandle(Handle
, KernelMode
);
2299 PhysSection
->AllocationAttributes
|= SEC_PHYSICALMEMORY
;
2300 PhysSection
->Segment
->Flags
&= ~MM_PAGEFILE_SEGMENT
;
2302 return(STATUS_SUCCESS
);
2308 MmInitSectionImplementation(VOID
)
2310 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
2311 UNICODE_STRING Name
;
2313 DPRINT("Creating Section Object Type\n");
2315 /* Initialize the Section object type */
2316 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
2317 RtlInitUnicodeString(&Name
, L
"Section");
2318 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
2319 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(ROS_SECTION_OBJECT
);
2320 ObjectTypeInitializer
.PoolType
= PagedPool
;
2321 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
2322 ObjectTypeInitializer
.GenericMapping
= MmpSectionMapping
;
2323 ObjectTypeInitializer
.DeleteProcedure
= MmpDeleteSection
;
2324 ObjectTypeInitializer
.CloseProcedure
= MmpCloseSection
;
2325 ObjectTypeInitializer
.ValidAccessMask
= SECTION_ALL_ACCESS
;
2326 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &MmSectionObjectType
);
2328 return(STATUS_SUCCESS
);
2333 MmCreatePageFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2334 ACCESS_MASK DesiredAccess
,
2335 POBJECT_ATTRIBUTES ObjectAttributes
,
2336 PLARGE_INTEGER UMaximumSize
,
2337 ULONG SectionPageProtection
,
2338 ULONG AllocationAttributes
)
2340 * Create a section which is backed by the pagefile
2343 LARGE_INTEGER MaximumSize
;
2344 PROS_SECTION_OBJECT Section
;
2345 PMM_SECTION_SEGMENT Segment
;
2348 if (UMaximumSize
== NULL
)
2350 return(STATUS_UNSUCCESSFUL
);
2352 MaximumSize
= *UMaximumSize
;
2355 * Create the section
2357 Status
= ObCreateObject(ExGetPreviousMode(),
2358 MmSectionObjectType
,
2360 ExGetPreviousMode(),
2362 sizeof(ROS_SECTION_OBJECT
),
2365 (PVOID
*)(PVOID
)&Section
);
2366 if (!NT_SUCCESS(Status
))
2374 Section
->SectionPageProtection
= SectionPageProtection
;
2375 Section
->AllocationAttributes
= AllocationAttributes
;
2376 Section
->Segment
= NULL
;
2377 Section
->FileObject
= NULL
;
2378 Section
->MaximumSize
= MaximumSize
;
2379 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2380 TAG_MM_SECTION_SEGMENT
);
2381 if (Segment
== NULL
)
2383 ObDereferenceObject(Section
);
2384 return(STATUS_NO_MEMORY
);
2386 Section
->Segment
= Segment
;
2387 Segment
->ReferenceCount
= 1;
2388 ExInitializeFastMutex(&Segment
->Lock
);
2389 Segment
->FileOffset
= 0;
2390 Segment
->Protection
= SectionPageProtection
;
2391 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2392 Segment
->Length
= PAGE_ROUND_UP(MaximumSize
.u
.LowPart
);
2393 Segment
->Flags
= MM_PAGEFILE_SEGMENT
;
2394 Segment
->WriteCopy
= FALSE
;
2395 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2396 Segment
->VirtualAddress
= 0;
2397 Segment
->Characteristics
= 0;
2398 *SectionObject
= Section
;
2399 return(STATUS_SUCCESS
);
2405 MmCreateDataFileSection(PROS_SECTION_OBJECT
*SectionObject
,
2406 ACCESS_MASK DesiredAccess
,
2407 POBJECT_ATTRIBUTES ObjectAttributes
,
2408 PLARGE_INTEGER UMaximumSize
,
2409 ULONG SectionPageProtection
,
2410 ULONG AllocationAttributes
,
2413 * Create a section backed by a data file
2416 PROS_SECTION_OBJECT Section
;
2418 LARGE_INTEGER MaximumSize
;
2419 PFILE_OBJECT FileObject
;
2420 PMM_SECTION_SEGMENT Segment
;
2422 IO_STATUS_BLOCK Iosb
;
2423 LARGE_INTEGER Offset
;
2425 FILE_STANDARD_INFORMATION FileInfo
;
2428 * Create the section
2430 Status
= ObCreateObject(ExGetPreviousMode(),
2431 MmSectionObjectType
,
2433 ExGetPreviousMode(),
2435 sizeof(ROS_SECTION_OBJECT
),
2438 (PVOID
*)(PVOID
)&Section
);
2439 if (!NT_SUCCESS(Status
))
2446 Section
->SectionPageProtection
= SectionPageProtection
;
2447 Section
->AllocationAttributes
= AllocationAttributes
;
2448 Section
->Segment
= NULL
;
2451 * Check file access required
2453 if (SectionPageProtection
& PAGE_READWRITE
||
2454 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
2456 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
2460 FileAccess
= FILE_READ_DATA
;
2464 * Reference the file handle
2466 Status
= ObReferenceObjectByHandle(FileHandle
,
2469 ExGetPreviousMode(),
2470 (PVOID
*)(PVOID
)&FileObject
,
2472 if (!NT_SUCCESS(Status
))
2474 ObDereferenceObject(Section
);
2479 * FIXME: This is propably not entirely correct. We can't look into
2480 * the standard FCB header because it might not be initialized yet
2481 * (as in case of the EXT2FS driver by Manoj Paul Joseph where the
2482 * standard file information is filled on first request).
2484 Status
= IoQueryFileInformation(FileObject
,
2485 FileStandardInformation
,
2486 sizeof(FILE_STANDARD_INFORMATION
),
2489 if (!NT_SUCCESS(Status
))
2491 ObDereferenceObject(Section
);
2492 ObDereferenceObject(FileObject
);
2497 * FIXME: Revise this once a locking order for file size changes is
2500 if ((UMaximumSize
!= NULL
) && (UMaximumSize
->QuadPart
!= 0))
2502 MaximumSize
= *UMaximumSize
;
2506 MaximumSize
= FileInfo
.EndOfFile
;
2507 /* Mapping zero-sized files isn't allowed. */
2508 if (MaximumSize
.QuadPart
== 0)
2510 ObDereferenceObject(Section
);
2511 ObDereferenceObject(FileObject
);
2512 return STATUS_FILE_INVALID
;
2516 if (MaximumSize
.QuadPart
> FileInfo
.EndOfFile
.QuadPart
)
2518 Status
= IoSetInformation(FileObject
,
2519 FileAllocationInformation
,
2520 sizeof(LARGE_INTEGER
),
2522 if (!NT_SUCCESS(Status
))
2524 ObDereferenceObject(Section
);
2525 ObDereferenceObject(FileObject
);
2526 return(STATUS_SECTION_NOT_EXTENDED
);
2530 if (FileObject
->SectionObjectPointer
== NULL
||
2531 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2534 * Read a bit so caching is initiated for the file object.
2535 * This is only needed because MiReadPage currently cannot
2536 * handle non-cached streams.
2538 Offset
.QuadPart
= 0;
2539 Status
= ZwReadFile(FileHandle
,
2548 if (!NT_SUCCESS(Status
) && (Status
!= STATUS_END_OF_FILE
))
2550 ObDereferenceObject(Section
);
2551 ObDereferenceObject(FileObject
);
2554 if (FileObject
->SectionObjectPointer
== NULL
||
2555 FileObject
->SectionObjectPointer
->SharedCacheMap
== NULL
)
2557 /* FIXME: handle this situation */
2558 ObDereferenceObject(Section
);
2559 ObDereferenceObject(FileObject
);
2560 return STATUS_INVALID_PARAMETER
;
2567 Status
= MmspWaitForFileLock(FileObject
);
2568 if (Status
!= STATUS_SUCCESS
)
2570 ObDereferenceObject(Section
);
2571 ObDereferenceObject(FileObject
);
2576 * If this file hasn't been mapped as a data file before then allocate a
2577 * section segment to describe the data file mapping
2579 if (FileObject
->SectionObjectPointer
->DataSectionObject
== NULL
)
2581 Segment
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MM_SECTION_SEGMENT
),
2582 TAG_MM_SECTION_SEGMENT
);
2583 if (Segment
== NULL
)
2585 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2586 ObDereferenceObject(Section
);
2587 ObDereferenceObject(FileObject
);
2588 return(STATUS_NO_MEMORY
);
2590 Section
->Segment
= Segment
;
2591 Segment
->ReferenceCount
= 1;
2592 ExInitializeFastMutex(&Segment
->Lock
);
2594 * Set the lock before assigning the segment to the file object
2596 ExAcquireFastMutex(&Segment
->Lock
);
2597 FileObject
->SectionObjectPointer
->DataSectionObject
= (PVOID
)Segment
;
2599 Segment
->FileOffset
= 0;
2600 Segment
->Protection
= SectionPageProtection
;
2601 Segment
->Flags
= MM_DATAFILE_SEGMENT
;
2602 Segment
->Characteristics
= 0;
2603 Segment
->WriteCopy
= FALSE
;
2604 if (AllocationAttributes
& SEC_RESERVE
)
2606 Segment
->Length
= Segment
->RawLength
= 0;
2610 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2611 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2613 Segment
->VirtualAddress
= 0;
2614 RtlZeroMemory(&Segment
->PageDirectory
, sizeof(SECTION_PAGE_DIRECTORY
));
2619 * If the file is already mapped as a data file then we may need
2623 (PMM_SECTION_SEGMENT
)FileObject
->SectionObjectPointer
->
2625 Section
->Segment
= Segment
;
2626 (void)InterlockedIncrementUL(&Segment
->ReferenceCount
);
2627 MmLockSectionSegment(Segment
);
2629 if (MaximumSize
.u
.LowPart
> Segment
->RawLength
&&
2630 !(AllocationAttributes
& SEC_RESERVE
))
2632 Segment
->RawLength
= MaximumSize
.u
.LowPart
;
2633 Segment
->Length
= PAGE_ROUND_UP(Segment
->RawLength
);
2636 MmUnlockSectionSegment(Segment
);
2637 Section
->FileObject
= FileObject
;
2638 Section
->MaximumSize
= MaximumSize
;
2639 CcRosReferenceCache(FileObject
);
2640 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2641 *SectionObject
= Section
;
2642 return(STATUS_SUCCESS
);
2646 TODO: not that great (declaring loaders statically, having to declare all of
2647 them, having to keep them extern, etc.), will fix in the future
2649 extern NTSTATUS NTAPI PeFmtCreateSection
2651 IN CONST VOID
* FileHeader
,
2652 IN SIZE_T FileHeaderSize
,
2654 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2656 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2657 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2660 extern NTSTATUS NTAPI ElfFmtCreateSection
2662 IN CONST VOID
* FileHeader
,
2663 IN SIZE_T FileHeaderSize
,
2665 OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2667 IN PEXEFMT_CB_READ_FILE ReadFileCb
,
2668 IN PEXEFMT_CB_ALLOCATE_SEGMENTS AllocateSegmentsCb
2671 /* TODO: this is a standard DDK/PSDK macro */
2672 #ifndef RTL_NUMBER_OF
2673 #define RTL_NUMBER_OF(ARR_) (sizeof(ARR_) / sizeof((ARR_)[0]))
2676 static PEXEFMT_LOADER ExeFmtpLoaders
[] =
2687 ExeFmtpAllocateSegments(IN ULONG NrSegments
)
2689 SIZE_T SizeOfSegments
;
2690 PMM_SECTION_SEGMENT Segments
;
2692 /* TODO: check for integer overflow */
2693 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * NrSegments
;
2695 Segments
= ExAllocatePoolWithTag(NonPagedPool
,
2697 TAG_MM_SECTION_SEGMENT
);
2700 RtlZeroMemory(Segments
, SizeOfSegments
);
2708 ExeFmtpReadFile(IN PVOID File
,
2709 IN PLARGE_INTEGER Offset
,
2712 OUT PVOID
* AllocBase
,
2713 OUT PULONG ReadSize
)
2716 LARGE_INTEGER FileOffset
;
2718 ULONG OffsetAdjustment
;
2723 ASSERT_IRQL_LESS(DISPATCH_LEVEL
);
2727 KeBugCheck(MEMORY_MANAGEMENT
);
2730 FileOffset
= *Offset
;
2732 /* Negative/special offset: it cannot be used in this context */
2733 if(FileOffset
.u
.HighPart
< 0)
2735 KeBugCheck(MEMORY_MANAGEMENT
);
2738 AdjustOffset
= PAGE_ROUND_DOWN(FileOffset
.u
.LowPart
);
2739 OffsetAdjustment
= FileOffset
.u
.LowPart
- AdjustOffset
;
2740 FileOffset
.u
.LowPart
= AdjustOffset
;
2742 BufferSize
= Length
+ OffsetAdjustment
;
2743 BufferSize
= PAGE_ROUND_UP(BufferSize
);
2746 * It's ok to use paged pool, because this is a temporary buffer only used in
2747 * the loading of executables. The assumption is that MmCreateSection is
2748 * always called at low IRQLs and that these buffers don't survive a brief
2749 * initialization phase
2751 Buffer
= ExAllocatePoolWithTag(PagedPool
,
2753 TAG('M', 'm', 'X', 'r'));
2758 Status
= MmspPageRead(File
,
2765 * FIXME: if we don't use ZwReadFile, caching is not enabled for the file and
2766 * nothing will work. But using ZwReadFile is wrong, and using its side effects
2767 * to initialize internal state is even worse. Our cache manager is in need of
2771 IO_STATUS_BLOCK Iosb
;
2773 Status
= ZwReadFile(File
,
2783 if(NT_SUCCESS(Status
))
2785 UsedSize
= Iosb
.Information
;
2790 if(NT_SUCCESS(Status
) && UsedSize
< OffsetAdjustment
)
2792 Status
= STATUS_IN_PAGE_ERROR
;
2793 ASSERT(!NT_SUCCESS(Status
));
2796 if(NT_SUCCESS(Status
))
2798 *Data
= (PVOID
)((ULONG_PTR
)Buffer
+ OffsetAdjustment
);
2799 *AllocBase
= Buffer
;
2800 *ReadSize
= UsedSize
- OffsetAdjustment
;
2804 ExFreePoolWithTag(Buffer
, TAG('M', 'm', 'X', 'r'));
2811 # define MmspAssertSegmentsSorted(OBJ_) ((void)0)
2812 # define MmspAssertSegmentsNoOverlap(OBJ_) ((void)0)
2813 # define MmspAssertSegmentsPageAligned(OBJ_) ((void)0)
2818 MmspAssertSegmentsSorted(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2822 for( i
= 1; i
< ImageSectionObject
->NrSegments
; ++ i
)
2824 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2825 ImageSectionObject
->Segments
[i
- 1].VirtualAddress
);
2832 MmspAssertSegmentsNoOverlap(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2836 MmspAssertSegmentsSorted(ImageSectionObject
);
2838 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2840 ASSERT(ImageSectionObject
->Segments
[i
].Length
> 0);
2844 ASSERT(ImageSectionObject
->Segments
[i
].VirtualAddress
>=
2845 (ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2846 ImageSectionObject
->Segments
[i
- 1].Length
));
2854 MmspAssertSegmentsPageAligned(IN PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
2858 for( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2860 ASSERT((ImageSectionObject
->Segments
[i
].VirtualAddress
% PAGE_SIZE
) == 0);
2861 ASSERT((ImageSectionObject
->Segments
[i
].Length
% PAGE_SIZE
) == 0);
2869 MmspCompareSegments(const void * x
,
2872 const MM_SECTION_SEGMENT
*Segment1
= (const MM_SECTION_SEGMENT
*)x
;
2873 const MM_SECTION_SEGMENT
*Segment2
= (const MM_SECTION_SEGMENT
*)y
;
2876 (Segment1
->VirtualAddress
- Segment2
->VirtualAddress
) >>
2877 ((sizeof(ULONG_PTR
) - sizeof(int)) * 8);
2881 * Ensures an image section's segments are sorted in memory
2886 MmspSortSegments(IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2889 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_SORTED
)
2891 MmspAssertSegmentsSorted(ImageSectionObject
);
2895 qsort(ImageSectionObject
->Segments
,
2896 ImageSectionObject
->NrSegments
,
2897 sizeof(ImageSectionObject
->Segments
[0]),
2898 MmspCompareSegments
);
2904 * Ensures an image section's segments don't overlap in memory and don't have
2905 * gaps and don't have a null size. We let them map to overlapping file regions,
2906 * though - that's not necessarily an error
2911 MmspCheckSegmentBounds
2913 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2919 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_NO_OVERLAP
)
2921 MmspAssertSegmentsNoOverlap(ImageSectionObject
);
2925 ASSERT(ImageSectionObject
->NrSegments
>= 1);
2927 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2929 if(ImageSectionObject
->Segments
[i
].Length
== 0)
2937 * TODO: relax the limitation on gaps. For example, gaps smaller than a
2938 * page could be OK (Windows seems to be OK with them), and larger gaps
2939 * could lead to image sections spanning several discontiguous regions
2940 * (NtMapViewOfSection could then refuse to map them, and they could
2941 * e.g. only be allowed as parameters to NtCreateProcess, like on UNIX)
2943 if ((ImageSectionObject
->Segments
[i
- 1].VirtualAddress
+
2944 ImageSectionObject
->Segments
[i
- 1].Length
) !=
2945 ImageSectionObject
->Segments
[i
].VirtualAddress
)
2956 * Merges and pads an image section's segments until they all are page-aligned
2957 * and have a size that is a multiple of the page size
2962 MmspPageAlignSegments
2964 IN OUT PMM_IMAGE_SECTION_OBJECT ImageSectionObject
,
2970 BOOLEAN Initialized
;
2971 PMM_SECTION_SEGMENT EffectiveSegment
;
2973 if (Flags
& EXEFMT_LOAD_ASSUME_SEGMENTS_PAGE_ALIGNED
)
2975 MmspAssertSegmentsPageAligned(ImageSectionObject
);
2979 Initialized
= FALSE
;
2981 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
2983 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
2986 * The first segment requires special handling
2990 ULONG_PTR VirtualAddress
;
2991 ULONG_PTR VirtualOffset
;
2993 VirtualAddress
= EffectiveSegment
->VirtualAddress
;
2995 /* Round down the virtual address to the nearest page */
2996 EffectiveSegment
->VirtualAddress
= PAGE_ROUND_DOWN(VirtualAddress
);
2998 /* Round up the virtual size to the nearest page */
2999 EffectiveSegment
->Length
= PAGE_ROUND_UP(VirtualAddress
+ EffectiveSegment
->Length
) -
3000 EffectiveSegment
->VirtualAddress
;
3002 /* Adjust the raw address and size */
3003 VirtualOffset
= VirtualAddress
- EffectiveSegment
->VirtualAddress
;
3005 if (EffectiveSegment
->FileOffset
< VirtualOffset
)
3011 * Garbage in, garbage out: unaligned base addresses make the file
3012 * offset point in curious and odd places, but that's what we were
3015 EffectiveSegment
->FileOffset
-= VirtualOffset
;
3016 EffectiveSegment
->RawLength
+= VirtualOffset
;
3020 PMM_SECTION_SEGMENT Segment
= &ImageSectionObject
->Segments
[i
];
3021 ULONG_PTR EndOfEffectiveSegment
;
3023 EndOfEffectiveSegment
= EffectiveSegment
->VirtualAddress
+ EffectiveSegment
->Length
;
3024 ASSERT((EndOfEffectiveSegment
% PAGE_SIZE
) == 0);
3027 * The current segment begins exactly where the current effective
3028 * segment ended, therefore beginning a new effective segment
3030 if (EndOfEffectiveSegment
== Segment
->VirtualAddress
)
3033 ASSERT(LastSegment
<= i
);
3034 ASSERT(LastSegment
< ImageSectionObject
->NrSegments
);
3036 EffectiveSegment
= &ImageSectionObject
->Segments
[LastSegment
];
3038 if (LastSegment
!= i
)
3041 * Copy the current segment. If necessary, the effective segment
3042 * will be expanded later
3044 *EffectiveSegment
= *Segment
;
3048 * Page-align the virtual size. We know for sure the virtual address
3051 ASSERT((EffectiveSegment
->VirtualAddress
% PAGE_SIZE
) == 0);
3052 EffectiveSegment
->Length
= PAGE_ROUND_UP(EffectiveSegment
->Length
);
3055 * The current segment is still part of the current effective segment:
3056 * extend the effective segment to reflect this
3058 else if (EndOfEffectiveSegment
> Segment
->VirtualAddress
)
3060 static const ULONG FlagsToProtection
[16] =
3068 PAGE_EXECUTE_READWRITE
,
3069 PAGE_EXECUTE_READWRITE
,
3074 PAGE_EXECUTE_WRITECOPY
,
3075 PAGE_EXECUTE_WRITECOPY
,
3076 PAGE_EXECUTE_WRITECOPY
,
3077 PAGE_EXECUTE_WRITECOPY
3080 unsigned ProtectionFlags
;
3083 * Extend the file size
3086 /* Unaligned segments must be contiguous within the file */
3087 if (Segment
->FileOffset
!= (EffectiveSegment
->FileOffset
+
3088 EffectiveSegment
->RawLength
))
3093 EffectiveSegment
->RawLength
+= Segment
->RawLength
;
3096 * Extend the virtual size
3098 ASSERT(PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) >= EndOfEffectiveSegment
);
3100 EffectiveSegment
->Length
= PAGE_ROUND_UP(Segment
->VirtualAddress
+ Segment
->Length
) -
3101 EffectiveSegment
->VirtualAddress
;
3104 * Merge the protection
3106 EffectiveSegment
->Protection
|= Segment
->Protection
;
3108 /* Clean up redundance */
3109 ProtectionFlags
= 0;
3111 if(EffectiveSegment
->Protection
& PAGE_IS_READABLE
)
3112 ProtectionFlags
|= 1 << 0;
3114 if(EffectiveSegment
->Protection
& PAGE_IS_WRITABLE
)
3115 ProtectionFlags
|= 1 << 1;
3117 if(EffectiveSegment
->Protection
& PAGE_IS_EXECUTABLE
)
3118 ProtectionFlags
|= 1 << 2;
3120 if(EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3121 ProtectionFlags
|= 1 << 3;
3123 ASSERT(ProtectionFlags
< 16);
3124 EffectiveSegment
->Protection
= FlagsToProtection
[ProtectionFlags
];
3126 /* If a segment was required to be shared and cannot, fail */
3127 if(!(Segment
->Protection
& PAGE_IS_WRITECOPY
) &&
3128 EffectiveSegment
->Protection
& PAGE_IS_WRITECOPY
)
3134 * We assume no holes between segments at this point
3138 KeBugCheck(MEMORY_MANAGEMENT
);
3142 ImageSectionObject
->NrSegments
= LastSegment
+ 1;
3148 ExeFmtpCreateImageSection(HANDLE FileHandle
,
3149 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
)
3151 LARGE_INTEGER Offset
;
3153 PVOID FileHeaderBuffer
;
3154 ULONG FileHeaderSize
;
3156 ULONG OldNrSegments
;
3161 * Read the beginning of the file (2 pages). Should be enough to contain
3162 * all (or most) of the headers
3164 Offset
.QuadPart
= 0;
3166 /* FIXME: use FileObject instead of FileHandle */
3167 Status
= ExeFmtpReadFile (FileHandle
,
3174 if (!NT_SUCCESS(Status
))
3177 if (FileHeaderSize
== 0)
3179 ExFreePool(FileHeaderBuffer
);
3180 return STATUS_UNSUCCESSFUL
;
3184 * Look for a loader that can handle this executable
3186 for (i
= 0; i
< RTL_NUMBER_OF(ExeFmtpLoaders
); ++ i
)
3188 RtlZeroMemory(ImageSectionObject
, sizeof(*ImageSectionObject
));
3191 /* FIXME: use FileObject instead of FileHandle */
3192 Status
= ExeFmtpLoaders
[i
](FileHeader
,
3198 ExeFmtpAllocateSegments
);
3200 if (!NT_SUCCESS(Status
))
3202 if (ImageSectionObject
->Segments
)
3204 ExFreePool(ImageSectionObject
->Segments
);
3205 ImageSectionObject
->Segments
= NULL
;
3209 if (Status
!= STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3213 ExFreePoolWithTag(FileHeaderBuffer
, TAG('M', 'm', 'X', 'r'));
3216 * No loader handled the format
3218 if (Status
== STATUS_ROS_EXEFMT_UNKNOWN_FORMAT
)
3220 Status
= STATUS_INVALID_IMAGE_NOT_MZ
;
3221 ASSERT(!NT_SUCCESS(Status
));
3224 if (!NT_SUCCESS(Status
))
3227 ASSERT(ImageSectionObject
->Segments
!= NULL
);
3232 /* FIXME? are these values platform-dependent? */
3233 if(ImageSectionObject
->StackReserve
== 0)
3234 ImageSectionObject
->StackReserve
= 0x40000;
3236 if(ImageSectionObject
->StackCommit
== 0)
3237 ImageSectionObject
->StackCommit
= 0x1000;
3239 if(ImageSectionObject
->ImageBase
== 0)
3241 if(ImageSectionObject
->ImageCharacteristics
& IMAGE_FILE_DLL
)
3242 ImageSectionObject
->ImageBase
= 0x10000000;
3244 ImageSectionObject
->ImageBase
= 0x00400000;
3248 * And now the fun part: fixing the segments
3251 /* Sort them by virtual address */
3252 MmspSortSegments(ImageSectionObject
, Flags
);
3254 /* Ensure they don't overlap in memory */
3255 if (!MmspCheckSegmentBounds(ImageSectionObject
, Flags
))
3256 return STATUS_INVALID_IMAGE_FORMAT
;
3258 /* Ensure they are aligned */
3259 OldNrSegments
= ImageSectionObject
->NrSegments
;
3261 if (!MmspPageAlignSegments(ImageSectionObject
, Flags
))
3262 return STATUS_INVALID_IMAGE_FORMAT
;
3264 /* Trim them if the alignment phase merged some of them */
3265 if (ImageSectionObject
->NrSegments
< OldNrSegments
)
3267 PMM_SECTION_SEGMENT Segments
;
3268 SIZE_T SizeOfSegments
;
3270 SizeOfSegments
= sizeof(MM_SECTION_SEGMENT
) * ImageSectionObject
->NrSegments
;
3272 Segments
= ExAllocatePoolWithTag(PagedPool
,
3274 TAG_MM_SECTION_SEGMENT
);
3276 if (Segments
== NULL
)
3277 return STATUS_INSUFFICIENT_RESOURCES
;
3279 RtlCopyMemory(Segments
, ImageSectionObject
->Segments
, SizeOfSegments
);
3280 ExFreePool(ImageSectionObject
->Segments
);
3281 ImageSectionObject
->Segments
= Segments
;
3284 /* And finish their initialization */
3285 for ( i
= 0; i
< ImageSectionObject
->NrSegments
; ++ i
)
3287 ExInitializeFastMutex(&ImageSectionObject
->Segments
[i
].Lock
);
3288 ImageSectionObject
->Segments
[i
].ReferenceCount
= 1;
3290 RtlZeroMemory(&ImageSectionObject
->Segments
[i
].PageDirectory
,
3291 sizeof(ImageSectionObject
->Segments
[i
].PageDirectory
));
3294 ASSERT(NT_SUCCESS(Status
));
3299 MmCreateImageSection(PROS_SECTION_OBJECT
*SectionObject
,
3300 ACCESS_MASK DesiredAccess
,
3301 POBJECT_ATTRIBUTES ObjectAttributes
,
3302 PLARGE_INTEGER UMaximumSize
,
3303 ULONG SectionPageProtection
,
3304 ULONG AllocationAttributes
,
3307 PROS_SECTION_OBJECT Section
;
3309 PFILE_OBJECT FileObject
;
3310 PMM_SECTION_SEGMENT SectionSegments
;
3311 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
3313 ULONG FileAccess
= 0;
3316 * Specifying a maximum size is meaningless for an image section
3318 if (UMaximumSize
!= NULL
)
3320 return(STATUS_INVALID_PARAMETER_4
);
3324 * Check file access required
3326 if (SectionPageProtection
& PAGE_READWRITE
||
3327 SectionPageProtection
& PAGE_EXECUTE_READWRITE
)
3329 FileAccess
= FILE_READ_DATA
| FILE_WRITE_DATA
;
3333 FileAccess
= FILE_READ_DATA
;
3337 * Reference the file handle
3339 Status
= ObReferenceObjectByHandle(FileHandle
,
3342 ExGetPreviousMode(),
3343 (PVOID
*)(PVOID
)&FileObject
,
3346 if (!NT_SUCCESS(Status
))
3352 * Create the section
3354 Status
= ObCreateObject (ExGetPreviousMode(),
3355 MmSectionObjectType
,
3357 ExGetPreviousMode(),
3359 sizeof(ROS_SECTION_OBJECT
),
3362 (PVOID
*)(PVOID
)&Section
);
3363 if (!NT_SUCCESS(Status
))
3365 ObDereferenceObject(FileObject
);
3372 Section
->SectionPageProtection
= SectionPageProtection
;
3373 Section
->AllocationAttributes
= AllocationAttributes
;
3376 * Initialized caching for this file object if previously caching
3377 * was initialized for the same on disk file
3379 Status
= CcTryToInitializeFileCache(FileObject
);
3381 if (!NT_SUCCESS(Status
) || FileObject
->SectionObjectPointer
->ImageSectionObject
== NULL
)
3383 NTSTATUS StatusExeFmt
;
3385 ImageSectionObject
= ExAllocatePoolWithTag(PagedPool
, sizeof(MM_IMAGE_SECTION_OBJECT
), TAG_MM_SECTION_SEGMENT
);
3386 if (ImageSectionObject
== NULL
)
3388 ObDereferenceObject(FileObject
);
3389 ObDereferenceObject(Section
);
3390 return(STATUS_NO_MEMORY
);
3393 RtlZeroMemory(ImageSectionObject
, sizeof(MM_IMAGE_SECTION_OBJECT
));
3395 StatusExeFmt
= ExeFmtpCreateImageSection(FileHandle
, ImageSectionObject
);
3397 if (!NT_SUCCESS(StatusExeFmt
))
3399 if(ImageSectionObject
->Segments
!= NULL
)
3400 ExFreePool(ImageSectionObject
->Segments
);
3402 ExFreePool(ImageSectionObject
);
3403 ObDereferenceObject(Section
);
3404 ObDereferenceObject(FileObject
);
3405 return(StatusExeFmt
);
3408 Section
->ImageSection
= ImageSectionObject
;
3409 ASSERT(ImageSectionObject
->Segments
);
3414 Status
= MmspWaitForFileLock(FileObject
);
3415 if (!NT_SUCCESS(Status
))
3417 ExFreePool(ImageSectionObject
->Segments
);
3418 ExFreePool(ImageSectionObject
);
3419 ObDereferenceObject(Section
);
3420 ObDereferenceObject(FileObject
);
3424 if (NULL
!= InterlockedCompareExchangePointer(&FileObject
->SectionObjectPointer
->ImageSectionObject
,
3425 ImageSectionObject
, NULL
))
3428 * An other thread has initialized the same image in the background
3430 ExFreePool(ImageSectionObject
->Segments
);
3431 ExFreePool(ImageSectionObject
);
3432 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3433 Section
->ImageSection
= ImageSectionObject
;
3434 SectionSegments
= ImageSectionObject
->Segments
;
3436 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3438 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3442 Status
= StatusExeFmt
;
3449 Status
= MmspWaitForFileLock(FileObject
);
3450 if (Status
!= STATUS_SUCCESS
)
3452 ObDereferenceObject(Section
);
3453 ObDereferenceObject(FileObject
);
3457 ImageSectionObject
= FileObject
->SectionObjectPointer
->ImageSectionObject
;
3458 Section
->ImageSection
= ImageSectionObject
;
3459 SectionSegments
= ImageSectionObject
->Segments
;
3462 * Otherwise just reference all the section segments
3464 for (i
= 0; i
< ImageSectionObject
->NrSegments
; i
++)
3466 (void)InterlockedIncrementUL(&SectionSegments
[i
].ReferenceCount
);
3469 Status
= STATUS_SUCCESS
;
3471 Section
->FileObject
= FileObject
;
3472 CcRosReferenceCache(FileObject
);
3473 //KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
3474 *SectionObject
= Section
;
3482 NtCreateSection (OUT PHANDLE SectionHandle
,
3483 IN ACCESS_MASK DesiredAccess
,
3484 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
3485 IN PLARGE_INTEGER MaximumSize OPTIONAL
,
3486 IN ULONG SectionPageProtection OPTIONAL
,
3487 IN ULONG AllocationAttributes
,
3488 IN HANDLE FileHandle OPTIONAL
)
3490 LARGE_INTEGER SafeMaximumSize
;
3491 PVOID SectionObject
;
3492 KPROCESSOR_MODE PreviousMode
;
3493 NTSTATUS Status
= STATUS_SUCCESS
;
3495 PreviousMode
= ExGetPreviousMode();
3497 if(MaximumSize
!= NULL
&& PreviousMode
!= KernelMode
)
3501 /* make a copy on the stack */
3502 SafeMaximumSize
= ProbeForReadLargeInteger(MaximumSize
);
3503 MaximumSize
= &SafeMaximumSize
;
3505 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3507 Status
= _SEH2_GetExceptionCode();
3511 if(!NT_SUCCESS(Status
))
3517 Status
= MmCreateSection(&SectionObject
,
3521 SectionPageProtection
,
3522 AllocationAttributes
,
3525 if (NT_SUCCESS(Status
))
3527 Status
= ObInsertObject ((PVOID
)SectionObject
,
3539 /**********************************************************************
3557 NtOpenSection(PHANDLE SectionHandle
,
3558 ACCESS_MASK DesiredAccess
,
3559 POBJECT_ATTRIBUTES ObjectAttributes
)
3562 KPROCESSOR_MODE PreviousMode
;
3563 NTSTATUS Status
= STATUS_SUCCESS
;
3565 PreviousMode
= ExGetPreviousMode();
3567 if(PreviousMode
!= KernelMode
)
3571 ProbeForWriteHandle(SectionHandle
);
3573 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3575 Status
= _SEH2_GetExceptionCode();
3579 if(!NT_SUCCESS(Status
))
3585 Status
= ObOpenObjectByName(ObjectAttributes
,
3586 MmSectionObjectType
,
3593 if(NT_SUCCESS(Status
))
3597 *SectionHandle
= hSection
;
3599 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3601 Status
= _SEH2_GetExceptionCode();
3610 MmMapViewOfSegment(PMM_AVL_TABLE AddressSpace
,
3611 PROS_SECTION_OBJECT Section
,
3612 PMM_SECTION_SEGMENT Segment
,
3617 ULONG AllocationType
)
3621 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
3623 BoundaryAddressMultiple
.QuadPart
= 0;
3625 Status
= MmCreateMemoryArea(AddressSpace
,
3626 MEMORY_AREA_SECTION_VIEW
,
3633 BoundaryAddressMultiple
);
3634 if (!NT_SUCCESS(Status
))
3636 DPRINT1("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
3637 (*BaseAddress
), (char*)(*BaseAddress
) + ViewSize
, Status
);
3641 ObReferenceObject((PVOID
)Section
);
3643 MArea
->Data
.SectionData
.Segment
= Segment
;
3644 MArea
->Data
.SectionData
.Section
= Section
;
3645 MArea
->Data
.SectionData
.ViewOffset
= ViewOffset
;
3646 MArea
->Data
.SectionData
.WriteCopyView
= FALSE
;
3647 MmInitializeRegion(&MArea
->Data
.SectionData
.RegionListHead
,
3648 ViewSize
, 0, Protect
);
3650 return(STATUS_SUCCESS
);
3654 /**********************************************************************
3656 * NtMapViewOfSection
3659 * Maps a view of a section into the virtual address space of a
3664 * Handle of the section.
3667 * Handle of the process.
3670 * Desired base address (or NULL) on entry;
3671 * Actual base address of the view on exit.
3674 * Number of high order address bits that must be zero.
3677 * Size in bytes of the initially committed section of
3681 * Offset in bytes from the beginning of the section
3682 * to the beginning of the view.
3685 * Desired length of map (or zero to map all) on entry
3686 * Actual length mapped on exit.
3688 * InheritDisposition
3689 * Specified how the view is to be shared with
3693 * Type of allocation for the pages.
3696 * Protection for the committed region of the view.
3704 NtMapViewOfSection(IN HANDLE SectionHandle
,
3705 IN HANDLE ProcessHandle
,
3706 IN OUT PVOID
* BaseAddress OPTIONAL
,
3707 IN ULONG_PTR ZeroBits OPTIONAL
,
3708 IN SIZE_T CommitSize
,
3709 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
3710 IN OUT PSIZE_T ViewSize
,
3711 IN SECTION_INHERIT InheritDisposition
,
3712 IN ULONG AllocationType OPTIONAL
,
3715 PVOID SafeBaseAddress
;
3716 LARGE_INTEGER SafeSectionOffset
;
3717 SIZE_T SafeViewSize
;
3718 PROS_SECTION_OBJECT Section
;
3720 KPROCESSOR_MODE PreviousMode
;
3721 PMM_AVL_TABLE AddressSpace
;
3722 NTSTATUS Status
= STATUS_SUCCESS
;
3726 * Check the protection
3728 if (Protect
& ~PAGE_FLAGS_VALID_FROM_USER_MODE
)
3730 return STATUS_INVALID_PARAMETER_10
;
3733 tmpProtect
= Protect
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
3734 if (tmpProtect
!= PAGE_NOACCESS
&&
3735 tmpProtect
!= PAGE_READONLY
&&
3736 tmpProtect
!= PAGE_READWRITE
&&
3737 tmpProtect
!= PAGE_WRITECOPY
&&
3738 tmpProtect
!= PAGE_EXECUTE
&&
3739 tmpProtect
!= PAGE_EXECUTE_READ
&&
3740 tmpProtect
!= PAGE_EXECUTE_READWRITE
&&
3741 tmpProtect
!= PAGE_EXECUTE_WRITECOPY
)
3743 return STATUS_INVALID_PAGE_PROTECTION
;
3746 PreviousMode
= ExGetPreviousMode();
3748 if(PreviousMode
!= KernelMode
)
3750 SafeBaseAddress
= NULL
;
3751 SafeSectionOffset
.QuadPart
= 0;
3756 if(BaseAddress
!= NULL
)
3758 ProbeForWritePointer(BaseAddress
);
3759 SafeBaseAddress
= *BaseAddress
;
3761 if(SectionOffset
!= NULL
)
3763 ProbeForWriteLargeInteger(SectionOffset
);
3764 SafeSectionOffset
= *SectionOffset
;
3766 ProbeForWriteSize_t(ViewSize
);
3767 SafeViewSize
= *ViewSize
;
3769 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3771 Status
= _SEH2_GetExceptionCode();
3775 if(!NT_SUCCESS(Status
))
3782 SafeBaseAddress
= (BaseAddress
!= NULL
? *BaseAddress
: NULL
);
3783 SafeSectionOffset
.QuadPart
= (SectionOffset
!= NULL
? SectionOffset
->QuadPart
: 0);
3784 SafeViewSize
= (ViewSize
!= NULL
? *ViewSize
: 0);
3787 SafeSectionOffset
.LowPart
= PAGE_ROUND_DOWN(SafeSectionOffset
.LowPart
);
3789 Status
= ObReferenceObjectByHandle(ProcessHandle
,
3790 PROCESS_VM_OPERATION
,
3793 (PVOID
*)(PVOID
)&Process
,
3795 if (!NT_SUCCESS(Status
))
3800 AddressSpace
= &Process
->VadRoot
;
3802 Status
= ObReferenceObjectByHandle(SectionHandle
,
3804 MmSectionObjectType
,
3806 (PVOID
*)(PVOID
)&Section
,
3808 if (!(NT_SUCCESS(Status
)))
3810 DPRINT("ObReference failed rc=%x\n",Status
);
3811 ObDereferenceObject(Process
);
3815 Status
= MmMapViewOfSection(Section
,
3817 (BaseAddress
!= NULL
? &SafeBaseAddress
: NULL
),
3820 (SectionOffset
!= NULL
? &SafeSectionOffset
: NULL
),
3821 (ViewSize
!= NULL
? &SafeViewSize
: NULL
),
3826 /* Check if this is an image for the current process */
3827 if ((Section
->AllocationAttributes
& SEC_IMAGE
) &&
3828 (Process
== PsGetCurrentProcess()) &&
3829 (Status
!= STATUS_IMAGE_NOT_AT_BASE
))
3831 /* Notify the debugger */
3832 DbgkMapViewOfSection(Section
,
3834 SafeSectionOffset
.LowPart
,
3838 ObDereferenceObject(Section
);
3839 ObDereferenceObject(Process
);
3841 if(NT_SUCCESS(Status
))
3843 /* copy parameters back to the caller */
3846 if(BaseAddress
!= NULL
)
3848 *BaseAddress
= SafeBaseAddress
;
3850 if(SectionOffset
!= NULL
)
3852 *SectionOffset
= SafeSectionOffset
;
3854 if(ViewSize
!= NULL
)
3856 *ViewSize
= SafeViewSize
;
3859 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3861 Status
= _SEH2_GetExceptionCode();
3870 MmFreeSectionPage(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
3871 PFN_TYPE Page
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
)
3874 PFILE_OBJECT FileObject
;
3877 SWAPENTRY SavedSwapEntry
;
3880 PROS_SECTION_OBJECT Section
;
3881 PMM_SECTION_SEGMENT Segment
;
3882 PMM_AVL_TABLE AddressSpace
;
3885 AddressSpace
= (PMM_AVL_TABLE
)Context
;
3886 Process
= MmGetAddressSpaceOwner(AddressSpace
);
3888 Address
= (PVOID
)PAGE_ROUND_DOWN(Address
);
3890 Offset
= ((ULONG_PTR
)Address
- (ULONG_PTR
)MemoryArea
->StartingAddress
) +
3891 MemoryArea
->Data
.SectionData
.ViewOffset
;
3893 Section
= MemoryArea
->Data
.SectionData
.Section
;
3894 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
3896 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3900 MmUnlockSectionSegment(Segment
);
3901 MmUnlockAddressSpace(AddressSpace
);
3903 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
3904 if (Status
!= STATUS_SUCCESS
)
3906 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
3907 KeBugCheck(MEMORY_MANAGEMENT
);
3910 MmLockAddressSpace(AddressSpace
);
3911 MmLockSectionSegment(Segment
);
3912 MmspCompleteAndReleasePageOp(PageOp
);
3913 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
, Segment
, Offset
);
3916 Entry
= MmGetPageEntrySectionSegment(Segment
, Offset
);
3919 * For a dirty, datafile, non-private page mark it as dirty in the
3922 if (Segment
->Flags
& MM_DATAFILE_SEGMENT
)
3924 if (Page
== PFN_FROM_SSE(Entry
) && Dirty
)
3926 FileObject
= MemoryArea
->Data
.SectionData
.Section
->FileObject
;
3927 Bcb
= FileObject
->SectionObjectPointer
->SharedCacheMap
;
3928 CcRosMarkDirtyCacheSegment(Bcb
, Offset
+ Segment
->FileOffset
);
3929 ASSERT(SwapEntry
== 0);
3938 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3940 DPRINT1("Found a swap entry for a page in a pagefile section.\n");
3941 KeBugCheck(MEMORY_MANAGEMENT
);
3943 MmFreeSwapPage(SwapEntry
);
3947 if (IS_SWAP_FROM_SSE(Entry
) ||
3948 Page
!= PFN_FROM_SSE(Entry
))
3953 if (Segment
->Flags
& MM_PAGEFILE_SEGMENT
)
3955 DPRINT1("Found a private page in a pagefile section.\n");
3956 KeBugCheck(MEMORY_MANAGEMENT
);
3959 * Just dereference private pages
3961 SavedSwapEntry
= MmGetSavedSwapEntryPage(Page
);
3962 if (SavedSwapEntry
!= 0)
3964 MmFreeSwapPage(SavedSwapEntry
);
3965 MmSetSavedSwapEntryPage(Page
, 0);
3967 MmDeleteRmap(Page
, Process
, Address
);
3968 MmReleasePageMemoryConsumer(MC_USER
, Page
);
3972 MmDeleteRmap(Page
, Process
, Address
);
3973 MmUnsharePageEntrySectionSegment(Section
, Segment
, Offset
, Dirty
, FALSE
);
3979 MmUnmapViewOfSegment(PMM_AVL_TABLE AddressSpace
,
3983 PMEMORY_AREA MemoryArea
;
3984 PROS_SECTION_OBJECT Section
;
3985 PMM_SECTION_SEGMENT Segment
;
3986 PLIST_ENTRY CurrentEntry
;
3987 PMM_REGION CurrentRegion
;
3988 PLIST_ENTRY RegionListHead
;
3990 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
3992 if (MemoryArea
== NULL
)
3994 return(STATUS_UNSUCCESSFUL
);
3997 MemoryArea
->DeleteInProgress
= TRUE
;
3998 Section
= MemoryArea
->Data
.SectionData
.Section
;
3999 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4001 MmLockSectionSegment(Segment
);
4003 RegionListHead
= &MemoryArea
->Data
.SectionData
.RegionListHead
;
4004 while (!IsListEmpty(RegionListHead
))
4006 CurrentEntry
= RemoveHeadList(RegionListHead
);
4007 CurrentRegion
= CONTAINING_RECORD(CurrentEntry
, MM_REGION
, RegionListEntry
);
4008 ExFreePoolWithTag(CurrentRegion
, TAG_MM_REGION
);
4011 if (Section
->AllocationAttributes
& SEC_PHYSICALMEMORY
)
4013 Status
= MmFreeMemoryArea(AddressSpace
,
4020 Status
= MmFreeMemoryArea(AddressSpace
,
4025 MmUnlockSectionSegment(Segment
);
4026 ObDereferenceObject(Section
);
4027 return(STATUS_SUCCESS
);
4034 MmUnmapViewOfSection(PEPROCESS Process
,
4038 PMEMORY_AREA MemoryArea
;
4039 PMM_AVL_TABLE AddressSpace
;
4040 PROS_SECTION_OBJECT Section
;
4043 PVOID ImageBaseAddress
= 0;
4045 DPRINT("Opening memory area Process %x BaseAddress %x\n",
4046 Process
, BaseAddress
);
4050 AddressSpace
= &Process
->VadRoot
;
4052 MmLockAddressSpace(AddressSpace
);
4053 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4055 if (MemoryArea
== NULL
||
4056 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
||
4057 MemoryArea
->DeleteInProgress
)
4059 MmUnlockAddressSpace(AddressSpace
);
4060 return STATUS_NOT_MAPPED_VIEW
;
4063 MemoryArea
->DeleteInProgress
= TRUE
;
4065 while (MemoryArea
->PageOpCount
)
4067 Offset
= PAGE_ROUND_UP((ULONG_PTR
)MemoryArea
->EndingAddress
- (ULONG_PTR
)MemoryArea
->StartingAddress
);
4071 Offset
-= PAGE_SIZE
;
4072 PageOp
= MmCheckForPageOp(MemoryArea
, NULL
, NULL
,
4073 MemoryArea
->Data
.SectionData
.Segment
,
4074 Offset
+ MemoryArea
->Data
.SectionData
.ViewOffset
);
4077 MmUnlockAddressSpace(AddressSpace
);
4078 Status
= MmspWaitForPageOpCompletionEvent(PageOp
);
4079 if (Status
!= STATUS_SUCCESS
)
4081 DPRINT1("Failed to wait for page op, status = %x\n", Status
);
4082 KeBugCheck(MEMORY_MANAGEMENT
);
4084 MmLockAddressSpace(AddressSpace
);
4085 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
4087 if (MemoryArea
== NULL
||
4088 MemoryArea
->Type
!= MEMORY_AREA_SECTION_VIEW
)
4090 MmUnlockAddressSpace(AddressSpace
);
4091 return STATUS_NOT_MAPPED_VIEW
;
4098 Section
= MemoryArea
->Data
.SectionData
.Section
;
4100 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4104 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4105 PMM_SECTION_SEGMENT SectionSegments
;
4106 PMM_SECTION_SEGMENT Segment
;
4108 Segment
= MemoryArea
->Data
.SectionData
.Segment
;
4109 ImageSectionObject
= Section
->ImageSection
;
4110 SectionSegments
= ImageSectionObject
->Segments
;
4111 NrSegments
= ImageSectionObject
->NrSegments
;
4113 /* Search for the current segment within the section segments
4114 * and calculate the image base address */
4115 for (i
= 0; i
< NrSegments
; i
++)
4117 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4119 if (Segment
== &SectionSegments
[i
])
4121 ImageBaseAddress
= (char*)BaseAddress
- (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
;
4126 if (i
>= NrSegments
)
4128 KeBugCheck(MEMORY_MANAGEMENT
);
4131 for (i
= 0; i
< NrSegments
; i
++)
4133 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4135 PVOID SBaseAddress
= (PVOID
)
4136 ((char*)ImageBaseAddress
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4138 Status
= MmUnmapViewOfSegment(AddressSpace
, SBaseAddress
);
4144 Status
= MmUnmapViewOfSegment(AddressSpace
, BaseAddress
);
4147 /* Notify debugger */
4148 if (ImageBaseAddress
) DbgkUnMapViewOfSection(ImageBaseAddress
);
4150 MmUnlockAddressSpace(AddressSpace
);
4151 return(STATUS_SUCCESS
);
4154 /**********************************************************************
4156 * NtUnmapViewOfSection
4171 NtUnmapViewOfSection (HANDLE ProcessHandle
,
4175 KPROCESSOR_MODE PreviousMode
;
4178 DPRINT("NtUnmapViewOfSection(ProcessHandle %x, BaseAddress %x)\n",
4179 ProcessHandle
, BaseAddress
);
4181 PreviousMode
= ExGetPreviousMode();
4183 DPRINT("Referencing process\n");
4184 Status
= ObReferenceObjectByHandle(ProcessHandle
,
4185 PROCESS_VM_OPERATION
,
4188 (PVOID
*)(PVOID
)&Process
,
4190 if (!NT_SUCCESS(Status
))
4192 DPRINT("ObReferenceObjectByHandle failed (Status %x)\n", Status
);
4196 Status
= MmUnmapViewOfSection(Process
, BaseAddress
);
4198 ObDereferenceObject(Process
);
4205 * Queries the information of a section object.
4207 * @param SectionHandle
4208 * Handle to the section object. It must be opened with SECTION_QUERY
4210 * @param SectionInformationClass
4211 * Index to a certain information structure. Can be either
4212 * SectionBasicInformation or SectionImageInformation. The latter
4213 * is valid only for sections that were created with the SEC_IMAGE
4215 * @param SectionInformation
4216 * Caller supplies storage for resulting information.
4218 * Size of the supplied storage.
4219 * @param ResultLength
4227 NtQuerySection(IN HANDLE SectionHandle
,
4228 IN SECTION_INFORMATION_CLASS SectionInformationClass
,
4229 OUT PVOID SectionInformation
,
4230 IN ULONG SectionInformationLength
,
4231 OUT PULONG ResultLength OPTIONAL
)
4233 PROS_SECTION_OBJECT Section
;
4234 KPROCESSOR_MODE PreviousMode
;
4235 NTSTATUS Status
= STATUS_SUCCESS
;
4237 PreviousMode
= ExGetPreviousMode();
4239 Status
= DefaultQueryInfoBufferCheck(SectionInformationClass
,
4241 sizeof(ExSectionInfoClass
) / sizeof(ExSectionInfoClass
[0]),
4243 SectionInformationLength
,
4247 if(!NT_SUCCESS(Status
))
4249 DPRINT1("NtQuerySection() failed, Status: 0x%x\n", Status
);
4253 Status
= ObReferenceObjectByHandle(SectionHandle
,
4255 MmSectionObjectType
,
4257 (PVOID
*)(PVOID
)&Section
,
4259 if (NT_SUCCESS(Status
))
4261 switch (SectionInformationClass
)
4263 case SectionBasicInformation
:
4265 PSECTION_BASIC_INFORMATION Sbi
= (PSECTION_BASIC_INFORMATION
)SectionInformation
;
4269 Sbi
->Attributes
= Section
->AllocationAttributes
;
4270 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4272 Sbi
->BaseAddress
= 0;
4273 Sbi
->Size
.QuadPart
= 0;
4277 Sbi
->BaseAddress
= (PVOID
)Section
->Segment
->VirtualAddress
;
4278 Sbi
->Size
.QuadPart
= Section
->Segment
->Length
;
4281 if (ResultLength
!= NULL
)
4283 *ResultLength
= sizeof(SECTION_BASIC_INFORMATION
);
4285 Status
= STATUS_SUCCESS
;
4287 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4289 Status
= _SEH2_GetExceptionCode();
4296 case SectionImageInformation
:
4298 PSECTION_IMAGE_INFORMATION Sii
= (PSECTION_IMAGE_INFORMATION
)SectionInformation
;
4302 memset(Sii
, 0, sizeof(SECTION_IMAGE_INFORMATION
));
4303 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4305 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4306 ImageSectionObject
= Section
->ImageSection
;
4308 Sii
->TransferAddress
= (PVOID
)ImageSectionObject
->EntryPoint
;
4309 Sii
->MaximumStackSize
= ImageSectionObject
->StackReserve
;
4310 Sii
->CommittedStackSize
= ImageSectionObject
->StackCommit
;
4311 Sii
->SubSystemType
= ImageSectionObject
->Subsystem
;
4312 Sii
->SubSystemMinorVersion
= ImageSectionObject
->MinorSubsystemVersion
;
4313 Sii
->SubSystemMajorVersion
= ImageSectionObject
->MajorSubsystemVersion
;
4314 Sii
->ImageCharacteristics
= ImageSectionObject
->ImageCharacteristics
;
4315 Sii
->Machine
= ImageSectionObject
->Machine
;
4316 Sii
->ImageContainsCode
= ImageSectionObject
->Executable
;
4319 if (ResultLength
!= NULL
)
4321 *ResultLength
= sizeof(SECTION_IMAGE_INFORMATION
);
4323 Status
= STATUS_SUCCESS
;
4325 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4327 Status
= _SEH2_GetExceptionCode();
4335 ObDereferenceObject(Section
);
4343 * Extends size of file backed section.
4345 * @param SectionHandle
4346 * Handle to the section object. It must be opened with
4347 * SECTION_EXTEND_SIZE access.
4348 * @param NewMaximumSize
4349 * New maximum size of the section in bytes.
4353 * @todo Move the actual code to internal function MmExtendSection.
4357 NtExtendSection(IN HANDLE SectionHandle
,
4358 IN PLARGE_INTEGER NewMaximumSize
)
4360 LARGE_INTEGER SafeNewMaximumSize
;
4361 PROS_SECTION_OBJECT Section
;
4362 KPROCESSOR_MODE PreviousMode
;
4363 NTSTATUS Status
= STATUS_SUCCESS
;
4365 PreviousMode
= ExGetPreviousMode();
4367 if(PreviousMode
!= KernelMode
)
4371 /* make a copy on the stack */
4372 SafeNewMaximumSize
= ProbeForReadLargeInteger(NewMaximumSize
);
4373 NewMaximumSize
= &SafeNewMaximumSize
;
4375 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
4377 Status
= _SEH2_GetExceptionCode();
4381 if(!NT_SUCCESS(Status
))
4387 Status
= ObReferenceObjectByHandle(SectionHandle
,
4388 SECTION_EXTEND_SIZE
,
4389 MmSectionObjectType
,
4393 if (!NT_SUCCESS(Status
))
4398 if (!(Section
->AllocationAttributes
& SEC_FILE
))
4400 ObfDereferenceObject(Section
);
4401 return STATUS_INVALID_PARAMETER
;
4405 * - Acquire file extneding resource.
4406 * - Check if we're not resizing the section below it's actual size!
4407 * - Extend segments if needed.
4408 * - Set file information (FileAllocationInformation) to the new size.
4409 * - Release file extending resource.
4412 ObDereferenceObject(Section
);
4414 return STATUS_NOT_IMPLEMENTED
;
4418 /**********************************************************************
4420 * MmAllocateSection@4
4430 * Code taken from ntoskrnl/mm/special.c.
4435 MmAllocateSection (IN ULONG Length
, PVOID BaseAddress
)
4440 PMM_AVL_TABLE AddressSpace
;
4441 PHYSICAL_ADDRESS BoundaryAddressMultiple
;
4443 DPRINT("MmAllocateSection(Length %x)\n",Length
);
4445 BoundaryAddressMultiple
.QuadPart
= 0;
4447 AddressSpace
= MmGetKernelAddressSpace();
4448 Result
= BaseAddress
;
4449 MmLockAddressSpace(AddressSpace
);
4450 Status
= MmCreateMemoryArea (AddressSpace
,
4458 BoundaryAddressMultiple
);
4459 MmUnlockAddressSpace(AddressSpace
);
4461 if (!NT_SUCCESS(Status
))
4465 DPRINT("Result %p\n",Result
);
4467 /* Create a virtual mapping for this memory area */
4468 MmMapMemoryArea(Result
, Length
, MC_NPPOOL
, PAGE_READWRITE
);
4470 return ((PVOID
)Result
);
4474 /**********************************************************************
4476 * MmMapViewOfSection
4479 * Maps a view of a section into the virtual address space of a
4484 * Pointer to the section object.
4487 * Pointer to the process.
4490 * Desired base address (or NULL) on entry;
4491 * Actual base address of the view on exit.
4494 * Number of high order address bits that must be zero.
4497 * Size in bytes of the initially committed section of
4501 * Offset in bytes from the beginning of the section
4502 * to the beginning of the view.
4505 * Desired length of map (or zero to map all) on entry
4506 * Actual length mapped on exit.
4508 * InheritDisposition
4509 * Specified how the view is to be shared with
4513 * Type of allocation for the pages.
4516 * Protection for the committed region of the view.
4524 MmMapViewOfSection(IN PVOID SectionObject
,
4525 IN PEPROCESS Process
,
4526 IN OUT PVOID
*BaseAddress
,
4527 IN ULONG_PTR ZeroBits
,
4528 IN SIZE_T CommitSize
,
4529 IN OUT PLARGE_INTEGER SectionOffset OPTIONAL
,
4530 IN OUT PSIZE_T ViewSize
,
4531 IN SECTION_INHERIT InheritDisposition
,
4532 IN ULONG AllocationType
,
4535 PROS_SECTION_OBJECT Section
;
4536 PMM_AVL_TABLE AddressSpace
;
4538 NTSTATUS Status
= STATUS_SUCCESS
;
4542 if (!Protect
|| Protect
& ~PAGE_FLAGS_VALID_FOR_SECTION
)
4544 return STATUS_INVALID_PAGE_PROTECTION
;
4548 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4549 AddressSpace
= &Process
->VadRoot
;
4551 AllocationType
|= (Section
->AllocationAttributes
& SEC_NO_CHANGE
);
4553 MmLockAddressSpace(AddressSpace
);
4555 if (Section
->AllocationAttributes
& SEC_IMAGE
)
4559 ULONG_PTR ImageBase
;
4561 PMM_IMAGE_SECTION_OBJECT ImageSectionObject
;
4562 PMM_SECTION_SEGMENT SectionSegments
;
4564 ImageSectionObject
= Section
->ImageSection
;
4565 SectionSegments
= ImageSectionObject
->Segments
;
4566 NrSegments
= ImageSectionObject
->NrSegments
;
4569 ImageBase
= (ULONG_PTR
)*BaseAddress
;
4572 ImageBase
= ImageSectionObject
->ImageBase
;
4576 for (i
= 0; i
< NrSegments
; i
++)
4578 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4580 ULONG_PTR MaxExtent
;
4581 MaxExtent
= (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
+
4582 SectionSegments
[i
].Length
;
4583 ImageSize
= max(ImageSize
, MaxExtent
);
4587 ImageSectionObject
->ImageSize
= ImageSize
;
4589 /* Check there is enough space to map the section at that point. */
4590 if (MmLocateMemoryAreaByRegion(AddressSpace
, (PVOID
)ImageBase
,
4591 PAGE_ROUND_UP(ImageSize
)) != NULL
)
4593 /* Fail if the user requested a fixed base address. */
4594 if ((*BaseAddress
) != NULL
)
4596 MmUnlockAddressSpace(AddressSpace
);
4597 return(STATUS_UNSUCCESSFUL
);
4599 /* Otherwise find a gap to map the image. */
4600 ImageBase
= (ULONG_PTR
)MmFindGap(AddressSpace
, PAGE_ROUND_UP(ImageSize
), PAGE_SIZE
, FALSE
);
4603 MmUnlockAddressSpace(AddressSpace
);
4604 return(STATUS_UNSUCCESSFUL
);
4608 for (i
= 0; i
< NrSegments
; i
++)
4610 if (!(SectionSegments
[i
].Characteristics
& IMAGE_SCN_TYPE_NOLOAD
))
4612 PVOID SBaseAddress
= (PVOID
)
4613 ((char*)ImageBase
+ (ULONG_PTR
)SectionSegments
[i
].VirtualAddress
);
4614 MmLockSectionSegment(&SectionSegments
[i
]);
4615 Status
= MmMapViewOfSegment(AddressSpace
,
4617 &SectionSegments
[i
],
4619 SectionSegments
[i
].Length
,
4620 SectionSegments
[i
].Protection
,
4623 MmUnlockSectionSegment(&SectionSegments
[i
]);
4624 if (!NT_SUCCESS(Status
))
4626 MmUnlockAddressSpace(AddressSpace
);
4632 *BaseAddress
= (PVOID
)ImageBase
;
4636 /* check for write access */
4637 if ((Protect
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)) &&
4638 !(Section
->SectionPageProtection
& (PAGE_READWRITE
|PAGE_EXECUTE_READWRITE
)))
4640 MmUnlockAddressSpace(AddressSpace
);
4641 return STATUS_SECTION_PROTECTION
;
4643 /* check for read access */
4644 if ((Protect
& (PAGE_READONLY
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_WRITECOPY
)) &&
4645 !(Section
->SectionPageProtection
& (PAGE_READONLY
|PAGE_READWRITE
|PAGE_WRITECOPY
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4647 MmUnlockAddressSpace(AddressSpace
);
4648 return STATUS_SECTION_PROTECTION
;
4650 /* check for execute access */
4651 if ((Protect
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)) &&
4652 !(Section
->SectionPageProtection
& (PAGE_EXECUTE
|PAGE_EXECUTE_READ
|PAGE_EXECUTE_READWRITE
|PAGE_EXECUTE_WRITECOPY
)))
4654 MmUnlockAddressSpace(AddressSpace
);
4655 return STATUS_SECTION_PROTECTION
;
4658 if (ViewSize
== NULL
)
4660 /* Following this pointer would lead to us to the dark side */
4661 /* What to do? Bugcheck? Return status? Do the mambo? */
4662 KeBugCheck(MEMORY_MANAGEMENT
);
4665 if (SectionOffset
== NULL
)
4671 ViewOffset
= SectionOffset
->u
.LowPart
;
4674 if ((ViewOffset
% PAGE_SIZE
) != 0)
4676 MmUnlockAddressSpace(AddressSpace
);
4677 return(STATUS_MAPPED_ALIGNMENT
);
4680 if ((*ViewSize
) == 0)
4682 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4684 else if (((*ViewSize
)+ViewOffset
) > Section
->MaximumSize
.u
.LowPart
)
4686 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
- ViewOffset
;
4689 MmLockSectionSegment(Section
->Segment
);
4690 Status
= MmMapViewOfSegment(AddressSpace
,
4697 AllocationType
& (MEM_TOP_DOWN
|SEC_NO_CHANGE
));
4698 MmUnlockSectionSegment(Section
->Segment
);
4699 if (!NT_SUCCESS(Status
))
4701 MmUnlockAddressSpace(AddressSpace
);
4706 MmUnlockAddressSpace(AddressSpace
);
4708 return(STATUS_SUCCESS
);
4715 MmCanFileBeTruncated (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4716 IN PLARGE_INTEGER NewFileSize
)
4718 /* Check whether an ImageSectionObject exists */
4719 if (SectionObjectPointer
->ImageSectionObject
!= NULL
)
4721 DPRINT1("ERROR: File can't be truncated because it has an image section\n");
4725 if (SectionObjectPointer
->DataSectionObject
!= NULL
)
4727 PMM_SECTION_SEGMENT Segment
;
4729 Segment
= (PMM_SECTION_SEGMENT
)SectionObjectPointer
->
4732 if (Segment
->ReferenceCount
!= 0)
4734 /* Check size of file */
4735 if (SectionObjectPointer
->SharedCacheMap
)
4737 PBCB Bcb
= SectionObjectPointer
->SharedCacheMap
;
4738 if (NewFileSize
->QuadPart
<= Bcb
->FileSize
.QuadPart
)
4746 /* Something must gone wrong
4747 * how can we have a Section but no
4749 DPRINT1("ERROR: DataSectionObject without reference!\n");
4753 DPRINT1("FIXME: didn't check for outstanding write probes\n");
4763 MmDisableModifiedWriteOfSection (ULONG Unknown0
)
4773 MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4774 IN MMFLUSH_TYPE FlushType
)
4778 case MmFlushForDelete
:
4779 if (SectionObjectPointer
->ImageSectionObject
||
4780 SectionObjectPointer
->DataSectionObject
)
4784 CcRosSetRemoveOnClose(SectionObjectPointer
);
4786 case MmFlushForWrite
:
4796 MmForceSectionClosed (
4797 IN PSECTION_OBJECT_POINTERS SectionObjectPointer
,
4798 IN BOOLEAN DelayClose
)
4809 MmMapViewInSystemSpace (IN PVOID SectionObject
,
4810 OUT PVOID
* MappedBase
,
4811 IN OUT PULONG ViewSize
)
4813 PROS_SECTION_OBJECT Section
;
4814 PMM_AVL_TABLE AddressSpace
;
4817 DPRINT("MmMapViewInSystemSpace() called\n");
4819 Section
= (PROS_SECTION_OBJECT
)SectionObject
;
4820 AddressSpace
= MmGetKernelAddressSpace();
4822 MmLockAddressSpace(AddressSpace
);
4825 if ((*ViewSize
) == 0)
4827 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4829 else if ((*ViewSize
) > Section
->MaximumSize
.u
.LowPart
)
4831 (*ViewSize
) = Section
->MaximumSize
.u
.LowPart
;
4834 MmLockSectionSegment(Section
->Segment
);
4837 Status
= MmMapViewOfSegment(AddressSpace
,
4846 MmUnlockSectionSegment(Section
->Segment
);
4847 MmUnlockAddressSpace(AddressSpace
);
4857 MmMapViewInSessionSpace (
4859 OUT PVOID
*MappedBase
,
4860 IN OUT PSIZE_T ViewSize
4864 return STATUS_NOT_IMPLEMENTED
;
4872 MmUnmapViewInSystemSpace (IN PVOID MappedBase
)
4874 PMM_AVL_TABLE AddressSpace
;
4877 DPRINT("MmUnmapViewInSystemSpace() called\n");
4879 AddressSpace
= MmGetKernelAddressSpace();
4881 Status
= MmUnmapViewOfSegment(AddressSpace
, MappedBase
);
4891 MmUnmapViewInSessionSpace (
4896 return STATUS_NOT_IMPLEMENTED
;
4903 MmSetBankedSection (ULONG Unknown0
,
4911 return (STATUS_NOT_IMPLEMENTED
);
4915 /**********************************************************************
4920 * Creates a section object.
4923 * SectionObject (OUT)
4924 * Caller supplied storage for the resulting pointer
4925 * to a SECTION_OBJECT instance;
4928 * Specifies the desired access to the section can be a
4930 * STANDARD_RIGHTS_REQUIRED |
4932 * SECTION_MAP_WRITE |
4933 * SECTION_MAP_READ |
4934 * SECTION_MAP_EXECUTE
4936 * ObjectAttributes [OPTIONAL]
4937 * Initialized attributes for the object can be used
4938 * to create a named section;
4941 * Maximizes the size of the memory section. Must be
4942 * non-NULL for a page-file backed section.
4943 * If value specified for a mapped file and the file is
4944 * not large enough, file will be extended.
4946 * SectionPageProtection
4947 * Can be a combination of:
4953 * AllocationAttributes
4954 * Can be a combination of:
4959 * Handle to a file to create a section mapped to a file
4960 * instead of a memory backed section;
4971 MmCreateSection (OUT PVOID
* Section
,
4972 IN ACCESS_MASK DesiredAccess
,
4973 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
4974 IN PLARGE_INTEGER MaximumSize
,
4975 IN ULONG SectionPageProtection
,
4976 IN ULONG AllocationAttributes
,
4977 IN HANDLE FileHandle OPTIONAL
,
4978 IN PFILE_OBJECT File OPTIONAL
)
4981 PROS_SECTION_OBJECT
*SectionObject
= (PROS_SECTION_OBJECT
*)Section
;
4984 * Check the protection
4986 Protection
= SectionPageProtection
& ~(PAGE_GUARD
|PAGE_NOCACHE
);
4987 if (Protection
!= PAGE_NOACCESS
&&
4988 Protection
!= PAGE_READONLY
&&
4989 Protection
!= PAGE_READWRITE
&&
4990 Protection
!= PAGE_WRITECOPY
&&
4991 Protection
!= PAGE_EXECUTE
&&
4992 Protection
!= PAGE_EXECUTE_READ
&&
4993 Protection
!= PAGE_EXECUTE_READWRITE
&&
4994 Protection
!= PAGE_EXECUTE_WRITECOPY
)
4996 return STATUS_INVALID_PAGE_PROTECTION
;
4999 if (AllocationAttributes
& SEC_IMAGE
)
5001 return(MmCreateImageSection(SectionObject
,
5005 SectionPageProtection
,
5006 AllocationAttributes
,
5010 if (FileHandle
!= NULL
)
5012 return(MmCreateDataFileSection(SectionObject
,
5016 SectionPageProtection
,
5017 AllocationAttributes
,
5021 return(MmCreatePageFileSection(SectionObject
,
5025 SectionPageProtection
,
5026 AllocationAttributes
));
5031 NtAllocateUserPhysicalPages(IN HANDLE ProcessHandle
,
5032 IN OUT PULONG_PTR NumberOfPages
,
5033 IN OUT PULONG_PTR UserPfnArray
)
5036 return STATUS_NOT_IMPLEMENTED
;
5041 NtMapUserPhysicalPages(IN PVOID VirtualAddresses
,
5042 IN ULONG_PTR NumberOfPages
,
5043 IN OUT PULONG_PTR UserPfnArray
)
5046 return STATUS_NOT_IMPLEMENTED
;
5051 NtMapUserPhysicalPagesScatter(IN PVOID
*VirtualAddresses
,
5052 IN ULONG_PTR NumberOfPages
,
5053 IN OUT PULONG_PTR UserPfnArray
)
5056 return STATUS_NOT_IMPLEMENTED
;
5061 NtFreeUserPhysicalPages(IN HANDLE ProcessHandle
,
5062 IN OUT PULONG_PTR NumberOfPages
,
5063 IN OUT PULONG_PTR UserPfnArray
)
5066 return STATUS_NOT_IMPLEMENTED
;
5071 NtAreMappedFilesTheSame(IN PVOID File1MappedAsAnImage
,
5072 IN PVOID File2MappedAsFile
)
5075 return STATUS_NOT_IMPLEMENTED
;